Define register banks.
Add a RegBank class for describing CPU register banks. Define register banks for all the ISA stubs. The ARM32 floating point bank in particular requires attention.
This commit is contained in:
@@ -10,6 +10,7 @@ try:
|
|||||||
from .predicates import Predicate, FieldPredicate # noqa
|
from .predicates import Predicate, FieldPredicate # noqa
|
||||||
from .settings import SettingGroup # noqa
|
from .settings import SettingGroup # noqa
|
||||||
from .types import ValueType # noqa
|
from .types import ValueType # noqa
|
||||||
|
from .registers import RegBank # noqa
|
||||||
AnyPredicate = Union[Predicate, FieldPredicate]
|
AnyPredicate = Union[Predicate, FieldPredicate]
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
@@ -32,6 +33,7 @@ class TargetISA(object):
|
|||||||
self.settings = None # type: SettingGroup
|
self.settings = None # type: SettingGroup
|
||||||
self.instruction_groups = instruction_groups
|
self.instruction_groups = instruction_groups
|
||||||
self.cpumodes = list() # type: List[CPUMode]
|
self.cpumodes = list() # type: List[CPUMode]
|
||||||
|
self.regbanks = list() # type: List[RegBank]
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
# type: () -> TargetISA
|
# type: () -> TargetISA
|
||||||
|
|||||||
80
lib/cretonne/meta/cdsl/registers.py
Normal file
80
lib/cretonne/meta/cdsl/registers.py
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
"""
|
||||||
|
Register set definitions
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Each ISA defines a separate register set that is used by the register allocator
|
||||||
|
and the final binary encoding of machine code.
|
||||||
|
|
||||||
|
The CPU registers are first divided into disjoint register banks, represented
|
||||||
|
by a `RegBank` instance. Registers in different register banks never interfere
|
||||||
|
with each other. A typical CPU will have a general purpose and a floating point
|
||||||
|
register bank.
|
||||||
|
|
||||||
|
A register bank consists of a number of *register units* which are the smallest
|
||||||
|
indivisible units of allocation and interference. A register unit doesn't
|
||||||
|
necesarily correspond to a particular number of bits in a register, it is more
|
||||||
|
like a placeholder that can be used to determine of a register is taken or not.
|
||||||
|
|
||||||
|
The register allocator works with *register classes* which can allocate one or
|
||||||
|
more register units at a time. A register class allocates more than one
|
||||||
|
register unit at a time when its registers are composed of smaller alocatable
|
||||||
|
units. For example, the ARM double precision floating point registers are
|
||||||
|
composed of two single precision registers. """
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from . import is_power_of_two, next_power_of_two
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from typing import Sequence # noqa
|
||||||
|
from .isa import TargetISA # noqa
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class RegBank(object):
|
||||||
|
"""
|
||||||
|
A register bank belonging to an ISA.
|
||||||
|
|
||||||
|
A register bank controls a set of *register units* disjoint from all the
|
||||||
|
other register banks in the ISA. The register units are numbered uniquely
|
||||||
|
within the target ISA, and the units in a register bank form a contiguous
|
||||||
|
sequence starting from a sufficiently aligned point that their low bits can
|
||||||
|
be used directly when encoding machine code instructions.
|
||||||
|
|
||||||
|
Register units can be given generated names like `r0`, `r1`, ..., or a
|
||||||
|
tuple of special register unit names can be provided.
|
||||||
|
|
||||||
|
:param name: Name of this register bank.
|
||||||
|
:param doc: Documentation string.
|
||||||
|
:param units: Number of register units.
|
||||||
|
:param prefix: Prefix for generated unit names.
|
||||||
|
:param names: Special names for the first units. May be shorter than
|
||||||
|
`units`, the remaining units are named using `prefix`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, isa, doc, units, prefix='p', names=()):
|
||||||
|
# type: (str, TargetISA, str, int, str, Sequence[str]) -> None
|
||||||
|
self.name = name
|
||||||
|
self.isa = isa
|
||||||
|
self.first_unit = 0
|
||||||
|
self.units = units
|
||||||
|
self.prefix = prefix
|
||||||
|
self.names = names
|
||||||
|
|
||||||
|
assert len(names) <= units
|
||||||
|
|
||||||
|
if isa.regbanks:
|
||||||
|
# Get the next free unit number.
|
||||||
|
last = isa.regbanks[-1]
|
||||||
|
u = last.first_unit + last.units
|
||||||
|
align = units
|
||||||
|
if not is_power_of_two(align):
|
||||||
|
align = next_power_of_two(align)
|
||||||
|
self.first_unit = (u + align - 1) & -align
|
||||||
|
|
||||||
|
isa.regbanks.append(self)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
# type: () -> str
|
||||||
|
return ('RegBank({}, units={}, first_unit={})'
|
||||||
|
.format(self.name, self.units, self.first_unit))
|
||||||
29
lib/cretonne/meta/isa/arm32/registers.py
Normal file
29
lib/cretonne/meta/isa/arm32/registers.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
"""
|
||||||
|
ARM32 register banks.
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from cdsl.registers import RegBank
|
||||||
|
from .defs import ISA
|
||||||
|
|
||||||
|
|
||||||
|
# Special register units:
|
||||||
|
# - r15 is the program counter.
|
||||||
|
# - r14 is the link register.
|
||||||
|
# - r13 is usually the stack pointer.
|
||||||
|
IntRegs = RegBank(
|
||||||
|
'IntRegs', ISA,
|
||||||
|
'General purpose registers',
|
||||||
|
units=16, prefix='r')
|
||||||
|
|
||||||
|
FloatRegs = RegBank(
|
||||||
|
'FloatRegs', ISA, r"""
|
||||||
|
Floating point registers.
|
||||||
|
|
||||||
|
The floating point register units correspond to the S-registers, but
|
||||||
|
extended as if there were 64 registers.
|
||||||
|
|
||||||
|
- S registers are one unit each.
|
||||||
|
- D registers are two units each, even D16 and above.
|
||||||
|
- Q registers are 4 units each.
|
||||||
|
""",
|
||||||
|
units=64, prefix='s')
|
||||||
19
lib/cretonne/meta/isa/arm64/registers.py
Normal file
19
lib/cretonne/meta/isa/arm64/registers.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
"""
|
||||||
|
Aarch64 register banks.
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from cdsl.registers import RegBank
|
||||||
|
from .defs import ISA
|
||||||
|
|
||||||
|
|
||||||
|
# The `x31` regunit serves as the stack pointer / zero register depending on
|
||||||
|
# context. We reserve it and don't model the difference.
|
||||||
|
IntRegs = RegBank(
|
||||||
|
'IntRegs', ISA,
|
||||||
|
'General purpose registers',
|
||||||
|
units=32, prefix='x')
|
||||||
|
|
||||||
|
FloatRegs = RegBank(
|
||||||
|
'FloatRegs', ISA,
|
||||||
|
'Floating point registers',
|
||||||
|
units=32, prefix='v')
|
||||||
39
lib/cretonne/meta/isa/intel/registers.py
Normal file
39
lib/cretonne/meta/isa/intel/registers.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
"""
|
||||||
|
Intel register banks.
|
||||||
|
|
||||||
|
While the floating-point registers are straight-forward, the general purpose
|
||||||
|
register bank has a few quirks on Intel architectures. We have these encodings
|
||||||
|
of the 8-bit registers:
|
||||||
|
|
||||||
|
I32 I64 | 16b 32b 64b
|
||||||
|
000 AL AL | AX EAX RAX
|
||||||
|
001 CL CL | CX ECX RCX
|
||||||
|
010 DL DL | DX EDX RDX
|
||||||
|
011 BL BL | BX EBX RBX
|
||||||
|
100 AH SPL | SP ESP RSP
|
||||||
|
101 CH BPL | BP EBP RBP
|
||||||
|
110 DH SIL | SI ESI RSI
|
||||||
|
111 BH DIL | DI EDI RDI
|
||||||
|
|
||||||
|
Here, the I64 column refers to the registers you get with a REX prefix. Without
|
||||||
|
the REX prefix, you get the I32 registers.
|
||||||
|
|
||||||
|
The 8-bit registers are not that useful since WebAssembly only has i32 and i64
|
||||||
|
data types, and the H-registers even less so. Rather than trying to model the
|
||||||
|
H-registers accurately, we'll avoid using them in both I32 and I64 modes.
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from cdsl.registers import RegBank
|
||||||
|
from .defs import ISA
|
||||||
|
|
||||||
|
|
||||||
|
IntRegs = RegBank(
|
||||||
|
'IntRegs', ISA,
|
||||||
|
'General purpose registers',
|
||||||
|
units=16, prefix='r',
|
||||||
|
names='rax rcx rdx rbx rsp rbp rsi rdi'.split())
|
||||||
|
|
||||||
|
FloatRegs = RegBank(
|
||||||
|
'FloatRegs', ISA,
|
||||||
|
'SSE floating point registers',
|
||||||
|
units=16, prefix='xmm')
|
||||||
18
lib/cretonne/meta/isa/riscv/registers.py
Normal file
18
lib/cretonne/meta/isa/riscv/registers.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
"""
|
||||||
|
RISC-V register banks.
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from cdsl.registers import RegBank
|
||||||
|
from .defs import ISA
|
||||||
|
|
||||||
|
|
||||||
|
# We include `x0`, a.k.a `zero` in the register bank. It will be reserved.
|
||||||
|
IntRegs = RegBank(
|
||||||
|
'IntRegs', ISA,
|
||||||
|
'General purpose registers',
|
||||||
|
units=32, prefix='x')
|
||||||
|
|
||||||
|
FloatRegs = RegBank(
|
||||||
|
'FloatRegs', ISA,
|
||||||
|
'Floating point registers',
|
||||||
|
units=32, prefix='f')
|
||||||
Reference in New Issue
Block a user