Mercurial > lcfOS
comparison python/ppci/frontends/ks/irgenerator.py @ 103:28a35161ef23
Added forgotten ir generator
author | windel |
---|---|
date | Wed, 26 Dec 2012 10:53:33 +0100 |
parents | |
children | ed230e947dc6 |
comparison
equal
deleted
inserted
replaced
102:63937c8d1478 | 103:28a35161ef23 |
---|---|
1 """ | |
2 Generates ir code from ast tree. | |
3 """ | |
4 | |
5 from .nodes import * | |
6 from ...core.errors import Error | |
7 from ... import core | |
8 from .builtin import real, integer, boolean, char | |
9 #from .assembler import * | |
10 | |
11 class KsIrGenerator: | |
12 def __init__(self): | |
13 pass | |
14 | |
15 # Code generation functions: | |
16 def genexprcode(self, node): | |
17 """ | |
18 Generate code for expressions! | |
19 Recursively evaluates, and ensures a register contains the answer. | |
20 register is an integer register or a floating point reg | |
21 """ | |
22 if isinstance(node, Binop): | |
23 """ Handle a binary operation (two arguments) of some kind """ | |
24 self.genexprcode(node.a) | |
25 self.genexprcode(node.b) | |
26 | |
27 if node.op == 'mod': | |
28 assert(node.typ.isType(integer)) | |
29 self.addCode(mov('rax', node.a.reg)) | |
30 elif node.op == 'div': | |
31 assert(node.typ.isType(integer)) | |
32 self.addCode(mov('rax', node.a.reg)) | |
33 elif node.op == '*': | |
34 if node.typ.isType(integer): | |
35 self.addCode(imulreg64(node.a.reg, node.b.reg)) | |
36 elif node.op == '+': | |
37 if node.typ.isType(integer): | |
38 self.addCode(addreg64(node.a.reg, node.b.reg)) | |
39 elif node.op == '-': | |
40 if node.typ.isType(integer): | |
41 self.addCode(subreg64(node.a.reg, node.b.reg)) | |
42 else: | |
43 Error('Unknown Binop {0}'.format(node.op)) | |
44 | |
45 elif type(node) is Unop: | |
46 if node.op == 'INTTOREAL': | |
47 self.genexprcode(node.a) | |
48 node.reg = node.a.reg | |
49 # TODO use 'FILD' instruction | |
50 freg = 12 | |
51 code.append('Unop inttoreal TODO') | |
52 elif node.op == 'ABS': | |
53 if isType(node.typ, real): | |
54 code = [0xD9, 0xE1] # st(0) = fabs st(0) | |
55 Error('ABS error integer') | |
56 elif isType(node.typ, integer): | |
57 code = [] | |
58 Error('ABS error integer') | |
59 else: | |
60 Error('ABS error') | |
61 else: | |
62 Error('Unknown Unop {0}'.format(node.op)) | |
63 | |
64 elif isinstance(node, Designator): | |
65 # dereference, array index. Make sure that the result comes into a register | |
66 if len(node.selectors) > 0: | |
67 self.gencode(node) # Load the pointer into some register | |
68 | |
69 # Now we can access the object at location '[node.reg]': | |
70 if node.typ.isType(integer): | |
71 self.addCode( mov(node.reg, [node.reg, 0x0]) ) | |
72 else: | |
73 Error('Only integer types implemented') | |
74 else: | |
75 # No selectors, load variable directly | |
76 if node.obj.typ.isType(integer): | |
77 if type(node.obj) is Constant: | |
78 self.genexprcode(node.obj) | |
79 node.reg = node.obj.reg | |
80 else: | |
81 self.getreg(node) | |
82 # Get a register to store the integer value | |
83 if node.obj.isLocal: | |
84 # relative to rbp: | |
85 self.addCode( mov(node.reg, ['rbp', node.obj.offset]) ) | |
86 else: | |
87 self.addCode(mov(node.reg, ['RIP', 0x0])) | |
88 self.fixCode(self.rip-4, imm32(node.obj.offset - self.rip)) | |
89 else: | |
90 Error('Cannot load variable type {0}'.format(node.typ)) | |
91 | |
92 elif isinstance(node, Relop): | |
93 # Create a boolean from operands | |
94 # TODO create an alternative for expressions used as conditions. | |
95 self.genexprcode(node.a) | |
96 self.genexprcode(node.b) | |
97 | |
98 if node.a.typ.isType(integer): | |
99 self.freereg(node.b) | |
100 else: | |
101 Error('Relop not implemented for {0}'.format(node.a.typ)) | |
102 | |
103 elif type(node) is Constant: | |
104 if node.typ.isType(integer): | |
105 self.getreg(node) | |
106 | |
107 elif type(node) is ProcedureCall: | |
108 if type(node.proc.obj) is BuiltinProcedure: | |
109 # Handle builtin procedures different, these not always call | |
110 # a function, but generate code. | |
111 bi = node.proc.obj | |
112 if bi.name == 'chr': | |
113 arg = node.args[0] | |
114 self.genexprcode(arg) | |
115 # Store character in full width register: | |
116 # TODO: store in char only register | |
117 node.reg = arg.reg | |
118 else: | |
119 Error('Unknown builtin function {0}'.format(bi.name)) | |
120 else: | |
121 # Use generic procedure call first | |
122 self.gencode(node) | |
123 # Retrieve result: | |
124 if node.typ.isType(integer): | |
125 # Store result! | |
126 self.getreg(node) | |
127 self.addCode( mov(node.reg, 'rax') ) | |
128 else: | |
129 Error('Return type not supported {0}'.format(node.typ)) | |
130 else: | |
131 Error('Cannot generate expression code for: {0}'.format(node)) | |
132 | |
133 def gencode(self, node): | |
134 """ Code generation function for AST nodes """ | |
135 if isinstance(node, Module): | |
136 # TODO: recurse! | |
137 return core.Module() | |
138 | |
139 elif type(node) is Procedure: | |
140 # calculate offsets for local variables and parameters | |
141 # Variable location relative to 'rbp' register | |
142 variables = node.symtable.getAllLocal(Variable) | |
143 offset = 0 | |
144 paramoffset = 16 | |
145 for var in variables: | |
146 var.isLocal = True | |
147 if not var.isParameter: | |
148 offset += var.typ.size | |
149 # Offset is negative of rbp in stack frame | |
150 var.offset = -offset | |
151 node.framesize = offset | |
152 # Calculate offsets of parameters relative to rbp register | |
153 for par in reversed(node.typ.parameters): | |
154 pvar = node.symtable.getLocal(Variable, par.name) | |
155 pvar.offset = paramoffset | |
156 paramoffset += pvar.typ.size | |
157 | |
158 # code generation | |
159 node.entrypoint = self.rip | |
160 self.addCode(push('rbp')) | |
161 self.addCode(mov('rbp', 'rsp')) # Setup the base pointer | |
162 self.addCode(subreg64('rsp', node.framesize)) # reserve space for locals | |
163 self.gencode(node.block) | |
164 if node.retexpr: | |
165 if node.retexpr.typ.isType(integer): | |
166 self.genexprcode(node.retexpr) | |
167 self.addCode( mov('rax', node.retexpr.reg) ) | |
168 self.freereg(node.retexpr) | |
169 else: | |
170 Error('Cannot return this kind yet {0}'.format(node.retexpr.typ)) | |
171 self.addCode( addreg64('rsp', node.framesize) ) | |
172 self.addCode( pop('rbp') ) | |
173 self.addCode( ret() ) | |
174 assert(len(self.usedregs) == 0) | |
175 | |
176 elif isinstance(node, StatementSequence): | |
177 for s in node.statements: | |
178 self.gencode(s) | |
179 | |
180 elif type(node) is ProcedureCall: | |
181 # Prepare parameters on the stack: | |
182 stacksize = 0 | |
183 assert(len(node.args) == len(node.proc.typ.parameters)) | |
184 for arg, param in zip(node.args, node.proc.typ.parameters): | |
185 | |
186 if param.kind == 'value': | |
187 self.genexprcode(arg) | |
188 self.addCode( push(arg.reg) ) | |
189 self.freereg( arg ) | |
190 stacksize += 8 | |
191 else: | |
192 Error('Parameter kind other than value') | |
193 | |
194 # Calculate address using designator | |
195 if type(node.proc.obj) is Procedure: | |
196 self.addCode( call(0x0) ) | |
197 self.fixCode( self.rip - 4, imm32(node.proc.obj.entrypoint - self.rip)) | |
198 elif type(node.proc.obj) is ImportedSymbol: | |
199 # Load the entry point of the import table | |
200 self.getreg(node.proc.obj) | |
201 # Load the address of the procedure: | |
202 self.addCode( mov(node.proc.obj.reg, ['RIP', 0x0]) ) | |
203 self.fixCode( self.rip - 4, imm32(node.proc.obj.offset - self.rip) ) | |
204 # Call to the address in register: | |
205 self.addCode( call(node.proc.obj.reg) ) | |
206 # Free register that holds the address of the object | |
207 self.freereg( node.proc.obj ) | |
208 elif type(node.proc.obj) is BuiltinProcedure: | |
209 if node.proc.obj.name == 'chr': | |
210 print('int to char') | |
211 else: | |
212 Error('Unknown builtin function {0}'.format(node.proc.obj.name)) | |
213 else: | |
214 Error('Cannot call designator of type {0}'.format(node.proc.obj)) | |
215 | |
216 # Restore stack (pop all arguments of): | |
217 self.addCode(addreg64('rsp', stacksize)) | |
218 | |
219 elif type(node) is Assignment: | |
220 if node.lval.typ.isType(integer): | |
221 # TODO if node.rval is Constant of some datatype, move it to mem directly | |
222 self.genexprcode(node.rval) # Calculate the value that has to be stored. | |
223 self.storeRegInDesignator(node.rval.reg, node.lval) | |
224 self.freereg(node.rval) | |
225 else: | |
226 Error('Assignments of other types not implemented') | |
227 # TODO if left and right are designators, do some sort of memcpy. | |
228 | |
229 elif type(node) is IfStatement: | |
230 self.genexprcode(node.condition) | |
231 self.addCode( cmpreg64(node.condition.reg, 1) ) | |
232 self.freereg(node.condition) | |
233 if node.falsestatement: | |
234 # If with else clause | |
235 self.addCode( nearjump(0x0, condition='NE') ) # if Not Equal jump to false | |
236 rip1 = self.rip | |
237 fixloc1 = self.rip - 4 | |
238 self.gencode(node.truestatement) | |
239 self.addCode( nearjump( 0x0 ) ) # jump over false code | |
240 fixloc2 = self.rip - 4 | |
241 self.fixCode(fixloc1, imm32(self.rip - rip1)) | |
242 rip2 = self.rip | |
243 self.gencode(node.falsestatement) | |
244 self.fixCode(fixloc2, imm32(self.rip - rip2)) | |
245 else: | |
246 # If without else clause | |
247 self.addCode( nearjump(0x0, condition='NE') ) # if Not Equal jump to false | |
248 rip1 = self.rip | |
249 fixloc1 = self.rip - 4 | |
250 self.gencode(node.truestatement) | |
251 self.fixCode(fixloc1, imm32(self.rip - rip1)) # Fixup near jump over true code. | |
252 | |
253 elif isinstance(node, WhileStatement): | |
254 rip1 = self.rip # Store the start of the while loop | |
255 self.genexprcode(node.condition) | |
256 self.addCode( cmpreg64(node.condition.reg, 1) ) # Test condition for true-ness | |
257 self.freereg(node.condition) | |
258 self.addCode( nearjump(0x0, condition='NE') ) # If Not Equal jump over while code AND jump back (fix later) | |
259 fixloc1 = self.rip - 4 | |
260 rip2 = self.rip | |
261 self.gencode(node.dostatements) | |
262 self.addCode( nearjump(0x0) ) # JMP to condition, fix exact jump position below | |
263 fixloc2 = self.rip - 4 | |
264 rip3 = self.rip # end of while loop | |
265 self.fixCode(fixloc2, imm32(rip1 - rip3)) # Fixup jump to start of while loop | |
266 self.fixCode(fixloc1, imm32(rip3 - rip2)) # Fixup jump out of while loop | |
267 | |
268 elif type(node) is ForStatement: | |
269 # Initial load of iterator variable: | |
270 self.genexprcode(node.begin) | |
271 self.genexprcode(node.end) | |
272 # TODO: link reg with variable so that a register is used instead of a variable | |
273 iterreg = node.begin.reg # Get the register used for the loop | |
274 #self.addCode(cmpreg64(iterreg, node.endvalue)) | |
275 rip1 = self.rip | |
276 self.gencode(node.statements) | |
277 #self.loadDesignatorInReg(node. | |
278 #self.addCode( addreg64(node.variable, node.increment) ) | |
279 self.addCode(nearjump(0x0)) | |
280 fixloc1 = self.rip - 4 | |
281 rip2 = self.rip | |
282 self.fixCode(fixloc1, imm32(rip1 - rip2)) | |
283 | |
284 self.freereg(node.begin) # Release register used in loop | |
285 self.freereg(node.end) | |
286 Error('No implementation of FOR statement') | |
287 | |
288 elif type(node) is AsmCode: | |
289 def processOperand(op): | |
290 if type(op) is list: | |
291 if type(op[0]) is Variable: | |
292 var = op[0] | |
293 if var.isLocal: | |
294 return ['rbp', var.offset] | |
295 else: | |
296 Error('Can only use local variables in inline assembler') | |
297 return op | |
298 for asmline in node.asmcode: | |
299 opcode, operands = asmline | |
300 operands = [processOperand(opx) for opx in operands] | |
301 print('assembling', opcode, *operands) | |
302 func,nargs = opcodes[opcode] | |
303 code = func(*operands) | |
304 self.addCode(code) | |
305 | |
306 elif isinstance(node, EmptyStatement): | |
307 pass | |
308 | |
309 elif type(node) is StringConstant: | |
310 self.strings.append(node) | |
311 self.data.append(node.value) # Add string to the data section | |
312 | |
313 elif type(node) is Designator: | |
314 if len(node.selectors) > 0: | |
315 self.getreg(node) | |
316 # Load starting address | |
317 if node.obj.isLocal: | |
318 self.addCode( leareg64(node.reg, ['rbp', node.obj.offset]) ) | |
319 else: | |
320 # Global variables need to be relocated... | |
321 self.addCode(leareg64(node.reg, ['RIP', 0])) | |
322 self.fixCode(self.rip - 4, imm32(node.obj.offset - self.rip)) | |
323 # Loop over all designators.. | |
324 for selector in node.selectors: | |
325 if type(selector) is Index: | |
326 # Deref an array index | |
327 self.genexprcode(selector.index) | |
328 self.getreg(selector) | |
329 self.addCode( mov(selector.reg, selector.typ.elementType.size) ) | |
330 self.addCode( imulreg64(selector.reg, selector.index.reg ) ) | |
331 self.freereg(selector.index) | |
332 self.addCode(addreg64(node.reg, selector.reg)) | |
333 self.freereg(selector) | |
334 elif type(selector) is Field: | |
335 print('Field') | |
336 Error('Field not implemented') | |
337 else: | |
338 Error('Unknown selector') | |
339 else: | |
340 Error('Can only gencode for designator with selectors') | |
341 | |
342 else: | |
343 print('not generating code for {0}'.format(node)) | |
344 | |
345 def generateIr(self, ast): | |
346 """ ir generation front end """ | |
347 return self.gencode(ast) | |
348 |