2025-09-11 20:22:17 +00:00
|
|
|
from typing import Generator
|
2025-10-07 21:23:14 +00:00
|
|
|
import argparse
|
2025-09-11 20:22:17 +00:00
|
|
|
|
|
|
|
|
|
2025-10-09 20:54:11 +00:00
|
|
|
op_signs = {'add': '+', 'sub': '-', 'mul': '*', 'div': '/',
|
2025-10-03 21:26:51 +00:00
|
|
|
'gt': '>', 'eq': '==', 'mod': '%'}
|
2025-09-11 20:22:17 +00:00
|
|
|
|
2025-10-08 20:47:49 +00:00
|
|
|
entry_func_prefix = ''
|
2025-10-10 21:22:16 +00:00
|
|
|
stencil_func_prefix = '__attribute__((naked)) ' # Remove callee prolog
|
2025-09-20 21:25:07 +00:00
|
|
|
|
2025-10-01 21:09:49 +00:00
|
|
|
def get_function_start() -> str:
|
2025-10-07 21:23:14 +00:00
|
|
|
return f"""
|
2025-10-08 20:47:49 +00:00
|
|
|
{entry_func_prefix}int function_start(){{
|
2025-10-10 21:22:16 +00:00
|
|
|
result_int(0);
|
2025-10-01 21:09:49 +00:00
|
|
|
return 1;
|
2025-10-07 21:23:14 +00:00
|
|
|
}}
|
2025-09-30 21:11:14 +00:00
|
|
|
"""
|
|
|
|
|
|
2025-10-01 21:09:49 +00:00
|
|
|
|
|
|
|
|
def get_function_end() -> str:
|
2025-10-07 21:23:14 +00:00
|
|
|
return f"""
|
2025-10-08 20:47:49 +00:00
|
|
|
{entry_func_prefix}int function_end(){{
|
2025-10-10 21:22:16 +00:00
|
|
|
result_int(0);
|
2025-10-01 21:09:49 +00:00
|
|
|
return 1;
|
2025-10-07 21:23:14 +00:00
|
|
|
}}
|
2025-09-30 21:11:14 +00:00
|
|
|
"""
|
|
|
|
|
|
2025-10-01 21:09:49 +00:00
|
|
|
|
|
|
|
|
def get_op_code(op: str, type1: str, type2: str, type_out: str) -> str:
|
2025-09-11 20:22:17 +00:00
|
|
|
return f"""
|
2025-10-08 20:47:49 +00:00
|
|
|
{stencil_func_prefix}void {op}_{type1}_{type2}({type1} arg1, {type2} arg2) {{
|
2025-09-11 20:22:17 +00:00
|
|
|
result_{type_out}_{type2}(arg1 {op_signs[op]} arg2, arg2);
|
|
|
|
|
}}
|
|
|
|
|
"""
|
|
|
|
|
|
2025-10-01 21:09:49 +00:00
|
|
|
|
2025-10-08 20:21:33 +00:00
|
|
|
def get_conv_code(type1: str, type2: str, type_out: str) -> str:
|
|
|
|
|
return f"""
|
2025-10-08 20:47:49 +00:00
|
|
|
{stencil_func_prefix}void conv_{type1}_{type2}({type1} arg1, {type2} arg2) {{
|
2025-10-08 20:21:33 +00:00
|
|
|
result_{type_out}_{type2}(({type_out})arg1, arg2);
|
|
|
|
|
}}
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
2025-10-04 21:20:25 +00:00
|
|
|
def get_op_code_float(op: str, type1: str, type2: str) -> str:
|
|
|
|
|
return f"""
|
2025-10-08 20:47:49 +00:00
|
|
|
{stencil_func_prefix}void {op}_{type1}_{type2}({type1} arg1, {type2} arg2) {{
|
2025-10-08 20:21:33 +00:00
|
|
|
result_float_{type2}((float)arg1 {op_signs[op]} (float)arg2, arg2);
|
2025-10-04 21:20:25 +00:00
|
|
|
}}
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
2025-10-09 20:54:11 +00:00
|
|
|
def get_floordiv(op: str, type1: str, type2: str) -> str:
|
2025-10-04 21:20:25 +00:00
|
|
|
return f"""
|
2025-10-08 20:47:49 +00:00
|
|
|
{stencil_func_prefix}void {op}_{type1}_{type2}({type1} arg1, {type2} arg2) {{
|
2025-10-09 20:54:41 +00:00
|
|
|
float x = (float)arg1 / (float)arg2;
|
|
|
|
|
int i = (int)x;
|
|
|
|
|
if (x < 0 && x != (float)i) i -= 1;
|
|
|
|
|
result_int_{type2}(i, arg2);
|
2025-10-04 21:20:25 +00:00
|
|
|
}}
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
2025-10-01 21:09:49 +00:00
|
|
|
def get_result_stubs1(type1: str) -> str:
|
2025-09-11 20:46:53 +00:00
|
|
|
return f"""
|
|
|
|
|
void result_{type1}({type1} arg1);
|
|
|
|
|
"""
|
|
|
|
|
|
2025-09-20 21:25:07 +00:00
|
|
|
|
2025-10-01 21:09:49 +00:00
|
|
|
def get_result_stubs2(type1: str, type2: str) -> str:
|
2025-09-11 20:22:17 +00:00
|
|
|
return f"""
|
|
|
|
|
void result_{type1}_{type2}({type1} arg1, {type2} arg2);
|
|
|
|
|
"""
|
|
|
|
|
|
2025-09-20 21:25:07 +00:00
|
|
|
|
2025-10-01 21:09:49 +00:00
|
|
|
def get_read_reg0_code(type1: str, type2: str, type_out: str) -> str:
|
2025-09-11 20:22:17 +00:00
|
|
|
return f"""
|
2025-10-08 20:47:49 +00:00
|
|
|
{stencil_func_prefix}void read_{type_out}_reg0_{type1}_{type2}({type1} arg1, {type2} arg2) {{
|
2025-09-11 20:22:17 +00:00
|
|
|
result_{type_out}_{type2}(dummy_{type_out}, arg2);
|
|
|
|
|
}}
|
|
|
|
|
"""
|
|
|
|
|
|
2025-09-20 21:25:07 +00:00
|
|
|
|
2025-10-01 21:09:49 +00:00
|
|
|
def get_read_reg1_code(type1: str, type2: str, type_out: str) -> str:
|
2025-09-11 20:22:17 +00:00
|
|
|
return f"""
|
2025-10-08 20:47:49 +00:00
|
|
|
{stencil_func_prefix}void read_{type_out}_reg1_{type1}_{type2}({type1} arg1, {type2} arg2) {{
|
2025-09-11 20:22:17 +00:00
|
|
|
result_{type1}_{type_out}(arg1, dummy_{type_out});
|
|
|
|
|
}}
|
|
|
|
|
"""
|
|
|
|
|
|
2025-09-20 21:25:07 +00:00
|
|
|
|
2025-10-01 21:09:49 +00:00
|
|
|
def get_write_code(type1: str) -> str:
|
2025-09-11 20:22:17 +00:00
|
|
|
return f"""
|
2025-10-08 20:47:49 +00:00
|
|
|
{stencil_func_prefix}void write_{type1}({type1} arg1) {{
|
2025-09-11 20:22:17 +00:00
|
|
|
dummy_{type1} = arg1;
|
2025-09-11 20:46:53 +00:00
|
|
|
result_{type1}(arg1);
|
2025-09-11 20:22:17 +00:00
|
|
|
}}
|
|
|
|
|
"""
|
|
|
|
|
|
2025-09-20 21:25:07 +00:00
|
|
|
|
2025-09-11 20:22:17 +00:00
|
|
|
def permutate(*lists: list[str]) -> Generator[list[str], None, None]:
|
|
|
|
|
if len(lists) == 0:
|
|
|
|
|
yield []
|
|
|
|
|
return
|
|
|
|
|
first, *rest = lists
|
|
|
|
|
for item in first:
|
|
|
|
|
for items in permutate(*rest):
|
|
|
|
|
yield [item, *items]
|
|
|
|
|
|
2025-09-20 21:25:07 +00:00
|
|
|
|
2025-09-11 20:22:17 +00:00
|
|
|
if __name__ == "__main__":
|
2025-10-07 21:23:14 +00:00
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
|
parser.add_argument("path", type=str, help="Output file path")
|
|
|
|
|
parser.add_argument("--abi", type=str, default="", help="Optionaler String (Standard: '')")
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
|
|
if args.abi:
|
2025-10-08 20:47:49 +00:00
|
|
|
entry_func_prefix = f"__attribute__(({args.abi}_abi)) "
|
2025-10-07 21:23:14 +00:00
|
|
|
|
2025-09-11 20:22:17 +00:00
|
|
|
code = """
|
2025-09-11 20:46:53 +00:00
|
|
|
// Auto-generated stencils for copapy
|
2025-09-11 20:22:17 +00:00
|
|
|
// Do not edit manually
|
|
|
|
|
|
|
|
|
|
volatile int dummy_int = 1337;
|
|
|
|
|
volatile float dummy_float = 1337;
|
|
|
|
|
"""
|
2025-09-11 20:46:53 +00:00
|
|
|
|
2025-10-09 20:53:51 +00:00
|
|
|
# Scalar arithmetic:
|
|
|
|
|
types = ['int', 'float']
|
|
|
|
|
ops = ['add', 'sub', 'mul', 'div', 'floordiv', 'gt', 'eq']
|
|
|
|
|
|
2025-09-11 20:46:53 +00:00
|
|
|
for t1 in types:
|
|
|
|
|
code += get_result_stubs1(t1)
|
|
|
|
|
|
2025-09-11 20:22:17 +00:00
|
|
|
for t1, t2 in permutate(types, types):
|
2025-09-11 20:46:53 +00:00
|
|
|
code += get_result_stubs2(t1, t2)
|
2025-09-11 20:22:17 +00:00
|
|
|
|
|
|
|
|
for op, t1, t2 in permutate(ops, types, types):
|
|
|
|
|
t_out = t1 if t1 == t2 else 'float'
|
2025-10-04 21:20:25 +00:00
|
|
|
if op == 'floordiv':
|
2025-10-09 20:54:11 +00:00
|
|
|
code += get_floordiv('floordiv', t1, t2)
|
2025-10-08 20:21:33 +00:00
|
|
|
elif op == 'div':
|
2025-10-04 21:20:25 +00:00
|
|
|
code += get_op_code_float(op, t1, t2)
|
2025-10-09 20:53:51 +00:00
|
|
|
elif op == 'gt' or op == 'eq':
|
|
|
|
|
code += get_op_code(op, t1, t2, 'int')
|
2025-10-04 21:20:25 +00:00
|
|
|
else:
|
|
|
|
|
code += get_op_code(op, t1, t2, t_out)
|
2025-09-11 20:22:17 +00:00
|
|
|
|
2025-10-03 21:26:51 +00:00
|
|
|
code += get_op_code('mod', 'int', 'int', 'int')
|
|
|
|
|
|
2025-09-11 20:22:17 +00:00
|
|
|
for t1, t2, t_out in permutate(types, types, types):
|
|
|
|
|
code += get_read_reg0_code(t1, t2, t_out)
|
|
|
|
|
code += get_read_reg1_code(t1, t2, t_out)
|
2025-10-01 21:09:49 +00:00
|
|
|
|
2025-09-11 20:46:53 +00:00
|
|
|
for t1 in types:
|
|
|
|
|
code += get_write_code(t1)
|
2025-09-11 20:22:17 +00:00
|
|
|
|
2025-09-30 21:11:14 +00:00
|
|
|
code += get_function_start() + get_function_end()
|
|
|
|
|
|
2025-10-07 21:23:14 +00:00
|
|
|
with open(args.path, 'w') as f:
|
2025-09-11 20:22:17 +00:00
|
|
|
f.write(code)
|