2018-12-03 20:40:43 -08:00
|
|
|
package pass_test
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"github.com/mmcloughlin/avo/reg"
|
|
|
|
|
|
|
|
|
|
"github.com/mmcloughlin/avo/pass"
|
|
|
|
|
|
|
|
|
|
"github.com/mmcloughlin/avo"
|
|
|
|
|
"github.com/mmcloughlin/avo/build"
|
|
|
|
|
"github.com/mmcloughlin/avo/operand"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestLivenessBasic(t *testing.T) {
|
|
|
|
|
// Build: a = 1, b = 2, a = a+b
|
|
|
|
|
ctx := build.NewContext()
|
|
|
|
|
ctx.Function("add")
|
2019-01-04 18:23:44 -08:00
|
|
|
a := ctx.GP64()
|
|
|
|
|
b := ctx.GP64()
|
2018-12-26 16:42:39 -08:00
|
|
|
ctx.MOVQ(operand.U64(1), a)
|
|
|
|
|
ctx.MOVQ(operand.U64(2), b)
|
2018-12-03 20:40:43 -08:00
|
|
|
ctx.ADDQ(a, b)
|
|
|
|
|
|
|
|
|
|
AssertLiveness(t, ctx,
|
|
|
|
|
[][]reg.Register{
|
|
|
|
|
{},
|
|
|
|
|
{a},
|
|
|
|
|
{a, b},
|
|
|
|
|
},
|
|
|
|
|
[][]reg.Register{
|
|
|
|
|
{a},
|
|
|
|
|
{a, b},
|
|
|
|
|
{},
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func AssertLiveness(t *testing.T, ctx *build.Context, in, out [][]reg.Register) {
|
|
|
|
|
fn := ConstructLiveness(t, ctx)
|
|
|
|
|
is := fn.Instructions()
|
|
|
|
|
|
|
|
|
|
if len(in) != len(is) || len(out) != len(is) {
|
|
|
|
|
t.Fatalf("%d instructions: %d/%d in/out expectations", len(is), len(in), len(out))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for idx, i := range is {
|
|
|
|
|
AssertRegistersMatchSet(t, in[idx], i.LiveIn)
|
|
|
|
|
AssertRegistersMatchSet(t, out[idx], i.LiveOut)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-03 22:39:43 -08:00
|
|
|
func AssertRegistersMatchSet(t *testing.T, rs []reg.Register, s reg.Set) {
|
|
|
|
|
if !s.Equals(reg.NewSetFromSlice(rs)) {
|
|
|
|
|
t.Fatalf("register slice does not match set: %#v and %#v", rs, s)
|
2018-12-03 20:40:43 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ConstructLiveness(t *testing.T, ctx *build.Context) *avo.Function {
|
|
|
|
|
f, errs := ctx.Result()
|
|
|
|
|
if errs != nil {
|
|
|
|
|
for _, err := range errs {
|
|
|
|
|
t.Error(err)
|
|
|
|
|
}
|
|
|
|
|
t.FailNow()
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-26 18:58:12 -08:00
|
|
|
fns := f.Functions()
|
|
|
|
|
if len(fns) != 1 {
|
2018-12-03 20:40:43 -08:00
|
|
|
t.Fatalf("expect 1 function")
|
|
|
|
|
}
|
2018-12-26 18:58:12 -08:00
|
|
|
fn := fns[0]
|
2018-12-03 20:40:43 -08:00
|
|
|
|
|
|
|
|
passes := []func(*avo.Function) error{
|
|
|
|
|
pass.LabelTarget,
|
|
|
|
|
pass.CFG,
|
|
|
|
|
pass.Liveness,
|
|
|
|
|
}
|
|
|
|
|
for _, p := range passes {
|
|
|
|
|
if err := p(fn); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fn
|
|
|
|
|
}
|