// 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
|
|
import "testing"
|
|
type lca interface {
|
find(a, b *Block) *Block
|
}
|
|
func lcaEqual(f *Func, lca1, lca2 lca) bool {
|
for _, b := range f.Blocks {
|
for _, c := range f.Blocks {
|
if lca1.find(b, c) != lca2.find(b, c) {
|
return false
|
}
|
}
|
}
|
return true
|
}
|
|
func testLCAgen(t *testing.T, bg blockGen, size int) {
|
c := testConfig(t)
|
fun := c.Fun("entry", bg(size)...)
|
CheckFunc(fun.f)
|
if size == 4 {
|
t.Logf(fun.f.String())
|
}
|
lca1 := makeLCArange(fun.f)
|
lca2 := makeLCAeasy(fun.f)
|
for _, b := range fun.f.Blocks {
|
for _, c := range fun.f.Blocks {
|
l1 := lca1.find(b, c)
|
l2 := lca2.find(b, c)
|
if l1 != l2 {
|
t.Errorf("lca(%s,%s)=%s, want %s", b, c, l1, l2)
|
}
|
}
|
}
|
}
|
|
func TestLCALinear(t *testing.T) {
|
testLCAgen(t, genLinear, 10)
|
testLCAgen(t, genLinear, 100)
|
}
|
|
func TestLCAFwdBack(t *testing.T) {
|
testLCAgen(t, genFwdBack, 10)
|
testLCAgen(t, genFwdBack, 100)
|
}
|
|
func TestLCAManyPred(t *testing.T) {
|
testLCAgen(t, genManyPred, 10)
|
testLCAgen(t, genManyPred, 100)
|
}
|
|
func TestLCAMaxPred(t *testing.T) {
|
testLCAgen(t, genMaxPred, 10)
|
testLCAgen(t, genMaxPred, 100)
|
}
|
|
func TestLCAMaxPredValue(t *testing.T) {
|
testLCAgen(t, genMaxPredValue, 10)
|
testLCAgen(t, genMaxPredValue, 100)
|
}
|
|
// Simple implementation of LCA to compare against.
|
type lcaEasy struct {
|
parent []*Block
|
}
|
|
func makeLCAeasy(f *Func) *lcaEasy {
|
return &lcaEasy{parent: dominators(f)}
|
}
|
|
func (lca *lcaEasy) find(a, b *Block) *Block {
|
da := lca.depth(a)
|
db := lca.depth(b)
|
for da > db {
|
da--
|
a = lca.parent[a.ID]
|
}
|
for da < db {
|
db--
|
b = lca.parent[b.ID]
|
}
|
for a != b {
|
a = lca.parent[a.ID]
|
b = lca.parent[b.ID]
|
}
|
return a
|
}
|
|
func (lca *lcaEasy) depth(b *Block) int {
|
n := 0
|
for b != nil {
|
b = lca.parent[b.ID]
|
n++
|
}
|
return n
|
}
|