pass: test for liveness

This commit is contained in:
Michael McLoughlin
2018-12-03 20:40:43 -08:00
parent b52c67f3fb
commit faafa00e40
4 changed files with 136 additions and 6 deletions

View File

@@ -6,17 +6,20 @@ import (
"log" "log"
"github.com/mmcloughlin/avo" "github.com/mmcloughlin/avo"
"github.com/mmcloughlin/avo/reg"
) )
type Context struct { type Context struct {
file *avo.File file *avo.File
function *avo.Function function *avo.Function
errs []error errs []error
reg.Collection
} }
func NewContext() *Context { func NewContext() *Context {
return &Context{ return &Context{
file: avo.NewFile(), file: avo.NewFile(),
Collection: *reg.NewCollection(),
} }
} }

90
pass/reg_test.go Normal file
View File

@@ -0,0 +1,90 @@
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")
a := ctx.GP64v()
b := ctx.GP64v()
ctx.MOVQ(operand.Imm(1), a)
ctx.MOVQ(operand.Imm(2), b)
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)
}
}
func AssertRegistersMatchSet(t *testing.T, rs []reg.Register, s map[reg.ID]bool) {
if len(rs) != len(s) {
t.Fatalf("size mismatch")
}
for _, r := range rs {
if _, found := s[r.ID()]; !found {
t.Fatalf("missing register ID %v", r.ID())
}
}
}
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()
}
if len(f.Functions) != 1 {
t.Fatalf("expect 1 function")
}
fn := f.Functions[0]
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
}

33
reg/collection.go Normal file
View File

@@ -0,0 +1,33 @@
package reg
type Collection struct {
vid map[Kind]VID
}
func NewCollection() *Collection {
return &Collection{
vid: map[Kind]VID{},
}
}
func (c *Collection) VirtualRegister(k Kind, s Size) Virtual {
vid := c.vid[k]
c.vid[k]++
return NewVirtual(vid, k, s)
}
func (c *Collection) GP8v() Virtual { return c.GPv(B8) }
func (c *Collection) GP16v() Virtual { return c.GPv(B16) }
func (c *Collection) GP32v() Virtual { return c.GPv(B32) }
func (c *Collection) GP64v() Virtual { return c.GPv(B64) }
func (c *Collection) GPv(s Size) Virtual { return c.VirtualRegister(GP, s) }
func (c *Collection) Xv() Virtual { return c.VirtualRegister(SSEAVX, B128) }
func (c *Collection) Yv() Virtual { return c.VirtualRegister(SSEAVX, B256) }
func (c *Collection) Zv() Virtual { return c.VirtualRegister(SSEAVX, B512) }

View File

@@ -38,11 +38,7 @@ func (f *Family) define(s Spec, id PID, name string) Physical {
} }
func (f *Family) Virtual(id VID, s Size) Virtual { func (f *Family) Virtual(id VID, s Size) Virtual {
return virtual{ return NewVirtual(id, f.Kind, s)
id: id,
kind: f.Kind,
Size: s,
}
} }
type private interface { type private interface {
@@ -74,6 +70,14 @@ type virtual struct {
Size Size
} }
func NewVirtual(id VID, k Kind, s Size) Virtual {
return virtual{
id: id,
kind: k,
Size: s,
}
}
func (v virtual) VirtualID() VID { return v.id } func (v virtual) VirtualID() VID { return v.id }
func (v virtual) Kind() Kind { return v.kind } func (v virtual) Kind() Kind { return v.kind }