mirror of
https://github.com/RRZE-HPC/OSACA.git
synced 2025-12-13 07:30:06 +01:00
Apply selected improvements from 1ceac6e: enhanced RISC-V parser, ImmediateOperand enhancements, and rv6→rv64 file renames
- Enhanced ImmediateOperand with reloc_type and symbol attributes for better RISC-V support - Updated RISC-V parser with relocation type support (%hi, %lo, %pcrel_hi, etc.) - Renamed example files from rv6 to rv64 for consistency - Updated related configuration and test files - All 115 tests pass successfully
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,7 +1,5 @@
|
||||
# OSACA specific files and folders
|
||||
*.*.pickle
|
||||
osaca_testfront_venv/
|
||||
examples/riscy_asm_files/
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
|
||||
@@ -661,7 +661,7 @@ instruction_forms:
|
||||
latency: 3
|
||||
throughput: 1
|
||||
port_pressure: [[1, ["FP"]]]
|
||||
|
||||
|
||||
- name: VFMADD.VV
|
||||
operands:
|
||||
- class: register
|
||||
|
||||
@@ -10,6 +10,8 @@ class ImmediateOperand(Operand):
|
||||
imd_type=None,
|
||||
value=None,
|
||||
shift=None,
|
||||
reloc_type=None,
|
||||
symbol=None,
|
||||
source=False,
|
||||
destination=False,
|
||||
):
|
||||
@@ -18,6 +20,8 @@ class ImmediateOperand(Operand):
|
||||
self._imd_type = imd_type
|
||||
self._value = value
|
||||
self._shift = shift
|
||||
self._reloc_type = reloc_type
|
||||
self._symbol = symbol
|
||||
|
||||
@property
|
||||
def identifier(self):
|
||||
@@ -33,7 +37,15 @@ class ImmediateOperand(Operand):
|
||||
|
||||
@property
|
||||
def shift(self):
|
||||
return self._imd_type
|
||||
return self._shift
|
||||
|
||||
@property
|
||||
def reloc_type(self):
|
||||
return self._reloc_type
|
||||
|
||||
@property
|
||||
def symbol(self):
|
||||
return self._symbol
|
||||
|
||||
@imd_type.setter
|
||||
def imd_type(self, itype):
|
||||
@@ -51,10 +63,19 @@ class ImmediateOperand(Operand):
|
||||
def shift(self, shift):
|
||||
self._shift = shift
|
||||
|
||||
@reloc_type.setter
|
||||
def reloc_type(self, reloc_type):
|
||||
self._reloc_type = reloc_type
|
||||
|
||||
@symbol.setter
|
||||
def symbol(self, symbol):
|
||||
self._symbol = symbol
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
f"Immediate(identifier={self._identifier}, imd_type={self._imd_type}, "
|
||||
f"value={self._value}, shift={self._shift}, source={self._source}, destination={self._destination})"
|
||||
f"value={self._value}, shift={self._shift}, reloc_type={self._reloc_type}, "
|
||||
f"symbol={self._symbol}, source={self._source}, destination={self._destination})"
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
@@ -62,10 +83,18 @@ class ImmediateOperand(Operand):
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, ImmediateOperand):
|
||||
# Handle cases where old instances might not have the new attributes
|
||||
self_reloc_type = getattr(self, "_reloc_type", None)
|
||||
self_symbol = getattr(self, "_symbol", None)
|
||||
other_reloc_type = getattr(other, "_reloc_type", None)
|
||||
other_symbol = getattr(other, "_symbol", None)
|
||||
|
||||
return (
|
||||
self._identifier == other._identifier
|
||||
and self._imd_type == other._imd_type
|
||||
and self._value == other._value
|
||||
and self._shift == other._shift
|
||||
and self_reloc_type == other_reloc_type
|
||||
and self_symbol == other_symbol
|
||||
)
|
||||
return False
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -873,13 +873,13 @@ class MachineModel(object):
|
||||
if not isinstance(i_operand, RegisterOperand):
|
||||
return False
|
||||
return self._is_RISCV_reg_type(i_operand, operand)
|
||||
|
||||
|
||||
# memory
|
||||
if isinstance(operand, MemoryOperand):
|
||||
if not isinstance(i_operand, MemoryOperand):
|
||||
return False
|
||||
return self._is_RISCV_mem_type(i_operand, operand)
|
||||
|
||||
|
||||
# immediate
|
||||
if isinstance(operand, (ImmediateOperand, int)):
|
||||
if not isinstance(i_operand, ImmediateOperand):
|
||||
@@ -895,7 +895,7 @@ class MachineModel(object):
|
||||
if i_operand.imd_type == self.WILDCARD:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# identifier
|
||||
if isinstance(operand, IdentifierOperand) or (
|
||||
isinstance(operand, ImmediateOperand) and operand.identifier is not None
|
||||
@@ -1011,7 +1011,7 @@ class MachineModel(object):
|
||||
# check for wildcards
|
||||
if reg.prefix == self.WILDCARD or i_reg.prefix == self.WILDCARD:
|
||||
return True
|
||||
|
||||
|
||||
# First handle potentially None values to avoid AttributeError
|
||||
if reg.name is None or i_reg.name is None:
|
||||
# If both have same prefix, they might still match
|
||||
@@ -1019,12 +1019,13 @@ class MachineModel(object):
|
||||
return True
|
||||
# If we can't determine canonical names, be conservative and return False
|
||||
return False
|
||||
|
||||
|
||||
# Check for ABI name (a0, t0, etc.) vs x-prefix registers (x10, x5, etc.)
|
||||
if (reg.prefix is None and i_reg.prefix == "x") or (reg.prefix == "x" and i_reg.prefix is None):
|
||||
try:
|
||||
# Need to check if they refer to the same register
|
||||
from osaca.parser import ParserRISCV
|
||||
|
||||
parser = ParserRISCV()
|
||||
reg_canonical = parser._get_canonical_reg_name(reg)
|
||||
i_reg_canonical = parser._get_canonical_reg_name(i_reg)
|
||||
@@ -1032,16 +1033,16 @@ class MachineModel(object):
|
||||
return True
|
||||
except (AttributeError, KeyError):
|
||||
return False
|
||||
|
||||
|
||||
# Check for direct prefix matches
|
||||
if reg.prefix == i_reg.prefix:
|
||||
# For vector registers, check lanes if present
|
||||
if reg.prefix == "v" and reg.lanes is not None and i_reg.lanes is not None:
|
||||
return reg.lanes == i_reg.lanes or self.WILDCARD in (reg.lanes + i_reg.lanes)
|
||||
return True
|
||||
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _is_AArch64_mem_type(self, i_mem, mem):
|
||||
"""Check if memory addressing type match."""
|
||||
if (
|
||||
@@ -1181,4 +1182,4 @@ class MachineModel(object):
|
||||
|
||||
def __represent_none(self, yaml_obj, data):
|
||||
"""YAML representation for `None`"""
|
||||
return yaml_obj.represent_scalar("tag:yaml.org,2002:null", "~")
|
||||
return yaml_obj.represent_scalar("tag:yaml.org,2002:null", "~")
|
||||
|
||||
@@ -307,11 +307,13 @@ class TestCLI(unittest.TestCase):
|
||||
@staticmethod
|
||||
def _find_file(kernel, arch, comp):
|
||||
testdir = os.path.dirname(__file__)
|
||||
# Handle special case for rv64 architecture
|
||||
arch_prefix = arch.lower() if arch.lower() == "rv64" else arch[:3].lower()
|
||||
name = os.path.join(
|
||||
testdir,
|
||||
"../examples",
|
||||
kernel,
|
||||
kernel + ".s." + arch[:3].lower() + "." + comp.lower() + ".s",
|
||||
kernel + ".s." + arch_prefix + "." + comp.lower() + ".s",
|
||||
)
|
||||
if kernel == "j2d" and arch.lower() == "csx":
|
||||
name = name[:-1] + "AVX.s"
|
||||
|
||||
@@ -8,9 +8,7 @@ import unittest
|
||||
|
||||
from pyparsing import ParseException
|
||||
|
||||
from osaca.parser import ParserRISCV, InstructionForm
|
||||
from osaca.parser.directive import DirectiveOperand
|
||||
from osaca.parser.memory import MemoryOperand
|
||||
from osaca.parser import ParserRISCV
|
||||
from osaca.parser.register import RegisterOperand
|
||||
from osaca.parser.immediate import ImmediateOperand
|
||||
from osaca.parser.identifier import IdentifierOperand
|
||||
@@ -105,7 +103,7 @@ class TestParserRISCV(unittest.TestCase):
|
||||
# Test 1: Line with label and instruction
|
||||
parsed_1 = self.parser.parse_line(".L2:")
|
||||
self.assertEqual(parsed_1.label, ".L2")
|
||||
|
||||
|
||||
# Test 2: Line with instruction and comment
|
||||
parsed_2 = self.parser.parse_line("addi x10, x10, 1 # increment")
|
||||
self.assertEqual(parsed_2.mnemonic, "addi")
|
||||
@@ -118,14 +116,14 @@ class TestParserRISCV(unittest.TestCase):
|
||||
def test_parse_file(self):
|
||||
parsed = self.parser.parse_file(self.riscv_code)
|
||||
self.assertGreater(len(parsed), 10) # There should be multiple lines
|
||||
|
||||
|
||||
# Find common elements that should exist in any RISC-V file
|
||||
# without being tied to specific line numbers
|
||||
|
||||
|
||||
# Verify that we can find at least one label
|
||||
label_forms = [form for form in parsed if form.label is not None]
|
||||
self.assertGreater(len(label_forms), 0, "No labels found in the file")
|
||||
|
||||
|
||||
# Verify that we can find at least one branch instruction
|
||||
branch_forms = [form for form in parsed if form.mnemonic and form.mnemonic.startswith("b")]
|
||||
self.assertGreater(len(branch_forms), 0, "No branch instructions found in the file")
|
||||
@@ -148,7 +146,7 @@ class TestParserRISCV(unittest.TestCase):
|
||||
reg_a0 = RegisterOperand(name="a0")
|
||||
reg_t1 = RegisterOperand(name="t1")
|
||||
reg_s2 = RegisterOperand(name="s2")
|
||||
|
||||
|
||||
reg_x0 = RegisterOperand(prefix="x", name="0")
|
||||
reg_x1 = RegisterOperand(prefix="x", name="1")
|
||||
reg_x2 = RegisterOperand(prefix="x", name="2")
|
||||
@@ -156,7 +154,7 @@ class TestParserRISCV(unittest.TestCase):
|
||||
reg_x10 = RegisterOperand(prefix="x", name="10")
|
||||
reg_x6 = RegisterOperand(prefix="x", name="6")
|
||||
reg_x18 = RegisterOperand(prefix="x", name="18")
|
||||
|
||||
|
||||
# Test canonical name conversion
|
||||
self.assertEqual(self.parser._get_canonical_reg_name(reg_zero), "x0")
|
||||
self.assertEqual(self.parser._get_canonical_reg_name(reg_ra), "x1")
|
||||
@@ -164,7 +162,7 @@ class TestParserRISCV(unittest.TestCase):
|
||||
self.assertEqual(self.parser._get_canonical_reg_name(reg_a0), "x10")
|
||||
self.assertEqual(self.parser._get_canonical_reg_name(reg_t1), "x6")
|
||||
self.assertEqual(self.parser._get_canonical_reg_name(reg_s2), "x18")
|
||||
|
||||
|
||||
# Test register dependency
|
||||
self.assertTrue(self.parser.is_reg_dependend_of(reg_zero, reg_x0))
|
||||
self.assertTrue(self.parser.is_reg_dependend_of(reg_ra, reg_x1))
|
||||
@@ -172,29 +170,27 @@ class TestParserRISCV(unittest.TestCase):
|
||||
self.assertTrue(self.parser.is_reg_dependend_of(reg_a0, reg_x10))
|
||||
self.assertTrue(self.parser.is_reg_dependend_of(reg_t1, reg_x6))
|
||||
self.assertTrue(self.parser.is_reg_dependend_of(reg_s2, reg_x18))
|
||||
|
||||
|
||||
# Test non-dependent registers
|
||||
self.assertFalse(self.parser.is_reg_dependend_of(reg_zero, reg_x1))
|
||||
self.assertFalse(self.parser.is_reg_dependend_of(reg_ra, reg_x2))
|
||||
self.assertFalse(self.parser.is_reg_dependend_of(reg_a0, reg_t1))
|
||||
|
||||
|
||||
# Test floating-point registers
|
||||
reg_fa0 = RegisterOperand(prefix="f", name="a0")
|
||||
reg_fa1 = RegisterOperand(prefix="f", name="a1")
|
||||
reg_f10 = RegisterOperand(prefix="f", name="10")
|
||||
|
||||
|
||||
# Test vector registers
|
||||
reg_v1 = RegisterOperand(prefix="v", name="1")
|
||||
reg_v2 = RegisterOperand(prefix="v", name="2")
|
||||
|
||||
|
||||
# Test register type detection
|
||||
self.assertTrue(self.parser.is_gpr(reg_a0))
|
||||
self.assertTrue(self.parser.is_gpr(reg_x5))
|
||||
self.assertTrue(self.parser.is_gpr(reg_sp))
|
||||
|
||||
|
||||
self.assertFalse(self.parser.is_gpr(reg_fa0))
|
||||
self.assertFalse(self.parser.is_gpr(reg_f10))
|
||||
|
||||
|
||||
self.assertTrue(self.parser.is_vector_register(reg_v1))
|
||||
self.assertFalse(self.parser.is_vector_register(reg_x10))
|
||||
self.assertFalse(self.parser.is_vector_register(reg_fa0))
|
||||
|
||||
Reference in New Issue
Block a user