'maximum recursion depth exceeded' while finalizing a large function
I'm generating a fairly large function using PeachPy (compiling from another language). When the function has a large number of labels it seems that the finalization invoked when RETURN is called is blowing the Python style.
Part of the stack trace:
File "function.py", line 549, in analyze_reachability
output_block.analyze_reachability()
File "function.py", line 549, in analyze_reachability
output_block.analyze_reachability()
File "function.py", line 549, in analyze_reachability
output_block.analyze_reachability()
File "function.py", line 549, in analyze_reachability
output_block.analyze_reachability()
FWIW I'm not even using the register allocation features, all my registers are managed manually. A silly reproducer below:
import peachpy
import peachpy.x86_64
x = peachpy.Argument(peachpy.int64_t)
y = peachpy.Argument(peachpy.int64_t)
with peachpy.x86_64.Function("Times", (x, y), peachpy.int64_t) as asm_function:
reg_x = peachpy.x86_64.rax
reg_y = peachpy.x86_64.rbx
reg_accum = peachpy.x86_64.rcx
peachpy.x86_64.LOAD.ARGUMENT(reg_x, x)
peachpy.x86_64.LOAD.ARGUMENT(reg_y, y)
peachpy.x86_64.MOV(reg_accum, 0)
for i in range(1000):
loop_start_label = peachpy.x86_64.Label('loop_start{}'.format(i))
loop_end_label = peachpy.x86_64.Label('loop_end{}'.format(i))
peachpy.x86_64.CMP(reg_y, 0)
peachpy.x86_64.JE(loop_end_label)
peachpy.x86_64.LABEL(loop_start_label) # bind the label
peachpy.x86_64.ADD(reg_accum, reg_x)
peachpy.x86_64.SUB(reg_y, 1)
peachpy.x86_64.JG(loop_start_label)
peachpy.x86_64.LABEL(loop_end_label) # bind the label
peachpy.x86_64.RETURN(reg_accum)
abi = peachpy.x86_64.abi.detect()
encoded_function = asm_function.finalize(abi).encode()
python_function = encoded_function.load()
print(encoded_function.format())
code = python_function.code_segment
fname = '/tmp/ppout.bin'
with open(fname, 'wb') as f:
f.write(code)
print('Wrote code to file [{0}]: {1}'.format(fname, code))
# The JIT call
print(python_function(3, 4))
PeachPy wasn't designed as a backend for other languages, and it doesn't scale to large number of instructions/branches/labels. In particular, most analysis passes are implemented as recursive functions, where recursion depth can be as high as the number of basic blocks. Rewriting these recursive functions as while loops would likely solve your problem, but its not a high-priority task for me.