diff --git a/osaca/parser/parser_x86att.py b/osaca/parser/parser_x86att.py index 08fc8ba..0bc8d96 100755 --- a/osaca/parser/parser_x86att.py +++ b/osaca/parser/parser_x86att.py @@ -92,6 +92,8 @@ class ParserX86ATT(BaseParser): + pp.Optional(operand_rest.setResultsName('operand2')) + pp.Optional(pp.Suppress(pp.Literal(','))) + pp.Optional(operand_rest.setResultsName('operand3')) + + pp.Optional(pp.Suppress(pp.Literal(','))) + + pp.Optional(operand_rest.setResultsName('operand4')) + pp.Optional(self.comment) ) @@ -179,9 +181,15 @@ class ParserX86ATT(BaseParser): result = AttrDict.convert_dict(result) operands = AttrDict({'source': [], 'destination': []}) # Check from right to left + # Check fourth operand + if 'operand4' in result: + operands['destination'].append(self.process_operand(result['operand4'])) # Check third operand if 'operand3' in result: - operands['destination'].append(self.process_operand(result['operand3'])) + if len(operands['destination']) != 0: + operands['source'].insert(0, self.process_operand(result['operand3'])) + else: + operands['destination'].append(self.process_operand(result['operand3'])) # Check second operand if 'operand2' in result: if len(operands['destination']) != 0: diff --git a/tests/all_tests.py b/tests/all_tests.py index b4d7607..44d6392 100755 --- a/tests/all_tests.py +++ b/tests/all_tests.py @@ -8,7 +8,8 @@ suite = unittest.TestLoader().loadTestsFromNames( [ 'test_parser_x86att', 'test_parser_AArch64v81', - 'test_marker_utils' + 'test_marker_utils', + 'test_dependency_finder' ] ) diff --git a/tests/test_dependency_finder.py b/tests/test_dependency_finder.py new file mode 100755 index 0000000..c886964 --- /dev/null +++ b/tests/test_dependency_finder.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +""" +Unit tests for KernelDAG +""" + +import os +import unittest + +from osaca.dependency_finder import KernelDAG +from osaca.parser import AttrDict, ParserAArch64v81, ParserX86ATT + + +class TestDependencyFinder(unittest.TestCase): + def setUp(self): + self.parser_x86 = ParserX86ATT() + self.parser_AArch64 = ParserAArch64v81() + with open(self._find_file('kernel-x86.s')) as f: + code_x86 = f.read() + with open(self._find_file('kernel-AArch64.s')) as f: + code_AArch64 = f.read() + self.kernel_x86 = self.parser_x86.parse_file(code_x86) + self.kernel_AArch64 = self.parser_AArch64.parse_file(code_AArch64) + + ########### + # Tests + ########### + + def test_is_read_is_written_x86(self): + # independent form HW model + dag = KernelDAG(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)') + instr_form_non_r_c = self.parser_x86.parse_line('movl %xmm0, (%r15,%rax,8)') + instr_form_w_c = self.parser_x86.parse_line('movi $0x05ACA, %rcx') + + instr_form_rw_ymm_1 = self.parser_x86.parse_line('vinsertf128 $0x1, %xmm1, %ymm0, %ymm1') + instr_form_rw_ymm_2 = self.parser_x86.parse_line('vinsertf128 $0x1, %xmm0, %ymm1, %ymm1') + instr_form_r_ymm = self.parser_x86.parse_line('vmovapd %ymm1, %ymm0') + + self.assertTrue(dag.is_read(reg_rcx, instr_form_r_c)) + self.assertFalse(dag.is_read(reg_rcx, instr_form_non_r_c)) + self.assertFalse(dag.is_read(reg_rcx, instr_form_w_c)) + self.assertTrue(dag.is_written(reg_rcx, instr_form_w_c)) + self.assertFalse(dag.is_written(reg_rcx, instr_form_r_c)) + + self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_1)) + self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_2)) + self.assertTrue(dag.is_read(reg_ymm1, instr_form_r_ymm)) + self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_1)) + self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_2)) + self.assertFalse(dag.is_written(reg_ymm1, instr_form_r_ymm)) + + def test_is_read_is_written_AArch64(self): + # independent form HW model + dag = KernelDAG(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]') + instr_form_r_2 = self.parser_AArch64.parse_line('fadd v2.2d, v1.2d, v0.2d') + instr_form_w_1 = self.parser_AArch64.parse_line('ldr x0, [x0, #:got_lo12:q2c]') + instr_form_rw_1 = self.parser_AArch64.parse_line('fmul v1.2d, v1.2d, v0.2d') + instr_form_rw_2 = self.parser_AArch64.parse_line('ldp q2, q4, [x1, #64]!') + instr_form_rw_3 = self.parser_AArch64.parse_line('str x4, [x1], #64') + instr_form_non_rw_1 = self.parser_AArch64.parse_line('adds x0, x11') + + for reg in regs: + with self.subTest(reg=reg): + self.assertTrue(dag.is_read(reg, instr_form_r_1)) + self.assertTrue(dag.is_read(reg, instr_form_r_2)) + self.assertTrue(dag.is_read(reg, instr_form_rw_1)) + self.assertTrue(dag.is_read(reg, instr_form_rw_2)) + self.assertTrue(dag.is_read(reg, instr_form_rw_3)) + self.assertFalse(dag.is_read(reg, instr_form_w_1)) + self.assertTrue(dag.is_written(reg, instr_form_rw_1)) + self.assertTrue(dag.is_written(reg, instr_form_rw_2)) + self.assertTrue(dag.is_written(reg, instr_form_rw_3)) + self.assertFalse(dag.is_written(reg, instr_form_non_rw_1)) + self.assertFalse(dag.is_written(reg, instr_form_non_rw_1)) + + ################## + # Helper functions + ################## + + @staticmethod + def _find_file(name): + testdir = os.path.dirname(__file__) + name = os.path.join(testdir, 'test_files', name) + assert os.path.exists(name) + return name + + +if __name__ == '__main__': + suite = unittest.TestLoader().loadTestsFromTestCase(TestDependencyFinder) + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/tests/test_files/kernel-AArch64.s b/tests/test_files/kernel-AArch64.s new file mode 100644 index 0000000..af5d048 --- /dev/null +++ b/tests/test_files/kernel-AArch64.s @@ -0,0 +1,20 @@ +.LBB0_32: + ldp q4, q5, [x9, #-32] + ldp q6, q7, [x9], #64 + ldp q16, q17, [x11, #-32] + ldp q18, q19, [x11], #64 + fmul v4.2d, v4.2d, v16.2d + fmul v5.2d, v5.2d, v17.2d + fmul v6.2d, v6.2d, v18.2d + fmul v7.2d, v7.2d, v19.2d + ldp q0, q1, [x8, #-32] + ldp q2, q3, [x8], #64 + fadd v0.2d, v0.2d, v4.2d + fadd v1.2d, v1.2d, v5.2d + stp q0, q1, [x10, #-32] + fadd v2.2d, v2.2d, v6.2d + fadd v3.2d, v3.2d, v7.2d + stp q2, q3, [x10] + add x10, x10, #64 // =64 + adds x12, x12, #1 // =1 + b.ne .LBB0_32 diff --git a/tests/test_files/kernel-x86.s b/tests/test_files/kernel-x86.s new file mode 100644 index 0000000..3dd3185 --- /dev/null +++ b/tests/test_files/kernel-x86.s @@ -0,0 +1,9 @@ +.L10: + vmovapd (%r15,%rax), %ymm0 + vmovapd (%r12,%rax), %ymm3 + addl $1, %ecx + vfmadd132pd 0(%r13,%rax), %ymm3, %ymm0 + vmovapd %ymm0, (%r14,%rax) + addq $32, %rax + cmpl %ecx, %r10d + ja .L10 diff --git a/tests/test_parser_x86att.py b/tests/test_parser_x86att.py index 9927956..2b678e4 100755 --- a/tests/test_parser_x86att.py +++ b/tests/test_parser_x86att.py @@ -75,6 +75,7 @@ class TestParserX86ATT(unittest.TestCase): instr4 = 'vmovss %xmm4, -4(%rsp,%rax,8) #12.9' instr5 = 'mov %ebx,var(,1)' instr6 = 'lea (,%rax,8),%rbx' + instr7 = 'vinsertf128 $0x1, %xmm0, %ymm1, %ymm1' parsed_1 = self.parser.parse_instruction(instr1) parsed_2 = self.parser.parse_instruction(instr2) @@ -82,6 +83,7 @@ class TestParserX86ATT(unittest.TestCase): parsed_4 = self.parser.parse_instruction(instr4) parsed_5 = self.parser.parse_instruction(instr5) parsed_6 = self.parser.parse_instruction(instr6) + parsed_7 = self.parser.parse_instruction(instr7) self.assertEqual(parsed_1.instruction, 'vcvtsi2ss') self.assertEqual(parsed_1.operands.destination[0].register.name, 'xmm2') @@ -120,6 +122,11 @@ class TestParserX86ATT(unittest.TestCase): self.assertEqual(parsed_6.operands.source[0].memory.scale, '8') self.assertEqual(parsed_6.operands.destination[0].register.name, 'rbx') + self.assertEqual(parsed_7.operands.source[0].immediate.value, '0x1') + self.assertEqual(parsed_7.operands.source[1].register.name, 'xmm0') + self.assertEqual(parsed_7.operands.source[2].register.name, 'ymm1') + self.assertEqual(parsed_7.operands.destination[0].register.name, 'ymm1') + def test_parse_line(self): line_comment = '# -- Begin main' line_label = '..B1.7: # Preds ..B1.6'