diff --git a/ast.go b/ast.go index f0c3bb4..1df68f2 100644 --- a/ast.go +++ b/ast.go @@ -47,8 +47,8 @@ type Instruction struct { Succ []*Instruction // LiveIn/LiveOut are sets of live register IDs pre/post execution. - LiveIn map[reg.ID]bool - LiveOut map[reg.ID]bool + LiveIn reg.Set + LiveOut reg.Set } func (i *Instruction) node() {} diff --git a/pass/reg.go b/pass/reg.go index 4e64163..b69defb 100644 --- a/pass/reg.go +++ b/pass/reg.go @@ -11,8 +11,8 @@ func Liveness(fn *avo.Function) error { // Initialize to empty sets. for _, i := range is { - i.LiveIn = map[reg.ID]bool{} - i.LiveOut = map[reg.ID]bool{} + i.LiveIn = reg.NewEmptySet() + i.LiveOut = reg.NewEmptySet() } // Iterative dataflow analysis. @@ -22,18 +22,9 @@ func Liveness(fn *avo.Function) error { for _, i := range is { // in[n] = use[n] UNION (out[n] - def[n]) nin := len(i.LiveIn) - for _, r := range i.InputRegisters() { - i.LiveIn[r.ID()] = true - } - def := map[reg.ID]bool{} - for _, r := range i.OutputRegisters() { - def[r.ID()] = true - } - for id := range i.LiveOut { - if !def[id] { - i.LiveIn[id] = true - } - } + i.LiveIn.Update(reg.NewSetFromSlice(i.InputRegisters())) + def := reg.NewSetFromSlice(i.OutputRegisters()) + i.LiveIn.Update(i.LiveOut.Difference(def)) if len(i.LiveIn) != nin { changes = true } @@ -44,9 +35,7 @@ func Liveness(fn *avo.Function) error { if s == nil { continue } - for id := range s.LiveIn { - i.LiveOut[id] = true - } + i.LiveOut.Update(s.LiveIn) } if len(i.LiveOut) != nout { changes = true @@ -60,3 +49,7 @@ func Liveness(fn *avo.Function) error { return nil } + +func AllocateRegisters(fn *avo.Function) error { + return nil +} diff --git a/pass/reg_test.go b/pass/reg_test.go index d4dd542..38a735f 100644 --- a/pass/reg_test.go +++ b/pass/reg_test.go @@ -50,14 +50,9 @@ func AssertLiveness(t *testing.T, ctx *build.Context, in, out [][]reg.Register) } } -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 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) } } diff --git a/reg/set.go b/reg/set.go new file mode 100644 index 0000000..3fb9a41 --- /dev/null +++ b/reg/set.go @@ -0,0 +1,71 @@ +package reg + +// Set is a set of registers. +type Set map[ID]Register + +// NewEmptySet builds an empty register set. +func NewEmptySet() Set { + return Set{} +} + +// NewSetFromSlice forms a set from the given register list. +func NewSetFromSlice(rs []Register) Set { + s := NewEmptySet() + for _, r := range rs { + s.Add(r) + } + return s +} + +// Clone returns a copy of s. +func (s Set) Clone() Set { + c := NewEmptySet() + for _, r := range s { + c.Add(r) + } + return c +} + +// Add r to s. +func (s Set) Add(r Register) { + s[r.ID()] = r +} + +// Discard removes r from s, if present. +func (s Set) Discard(r Register) { + delete(s, r.ID()) +} + +// Update adds every register in t to s. +func (s Set) Update(t Set) { + for _, r := range t { + s.Add(r) + } +} + +// Difference returns the set of registers in s but not t. +func (s Set) Difference(t Set) Set { + d := s.Clone() + d.DifferenceUpdate(t) + return d +} + +// DifferenceUpdate removes every element of t from s. +func (s Set) DifferenceUpdate(t Set) { + for _, r := range t { + s.Discard(r) + } +} + +// Equals returns true if s and t contain the same registers. +func (s Set) Equals(t Set) bool { + if len(s) != len(t) { + return false + } + for _, r := range s { + if _, found := t[r.ID()]; !found { + return false + } + } + return true +} diff --git a/reg/set_test.go b/reg/set_test.go new file mode 100644 index 0000000..14683fe --- /dev/null +++ b/reg/set_test.go @@ -0,0 +1,12 @@ +package reg + +import "testing" + +func TestFamilyRegisterSets(t *testing.T) { + fs := []*Family{GeneralPurpose, SIMD} + for _, f := range fs { + if len(f.Set()) != len(f.Registers()) { + t.Fatal("family set and list should have same size") + } + } +} diff --git a/reg/types.go b/reg/types.go index ed455ee..2c2547f 100644 --- a/reg/types.go +++ b/reg/types.go @@ -2,7 +2,6 @@ package reg import ( "fmt" - "math" ) type Size uint @@ -41,6 +40,24 @@ func (f *Family) Virtual(id VID, s Size) Virtual { return NewVirtual(id, f.Kind, s) } +// Registers returns the registers in this family. +func (f *Family) Registers() []Physical { + rs := make([]Physical, 0, len(f.registers)) + for _, r := range f.registers { + rs = append(rs, r) + } + return rs +} + +// Set returns the set of registers in the family. +func (f *Family) Set() Set { + s := NewEmptySet() + for _, r := range f.registers { + s.Add(r) + } + return s +} + type private interface { private() } @@ -82,7 +99,7 @@ func (v virtual) VirtualID() VID { return v.id } func (v virtual) Kind() Kind { return v.kind } func (v virtual) ID() ID { - return (ID(math.MaxUint16) << 16) | ID(v.VirtualID()) + return (ID(1) << 31) | ID(v.VirtualID()) } func (v virtual) Asm() string { @@ -106,7 +123,7 @@ type register struct { } func (r register) PhysicalID() PID { return r.id } -func (r register) ID() ID { return ID(r.id) } +func (r register) ID() ID { return (ID(r.Mask()) << 16) | ID(r.id) } func (r register) Kind() Kind { return r.kind } func (r register) Asm() string { return r.name } func (r register) private() {}