-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathasm_gen.py
120 lines (99 loc) · 3.98 KB
/
asm_gen.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
from collections import OrderedDict
from ir import Lable
from ir_gen import IRGen
from n_asm import Mov, Push, Sub
from spotmap import (MemSpot, bp, r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10,
r11, sp)
from symbol_table import NewSymbolTable
class AsmGen:
"""State of asm generation phase."""
def __init__(self, symbol_table: NewSymbolTable, ir_gen: IRGen):
self.cmds = []
self.spotmap = {}
self._symbol_table = symbol_table
self._ir_gen = ir_gen
self._regs = OrderedDict()
for reg in (r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11):
self._regs[reg] = True
def get_reg(self):
for reg, is_free in self._regs.items():
if is_free:
self._regs[reg] = False
return reg
raise Exception('No more free regs in usage')
def free_regs(self, regs):
for reg in regs:
self._regs[reg] = True
def clean_regs(self):
for reg in self._regs:
self._regs[reg] = True
def book_reg(self, reg):
if self._regs[reg]:
self._regs[reg] = False
else:
raise Exception('try to book register, that already in use')
@property
def regs_in_use(self):
return [r for r in self._regs if self._regs[r] == False]
def add(self, cmd):
self.cmds.append(f'\t{cmd}')
def make_asm(self):
# put global variables in file as
# var: .word {{value}}
if self._ir_gen.globals:
base = 0
self.cmds.append('.data')
for global_var, value in self._ir_gen.globals.items():
self.spotmap[global_var] = MemSpot(base)
base += global_var.c_type.size
self.cmds.append(f'{global_var.literal}: .word {value}')
self.cmds.append('')
# entry point
self.cmds.append('.text')
self.cmds.append('.global _start')
self.cmds.append('_start:')
self.cmds.append('\tb main')
# check for main function without any arguments
if 'main' not in self._ir_gen.func_args:
raise Exception('provide main function as entry point')
elif len(self._ir_gen.func_args['main']) != 0:
raise Exception('main function should not receive any arguments')
for func_name, args in self._ir_gen.func_args.items():
offset = 4
for arg in args:
self.spotmap[arg] = MemSpot(bp, offset)
offset += arg.c_type.size
# frame pointer size for every function
fp_size = {}
for func_name, locals in self._ir_gen.func_locals.items():
if not locals:
fp_size[func_name] = 0
continue
offset = -4
for local in locals:
self.spotmap[local] = MemSpot(bp, offset)
offset -= local.c_type.size
fp_size[func_name] = offset
for func_name, cmds in self._ir_gen.cmds.items():
self.clean_regs()
self.cmds.append(f'{func_name}:')
# hacks, but this is prolog to function
self.add(Push([bp]))
self.add(Mov(bp, sp))
frame_pointer_size = fp_size[func_name]
if frame_pointer_size:
self.add(Sub(sp, sp, imm=abs(frame_pointer_size)))
for c in cmds:
if type(c) == Lable:
self.cmds.append(f'{c.lable}:')
continue
if type(c) == str:
continue
c.make_asm(self)
self.cmds.append('')
# put addresses of global variables at the end of the file as
# adr_var: .word {{variable_name}}
for global_var, value in self._ir_gen.globals.items():
self.spotmap[global_var] = MemSpot(base)
base += global_var.c_type.size
self.cmds.append(f'adr_{global_var.literal}: .word {global_var.literal}')