2016-01-25 09:21:17 -08:00
|
|
|
// Copyright 2016 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package ssa
|
|
|
|
|
|
|
|
|
|
// Shortcircuit finds situations where branch directions
|
|
|
|
|
// are always correlated and rewrites the CFG to take
|
|
|
|
|
// advantage of that fact.
|
|
|
|
|
// This optimization is useful for compiling && and || expressions.
|
|
|
|
|
func shortcircuit(f *Func) {
|
|
|
|
|
// Step 1: Replace a phi arg with a constant if that arg
|
|
|
|
|
// is the control value of a preceding If block.
|
|
|
|
|
// b1:
|
|
|
|
|
// If a goto b2 else b3
|
|
|
|
|
// b2: <- b1 ...
|
|
|
|
|
// x = phi(a, ...)
|
|
|
|
|
//
|
|
|
|
|
// We can replace the "a" in the phi with the constant true.
|
|
|
|
|
ct := f.ConstBool(f.Entry.Line, f.Config.fe.TypeBool(), true)
|
|
|
|
|
cf := f.ConstBool(f.Entry.Line, f.Config.fe.TypeBool(), false)
|
|
|
|
|
for _, b := range f.Blocks {
|
|
|
|
|
for _, v := range b.Values {
|
|
|
|
|
if v.Op != OpPhi {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if !v.Type.IsBoolean() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
for i, a := range v.Args {
|
2016-04-28 16:52:47 -07:00
|
|
|
e := b.Preds[i]
|
|
|
|
|
p := e.b
|
2016-01-25 09:21:17 -08:00
|
|
|
if p.Kind != BlockIf {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if p.Control != a {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2016-04-28 16:52:47 -07:00
|
|
|
if e.i == 0 {
|
2016-03-15 20:45:50 -07:00
|
|
|
v.SetArg(i, ct)
|
2016-01-25 09:21:17 -08:00
|
|
|
} else {
|
2016-03-15 20:45:50 -07:00
|
|
|
v.SetArg(i, cf)
|
2016-01-25 09:21:17 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 2: Compute which values are live across blocks.
|
|
|
|
|
live := make([]bool, f.NumValues())
|
|
|
|
|
for _, b := range f.Blocks {
|
|
|
|
|
for _, v := range b.Values {
|
|
|
|
|
for _, a := range v.Args {
|
|
|
|
|
if a.Block != v.Block {
|
|
|
|
|
live[a.ID] = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if b.Control != nil && b.Control.Block != b {
|
|
|
|
|
live[b.Control.ID] = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 3: Redirect control flow around known branches.
|
|
|
|
|
// p:
|
|
|
|
|
// ... goto b ...
|
|
|
|
|
// b: <- p ...
|
|
|
|
|
// v = phi(true, ...)
|
|
|
|
|
// if v goto t else u
|
|
|
|
|
// We can redirect p to go directly to t instead of b.
|
|
|
|
|
// (If v is not live after b).
|
|
|
|
|
for _, b := range f.Blocks {
|
|
|
|
|
if b.Kind != BlockIf {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if len(b.Values) != 1 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
v := b.Values[0]
|
|
|
|
|
if v.Op != OpPhi {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if b.Control != v {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if live[v.ID] {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
for i := 0; i < len(v.Args); i++ {
|
|
|
|
|
a := v.Args[i]
|
|
|
|
|
if a.Op != OpConstBool {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The predecessor we come in from.
|
2016-04-28 16:52:47 -07:00
|
|
|
e1 := b.Preds[i]
|
|
|
|
|
p := e1.b
|
|
|
|
|
pi := e1.i
|
|
|
|
|
|
2016-01-25 09:21:17 -08:00
|
|
|
// The successor we always go to when coming in
|
|
|
|
|
// from that predecessor.
|
2016-04-28 16:52:47 -07:00
|
|
|
e2 := b.Succs[1-a.AuxInt]
|
|
|
|
|
t := e2.b
|
|
|
|
|
ti := e2.i
|
2016-01-25 09:21:17 -08:00
|
|
|
|
2016-04-28 16:52:47 -07:00
|
|
|
// Remove b's incoming edge from p.
|
|
|
|
|
b.removePred(i)
|
|
|
|
|
n := len(b.Preds)
|
|
|
|
|
v.Args[i].Uses--
|
|
|
|
|
v.Args[i] = v.Args[n]
|
|
|
|
|
v.Args[n] = nil
|
|
|
|
|
v.Args = v.Args[:n]
|
|
|
|
|
|
|
|
|
|
// Redirect p's outgoing edge to t.
|
|
|
|
|
p.Succs[pi] = Edge{t, len(t.Preds)}
|
2016-01-25 09:21:17 -08:00
|
|
|
|
|
|
|
|
// Fix up t to have one more predecessor.
|
2016-04-28 16:52:47 -07:00
|
|
|
t.Preds = append(t.Preds, Edge{p, pi})
|
2016-01-25 09:21:17 -08:00
|
|
|
for _, w := range t.Values {
|
|
|
|
|
if w.Op != OpPhi {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2016-04-28 16:52:47 -07:00
|
|
|
w.AddArg(w.Args[ti])
|
2016-01-25 09:21:17 -08:00
|
|
|
}
|
|
|
|
|
|
2016-04-28 16:52:47 -07:00
|
|
|
if len(b.Preds) == 1 {
|
2016-01-25 09:21:17 -08:00
|
|
|
v.Op = OpCopy
|
|
|
|
|
// No longer a phi, stop optimizing here.
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
i--
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|