2018-11-11 22:17:06 -06:00
|
|
|
package reg
|
|
|
|
|
|
2018-12-02 23:59:29 -08:00
|
|
|
import (
|
2018-12-05 00:05:57 -08:00
|
|
|
"errors"
|
2018-12-02 23:59:29 -08:00
|
|
|
"fmt"
|
|
|
|
|
)
|
2018-12-02 15:15:00 -08:00
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// Kind is a class of registers.
|
2018-11-11 22:17:06 -06:00
|
|
|
type Kind uint8
|
|
|
|
|
|
2020-01-22 22:50:40 -08:00
|
|
|
// Index of a register within a kind.
|
|
|
|
|
type Index uint16
|
|
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// Family is a collection of Physical registers of a common kind.
|
2018-11-11 22:17:06 -06:00
|
|
|
type Family struct {
|
|
|
|
|
Kind Kind
|
2018-12-02 21:35:33 -08:00
|
|
|
registers []Physical
|
2018-11-11 22:17:06 -06:00
|
|
|
}
|
|
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// define builds a register and adds it to the Family.
|
2020-01-22 22:50:40 -08:00
|
|
|
func (f *Family) define(s Spec, idx Index, name string, flags ...Info) Physical {
|
|
|
|
|
r := newregister(f, s, idx, name, flags...)
|
2018-12-30 18:40:45 -08:00
|
|
|
f.add(r)
|
2018-11-11 22:17:06 -06:00
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// add r to the family.
|
2018-12-30 18:40:45 -08:00
|
|
|
func (f *Family) add(r Physical) {
|
|
|
|
|
if r.Kind() != f.Kind {
|
|
|
|
|
panic("bad kind")
|
|
|
|
|
}
|
|
|
|
|
f.registers = append(f.registers, r)
|
2018-12-13 00:18:44 -08:00
|
|
|
}
|
|
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// Virtual returns a virtual register from this family's kind.
|
2020-01-22 22:50:40 -08:00
|
|
|
func (f *Family) Virtual(idx Index, s Spec) Virtual {
|
|
|
|
|
return NewVirtual(idx, f.Kind, s)
|
2018-11-11 22:17:06 -06:00
|
|
|
}
|
|
|
|
|
|
2018-12-03 22:39:43 -08:00
|
|
|
// Registers returns the registers in this family.
|
|
|
|
|
func (f *Family) Registers() []Physical {
|
2018-12-05 00:27:42 -08:00
|
|
|
return append([]Physical(nil), f.registers...)
|
2018-12-03 22:39:43 -08:00
|
|
|
}
|
|
|
|
|
|
2020-01-22 22:50:40 -08:00
|
|
|
// Lookup returns the register with given physical index and spec. Returns nil if no such register exists.
|
|
|
|
|
func (f *Family) Lookup(idx Index, s Spec) Physical {
|
2018-12-30 18:40:45 -08:00
|
|
|
for _, r := range f.registers {
|
2020-01-22 22:50:40 -08:00
|
|
|
if r.PhysicalIndex() == idx && r.Mask() == s.Mask() {
|
2018-12-30 18:40:45 -08:00
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 22:50:40 -08:00
|
|
|
// ID is a register identifier.
|
|
|
|
|
type ID uint32
|
|
|
|
|
|
|
|
|
|
// newid builds a new register ID from the virtual flag v, kind and index.
|
|
|
|
|
func newid(v uint8, kind Kind, idx Index) ID {
|
|
|
|
|
return ID(v) | (ID(kind) << 8) | (ID(idx) << 16)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IsVirtual reports whether this is an ID for a virtual register.
|
|
|
|
|
func (id ID) IsVirtual() bool { return (id & 1) == 1 }
|
|
|
|
|
|
|
|
|
|
// IsPhysical reports whether this is an ID for a physical register.
|
|
|
|
|
func (id ID) IsPhysical() bool { return !id.IsVirtual() }
|
|
|
|
|
|
|
|
|
|
// Kind extracts the kind from the register ID.
|
|
|
|
|
func (id ID) Kind() Kind { return Kind(id >> 8) }
|
|
|
|
|
|
|
|
|
|
// Index extracts the index from the register ID.
|
|
|
|
|
func (id ID) Index() Index { return Index(id >> 16) }
|
|
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// Register represents a virtual or physical register.
|
2018-12-02 21:35:33 -08:00
|
|
|
type Register interface {
|
2020-01-22 22:50:40 -08:00
|
|
|
ID() ID
|
2018-11-11 22:17:06 -06:00
|
|
|
Kind() Kind
|
2019-04-01 20:27:44 -07:00
|
|
|
Size() uint
|
2020-01-22 22:50:40 -08:00
|
|
|
Mask() uint16
|
2018-12-02 15:15:00 -08:00
|
|
|
Asm() string
|
2018-12-30 18:40:45 -08:00
|
|
|
as(Spec) Register
|
2020-01-22 22:50:40 -08:00
|
|
|
spec() Spec
|
2018-12-05 00:27:42 -08:00
|
|
|
register()
|
2018-12-02 15:15:00 -08:00
|
|
|
}
|
|
|
|
|
|
2020-01-22 22:50:40 -08:00
|
|
|
// Equal reports whether a and b are equal registers.
|
|
|
|
|
func Equal(a, b Register) bool {
|
|
|
|
|
return (a.ID() == b.ID()) && (a.Mask() == b.Mask())
|
|
|
|
|
}
|
2019-01-04 22:06:00 -08:00
|
|
|
|
|
|
|
|
// Virtual is a register of a given type and size, not yet allocated to a physical register.
|
2018-12-02 15:15:00 -08:00
|
|
|
type Virtual interface {
|
2020-01-22 22:50:40 -08:00
|
|
|
VirtualIndex() Index
|
2018-12-02 21:35:33 -08:00
|
|
|
Register
|
2018-11-11 22:17:06 -06:00
|
|
|
}
|
|
|
|
|
|
2018-12-05 00:05:57 -08:00
|
|
|
// ToVirtual converts r to Virtual if possible, otherwise returns nil.
|
|
|
|
|
func ToVirtual(r Register) Virtual {
|
|
|
|
|
if v, ok := r.(Virtual); ok {
|
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-11 22:17:06 -06:00
|
|
|
type virtual struct {
|
2020-01-22 22:50:40 -08:00
|
|
|
idx Index
|
2018-11-11 22:17:06 -06:00
|
|
|
kind Kind
|
2020-01-22 22:50:40 -08:00
|
|
|
Spec
|
2018-11-11 22:17:06 -06:00
|
|
|
}
|
|
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// NewVirtual builds a Virtual register.
|
2020-01-22 22:50:40 -08:00
|
|
|
func NewVirtual(idx Index, k Kind, s Spec) Virtual {
|
2018-12-03 20:40:43 -08:00
|
|
|
return virtual{
|
2020-01-22 22:50:40 -08:00
|
|
|
idx: idx,
|
|
|
|
|
kind: k,
|
|
|
|
|
Spec: s,
|
2018-12-03 20:40:43 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 22:50:40 -08:00
|
|
|
func (v virtual) ID() ID { return newid(1, v.kind, v.idx) }
|
|
|
|
|
func (v virtual) VirtualIndex() Index { return v.idx }
|
|
|
|
|
func (v virtual) Kind() Kind { return v.kind }
|
2018-12-02 23:59:29 -08:00
|
|
|
|
2018-12-02 15:15:00 -08:00
|
|
|
func (v virtual) Asm() string {
|
|
|
|
|
// TODO(mbm): decide on virtual register syntax
|
2020-01-22 22:50:40 -08:00
|
|
|
return fmt.Sprintf("<virtual:%v:%v:%v>", v.idx, v.Kind(), v.Size())
|
2018-12-30 18:40:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (v virtual) as(s Spec) Register {
|
|
|
|
|
return virtual{
|
2020-01-22 22:50:40 -08:00
|
|
|
idx: v.idx,
|
|
|
|
|
kind: v.kind,
|
|
|
|
|
Spec: s,
|
2018-12-30 18:40:45 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 22:50:40 -08:00
|
|
|
func (v virtual) spec() Spec { return v.Spec }
|
|
|
|
|
func (v virtual) register() {}
|
2018-12-02 15:15:00 -08:00
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// Info is a bitmask of register properties.
|
2018-12-13 00:18:44 -08:00
|
|
|
type Info uint8
|
|
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// Defined register Info flags.
|
2018-12-13 00:18:44 -08:00
|
|
|
const (
|
|
|
|
|
None Info = 0
|
|
|
|
|
Restricted Info = 1 << iota
|
|
|
|
|
)
|
|
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// Physical is a concrete register.
|
2018-12-02 21:35:33 -08:00
|
|
|
type Physical interface {
|
2020-01-22 22:50:40 -08:00
|
|
|
PhysicalIndex() Index
|
2018-12-13 00:18:44 -08:00
|
|
|
Info() Info
|
2018-12-02 21:35:33 -08:00
|
|
|
Register
|
2018-11-11 22:17:06 -06:00
|
|
|
}
|
|
|
|
|
|
2018-12-05 00:05:57 -08:00
|
|
|
// ToPhysical converts r to Physical if possible, otherwise returns nil.
|
|
|
|
|
func ToPhysical(r Register) Physical {
|
|
|
|
|
if p, ok := r.(Physical); ok {
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// register implements Physical.
|
2018-11-11 22:17:06 -06:00
|
|
|
type register struct {
|
2018-12-30 18:40:45 -08:00
|
|
|
family *Family
|
2020-01-22 22:50:40 -08:00
|
|
|
idx Index
|
2018-12-30 18:40:45 -08:00
|
|
|
name string
|
|
|
|
|
info Info
|
2018-11-11 22:17:06 -06:00
|
|
|
Spec
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 22:50:40 -08:00
|
|
|
func newregister(f *Family, s Spec, idx Index, name string, flags ...Info) register {
|
2018-12-30 18:40:45 -08:00
|
|
|
r := register{
|
|
|
|
|
family: f,
|
2020-01-22 22:50:40 -08:00
|
|
|
idx: idx,
|
2018-12-30 18:40:45 -08:00
|
|
|
name: name,
|
|
|
|
|
info: None,
|
|
|
|
|
Spec: s,
|
|
|
|
|
}
|
|
|
|
|
for _, flag := range flags {
|
|
|
|
|
r.info |= flag
|
|
|
|
|
}
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 22:50:40 -08:00
|
|
|
func (r register) ID() ID { return newid(0, r.Kind(), r.idx) }
|
|
|
|
|
func (r register) PhysicalIndex() Index { return r.idx }
|
|
|
|
|
func (r register) Kind() Kind { return r.family.Kind }
|
|
|
|
|
func (r register) Asm() string { return r.name }
|
|
|
|
|
func (r register) Info() Info { return r.info }
|
2018-12-30 18:40:45 -08:00
|
|
|
|
|
|
|
|
func (r register) as(s Spec) Register {
|
2020-01-22 22:50:40 -08:00
|
|
|
return r.family.Lookup(r.PhysicalIndex(), s)
|
2018-12-30 18:40:45 -08:00
|
|
|
}
|
|
|
|
|
|
2020-01-22 22:50:40 -08:00
|
|
|
func (r register) spec() Spec { return r.Spec }
|
|
|
|
|
func (r register) register() {}
|
2018-11-11 22:17:06 -06:00
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// Spec defines the size of a register as well as the bit ranges it occupies in
|
|
|
|
|
// an underlying physical register.
|
2018-11-11 22:17:06 -06:00
|
|
|
type Spec uint16
|
|
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// Spec values required for x86-64.
|
2018-11-11 22:17:06 -06:00
|
|
|
const (
|
2018-12-06 17:26:33 -08:00
|
|
|
S0 Spec = 0x0 // zero value reserved for pseudo registers
|
2018-11-11 22:17:06 -06:00
|
|
|
S8L Spec = 0x1
|
|
|
|
|
S8H Spec = 0x2
|
|
|
|
|
S8 = S8L
|
|
|
|
|
S16 Spec = 0x3
|
|
|
|
|
S32 Spec = 0x7
|
|
|
|
|
S64 Spec = 0xf
|
|
|
|
|
S128 Spec = 0x1f
|
|
|
|
|
S256 Spec = 0x3f
|
|
|
|
|
S512 Spec = 0x7f
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Mask returns a mask representing which bytes of an underlying register are
|
|
|
|
|
// used by this register. This is almost always the low bytes, except for the
|
|
|
|
|
// case of the high-byte registers. If bit n of the mask is set, this means
|
|
|
|
|
// bytes 2^(n-1) to 2^n-1 are used.
|
|
|
|
|
func (s Spec) Mask() uint16 {
|
|
|
|
|
return uint16(s)
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-01 20:27:44 -07:00
|
|
|
// Size returns the register width in bytes.
|
|
|
|
|
func (s Spec) Size() uint {
|
2018-11-11 22:17:06 -06:00
|
|
|
x := uint(s)
|
|
|
|
|
return (x >> 1) + (x & 1)
|
|
|
|
|
}
|
2018-12-05 00:05:57 -08:00
|
|
|
|
2020-01-22 22:50:40 -08:00
|
|
|
// LookupPhysical returns the physical register with the given parameters, or nil if not found.
|
|
|
|
|
func LookupPhysical(k Kind, idx Index, s Spec) Physical {
|
|
|
|
|
f := FamilyOfKind(k)
|
|
|
|
|
if f == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return f.Lookup(idx, s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LookupID returns the physical register with the given id and spec, or nil if not found.
|
|
|
|
|
func LookupID(id ID, s Spec) Physical {
|
|
|
|
|
if id.IsVirtual() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return LookupPhysical(id.Kind(), id.Index(), s)
|
2018-12-05 00:05:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allocation records a register allocation.
|
2020-01-22 22:50:40 -08:00
|
|
|
type Allocation map[ID]ID
|
2018-12-05 00:05:57 -08:00
|
|
|
|
2019-01-04 22:06:00 -08:00
|
|
|
// NewEmptyAllocation builds an empty register allocation.
|
2018-12-05 00:05:57 -08:00
|
|
|
func NewEmptyAllocation() Allocation {
|
|
|
|
|
return Allocation{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Merge allocations from b into a. Errors if there is disagreement on a common
|
|
|
|
|
// register.
|
|
|
|
|
func (a Allocation) Merge(b Allocation) error {
|
2020-01-22 22:50:40 -08:00
|
|
|
for id, p := range b {
|
|
|
|
|
if alt, found := a[id]; found && alt != p {
|
2018-12-05 00:05:57 -08:00
|
|
|
return errors.New("disagreement on overlapping register")
|
|
|
|
|
}
|
2020-01-22 22:50:40 -08:00
|
|
|
a[id] = p
|
2018-12-05 00:05:57 -08:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 22:50:40 -08:00
|
|
|
// LookupDefault returns the register ID assigned by this allocation, returning
|
|
|
|
|
// id if none is found.
|
|
|
|
|
func (a Allocation) LookupDefault(id ID) ID {
|
|
|
|
|
if _, found := a[id]; found {
|
|
|
|
|
return a[id]
|
|
|
|
|
}
|
|
|
|
|
return id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LookupRegister the allocation for register r, or return nil if there is none.
|
|
|
|
|
func (a Allocation) LookupRegister(r Register) Physical {
|
|
|
|
|
// Return immediately if it is already a physical register.
|
|
|
|
|
if p := ToPhysical(r); p != nil {
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Lookup an allocation for this virtual ID.
|
|
|
|
|
id, found := a[r.ID()]
|
|
|
|
|
if !found {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return LookupID(id, r.spec())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LookupRegisterDefault returns the register assigned to r, or r itself if there is none.
|
|
|
|
|
func (a Allocation) LookupRegisterDefault(r Register) Register {
|
|
|
|
|
if r == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if p := a.LookupRegister(r); p != nil {
|
2018-12-05 00:05:57 -08:00
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
return r
|
|
|
|
|
}
|