diff --git a/tests/backend/test_register.py b/tests/backend/test_register.py new file mode 100644 index 0000000000..ebf9b74613 --- /dev/null +++ b/tests/backend/test_register.py @@ -0,0 +1,31 @@ +import pytest + +from xdsl.backend.register_type import RegisterType +from xdsl.irdl import irdl_attr_definition + + +@irdl_attr_definition +class TestRegister(RegisterType): + name = "test.reg" + + def verify(self) -> None: ... + + @classmethod + def instruction_set_name(cls) -> str: + return "TEST" + + @classmethod + def abi_index_by_name(cls) -> dict[str, int]: + return {"x0": 0} + + @classmethod + def infinite_register_prefix(cls): + return "x" + + +def test_register_clashes(): + with pytest.raises( + AssertionError, + match="Invalid 'infinite' register name: x0 clashes with finite register set", + ): + TestRegister.infinite_register(0) diff --git a/xdsl/backend/register_type.py b/xdsl/backend/register_type.py index 3e30f1a27b..bb89278833 100644 --- a/xdsl/backend/register_type.py +++ b/xdsl/backend/register_type.py @@ -3,6 +3,8 @@ from abc import ABC, abstractmethod from collections.abc import Sequence +from typing_extensions import Self + from xdsl.dialects.builtin import ( IntAttr, NoneAttr, @@ -78,3 +80,25 @@ def instruction_set_name(cls) -> str: @abstractmethod def abi_index_by_name(cls) -> dict[str, int]: raise NotImplementedError() + + @classmethod + @abstractmethod + def infinite_register_prefix(cls) -> str: + """ + Provide the prefix for the spelling for a register at the given index in the + "infinite" register set. + For a prefix `x`, the spelling of the first infinite register will be `x0`. + """ + raise NotImplementedError() + + @classmethod + def infinite_register(cls, index: int) -> Self: + """ + Provide the register at the given index in the "infinite" register set. + """ + spelling = cls.infinite_register_prefix() + str(index) + res = cls(spelling) + assert isinstance(res.index, NoneAttr), ( + f"Invalid 'infinite' register name: {spelling} clashes with finite register set" + ) + return res diff --git a/xdsl/backend/riscv/riscv_register_queue.py b/xdsl/backend/riscv/riscv_register_queue.py index a71612510e..c61b5751fc 100644 --- a/xdsl/backend/riscv/riscv_register_queue.py +++ b/xdsl/backend/riscv/riscv_register_queue.py @@ -85,10 +85,10 @@ def pop( reg = available_registers.pop() else: if issubclass(reg_type, IntRegisterType): - reg = reg_type(f"j_{self._j_idx}") + reg = reg_type.infinite_register(self._j_idx) self._j_idx += 1 else: - reg = reg_type(f"fj_{self._fj_idx}") + reg = reg_type.infinite_register(self._fj_idx) self._fj_idx += 1 reserved_registers = ( diff --git a/xdsl/dialects/arm/register.py b/xdsl/dialects/arm/register.py index 309a129c45..bfac1356ba 100644 --- a/xdsl/dialects/arm/register.py +++ b/xdsl/dialects/arm/register.py @@ -35,6 +35,10 @@ def instruction_set_name(cls) -> str: def abi_index_by_name(cls) -> dict[str, int]: return ARM_INDEX_BY_NAME + @classmethod + def infinite_register_prefix(cls): + return "inf_" + UNALLOCATED_INT = IntRegisterType("") X0 = IntRegisterType("x0") diff --git a/xdsl/dialects/riscv.py b/xdsl/dialects/riscv.py index 8ed9e42c2f..c36f4e87f9 100644 --- a/xdsl/dialects/riscv.py +++ b/xdsl/dialects/riscv.py @@ -156,6 +156,10 @@ def abi_index_by_name(cls) -> dict[str, int]: def a_register(cls, index: int) -> IntRegisterType: return Registers.A[index] + @classmethod + def infinite_register_prefix(cls): + return "j_" + RV32F_INDEX_BY_NAME = { "ft0": 0, @@ -213,6 +217,10 @@ def abi_index_by_name(cls) -> dict[str, int]: def a_register(cls, index: int) -> FloatRegisterType: return Registers.FA[index] + @classmethod + def infinite_register_prefix(cls): + return "fj_" + RDInvT = TypeVar("RDInvT", bound=RISCVRegisterType) RSInvT = TypeVar("RSInvT", bound=RISCVRegisterType) diff --git a/xdsl/dialects/x86/register.py b/xdsl/dialects/x86/register.py index f5d1540555..a20fc7ff0d 100644 --- a/xdsl/dialects/x86/register.py +++ b/xdsl/dialects/x86/register.py @@ -67,6 +67,10 @@ def instruction_set_name(cls) -> str: def abi_index_by_name(cls) -> dict[str, int]: return X86_INDEX_BY_NAME + @classmethod + def infinite_register_prefix(cls): + return "inf_reg_" + UNALLOCATED_GENERAL = GeneralRegisterType("") RAX = GeneralRegisterType("rax") @@ -117,6 +121,10 @@ def instruction_set_name(cls) -> str: def abi_index_by_name(cls) -> dict[str, int]: return RFLAGS_INDEX_BY_NAME + @classmethod + def infinite_register_prefix(cls): + return "inf_rflags_" + UNALLOCATED_RFLAGS = RFLAGSRegisterType("") RFLAGS = RFLAGSRegisterType("rflags") @@ -146,6 +154,10 @@ def instruction_set_name(cls) -> str: def abi_index_by_name(cls) -> dict[str, int]: return SSE_INDEX_BY_NAME + @classmethod + def infinite_register_prefix(cls): + return "inf_sse_" + # See https://wiki.osdev.org/X86-64_Instruction_Encoding#Registers SSE_INDEX_BY_NAME = { @@ -202,6 +214,10 @@ def instruction_set_name(cls) -> str: def abi_index_by_name(cls) -> dict[str, int]: return AVX2_INDEX_BY_NAME + @classmethod + def infinite_register_prefix(cls): + return "inf_avx2_" + # See https://wiki.osdev.org/X86-64_Instruction_Encoding#Registers AVX2_INDEX_BY_NAME = { @@ -258,6 +274,10 @@ def instruction_set_name(cls) -> str: def abi_index_by_name(cls) -> dict[str, int]: return X86AVX512_INDEX_BY_NAME + @classmethod + def infinite_register_prefix(cls): + return "inf_avx512_" + # See https://wiki.osdev.org/X86-64_Instruction_Encoding#Registers X86AVX512_INDEX_BY_NAME = {