Commit ddb5d0db authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

cmd/compile: process blocks containing only dead values in fuseIf

The code in #29218 resulted in an If block containing only its control.
That block was then converted by fuseIf into a plain block;
as a result, that control value was dead.
However, the control value was still present in b.Values.
This prevented further fusing of that block.

This change beefs up the check in fuseIf to allow fusing
blocks that contain only dead values (if any).
In the case of #29218, this enables enough extra
fusing that the control value could be eliminated,
allowing all values in turn to be eliminated.

This change also fuses 34 new blocks during make.bash.

It is not clear that this fixes every variant of #29218,
but it is a reasonable standalone change.
And code like #29218 is rare and fundamentally buggy,
so we can handle new instances if/when they actually occur.

Fixes #29218

Negligible toolspeed impact.

name        old time/op       new time/op       delta
Template          213ms ± 3%        213ms ± 2%    ~     (p=0.914 n=97+88)
Unicode          89.8ms ± 2%       89.6ms ± 2%  -0.22%  (p=0.045 n=93+95)
GoTypes           712ms ± 3%        709ms ± 2%  -0.35%  (p=0.023 n=95+95)
Compiler          3.24s ± 2%        3.23s ± 2%  -0.30%  (p=0.020 n=98+97)
SSA               10.0s ± 1%        10.0s ± 1%    ~     (p=0.382 n=98+99)
Flate             135ms ± 3%        135ms ± 2%    ~     (p=0.983 n=98+98)
GoParser          158ms ± 2%        158ms ± 2%    ~     (p=0.170 n=99+99)
Reflect           447ms ± 3%        447ms ± 2%    ~     (p=0.538 n=98+89)
Tar               189ms ± 2%        189ms ± 3%    ~     (p=0.874 n=95+96)
XML               251ms ± 2%        251ms ± 2%    ~     (p=0.434 n=94+96)
[Geo mean]        427ms             426ms       -0.15%

name        old user-time/op  new user-time/op  delta
Template          264ms ± 2%        265ms ± 2%    ~     (p=0.075 n=96+90)
Unicode           119ms ± 6%        119ms ± 7%    ~     (p=0.864 n=99+98)
GoTypes           926ms ± 2%        924ms ± 2%    ~     (p=0.071 n=94+94)
Compiler          4.38s ± 2%        4.37s ± 2%  -0.34%  (p=0.001 n=98+97)
SSA               13.4s ± 1%        13.4s ± 1%    ~     (p=0.693 n=90+93)
Flate             162ms ± 3%        161ms ± 2%    ~     (p=0.163 n=99+99)
GoParser          186ms ± 2%        186ms ± 3%    ~     (p=0.130 n=96+100)
Reflect           572ms ± 3%        572ms ± 2%    ~     (p=0.608 n=97+97)
Tar               239ms ± 2%        239ms ± 3%    ~     (p=0.999 n=93+91)
XML               302ms ± 2%        302ms ± 2%    ~     (p=0.627 n=91+97)
[Geo mean]        540ms             540ms       -0.08%

file    before    after     Δ       %       
asm     4862704   4858608   -4096   -0.084% 
compile 24001568  24001680  +112    +0.000% 
total   132520780 132516796 -3984   -0.003% 

file                       before    after     Δ       %       
cmd/compile/internal/gc.a  8887638   8887596   -42     -0.000% 
cmd/compile/internal/ssa.a 29995056  29998986  +3930   +0.013% 
cmd/internal/obj/wasm.a    209444    203652    -5792   -2.765% 
total                      129471798 129469894 -1904   -0.001% 

Change-Id: I2d18f9278e68b9766058ae8ca621e844f9d89dd8
Reviewed-on: https://go-review.googlesource.com/c/go/+/177140
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
Reviewed-by: default avatarCuong Manh Le <cuong.manhle.vn@gmail.com>
parent bd61fc3d
...@@ -66,7 +66,7 @@ func fuseBlockIf(b *Block) bool { ...@@ -66,7 +66,7 @@ func fuseBlockIf(b *Block) bool {
var ss0, ss1 *Block var ss0, ss1 *Block
s0 := b.Succs[0].b s0 := b.Succs[0].b
i0 := b.Succs[0].i i0 := b.Succs[0].i
if s0.Kind != BlockPlain || len(s0.Preds) != 1 || len(s0.Values) != 0 { if s0.Kind != BlockPlain || len(s0.Preds) != 1 || !isEmpty(s0) {
s0, ss0 = b, s0 s0, ss0 = b, s0
} else { } else {
ss0 = s0.Succs[0].b ss0 = s0.Succs[0].b
...@@ -74,7 +74,7 @@ func fuseBlockIf(b *Block) bool { ...@@ -74,7 +74,7 @@ func fuseBlockIf(b *Block) bool {
} }
s1 := b.Succs[1].b s1 := b.Succs[1].b
i1 := b.Succs[1].i i1 := b.Succs[1].i
if s1.Kind != BlockPlain || len(s1.Preds) != 1 || len(s1.Values) != 0 { if s1.Kind != BlockPlain || len(s1.Preds) != 1 || !isEmpty(s1) {
s1, ss1 = b, s1 s1, ss1 = b, s1
} else { } else {
ss1 = s1.Succs[0].b ss1 = s1.Succs[0].b
...@@ -120,18 +120,34 @@ func fuseBlockIf(b *Block) bool { ...@@ -120,18 +120,34 @@ func fuseBlockIf(b *Block) bool {
b.Likely = BranchUnknown b.Likely = BranchUnknown
b.SetControl(nil) b.SetControl(nil)
// Trash the empty blocks s0 & s1. // Trash the empty blocks s0 and s1.
if s0 != b { blocks := [...]*Block{s0, s1}
s0.Kind = BlockInvalid for _, s := range &blocks {
s0.Values = nil if s == b {
s0.Succs = nil continue
s0.Preds = nil }
} // Move any (dead) values in s0 or s1 to b,
if s1 != b { // where they will be eliminated by the next deadcode pass.
s1.Kind = BlockInvalid for _, v := range s.Values {
s1.Values = nil v.Block = b
s1.Succs = nil }
s1.Preds = nil b.Values = append(b.Values, s.Values...)
// Clear s.
s.Kind = BlockInvalid
s.Values = nil
s.Succs = nil
s.Preds = nil
}
return true
}
// isEmpty reports whether b contains any live values.
// There may be false positives.
func isEmpty(b *Block) bool {
for _, v := range b.Values {
if v.Uses > 0 || v.Type.IsVoid() {
return false
}
} }
return true return true
} }
......
// compile
// Copyright 2019 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 p
type T struct {
b bool
string
}
func f() {
var b bool
var t T
for {
switch &t.b {
case &b:
if b {
}
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment