mirror of
https://github.com/RRZE-HPC/OSACA.git
synced 2025-12-16 09:00:05 +01:00
finished refactoring for semanticsAppender, including first tests
This commit is contained in:
@@ -45,11 +45,11 @@ instruction_forms:
|
||||
prefix: "d"
|
||||
source: false
|
||||
destination: true
|
||||
- class: "register"
|
||||
- class: "register"
|
||||
prefix: "d"
|
||||
source: false
|
||||
destination: true
|
||||
- class: "memory"
|
||||
- class: "memory"
|
||||
base: "x"
|
||||
offset: "imd"
|
||||
index: ~
|
||||
@@ -64,11 +64,11 @@ instruction_forms:
|
||||
prefix: "q"
|
||||
source: false
|
||||
destination: true
|
||||
- class: "register"
|
||||
- class: "register"
|
||||
prefix: "q"
|
||||
source: false
|
||||
destination: true
|
||||
- class: "memory"
|
||||
- class: "memory"
|
||||
base: "x"
|
||||
offset: "imd"
|
||||
index: ~
|
||||
@@ -83,11 +83,11 @@ instruction_forms:
|
||||
prefix: "d"
|
||||
source: true
|
||||
destination: false
|
||||
- class: "register"
|
||||
- class: "register"
|
||||
prefix: "d"
|
||||
source: true
|
||||
destination: false
|
||||
- class: "memory"
|
||||
- class: "memory"
|
||||
base: "x"
|
||||
offset: "imd"
|
||||
index: ~
|
||||
@@ -102,11 +102,11 @@ instruction_forms:
|
||||
prefix: "q"
|
||||
source: true
|
||||
destination: false
|
||||
- class: "register"
|
||||
- class: "register"
|
||||
prefix: "q"
|
||||
source: true
|
||||
destination: false
|
||||
- class: "memory"
|
||||
- class: "memory"
|
||||
base: "x"
|
||||
offset: "imd"
|
||||
index: ~
|
||||
|
||||
@@ -48,10 +48,10 @@ instruction_forms:
|
||||
- name: vaddsd
|
||||
operands:
|
||||
- class: "register"
|
||||
name: "xmm"
|
||||
source: true
|
||||
destination: true
|
||||
- class: "register"
|
||||
name: "xmm"
|
||||
source: true
|
||||
destination: false
|
||||
name: "xmm"
|
||||
source: true
|
||||
destination: true
|
||||
- class: "register"
|
||||
name: "xmm"
|
||||
source: true
|
||||
destination: false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
from osaca.parser.parser_x86att import ParserX86ATT
|
||||
from osaca.parser import ParserX86ATT
|
||||
|
||||
from ruamel import yaml
|
||||
|
||||
@@ -34,7 +34,7 @@ class MachineModel(object):
|
||||
|
||||
def _find_file(self, name):
|
||||
data_dir = os.path.expanduser('~/.osaca/data')
|
||||
name = os.path.join(data_dir, name)
|
||||
name = os.path.join(data_dir, name + '.yml')
|
||||
assert os.path.exists(name)
|
||||
return name
|
||||
|
||||
@@ -92,7 +92,7 @@ class MachineModel(object):
|
||||
if 'memory' in operand:
|
||||
if i_operand['class'] != 'memory':
|
||||
return False
|
||||
return self._is_AArch64_mem_type(i_operand['memory'], operand['memory'])
|
||||
return self._is_AArch64_mem_type(i_operand, operand['memory'])
|
||||
# immediate
|
||||
if 'value' in operand:
|
||||
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'int'
|
||||
@@ -116,7 +116,7 @@ class MachineModel(object):
|
||||
if 'memory' in operand:
|
||||
if i_operand['class'] != 'memory':
|
||||
return False
|
||||
return self._is_x86_mem_type(i_operand['memory'], operand['memory'])
|
||||
return self._is_x86_mem_type(i_operand, operand['memory'])
|
||||
# immediate
|
||||
if 'value' in operand:
|
||||
return i_operand['class'] == 'immediate' and i_operand['imd'] == 'int'
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import os
|
||||
|
||||
from osaca.parser import AttrDict
|
||||
from .hw_model import MachineModel
|
||||
|
||||
|
||||
@@ -21,20 +22,71 @@ class SemanticsAppender(object):
|
||||
# - source
|
||||
# - destination
|
||||
# - source/destination
|
||||
|
||||
# for this, have a default implementation and get exceptions from generic x86/AArch64 ISA file
|
||||
def assign_src_dst(self, instruction_form):
|
||||
# if the instruction form doesn't have operands, there's nothing to do
|
||||
if instruction_form['operands'] is None:
|
||||
return
|
||||
# check if instruction form is in ISA yaml, otherwise apply standard operand assignment
|
||||
# (one dest, others source)
|
||||
isa_data = self._isa_model.get_instruction(
|
||||
instruction_form['name'], instruction_form['operands']
|
||||
instruction_form['instruction'], instruction_form['operands']
|
||||
)
|
||||
operands = instruction_form['operands']
|
||||
op_dict = {}
|
||||
if isa_data is None:
|
||||
# no irregular operand structure, apply default
|
||||
# TODO
|
||||
pass
|
||||
op_dict['source'] = self._get_regular_source_operands(instruction_form)
|
||||
op_dict['destination'] = self._get_regular_destination_operands(instruction_form)
|
||||
op_dict['src_dst'] = []
|
||||
else:
|
||||
# load src/dst structure from isa_data
|
||||
# TODO
|
||||
pass
|
||||
raise NotImplementedError
|
||||
op_dict['source'] = []
|
||||
op_dict['destination'] = []
|
||||
op_dict['src_dst'] = []
|
||||
for i, op in enumerate(isa_data['operands']):
|
||||
if op['source'] and op['destination']:
|
||||
op_dict['src_dst'].append(operands[i])
|
||||
continue
|
||||
if op['source']:
|
||||
op_dict['source'].append(operands[i])
|
||||
continue
|
||||
if op['destination']:
|
||||
op_dict['destination'].append(operands[i])
|
||||
continue
|
||||
# store operand list in dict and reassign operand key/value pair
|
||||
op_dict['operand_list'] = operands
|
||||
instruction_form['operands'] = AttrDict.convert_dict(op_dict)
|
||||
|
||||
def _get_regular_source_operands(self, instruction_form):
|
||||
if self._isa == 'x86':
|
||||
return self._get_regular_source_x86ATT(instruction_form)
|
||||
if self._isa == 'AArch64':
|
||||
return self._get_regular_source_AArch64(instruction_form)
|
||||
|
||||
def _get_regular_destination_operands(self, instruction_form):
|
||||
if self._isa == 'x86':
|
||||
return self._get_regular_destination_x86ATT(instruction_form)
|
||||
if self._isa == 'AArch64':
|
||||
return self._get_regular_destination_AArch64(instruction_form)
|
||||
|
||||
def _get_regular_source_x86ATT(self, instruction_form):
|
||||
# return all but last operand
|
||||
sources = [
|
||||
op for op in instruction_form['operands'][0:len(instruction_form['operands']) - 1]
|
||||
]
|
||||
return sources
|
||||
|
||||
def _get_regular_source_AArch64(self, instruction_form):
|
||||
# return all but first operand
|
||||
sources = [
|
||||
op for op in instruction_form['operands'][1:len(instruction_form['operands'])]
|
||||
]
|
||||
return sources
|
||||
|
||||
def _get_regular_destination_x86ATT(self, instruction_form):
|
||||
# return last operand
|
||||
return instruction_form['operands'][-1:]
|
||||
|
||||
def _get_regular_destination_AArch64(self, instruction_form):
|
||||
# return first operand
|
||||
return instruction_form['operands'][:1]
|
||||
|
||||
@@ -9,7 +9,7 @@ suite = unittest.TestLoader().loadTestsFromNames(
|
||||
'test_parser_x86att',
|
||||
'test_parser_AArch64v81',
|
||||
'test_marker_utils',
|
||||
# 'test_dependency_finder'
|
||||
'test_semantics'
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Unit tests for KernelDAG
|
||||
Unit tests for Semantic Analysis
|
||||
"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from osaca.dependency_finder import KernelDAG
|
||||
from osaca.parser import AttrDict, ParserAArch64v81, ParserX86ATT
|
||||
from osaca.semantics.kernel_dg import KernelDG
|
||||
from osaca.semantics.hw_model import MachineModel
|
||||
from osaca.semantics.semanticsAppender import SemanticsAppender
|
||||
|
||||
|
||||
class TestDependencyFinder(unittest.TestCase):
|
||||
class TestSemanticTools(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.parser_x86 = ParserX86ATT()
|
||||
self.parser_AArch64 = ParserAArch64v81()
|
||||
@@ -21,23 +23,54 @@ class TestDependencyFinder(unittest.TestCase):
|
||||
self.kernel_x86 = self.parser_x86.parse_file(code_x86)
|
||||
self.kernel_AArch64 = self.parser_AArch64.parse_file(code_AArch64)
|
||||
|
||||
self.machine_model_csl = MachineModel('csl')
|
||||
self.machine_model_tx2 = MachineModel('vulcan')
|
||||
self.semantics_csl = SemanticsAppender(self.machine_model_csl)
|
||||
self.semantics_tx2 = SemanticsAppender(self.machine_model_tx2)
|
||||
for i in range(len(self.kernel_x86)):
|
||||
self.semantics_csl.assign_src_dst(self.kernel_x86[i])
|
||||
for i in range(len(self.kernel_AArch64)):
|
||||
self.semantics_tx2.assign_src_dst(self.kernel_AArch64[i])
|
||||
|
||||
###########
|
||||
# Tests
|
||||
###########
|
||||
|
||||
def test_src_dst_assignment_x86(self):
|
||||
for instruction_form in self.kernel_x86:
|
||||
with self.subTest(instruction_form=instruction_form):
|
||||
if instruction_form['operands'] is not None:
|
||||
self.assertTrue('source' in instruction_form['operands'])
|
||||
self.assertTrue('destination' in instruction_form['operands'])
|
||||
self.assertTrue('src_dst' in instruction_form['operands'])
|
||||
|
||||
def test_src_dst_assignment_AArch64(self):
|
||||
for instruction_form in self.kernel_AArch64:
|
||||
with self.subTest(instruction_form=instruction_form):
|
||||
if instruction_form['operands'] is not None:
|
||||
self.assertTrue('source' in instruction_form['operands'])
|
||||
self.assertTrue('destination' in instruction_form['operands'])
|
||||
self.assertTrue('src_dst' in instruction_form['operands'])
|
||||
|
||||
def test_is_read_is_written_x86(self):
|
||||
# independent form HW model
|
||||
dag = KernelDAG(self.kernel_x86, self.parser_x86, None)
|
||||
dag = KernelDG(self.kernel_x86, self.parser_x86, None)
|
||||
reg_rcx = AttrDict({'name': 'rcx'})
|
||||
reg_ymm1 = AttrDict({'name': 'ymm1'})
|
||||
|
||||
instr_form_r_c = self.parser_x86.parse_line('vmovsd %xmm0, (%r15,%rcx,8)')
|
||||
self.semantics_csl.assign_src_dst(instr_form_r_c)
|
||||
instr_form_non_r_c = self.parser_x86.parse_line('movl %xmm0, (%r15,%rax,8)')
|
||||
self.semantics_csl.assign_src_dst(instr_form_non_r_c)
|
||||
instr_form_w_c = self.parser_x86.parse_line('movi $0x05ACA, %rcx')
|
||||
self.semantics_csl.assign_src_dst(instr_form_w_c)
|
||||
|
||||
instr_form_rw_ymm_1 = self.parser_x86.parse_line('vinsertf128 $0x1, %xmm1, %ymm0, %ymm1')
|
||||
self.semantics_csl.assign_src_dst(instr_form_rw_ymm_1)
|
||||
instr_form_rw_ymm_2 = self.parser_x86.parse_line('vinsertf128 $0x1, %xmm0, %ymm1, %ymm1')
|
||||
self.semantics_csl.assign_src_dst(instr_form_rw_ymm_2)
|
||||
instr_form_r_ymm = self.parser_x86.parse_line('vmovapd %ymm1, %ymm0')
|
||||
self.semantics_csl.assign_src_dst(instr_form_r_ymm)
|
||||
|
||||
self.assertTrue(dag.is_read(reg_rcx, instr_form_r_c))
|
||||
self.assertFalse(dag.is_read(reg_rcx, instr_form_non_r_c))
|
||||
@@ -54,19 +87,26 @@ class TestDependencyFinder(unittest.TestCase):
|
||||
|
||||
def test_is_read_is_written_AArch64(self):
|
||||
# independent form HW model
|
||||
dag = KernelDAG(self.kernel_AArch64, self.parser_AArch64, None)
|
||||
dag = KernelDG(self.kernel_AArch64, self.parser_AArch64, None)
|
||||
reg_x1 = AttrDict({'prefix': 'x', 'name': '1'})
|
||||
reg_q1 = AttrDict({'prefix': 'q', 'name': '1'})
|
||||
reg_v1 = AttrDict({'prefix': 'v', 'name': '1', 'lanes': '2', 'shape': 'd'})
|
||||
regs = [reg_x1, reg_q1, reg_v1]
|
||||
|
||||
instr_form_r_1 = self.parser_AArch64.parse_line('stp q1, q3, [x12, #192]')
|
||||
self.semantics_tx2.assign_src_dst(instr_form_r_1)
|
||||
instr_form_r_2 = self.parser_AArch64.parse_line('fadd v2.2d, v1.2d, v0.2d')
|
||||
self.semantics_tx2.assign_src_dst(instr_form_r_2)
|
||||
instr_form_w_1 = self.parser_AArch64.parse_line('ldr x0, [x0, #:got_lo12:q2c]')
|
||||
self.semantics_tx2.assign_src_dst(instr_form_w_1)
|
||||
instr_form_rw_1 = self.parser_AArch64.parse_line('fmul v1.2d, v1.2d, v0.2d')
|
||||
self.semantics_tx2.assign_src_dst(instr_form_rw_1)
|
||||
instr_form_rw_2 = self.parser_AArch64.parse_line('ldp q2, q4, [x1, #64]!')
|
||||
self.semantics_tx2.assign_src_dst(instr_form_rw_2)
|
||||
instr_form_rw_3 = self.parser_AArch64.parse_line('str x4, [x1], #64')
|
||||
self.semantics_tx2.assign_src_dst(instr_form_rw_3)
|
||||
instr_form_non_rw_1 = self.parser_AArch64.parse_line('adds x0, x11')
|
||||
self.semantics_tx2.assign_src_dst(instr_form_non_rw_1)
|
||||
|
||||
for reg in regs:
|
||||
with self.subTest(reg=reg):
|
||||
@@ -95,5 +135,5 @@ class TestDependencyFinder(unittest.TestCase):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestDependencyFinder)
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestSemanticTools)
|
||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
||||
Reference in New Issue
Block a user