|  | // 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 | 
|  | } |