Skip to content

Commit

Permalink
reg: virtual register takes mask
Browse files Browse the repository at this point in the history
Requires all virtual registers to specify a mask rather than just a
size. Currently avo allows specifying an 8-bit register, which could
resolve to a low or high byte register. This complicates liveness
analysis and register allocation for what ends up being a very niche use
case.

Removes the `reg.Width` type since this is no longer used anywhere.

Updates #100
  • Loading branch information
mmcloughlin committed Jan 18, 2020
1 parent b0ac744 commit efd92f7
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 77 deletions.
8 changes: 7 additions & 1 deletion build/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,13 @@ func Constraint(t buildtags.ConstraintConvertable) { ctx.Constraint(t) }
// constraint comments.
func ConstraintExpr(expr string) { ctx.ConstraintExpr(expr) }

// GP8 allocates and returns a general-purpose 8-bit register.
// GP8L allocates and returns a general-purpose 8-bit register (low byte).
func GP8L() reg.GPVirtual { return ctx.GP8L() }

// GP8H allocates and returns a general-purpose 8-bit register (high byte).
func GP8H() reg.GPVirtual { return ctx.GP8H() }

// GP8 allocates and returns a general-purpose 8-bit register (low byte).
func GP8() reg.GPVirtual { return ctx.GP8() }

// GP16 allocates and returns a general-purpose 16-bit register.
Expand Down
30 changes: 18 additions & 12 deletions reg/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,41 @@ func NewCollection() *Collection {
}

