2015-06-25 23:13:57 -05:00
|
|
|
// Copyright 2015 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
|
|
|
|
|
|
2015-07-05 18:23:25 -05:00
|
|
|
import "testing"
|
2015-06-25 23:13:57 -05:00
|
|
|
|
|
|
|
|
func BenchmarkDominatorsLinear(b *testing.B) { benchmarkDominators(b, 10000, genLinear) }
|
|
|
|
|
func BenchmarkDominatorsFwdBack(b *testing.B) { benchmarkDominators(b, 10000, genFwdBack) }
|
|
|
|
|
func BenchmarkDominatorsManyPred(b *testing.B) { benchmarkDominators(b, 10000, genManyPred) }
|
|
|
|
|
func BenchmarkDominatorsMaxPred(b *testing.B) { benchmarkDominators(b, 10000, genMaxPred) }
|
|
|
|
|
func BenchmarkDominatorsMaxPredVal(b *testing.B) { benchmarkDominators(b, 10000, genMaxPredValue) }
|
|
|
|
|
|
|
|
|
|
type blockGen func(size int) []bloc
|
|
|
|
|
|
|
|
|
|
// genLinear creates an array of blocks that succeed one another
|
|
|
|
|
// b_n -> [b_n+1].
|
|
|
|
|
func genLinear(size int) []bloc {
|
|
|
|
|
var blocs []bloc
|
|
|
|
|
blocs = append(blocs,
|
|
|
|
|
Bloc("entry",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
Goto(blockn(0)),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
for i := 0; i < size; i++ {
|
|
|
|
|
blocs = append(blocs, Bloc(blockn(i),
|
|
|
|
|
Goto(blockn(i+1))))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
blocs = append(blocs,
|
|
|
|
|
Bloc(blockn(size), Goto("exit")),
|
|
|
|
|
Bloc("exit", Exit("mem")),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return blocs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// genLinear creates an array of blocks that alternate between
|
|
|
|
|
// b_n -> [b_n+1], b_n -> [b_n+1, b_n-1] , b_n -> [b_n+1, b_n+2]
|
|
|
|
|
func genFwdBack(size int) []bloc {
|
|
|
|
|
var blocs []bloc
|
|
|
|
|
blocs = append(blocs,
|
|
|
|
|
Bloc("entry",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("p", OpConstBool, TypeBool, 1, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
Goto(blockn(0)),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
for i := 0; i < size; i++ {
|
|
|
|
|
switch i % 2 {
|
|
|
|
|
case 0:
|
|
|
|
|
blocs = append(blocs, Bloc(blockn(i),
|
|
|
|
|
If("p", blockn(i+1), blockn(i+2))))
|
|
|
|
|
case 1:
|
|
|
|
|
blocs = append(blocs, Bloc(blockn(i),
|
|
|
|
|
If("p", blockn(i+1), blockn(i-1))))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
blocs = append(blocs,
|
|
|
|
|
Bloc(blockn(size), Goto("exit")),
|
|
|
|
|
Bloc("exit", Exit("mem")),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return blocs
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-03 12:43:27 +01:00
|
|
|
// genManyPred creates an array of blocks where 1/3rd have a successor of the
|
2015-06-25 23:13:57 -05:00
|
|
|
// first block, 1/3rd the last block, and the remaining third are plain.
|
|
|
|
|
func genManyPred(size int) []bloc {
|
|
|
|
|
var blocs []bloc
|
|
|
|
|
blocs = append(blocs,
|
|
|
|
|
Bloc("entry",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("p", OpConstBool, TypeBool, 1, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
Goto(blockn(0)),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// We want predecessor lists to be long, so 2/3rds of the blocks have a
|
2016-04-03 12:43:27 +01:00
|
|
|
// successor of the first or last block.
|
2015-06-25 23:13:57 -05:00
|
|
|
for i := 0; i < size; i++ {
|
|
|
|
|
switch i % 3 {
|
|
|
|
|
case 0:
|
|
|
|
|
blocs = append(blocs, Bloc(blockn(i),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("a", OpConstBool, TypeBool, 1, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
Goto(blockn(i+1))))
|
|
|
|
|
case 1:
|
|
|
|
|
blocs = append(blocs, Bloc(blockn(i),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("a", OpConstBool, TypeBool, 1, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
If("p", blockn(i+1), blockn(0))))
|
|
|
|
|
case 2:
|
|
|
|
|
blocs = append(blocs, Bloc(blockn(i),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("a", OpConstBool, TypeBool, 1, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
If("p", blockn(i+1), blockn(size))))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
blocs = append(blocs,
|
|
|
|
|
Bloc(blockn(size), Goto("exit")),
|
|
|
|
|
Bloc("exit", Exit("mem")),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return blocs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// genMaxPred maximizes the size of the 'exit' predecessor list.
|
|
|
|
|
func genMaxPred(size int) []bloc {
|
|
|
|
|
var blocs []bloc
|
|
|
|
|
blocs = append(blocs,
|
|
|
|
|
Bloc("entry",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("p", OpConstBool, TypeBool, 1, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
Goto(blockn(0)),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for i := 0; i < size; i++ {
|
|
|
|
|
blocs = append(blocs, Bloc(blockn(i),
|
|
|
|
|
If("p", blockn(i+1), "exit")))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
blocs = append(blocs,
|
|
|
|
|
Bloc(blockn(size), Goto("exit")),
|
|
|
|
|
Bloc("exit", Exit("mem")),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return blocs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// genMaxPredValue is identical to genMaxPred but contains an
|
|
|
|
|
// additional value.
|
|
|
|
|
func genMaxPredValue(size int) []bloc {
|
|
|
|
|
var blocs []bloc
|
|
|
|
|
blocs = append(blocs,
|
|
|
|
|
Bloc("entry",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("p", OpConstBool, TypeBool, 1, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
Goto(blockn(0)),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for i := 0; i < size; i++ {
|
|
|
|
|
blocs = append(blocs, Bloc(blockn(i),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("a", OpConstBool, TypeBool, 1, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
If("p", blockn(i+1), "exit")))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
blocs = append(blocs,
|
|
|
|
|
Bloc(blockn(size), Goto("exit")),
|
|
|
|
|
Bloc("exit", Exit("mem")),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return blocs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sink for benchmark
|
|
|
|
|
var domBenchRes []*Block
|
|
|
|
|
|
|
|
|
|
func benchmarkDominators(b *testing.B, size int, bg blockGen) {
|
2017-03-16 22:42:10 -07:00
|
|
|
c := NewConfig("amd64", nil, true)
|
|
|
|
|
fun := Fun(c, DummyFrontend{b}, "entry", bg(size)...)
|
2015-06-25 23:13:57 -05:00
|
|
|
|
|
|
|
|
CheckFunc(fun.f)
|
|
|
|
|
b.SetBytes(int64(size))
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
domBenchRes = dominators(fun.f)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-05 18:23:25 -05:00
|
|
|
type domFunc func(f *Func) []*Block
|
|
|
|
|
|
|
|
|
|
// verifyDominators verifies that the dominators of fut (function under test)
|
|
|
|
|
// as determined by domFn, match the map node->dominator
|
|
|
|
|
func verifyDominators(t *testing.T, fut fun, domFn domFunc, doms map[string]string) {
|
2015-06-25 23:13:57 -05:00
|
|
|
blockNames := map[*Block]string{}
|
2015-07-05 18:23:25 -05:00
|
|
|
for n, b := range fut.blocks {
|
2015-06-25 23:13:57 -05:00
|
|
|
blockNames[b] = n
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-05 18:23:25 -05:00
|
|
|
calcDom := domFn(fut.f)
|
2015-06-25 23:13:57 -05:00
|
|
|
|
|
|
|
|
for n, d := range doms {
|
2015-07-05 18:23:25 -05:00
|
|
|
nblk, ok := fut.blocks[n]
|
2015-06-25 23:13:57 -05:00
|
|
|
if !ok {
|
|
|
|
|
t.Errorf("invalid block name %s", n)
|
|
|
|
|
}
|
2015-07-05 18:23:25 -05:00
|
|
|
dblk, ok := fut.blocks[d]
|
2015-06-25 23:13:57 -05:00
|
|
|
if !ok {
|
|
|
|
|
t.Errorf("invalid block name %s", d)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
domNode := calcDom[nblk.ID]
|
|
|
|
|
switch {
|
|
|
|
|
case calcDom[nblk.ID] == dblk:
|
|
|
|
|
calcDom[nblk.ID] = nil
|
|
|
|
|
continue
|
|
|
|
|
case calcDom[nblk.ID] != dblk:
|
|
|
|
|
t.Errorf("expected %s as dominator of %s, found %s", d, n, blockNames[domNode])
|
|
|
|
|
default:
|
|
|
|
|
t.Fatal("unexpected dominator condition")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for id, d := range calcDom {
|
|
|
|
|
// If nil, we've already verified it
|
|
|
|
|
if d == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2015-07-05 18:23:25 -05:00
|
|
|
for _, b := range fut.blocks {
|
2015-06-25 23:13:57 -05:00
|
|
|
if int(b.ID) == id {
|
|
|
|
|
t.Errorf("unexpected dominator of %s for %s", blockNames[d], blockNames[b])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-05 18:23:25 -05:00
|
|
|
func TestDominatorsSingleBlock(t *testing.T) {
|
2015-07-30 11:03:05 -07:00
|
|
|
c := testConfig(t)
|
2017-03-16 22:42:10 -07:00
|
|
|
fun := Fun(c, DummyFrontend{t}, "entry",
|
2015-07-05 18:23:25 -05:00
|
|
|
Bloc("entry",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-07-05 18:23:25 -05:00
|
|
|
Exit("mem")))
|
|
|
|
|
|
|
|
|
|
doms := map[string]string{}
|
|
|
|
|
|
|
|
|
|
CheckFunc(fun.f)
|
|
|
|
|
verifyDominators(t, fun, dominators, doms)
|
|
|
|
|
verifyDominators(t, fun, dominatorsSimple, doms)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-25 23:13:57 -05:00
|
|
|
func TestDominatorsSimple(t *testing.T) {
|
2015-07-30 11:03:05 -07:00
|
|
|
c := testConfig(t)
|
2017-03-16 22:42:10 -07:00
|
|
|
fun := Fun(c, DummyFrontend{t}, "entry",
|
2015-06-25 23:13:57 -05:00
|
|
|
Bloc("entry",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
Goto("a")),
|
|
|
|
|
Bloc("a",
|
|
|
|
|
Goto("b")),
|
|
|
|
|
Bloc("b",
|
|
|
|
|
Goto("c")),
|
|
|
|
|
Bloc("c",
|
|
|
|
|
Goto("exit")),
|
|
|
|
|
Bloc("exit",
|
|
|
|
|
Exit("mem")))
|
|
|
|
|
|
|
|
|
|
doms := map[string]string{
|
|
|
|
|
"a": "entry",
|
|
|
|
|
"b": "a",
|
|
|
|
|
"c": "b",
|
|
|
|
|
"exit": "c",
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-05 18:23:25 -05:00
|
|
|
CheckFunc(fun.f)
|
|
|
|
|
verifyDominators(t, fun, dominators, doms)
|
|
|
|
|
verifyDominators(t, fun, dominatorsSimple, doms)
|
2015-06-25 23:13:57 -05:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDominatorsMultPredFwd(t *testing.T) {
|
2015-07-30 11:03:05 -07:00
|
|
|
c := testConfig(t)
|
2017-03-16 22:42:10 -07:00
|
|
|
fun := Fun(c, DummyFrontend{t}, "entry",
|
2015-06-25 23:13:57 -05:00
|
|
|
Bloc("entry",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("p", OpConstBool, TypeBool, 1, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
If("p", "a", "c")),
|
|
|
|
|
Bloc("a",
|
|
|
|
|
If("p", "b", "c")),
|
|
|
|
|
Bloc("b",
|
|
|
|
|
Goto("c")),
|
|
|
|
|
Bloc("c",
|
|
|
|
|
Goto("exit")),
|
|
|
|
|
Bloc("exit",
|
|
|
|
|
Exit("mem")))
|
|
|
|
|
|
|
|
|
|
doms := map[string]string{
|
|
|
|
|
"a": "entry",
|
|
|
|
|
"b": "a",
|
|
|
|
|
"c": "entry",
|
|
|
|
|
"exit": "c",
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-05 18:23:25 -05:00
|
|
|
CheckFunc(fun.f)
|
|
|
|
|
verifyDominators(t, fun, dominators, doms)
|
|
|
|
|
verifyDominators(t, fun, dominatorsSimple, doms)
|
|
|
|
|
}
|
2015-06-25 23:13:57 -05:00
|
|
|
|
2015-07-05 18:23:25 -05:00
|
|
|
func TestDominatorsDeadCode(t *testing.T) {
|
2015-07-30 11:03:05 -07:00
|
|
|
c := testConfig(t)
|
2017-03-16 22:42:10 -07:00
|
|
|
fun := Fun(c, DummyFrontend{t}, "entry",
|
2015-07-05 18:23:25 -05:00
|
|
|
Bloc("entry",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("p", OpConstBool, TypeBool, 0, nil),
|
2015-07-05 18:23:25 -05:00
|
|
|
If("p", "b3", "b5")),
|
|
|
|
|
Bloc("b2", Exit("mem")),
|
|
|
|
|
Bloc("b3", Goto("b2")),
|
|
|
|
|
Bloc("b4", Goto("b2")),
|
|
|
|
|
Bloc("b5", Goto("b2")))
|
|
|
|
|
|
|
|
|
|
doms := map[string]string{
|
|
|
|
|
"b2": "entry",
|
|
|
|
|
"b3": "entry",
|
|
|
|
|
"b5": "entry",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CheckFunc(fun.f)
|
|
|
|
|
verifyDominators(t, fun, dominators, doms)
|
|
|
|
|
verifyDominators(t, fun, dominatorsSimple, doms)
|
2015-06-25 23:13:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDominatorsMultPredRev(t *testing.T) {
|
2015-07-30 11:03:05 -07:00
|
|
|
c := testConfig(t)
|
2017-03-16 22:42:10 -07:00
|
|
|
fun := Fun(c, DummyFrontend{t}, "entry",
|
2015-06-25 23:13:57 -05:00
|
|
|
Bloc("entry",
|
2015-08-12 14:51:24 -07:00
|
|
|
Goto("first")),
|
|
|
|
|
Bloc("first",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("p", OpConstBool, TypeBool, 1, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
Goto("a")),
|
|
|
|
|
Bloc("a",
|
2015-08-12 14:51:24 -07:00
|
|
|
If("p", "b", "first")),
|
2015-06-25 23:13:57 -05:00
|
|
|
Bloc("b",
|
|
|
|
|
Goto("c")),
|
|
|
|
|
Bloc("c",
|
|
|
|
|
If("p", "exit", "b")),
|
|
|
|
|
Bloc("exit",
|
|
|
|
|
Exit("mem")))
|
|
|
|
|
|
|
|
|
|
doms := map[string]string{
|
2015-08-12 14:51:24 -07:00
|
|
|
"first": "entry",
|
|
|
|
|
"a": "first",
|
|
|
|
|
"b": "a",
|
|
|
|
|
"c": "b",
|
|
|
|
|
"exit": "c",
|
2015-06-25 23:13:57 -05:00
|
|
|
}
|
2015-07-05 18:23:25 -05:00
|
|
|
|
|
|
|
|
CheckFunc(fun.f)
|
|
|
|
|
verifyDominators(t, fun, dominators, doms)
|
|
|
|
|
verifyDominators(t, fun, dominatorsSimple, doms)
|
2015-06-25 23:13:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDominatorsMultPred(t *testing.T) {
|
2015-07-30 11:03:05 -07:00
|
|
|
c := testConfig(t)
|
2017-03-16 22:42:10 -07:00
|
|
|
fun := Fun(c, DummyFrontend{t}, "entry",
|
2015-06-25 23:13:57 -05:00
|
|
|
Bloc("entry",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("p", OpConstBool, TypeBool, 1, nil),
|
2015-06-25 23:13:57 -05:00
|
|
|
If("p", "a", "c")),
|
|
|
|
|
Bloc("a",
|
|
|
|
|
If("p", "b", "c")),
|
|
|
|
|
Bloc("b",
|
|
|
|
|
Goto("c")),
|
|
|
|
|
Bloc("c",
|
|
|
|
|
If("p", "b", "exit")),
|
|
|
|
|
Bloc("exit",
|
|
|
|
|
Exit("mem")))
|
|
|
|
|
|
|
|
|
|
doms := map[string]string{
|
|
|
|
|
"a": "entry",
|
|
|
|
|
"b": "entry",
|
|
|
|
|
"c": "entry",
|
|
|
|
|
"exit": "c",
|
|
|
|
|
}
|
2015-07-05 18:23:25 -05:00
|
|
|
|
|
|
|
|
CheckFunc(fun.f)
|
|
|
|
|
verifyDominators(t, fun, dominators, doms)
|
|
|
|
|
verifyDominators(t, fun, dominatorsSimple, doms)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestInfiniteLoop(t *testing.T) {
|
2015-07-30 11:03:05 -07:00
|
|
|
c := testConfig(t)
|
2015-07-05 18:23:25 -05:00
|
|
|
// note lack of an exit block
|
2017-03-16 22:42:10 -07:00
|
|
|
fun := Fun(c, DummyFrontend{t}, "entry",
|
2015-07-05 18:23:25 -05:00
|
|
|
Bloc("entry",
|
2016-01-31 11:39:39 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("p", OpConstBool, TypeBool, 1, nil),
|
2015-07-05 18:23:25 -05:00
|
|
|
Goto("a")),
|
|
|
|
|
Bloc("a",
|
|
|
|
|
Goto("b")),
|
|
|
|
|
Bloc("b",
|
|
|
|
|
Goto("a")))
|
|
|
|
|
|
|
|
|
|
CheckFunc(fun.f)
|
|
|
|
|
doms := map[string]string{"a": "entry",
|
|
|
|
|
"b": "a"}
|
|
|
|
|
verifyDominators(t, fun, dominators, doms)
|
2015-06-25 23:13:57 -05:00
|
|
|
}
|
2016-04-22 12:15:08 -04:00
|
|
|
|
|
|
|
|
func TestDomTricky(t *testing.T) {
|
|
|
|
|
doms := map[string]string{
|
|
|
|
|
"4": "1",
|
|
|
|
|
"2": "4",
|
|
|
|
|
"5": "4",
|
|
|
|
|
"11": "4",
|
|
|
|
|
"15": "4", // the incorrect answer is "5"
|
|
|
|
|
"10": "15",
|
|
|
|
|
"19": "15",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if4 := [2]string{"2", "5"}
|
|
|
|
|
if5 := [2]string{"15", "11"}
|
|
|
|
|
if15 := [2]string{"19", "10"}
|
|
|
|
|
|
|
|
|
|
for i := 0; i < 8; i++ {
|
|
|
|
|
a := 1 & i
|
|
|
|
|
b := 1 & i >> 1
|
|
|
|
|
c := 1 & i >> 2
|
|
|
|
|
|
2017-03-16 22:42:10 -07:00
|
|
|
fun := Fun(testConfig(t), DummyFrontend{t}, "1",
|
2016-04-22 12:15:08 -04:00
|
|
|
Bloc("1",
|
|
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
|
|
|
|
Valu("p", OpConstBool, TypeBool, 1, nil),
|
|
|
|
|
Goto("4")),
|
|
|
|
|
Bloc("2",
|
|
|
|
|
Goto("11")),
|
|
|
|
|
Bloc("4",
|
|
|
|
|
If("p", if4[a], if4[1-a])), // 2, 5
|
|
|
|
|
Bloc("5",
|
|
|
|
|
If("p", if5[b], if5[1-b])), //15, 11
|
|
|
|
|
Bloc("10",
|
|
|
|
|
Exit("mem")),
|
|
|
|
|
Bloc("11",
|
|
|
|
|
Goto("15")),
|
|
|
|
|
Bloc("15",
|
|
|
|
|
If("p", if15[c], if15[1-c])), //19, 10
|
|
|
|
|
Bloc("19",
|
|
|
|
|
Goto("10")))
|
|
|
|
|
CheckFunc(fun.f)
|
|
|
|
|
verifyDominators(t, fun, dominators, doms)
|
|
|
|
|
verifyDominators(t, fun, dominatorsSimple, doms)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-25 16:24:11 -04:00
|
|
|
|
|
|
|
|
// generateDominatorMap uses dominatorsSimple to obtain a
|
|
|
|
|
// reference dominator tree for testing faster algorithms.
|
|
|
|
|
func generateDominatorMap(fut fun) map[string]string {
|
|
|
|
|
blockNames := map[*Block]string{}
|
|
|
|
|
for n, b := range fut.blocks {
|
|
|
|
|
blockNames[b] = n
|
|
|
|
|
}
|
|
|
|
|
referenceDom := dominatorsSimple(fut.f)
|
|
|
|
|
doms := make(map[string]string)
|
|
|
|
|
for _, b := range fut.f.Blocks {
|
|
|
|
|
if d := referenceDom[b.ID]; d != nil {
|
|
|
|
|
doms[blockNames[b]] = blockNames[d]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return doms
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDominatorsPostTricky(t *testing.T) {
|
|
|
|
|
c := testConfig(t)
|
2017-03-16 22:42:10 -07:00
|
|
|
fun := Fun(c, DummyFrontend{t}, "b1",
|
2016-04-25 16:24:11 -04:00
|
|
|
Bloc("b1",
|
|
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
|
|
|
|
Valu("p", OpConstBool, TypeBool, 1, nil),
|
|
|
|
|
If("p", "b3", "b2")),
|
|
|
|
|
Bloc("b3",
|
|
|
|
|
If("p", "b5", "b6")),
|
|
|
|
|
Bloc("b5",
|
|
|
|
|
Goto("b7")),
|
|
|
|
|
Bloc("b7",
|
|
|
|
|
If("p", "b8", "b11")),
|
|
|
|
|
Bloc("b8",
|
|
|
|
|
Goto("b13")),
|
|
|
|
|
Bloc("b13",
|
|
|
|
|
If("p", "b14", "b15")),
|
|
|
|
|
Bloc("b14",
|
|
|
|
|
Goto("b10")),
|
|
|
|
|
Bloc("b15",
|
|
|
|
|
Goto("b16")),
|
|
|
|
|
Bloc("b16",
|
|
|
|
|
Goto("b9")),
|
|
|
|
|
Bloc("b9",
|
|
|
|
|
Goto("b7")),
|
|
|
|
|
Bloc("b11",
|
|
|
|
|
Goto("b12")),
|
|
|
|
|
Bloc("b12",
|
|
|
|
|
If("p", "b10", "b8")),
|
|
|
|
|
Bloc("b10",
|
|
|
|
|
Goto("b6")),
|
|
|
|
|
Bloc("b6",
|
|
|
|
|
Goto("b17")),
|
|
|
|
|
Bloc("b17",
|
|
|
|
|
Goto("b18")),
|
|
|
|
|
Bloc("b18",
|
|
|
|
|
If("p", "b22", "b19")),
|
|
|
|
|
Bloc("b22",
|
|
|
|
|
Goto("b23")),
|
|
|
|
|
Bloc("b23",
|
|
|
|
|
If("p", "b21", "b19")),
|
|
|
|
|
Bloc("b19",
|
|
|
|
|
If("p", "b24", "b25")),
|
|
|
|
|
Bloc("b24",
|
|
|
|
|
Goto("b26")),
|
|
|
|
|
Bloc("b26",
|
|
|
|
|
Goto("b25")),
|
|
|
|
|
Bloc("b25",
|
|
|
|
|
If("p", "b27", "b29")),
|
|
|
|
|
Bloc("b27",
|
|
|
|
|
Goto("b30")),
|
|
|
|
|
Bloc("b30",
|
|
|
|
|
Goto("b28")),
|
|
|
|
|
Bloc("b29",
|
|
|
|
|
Goto("b31")),
|
|
|
|
|
Bloc("b31",
|
|
|
|
|
Goto("b28")),
|
|
|
|
|
Bloc("b28",
|
|
|
|
|
If("p", "b32", "b33")),
|
|
|
|
|
Bloc("b32",
|
|
|
|
|
Goto("b21")),
|
|
|
|
|
Bloc("b21",
|
|
|
|
|
Goto("b47")),
|
|
|
|
|
Bloc("b47",
|
|
|
|
|
If("p", "b45", "b46")),
|
|
|
|
|
Bloc("b45",
|
|
|
|
|
Goto("b48")),
|
|
|
|
|
Bloc("b48",
|
|
|
|
|
Goto("b49")),
|
|
|
|
|
Bloc("b49",
|
|
|
|
|
If("p", "b50", "b51")),
|
|
|
|
|
Bloc("b50",
|
|
|
|
|
Goto("b52")),
|
|
|
|
|
Bloc("b52",
|
|
|
|
|
Goto("b53")),
|
|
|
|
|
Bloc("b53",
|
|
|
|
|
Goto("b51")),
|
|
|
|
|
Bloc("b51",
|
|
|
|
|
Goto("b54")),
|
|
|
|
|
Bloc("b54",
|
|
|
|
|
Goto("b46")),
|
|
|
|
|
Bloc("b46",
|
|
|
|
|
Exit("mem")),
|
|
|
|
|
Bloc("b33",
|
|
|
|
|
Goto("b34")),
|
|
|
|
|
Bloc("b34",
|
|
|
|
|
Goto("b37")),
|
|
|
|
|
Bloc("b37",
|
|
|
|
|
If("p", "b35", "b36")),
|
|
|
|
|
Bloc("b35",
|
|
|
|
|
Goto("b38")),
|
|
|
|
|
Bloc("b38",
|
|
|
|
|
Goto("b39")),
|
|
|
|
|
Bloc("b39",
|
|
|
|
|
If("p", "b40", "b41")),
|
|
|
|
|
Bloc("b40",
|
|
|
|
|
Goto("b42")),
|
|
|
|
|
Bloc("b42",
|
|
|
|
|
Goto("b43")),
|
|
|
|
|
Bloc("b43",
|
|
|
|
|
Goto("b41")),
|
|
|
|
|
Bloc("b41",
|
|
|
|
|
Goto("b44")),
|
|
|
|
|
Bloc("b44",
|
|
|
|
|
Goto("b36")),
|
|
|
|
|
Bloc("b36",
|
|
|
|
|
Goto("b20")),
|
|
|
|
|
Bloc("b20",
|
|
|
|
|
Goto("b18")),
|
|
|
|
|
Bloc("b2",
|
|
|
|
|
Goto("b4")),
|
|
|
|
|
Bloc("b4",
|
|
|
|
|
Exit("mem")))
|
|
|
|
|
CheckFunc(fun.f)
|
|
|
|
|
doms := generateDominatorMap(fun)
|
|
|
|
|
verifyDominators(t, fun, dominators, doms)
|
|
|
|
|
}
|