mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Provide indexes along with block pointers for Preds and Succs arrays. This allows us to splice edges in and out of those arrays in constant time. Fixes worst-case O(n^2) behavior in deadcode and fuse. benchmark old ns/op new ns/op delta BenchmarkFuse1-8 2065 2057 -0.39% BenchmarkFuse10-8 9408 9073 -3.56% BenchmarkFuse100-8 105238 76277 -27.52% BenchmarkFuse1000-8 3982562 1026750 -74.22% BenchmarkFuse10000-8 301220329 12824005 -95.74% BenchmarkDeadCode1-8 1588 1566 -1.39% BenchmarkDeadCode10-8 4333 4250 -1.92% BenchmarkDeadCode100-8 32031 32574 +1.70% BenchmarkDeadCode1000-8 590407 468275 -20.69% BenchmarkDeadCode10000-8 17822890 5000818 -71.94% BenchmarkDeadCode100000-8 1388706640 78021127 -94.38% BenchmarkDeadCode200000-8 5372518479 168598762 -96.86% Change-Id: Iccabdbb9343fd1c921ba07bbf673330a1c36ee17 Reviewed-on: https://go-review.googlesource.com/22589 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com> Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
133 lines
2.8 KiB
Go
133 lines
2.8 KiB
Go
// 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 {
|
|
e := b.Preds[i]
|
|
p := e.b
|
|
if p.Kind != BlockIf {
|
|
continue
|
|
}
|
|
if p.Control != a {
|
|
continue
|
|
}
|
|
if e.i == 0 {
|
|
v.SetArg(i, ct)
|
|
} else {
|
|
v.SetArg(i, cf)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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.
|
|
e1 := b.Preds[i]
|
|
p := e1.b
|
|
pi := e1.i
|
|
|
|
// The successor we always go to when coming in
|
|
// from that predecessor.
|
|
e2 := b.Succs[1-a.AuxInt]
|
|
t := e2.b
|
|
ti := e2.i
|
|
|
|
// 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)}
|
|
|
|
// Fix up t to have one more predecessor.
|
|
t.Preds = append(t.Preds, Edge{p, pi})
|
|
for _, w := range t.Values {
|
|
if w.Op != OpPhi {
|
|
continue
|
|
}
|
|
w.AddArg(w.Args[ti])
|
|
}
|
|
|
|
if len(b.Preds) == 1 {
|
|
v.Op = OpCopy
|
|
// No longer a phi, stop optimizing here.
|
|
break
|
|
}
|
|
i--
|
|
}
|
|
}
|
|
}
|