From faafa00e403dd940fba75f0f79649b07c8e50461 Mon Sep 17 00:00:00 2001 From: Michael McLoughlin Date: Mon, 3 Dec 2018 20:40:43 -0800 Subject: [PATCH] pass: test for liveness --- build/context.go | 5 ++- pass/reg_test.go | 90 +++++++++++++++++++++++++++++++++++++++++++++++ reg/collection.go | 33 +++++++++++++++++ reg/types.go | 14 +++++--- 4 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 pass/reg_test.go create mode 100644 reg/collection.go diff --git a/build/context.go b/build/context.go index 3744b9b..ea86117 100644 --- a/build/context.go +++ b/build/context.go @@ -6,17 +6,20 @@ import ( "log" "github.com/mmcloughlin/avo" + "github.com/mmcloughlin/avo/reg" ) type Context struct { file *avo.File function *avo.Function errs []error + reg.Collection } func NewContext() *Context { return &Context{ - file: avo.NewFile(), + file: avo.NewFile(), + Collection: *reg.NewCollection(), } } diff --git a/pass/reg_test.go b/pass/reg_test.go new file mode 100644 index 0000000..d4dd542 --- /dev/null +++ b/pass/reg_test.go @@ -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 +} diff --git a/reg/collection.go b/reg/collection.go new file mode 100644 index 0000000..70ca8c6 --- /dev/null +++ b/reg/collection.go @@ -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) } diff --git a/reg/types.go b/reg/types.go index 1400a0c..ed455ee 100644 --- a/reg/types.go +++ b/reg/types.go @@ -38,11 +38,7 @@ func (f *Family) define(s Spec, id PID, name string) Physical { } func (f *Family) Virtual(id VID, s Size) Virtual { - return virtual{ - id: id, - kind: f.Kind, - Size: s, - } + return NewVirtual(id, f.Kind, s) } type private interface { @@ -74,6 +70,14 @@ type virtual struct { 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) Kind() Kind { return v.kind }