// VirtualRegister allocates and returns a new virtual register of the given kind and width.
func (c *Collection) VirtualRegister(k Kind, w Width) Virtual {
func (c *Collection) VirtualRegister(k Kind, s Spec) Virtual {
vid := c.vid[k]
c.vid[k]++
return NewVirtual(vid, k, w)
return NewVirtual(vid, k, s)
}

// GP8 allocates and returns a general-purpose 8-bit register.
func (c *Collection) GP8() GPVirtual { return c.GP(B8) }
// GP8L allocates and returns a general-purpose 8-bit register (low byte).
func (c *Collection) GP8L() GPVirtual { return c.GP(S8L) }

// GP8H allocates and returns a general-purpose 8-bit register (high byte).
func (c *Collection) GP8H() GPVirtual { return c.GP(S8H) }

// GP8 allocates and returns a general-purpose 8-bit register (low byte).
func (c *Collection) GP8() GPVirtual { return c.GP8L() }

// GP16 allocates and returns a general-purpose 16-bit register.
func (c *Collection) GP16() GPVirtual { return c.GP(B16) }
func (c *Collection) GP16() GPVirtual { return c.GP(S16) }

// GP32 allocates and returns a general-purpose 32-bit register.
func (c *Collection) GP32() GPVirtual { return c.GP(B32) }
func (c *Collection) GP32() GPVirtual { return c.GP(S32) }

// GP64 allocates and returns a general-purpose 64-bit register.
func (c *Collection) GP64() GPVirtual { return c.GP(B64) }
func (c *Collection) GP64() GPVirtual { return c.GP(S64) }

// GP allocates and returns a general-purpose register of the given width.
func (c *Collection) GP(w Width) GPVirtual { return newgpv(c.VirtualRegister(KindGP, w)) }
func (c *Collection) GP(s Spec) GPVirtual { return newgpv(c.VirtualRegister(KindGP, s)) }

// XMM allocates and returns a 128-bit vector register.
func (c *Collection) XMM() VecVirtual { return c.Vec(B128) }
func (c *Collection) XMM() VecVirtual { return c.Vec(S128) }

// YMM allocates and returns a 256-bit vector register.
func (c *Collection) YMM() VecVirtual { return c.Vec(B256) }
func (c *Collection) YMM() VecVirtual { return c.Vec(S256) }

// ZMM allocates and returns a 512-bit vector register.
func (c *Collection) ZMM() VecVirtual { return c.Vec(B512) }
func (c *Collection) ZMM() VecVirtual { return c.Vec(S512) }

// Vec allocates and returns a vector register of the given width.
func (c *Collection) Vec(w Width) VecVirtual { return newvecv(c.VirtualRegister(KindVector, w)) }
func (c *Collection) Vec(s Spec) VecVirtual { return newvecv(c.VirtualRegister(KindVector, s)) }
16 changes: 8 additions & 8 deletions reg/reg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestSpecSize(t *testing.T) {
}

func TestToVirtual(t *testing.T) {
v := GeneralPurpose.Virtual(42, B32)
v := GeneralPurpose.Virtual(42, S32)
if ToVirtual(v) != v {
t.Errorf("ToVirtual(v) != v for virtual register")
}
Expand All @@ -35,7 +35,7 @@ func TestToVirtual(t *testing.T) {
}

func TestToPhysical(t *testing.T) {
v := GeneralPurpose.Virtual(42, B32)
v := GeneralPurpose.Virtual(42, S32)
if ToPhysical(v) != nil {
t.Errorf("ToPhysical should be nil for virtual registers")
}
Expand Down Expand Up @@ -122,12 +122,12 @@ func TestVirtualAs(t *testing.T) {
Physical Physical
Match bool
}{
{GeneralPurpose.Virtual(0, B8), CL, true},
{GeneralPurpose.Virtual(0, B8), CH, true},
{GeneralPurpose.Virtual(0, B32).as(S8L), CL, true},
{GeneralPurpose.Virtual(0, B32).as(S8L), CH, false},
{GeneralPurpose.Virtual(0, B16).as(S32), R9L, true},
{GeneralPurpose.Virtual(0, B16).as(S32), R9, false},
{GeneralPurpose.Virtual(0, S8), CL, true},
{GeneralPurpose.Virtual(0, S8H), CH, true},
{GeneralPurpose.Virtual(0, S32).as(S8L), CL, true},
{GeneralPurpose.Virtual(0, S32).as(S8L), CH, false},
{GeneralPurpose.Virtual(0, S16).as(S32), R9L, true},
{GeneralPurpose.Virtual(0, S16).as(S32), R9, false},
}
for _, c := range cases {
if c.Virtual.(Virtual).SatisfiedBy(c.Physical) != c.Match {
Expand Down
10 changes: 5 additions & 5 deletions reg/set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import "testing"

func TestSetRegisterIdentity(t *testing.T) {
rs := []Register{
NewVirtual(42, KindGP, B32),
NewVirtual(43, KindGP, B32),
NewVirtual(42, KindVector, B32),
NewVirtual(42, KindGP, B64),
NewVirtual(42, KindGP, S32),
NewVirtual(43, KindGP, S32),
NewVirtual(42, KindVector, S32),
NewVirtual(42, KindGP, S64),
AL, AH, CL,
AX, R13W,
EDX, R9L,
Expand All @@ -32,7 +32,7 @@ func TestSetFamilyRegisters(t *testing.T) {
expect := 0
for _, f := range fs {
s.Update(f.Set())
s.Add(f.Virtual(42, B64))
s.Add(f.Virtual(42, S64))
expect += len(f.Registers()) + 1
}
if len(s) != expect {
Expand Down
41 changes: 11 additions & 30 deletions reg/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,6 @@ import (
"fmt"
)

// Width is a register width.
type Width uint

// Typical register width values.
const (
B8 Width = 1 << iota
B16
B32
B64
B128
B256
B512
)

// Size returns the register width in bytes.
func (w Width) Size() uint { return uint(w) }

// Kind is a class of registers.
type Kind uint8

Expand All @@ -47,8 +30,8 @@ func (f *Family) add(r Physical) {
}

// Virtual returns a virtual register from this family's kind.
func (f *Family) Virtual(id VID, w Width) Virtual {
return NewVirtual(id, f.Kind, w)
func (f *Family) Virtual(id VID, s Spec) Virtual {
return NewVirtual(id, f.Kind, s)
}

// Registers returns the registers in this family.
Expand Down Expand Up @@ -105,16 +88,15 @@ func ToVirtual(r Register) Virtual {
type virtual struct {
id VID
kind Kind
Width
mask uint16
Spec
}

// NewVirtual builds a Virtual register.
func NewVirtual(id VID, k Kind, w Width) Virtual {
func NewVirtual(id VID, k Kind, s Spec) Virtual {
return virtual{
id: id,
kind: k,
Width: w,
id: id,
kind: k,
Spec: s,
}
}

Expand All @@ -127,15 +109,14 @@ func (v virtual) Asm() string {
}

func (v virtual) SatisfiedBy(p Physical) bool {
return v.Kind() == p.Kind() && v.Size() == p.Size() && (v.mask == 0 || v.mask == p.Mask())
return v.Kind() == p.Kind() && v.Mask() == p.Mask()
}

func (v virtual) as(s Spec) Register {
return virtual{
id: v.id,
kind: v.kind,
Width: Width(s.Size()),
mask: s.Mask(),
id: v.id,
kind: v.kind,
Spec: s,
}
}

Expand Down
13 changes: 11 additions & 2 deletions tests/alloc/gp8/asm.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,17 @@ func main() {

// Allocate registers and initialize.
x := make([]Register, n)
for i := 0; i < n; i++ {
x[i] = GP8()
i := 0

// Low byte registers.
for ; i < 15; i++ {
x[i] = GP8L()
MOVB(U8(i+1), x[i])
}

// High byte registers.
for ; i < n; i++ {
x[i] = GP8H()
MOVB(U8(i+1), x[i])
}

Expand Down
38 changes: 19 additions & 19 deletions tests/alloc/gp8/gp8.s
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,24 @@ TEXT ·GP8(SB), NOSPLIT, $0-1
MOVB $0x02, CL
MOVB $0x03, DL
MOVB $0x04, BL
MOVB $0x05, AH
MOVB $0x06, CH
MOVB $0x07, DH
MOVB $0x08, BH
MOVB $0x09, BP
MOVB $0x0a, SI
MOVB $0x0b, DI
MOVB $0x0c, R8
MOVB $0x0d, R9
MOVB $0x0e, R10
MOVB $0x0f, R11
MOVB $0x10, R12
MOVB $0x11, R13
MOVB $0x12, R14
MOVB $0x13, R15
MOVB $0x05, BP
MOVB $0x06, SI
MOVB $0x07, DI
MOVB $0x08, R8
MOVB $0x09, R9
MOVB $0x0a, R10
MOVB $0x0b, R11
MOVB $0x0c, R12
MOVB $0x0d, R13
MOVB $0x0e, R14
MOVB $0x0f, R15
MOVB $0x10, AH
MOVB $0x11, CH
MOVB $0x12, DH
MOVB $0x13, BH
ADDB CL, AL
ADDB DL, AL
ADDB BL, AL
ADDB AH, AL
ADDB CH, AL
ADDB DH, AL
ADDB BH, AL
ADDB BP, AL
ADDB SI, AL
ADDB DI, AL
Expand All @@ -41,5 +37,9 @@ TEXT ·GP8(SB), NOSPLIT, $0-1
ADDB R13, AL
ADDB R14, AL
ADDB R15, AL
ADDB AH, AL
ADDB CH, AL
ADDB DH, AL
ADDB BH, AL
MOVB AL, ret+0(FP)
RET

0 comments on commit efd92f7

Please sign in to comment.