diff --git a/pyproject.toml b/pyproject.toml index c709828..a6e4231 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ dev = [ ] [tool.mypy] -files = ["src"] +files = ["src", "tools"] strict = true warn_return_any = true warn_unused_configs = true diff --git a/src/copapy/__init__.py b/src/copapy/__init__.py index 0e20853..90938ac 100644 --- a/src/copapy/__init__.py +++ b/src/copapy/__init__.py @@ -387,26 +387,30 @@ def compile_to_instruction_list(node_list: Iterable[Node], sdb: stencil_database offset = 0 # offset in generated code chunk # assemble stencils to main program - data = sdb.get_function_body('function_start', 'start') + data = sdb.get_function_body('entry_function_shell', 'start') data_list.append(data) offset += len(data) for associated_net, node in extended_output_ops: - assert node.name in sdb.function_definitions, f"- Warning: {node.name} prototype not found" + assert node.name in sdb.function_definitions, f"- Warning: {node.name} stencil not found" data = sdb.get_stencil_code(node.name) data_list.append(data) # print(f"* {node.name} ({offset}) " + ' '.join(f'{d:02X}' for d in data)) for patch in sdb.get_patch_positions(node.name): - assert associated_net, f"Relocation found but no net defined for operation {node.name}" - object_addr = object_addr_lookp[associated_net] - patch_value = object_addr + patch.addend - (offset + patch.addr) - # print('patch: ', patch, object_addr, patch_value) - patch_list.append((patch.type.value, offset + patch.addr, patch_value)) + if patch.target_symbol_info == 'STT_OBJECT': + assert associated_net, f"Relocation found but no net defined for operation {node.name}" + object_addr = object_addr_lookp[associated_net] + patch_value = object_addr + patch.addend - (offset + patch.addr) + # print('patch: ', patch, object_addr, patch_value) + patch_list.append((patch.type.value, offset + patch.addr, patch_value)) + print('++ ', patch.target_symbol_info, patch.target_symbol_name) + else: + raise ValueError(f"Unsupported: {node.name} {patch.target_symbol_info} {patch.target_symbol_name}") offset += len(data) - data = sdb.get_function_body('function_end', 'end') + data = sdb.get_function_body('entry_function_shell', 'end') data_list.append(data) offset += len(data) # print('function_end', offset, data) diff --git a/src/copapy/stencil_db.py b/src/copapy/stencil_db.py index 8a7d244..ae7e1b0 100644 --- a/src/copapy/stencil_db.py +++ b/src/copapy/stencil_db.py @@ -23,18 +23,15 @@ class patch_entry: type: RelocationType addr: int addend: int + target_symbol_name: str + target_symbol_info: str -def translate_relocation(relocation_addr: int, reloc_type: str, bits: int, r_addend: int) -> patch_entry: +def translate_relocation(relocation_addr: int, reloc_type: str, bits: int, r_addend: int) -> RelocationType: if reloc_type in ('R_AMD64_PLT32', 'R_AMD64_PC32'): # S + A - P - patch_offset = relocation_addr - return patch_entry(RelocationType.RELOC_RELATIVE_32, patch_offset, r_addend) + return RelocationType.RELOC_RELATIVE_32 else: - print('relocation_addr: ', relocation_addr) - print('reloc_type: ', reloc_type) - print('bits: ', bits) - print('r_addend: ', r_addend) raise Exception(f"Unknown relocation type: {reloc_type}") @@ -48,8 +45,11 @@ def get_return_function_type(symbol: elf_symbol) -> str: def strip_function(func: elf_symbol) -> bytes: """Return stencil code by striped stancil function""" - start_index, end_index = get_stencil_position(func) - return func.data[start_index:end_index] + if func.relocations and func.relocations[-1].symbol.info == 'STT_NOTYPE': + start_index, end_index = get_stencil_position(func) + return func.data[start_index:end_index] + else: + return func.data def get_stencil_position(func: elf_symbol) -> tuple[int, int]: @@ -117,13 +117,17 @@ class stencil_database(): for reloc in symbol.relocations: + patch_offset = reloc.fields['r_offset'] - symbol.fields['st_value'] - start_index + # address to fist byte to patch relative to the start of the symbol - patch = translate_relocation( - reloc.fields['r_offset'] - symbol.fields['st_value'] - start_index, + rtype = translate_relocation( + patch_offset, reloc.type, reloc.bits, reloc.fields['r_addend']) + patch = patch_entry(rtype, patch_offset, reloc.fields['r_addend'], reloc.symbol.name, reloc.symbol.info) + # Exclude the call to the result_* function if patch.addr < end_index - start_index: yield patch diff --git a/tests/test_ops.py b/tests/test_ops.py index 8cbc799..5bd7181 100644 --- a/tests/test_ops.py +++ b/tests/test_ops.py @@ -8,11 +8,14 @@ def function1(c1): def function2(c1): return [c1 / 4, c1 / -4, c1 / 4, c1 / -4, (c1 * -1) / 4] +def function3(c1): + return [c1 / 4] + def test_compile(): c1 = CPVariable(9) - ret = function2(c1) + ret = function3(c1) tg = Target() print('* compile and copy ...') @@ -22,7 +25,7 @@ def test_compile(): tg.run() #print('* finished') - ret_ref = function2(9) + ret_ref = function3(9) for test, ref, name in zip(ret, ret_ref, ['r1', 'r2', 'r3', 'r4', 'r5']): val = tg.read_value(test) diff --git a/tests/test_stencil_db.py b/tests/test_stencil_db.py index 4046e8d..39441b4 100644 --- a/tests/test_stencil_db.py +++ b/tests/test_stencil_db.py @@ -9,17 +9,20 @@ def test_list_symbols(): #print(sdb.function_definitions) for sym_name in sdb.function_definitions.keys(): print('\n-', sym_name) - print(list(sdb.get_patch_positions(sym_name))) + #print(list(sdb.get_patch_positions(sym_name))) def test_start_end_function(): for sym_name in sdb.function_definitions.keys(): symbol = sdb.elf.symbols[sym_name] - print('-', sym_name, stencil_db.get_stencil_position(symbol), len(symbol.data)) - start, end = stencil_db.get_stencil_position(symbol) + if symbol.relocations and symbol.relocations[-1].symbol.info == 'STT_NOTYPE': + + print('-', sym_name, stencil_db.get_stencil_position(symbol), len(symbol.data)) - assert start >= 0 and end >= start and end <= len(symbol.data) + start, end = stencil_db.get_stencil_position(symbol) + + assert start >= 0 and end >= start and end <= len(symbol.data) def test_aux_functions(): diff --git a/tools/generate_stencils.py b/tools/generate_stencils.py index 82a28a5..750af4e 100644 --- a/tools/generate_stencils.py +++ b/tools/generate_stencils.py @@ -8,21 +8,20 @@ op_signs = {'add': '+', 'sub': '-', 'mul': '*', 'div': '/', entry_func_prefix = '' stencil_func_prefix = '__attribute__((naked)) ' # Remove callee prolog -def get_function_start() -> str: +def get_aux_funcs() -> str: return f""" - {entry_func_prefix}int function_start(){{ + {entry_func_prefix}int entry_function_shell(){{ result_int(0); return 1; }} + """ + \ """ - - -def get_function_end() -> str: - return f""" - {entry_func_prefix}int function_end(){{ - result_int(0); - return 1; - }} + __attribute__((noinline)) int floor_div(float arg1, float arg2) { + float x = arg1 / arg2; + int i = (int)x; + if (x < 0 && x != (float)i) i -= 1; + return i; + } """ @@ -53,10 +52,7 @@ def get_op_code_float(op: str, type1: str, type2: str) -> str: def get_floordiv(op: str, type1: str, type2: str) -> str: return f""" {stencil_func_prefix}void {op}_{type1}_{type2}({type1} arg1, {type2} arg2) {{ - float x = (float)arg1 / (float)arg2; - int i = (int)x; - if (x < 0 && x != (float)i) i -= 1; - result_int_{type2}(i, arg2); + result_int_{type2}(floor_div((float)arg1, (float)arg2), arg2); }} """ @@ -135,6 +131,8 @@ if __name__ == "__main__": for t1, t2 in permutate(types, types): code += get_result_stubs2(t1, t2) + code += get_aux_funcs() + for op, t1, t2 in permutate(ops, types, types): t_out = t1 if t1 == t2 else 'float' if op == 'floordiv': @@ -155,7 +153,5 @@ if __name__ == "__main__": for t1 in types: code += get_write_code(t1) - code += get_function_start() + get_function_end() - with open(args.path, 'w') as f: f.write(code) diff --git a/tools/inspect.sh b/tools/inspect.sh index 4abceac..9ea8a75 100644 --- a/tools/inspect.sh +++ b/tools/inspect.sh @@ -1,6 +1,7 @@ #!/bin/bash source tools/build.sh -python tests/test_compile_div.py +objdump -d -x src/copapy/obj/stencils_x86_64_O3.o > bin/stencils_x86_64_O3.asm +python tools/make_example.py python tools/extract_code.py "bin/test.copapy" "bin/test.copapy.bin" objdump -D -b binary -m i386:x86-64 --adjust-vma=0x1000 bin/test.copapy.bin > bin/test.copapy.asm diff --git a/tools/make_example.py b/tools/make_example.py new file mode 100644 index 0000000..312557c --- /dev/null +++ b/tools/make_example.py @@ -0,0 +1,34 @@ +from copapy import CPVariable, Target, Write, binwrite +import copapy +from pytest import approx + + +def test_compile() -> None: + + c1 = CPVariable(9) + + #ret = [c1 / 4, c1 / -4, c1 // 4, c1 // -4, (c1 * -1) // 4] + ret = [c1 / 4] + + out = [Write(r) for r in ret] + + il, _ = copapy.compile_to_instruction_list(out, copapy.generic_sdb) + + # run program command + il.write_com(binwrite.Command.RUN_PROG) + il.write_int(0) + + il.write_com(binwrite.Command.READ_DATA) + il.write_int(0) + il.write_int(36) + + il.write_com(binwrite.Command.END_PROG) + + print('* Data to runner:') + il.print() + + il.to_file('bin/test.copapy') + + +if __name__ == "__main__": + test_compile()