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",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// genManyPred creates an array of blocks where 1/3rd have a sucessor of the
|
|
|
|
|
// 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",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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
|
|
|
|
|
// sucessor of the first or last block.
|
|
|
|
|
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",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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) {
|
2016-01-27 16:47:23 -08:00
|
|
|
c := NewConfig("amd64", DummyFrontend{b}, nil, true)
|
2015-06-25 23:13:57 -05:00
|
|
|
fun := Fun(c, "entry", bg(size)...)
|
|
|
|
|
|
|
|
|
|
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)
|
2015-07-05 18:23:25 -05:00
|
|
|
fun := Fun(c, "entry",
|
|
|
|
|
Bloc("entry",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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)
|
2015-06-25 23:13:57 -05:00
|
|
|
fun := Fun(c, "entry",
|
|
|
|
|
Bloc("entry",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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)
|
2015-06-25 23:13:57 -05:00
|
|
|
fun := Fun(c, "entry",
|
|
|
|
|
Bloc("entry",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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)
|
2015-07-05 18:23:25 -05:00
|
|
|
fun := Fun(c, "entry",
|
|
|
|
|
Bloc("entry",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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)
|
2015-06-25 23:13:57 -05:00
|
|
|
fun := Fun(c, "entry",
|
|
|
|
|
Bloc("entry",
|
2015-08-12 14:51:24 -07:00
|
|
|
Goto("first")),
|
|
|
|
|
Bloc("first",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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)
|
2015-06-25 23:13:57 -05:00
|
|
|
fun := Fun(c, "entry",
|
|
|
|
|
Bloc("entry",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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 TestPostDominators(t *testing.T) {
|
2015-07-30 11:03:05 -07:00
|
|
|
c := testConfig(t)
|
2015-07-05 18:23:25 -05:00
|
|
|
fun := Fun(c, "entry",
|
|
|
|
|
Bloc("entry",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
2015-09-03 18:24:22 -05:00
|
|
|
Valu("p", OpConstBool, TypeBool, 1, nil),
|
2015-07-05 18:23:25 -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{"entry": "c",
|
|
|
|
|
"a": "c",
|
|
|
|
|
"b": "c",
|
|
|
|
|
"c": "exit",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CheckFunc(fun.f)
|
|
|
|
|
verifyDominators(t, fun, postDominators, 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
|
|
|
|
|
fun := Fun(c, "entry",
|
|
|
|
|
Bloc("entry",
|
2015-11-02 08:10:26 -08:00
|
|
|
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
|
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)
|
|
|
|
|
|
|
|
|
|
// no exit block, so there are no post-dominators
|
|
|
|
|
postDoms := map[string]string{}
|
|
|
|
|
verifyDominators(t, fun, postDominators, postDoms)
|
2015-06-25 23:13:57 -05:00
|
|
|
}
|