1
0

Data flow improvements in pseudo code generator

This commit is contained in:
Aiden
2026-05-25 14:40:55 +10:00
parent 80819448cf
commit 1d7f00e59c
16 changed files with 105891 additions and 5141 deletions

108
tests/test_dataflow.py Normal file
View File

@@ -0,0 +1,108 @@
import unittest
from h8536.dataflow import analyze_dataflow, state_for_instruction
from h8536.model import Instruction
def reg_after(analysis, address, register):
return analysis["instructions"][address]["after"]["registers"][register]
def reg_before(analysis, address, register):
return analysis["instructions"][address]["before"]["registers"][register]
def control_after(analysis, address, register):
return analysis["instructions"][address]["after"]["control"][register]
class DataflowTest(unittest.TestCase):
def test_tracks_immediate_load_copy_and_simple_arithmetic(self):
instructions = {
0x0100: Instruction(0x0100, b"\x58\x02\x00", "MOV:I.W", "#H'0200, R0"),
0x0103: Instruction(0x0103, b"\xA0\x81", "MOV:G.W", "R0, R1"),
0x0105: Instruction(0x0105, b"\xA1\x08", "ADD:Q.W", "#1, R1"),
0x0107: Instruction(0x0107, b"\x0C\x00\x02\x31", "SUB.W", "#H'0002, R1"),
}
analysis = analyze_dataflow(instructions)
self.assertEqual(reg_after(analysis, 0x0100, "R0")["value"], 0x0200)
self.assertEqual(reg_after(analysis, 0x0100, "R0")["width"], 16)
self.assertEqual(reg_before(analysis, 0x0103, "R0")["value"], 0x0200)
self.assertEqual(reg_after(analysis, 0x0103, "R1")["value"], 0x0200)
self.assertEqual(reg_after(analysis, 0x0105, "R1")["value"], 0x0201)
self.assertEqual(reg_after(analysis, 0x0107, "R1")["value"], 0x01FF)
def test_tracks_byte_immediates_without_promising_word_width(self):
instructions = {
0x0200: Instruction(0x0200, b"\x52\x7F", "MOV:E.B", "#H'7F, R2"),
0x0202: Instruction(0x0202, b"\xA2\x83", "MOV:G.B", "R2, R3"),
0x0204: Instruction(0x0204, b"\x58\x20\x00", "MOV:I.W", "#H'2000, R0"),
0x0207: Instruction(0x0207, b"\xD0\x84", "MOV:G.W", "@R0, R4"),
}
analysis = analyze_dataflow(instructions)
self.assertEqual(reg_after(analysis, 0x0200, "R2")["value"], 0x7F)
self.assertEqual(reg_after(analysis, 0x0200, "R2")["width"], 8)
self.assertEqual(reg_after(analysis, 0x0202, "R3")["value"], 0x7F)
self.assertEqual(reg_after(analysis, 0x0202, "R3")["width"], 8)
self.assertEqual(reg_after(analysis, 0x0207, "R0")["value"], 0x2000)
self.assertFalse(reg_after(analysis, 0x0207, "R4")["known"])
self.assertEqual(reg_after(analysis, 0x0207, "R4")["reason"], "memory_load")
def test_calls_and_ambiguous_branches_do_not_leak_known_state(self):
instructions = {
0x0300: Instruction(0x0300, b"\x58\x12\x34", "MOV:I.W", "#H'1234, R0"),
0x0303: Instruction(0x0303, b"\x26\x03", "BNE", "loc_0308", kind="branch", targets=[0x0308]),
0x0305: Instruction(0x0305, b"\xA0\x08", "ADD:Q.W", "#1, R0"),
0x0308: Instruction(0x0308, b"\xA0\x08", "ADD:Q.W", "#1, R0"),
0x030A: Instruction(0x030A, b"\x18\x04\x00", "JSR", "@loc_0400", kind="call", targets=[0x0400]),
0x030D: Instruction(0x030D, b"\xA0\x08", "ADD:Q.W", "#1, R0"),
}
analysis = analyze_dataflow(instructions)
self.assertFalse(reg_before(analysis, 0x0305, "R0")["known"])
self.assertEqual(reg_before(analysis, 0x0305, "R0")["reason"], "block_entry")
self.assertFalse(reg_before(analysis, 0x0308, "R0")["known"])
self.assertEqual(reg_before(analysis, 0x0308, "R0")["reason"], "block_entry")
self.assertFalse(reg_after(analysis, 0x030A, "R0")["known"])
self.assertEqual(reg_after(analysis, 0x030A, "R0")["reason"], "call")
self.assertFalse(reg_before(analysis, 0x030D, "R0")["known"])
def test_tracks_control_register_loads_and_stc_copies(self):
instructions = {
0x0400: Instruction(
0x0400,
b"\x04\xFE\x89",
"LDC.B",
"#H'FE, BR",
writes_br=True,
br_value=0xFE,
),
0x0403: Instruction(0x0403, b"\xA0\x99", "STC.B", "BR, R1"),
0x0405: Instruction(0x0405, b"\x04\x01\x48", "ORC.B", "#H'01, CCR"),
}
analysis = analyze_dataflow(instructions)
self.assertEqual(control_after(analysis, 0x0400, "BR")["value"], 0xFE)
self.assertEqual(control_after(analysis, 0x0400, "BR")["width"], 8)
self.assertEqual(reg_after(analysis, 0x0403, "R1")["value"], 0xFE)
self.assertFalse(control_after(analysis, 0x0405, "CCR")["known"])
def test_state_lookup_helper_returns_instruction_record(self):
instructions = {
0x0500: Instruction(0x0500, b"\x58\x00\x01", "MOV:I.W", "#H'0001, R0"),
}
analysis = analyze_dataflow(instructions)
self.assertEqual(state_for_instruction(analysis, 0x0500)["after"]["registers"]["R0"]["value"], 1)
self.assertEqual(state_for_instruction(analysis, 0x9999), {})
if __name__ == "__main__":
unittest.main()