Implement variable length arguments, but really only for print
[fur] / optimization.py
1 from crossplatform_ir_generation import CIRProgram, CIRInstruction, CIRLabel
2
3 PUSHING_INSTRUCTIONS_WITHOUT_SIDE_EFFECTS = set(
4     ('push',),
5 )
6
7 # TODO Some instructions may not touch the stack, so if these occur between a push and a drop we could still optimize
8 def push_drop_optimization(ir):
9     ir = tuple(ir)
10
11     i = 0
12
13     while i < len(ir):
14         if isinstance(ir[i], CIRInstruction)\
15                 and ir[i].instruction in PUSHING_INSTRUCTIONS_WITHOUT_SIDE_EFFECTS\
16                 and i + 1 < len(ir)\
17                 and isinstance(ir[i + 1], CIRInstruction)\
18                 and ir[i + 1].instruction == 'drop':
19             i += 2
20         else:
21             yield ir[i]
22             i += 1
23
24 # TODO We might be able to trace program flow to eliminate usages even if variables have the same name
25 def unused_pop_optimization(ir):
26     ir = tuple(ir)
27
28     used_symbols = set()
29
30     for entry in ir:
31         # TODO Having symbols be a string starting with "sym" is a bit hacky
32         if isinstance(entry, CIRInstruction)\
33                 and entry.instruction != 'pop'\
34                 and isinstance(entry.argument, str)\
35                 and entry.argument.startswith('sym'):
36             used_symbols.add(entry.argument)
37
38     for entry in ir:
39         if isinstance(entry, CIRInstruction) and entry.instruction == 'pop' and entry.argument not in used_symbols:
40             yield CIRInstruction(instruction='drop', argument=None)
41         else:
42             yield entry
43
44 def optimize(cir_program):
45     ir = cir_program.entry_list
46
47     ir = push_drop_optimization(ir)
48     ir = unused_pop_optimization(ir)
49
50     return CIRProgram(entry_list=tuple(ir))