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