103
|
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
|
|
10 class KsIrGenerator:
|
|
11 def __init__(self):
|
|
12 pass
|
|
13
|
|
14 # Code generation functions:
|
|
15 def genexprcode(self, node):
|
|
16 """
|
|
17 Generate code for expressions!
|
|
18 Recursively evaluates, and ensures a register contains the answer.
|
|
19 register is an integer register or a floating point reg
|
|
20 """
|
|
21 if isinstance(node, Binop):
|
|
22 """ Handle a binary operation (two arguments) of some kind """
|
|
23 self.genexprcode(node.a)
|
|
24 self.genexprcode(node.b)
|
|
25
|
|
26 if node.op == 'mod':
|
|
27 assert(node.typ.isType(integer))
|
|
28 elif node.op == 'div':
|
|
29 assert(node.typ.isType(integer))
|
|
30 elif node.op == '*':
|
|
31 if node.typ.isType(integer):
|
104
|
32 pass
|
103
|
33 elif node.op == '+':
|
|
34 if node.typ.isType(integer):
|
104
|
35 pass
|
103
|
36 elif node.op == '-':
|
|
37 if node.typ.isType(integer):
|
104
|
38 pass
|
103
|
39 else:
|
|
40 Error('Unknown Binop {0}'.format(node.op))
|
|
41
|
|
42 elif type(node) is Unop:
|
|
43 if node.op == 'INTTOREAL':
|
|
44 self.genexprcode(node.a)
|
|
45 node.reg = node.a.reg
|
|
46 # TODO use 'FILD' instruction
|
|
47 freg = 12
|
|
48 code.append('Unop inttoreal TODO')
|
|
49 elif node.op == 'ABS':
|
|
50 if isType(node.typ, real):
|
|
51 code = [0xD9, 0xE1] # st(0) = fabs st(0)
|
|
52 Error('ABS error integer')
|
|
53 elif isType(node.typ, integer):
|
|
54 code = []
|
|
55 Error('ABS error integer')
|
|
56 else:
|
|
57 Error('ABS error')
|
|
58 else:
|
|
59 Error('Unknown Unop {0}'.format(node.op))
|
|
60
|
|
61 elif isinstance(node, Designator):
|
|
62 # dereference, array index. Make sure that the result comes into a register
|
|
63 if len(node.selectors) > 0:
|
|
64 self.gencode(node) # Load the pointer into some register
|
|
65
|
|
66 # Now we can access the object at location '[node.reg]':
|
|
67 if node.typ.isType(integer):
|
|
68 self.addCode( mov(node.reg, [node.reg, 0x0]) )
|
|
69 else:
|
|
70 Error('Only integer types implemented')
|
|
71 else:
|
|
72 # No selectors, load variable directly
|
|
73 if node.obj.typ.isType(integer):
|
|
74 if type(node.obj) is Constant:
|
|
75 self.genexprcode(node.obj)
|
|
76 node.reg = node.obj.reg
|
|
77 else:
|
104
|
78 pass
|
103
|
79 # Get a register to store the integer value
|
|
80 else:
|
|
81 Error('Cannot load variable type {0}'.format(node.typ))
|
|
82
|
|
83 elif isinstance(node, Relop):
|
|
84 # Create a boolean from operands
|
|
85 # TODO create an alternative for expressions used as conditions.
|
|
86 self.genexprcode(node.a)
|
|
87 self.genexprcode(node.b)
|
|
88
|
|
89 if node.a.typ.isType(integer):
|
|
90 self.freereg(node.b)
|
|
91 else:
|
|
92 Error('Relop not implemented for {0}'.format(node.a.typ))
|
|
93
|
|
94 elif type(node) is Constant:
|
104
|
95 print('TODO: constant')
|
103
|
96
|
|
97 elif type(node) is ProcedureCall:
|
104
|
98 Error('TODO: proc call')
|
103
|
99 else:
|
|
100 Error('Cannot generate expression code for: {0}'.format(node))
|
|
101
|
|
102 def gencode(self, node):
|
|
103 """ Code generation function for AST nodes """
|
|
104 if isinstance(node, Module):
|
|
105 # TODO: recurse!
|
104
|
106
|
|
107 self.mod = core.Module()
|
|
108 # Create a function called init for this module:
|
|
109 ftype = core.FunctionType(self.context.VoidType, [])
|
|
110 func = core.Function(ftype, "init", self.mod)
|
|
111 bb = self.gencode(node.initcode)
|
|
112 self.mod.dump()
|
|
113 return self.mod
|
103
|
114
|
|
115 elif type(node) is Procedure:
|
|
116 # calculate offsets for local variables and parameters
|
|
117 # Variable location relative to 'rbp' register
|
|
118 variables = node.symtable.getAllLocal(Variable)
|
|
119
|
|
120 elif isinstance(node, StatementSequence):
|
|
121 for s in node.statements:
|
|
122 self.gencode(s)
|
|
123
|
|
124 elif type(node) is ProcedureCall:
|
|
125 # Prepare parameters on the stack:
|
|
126 assert(len(node.args) == len(node.proc.typ.parameters))
|
|
127 for arg, param in zip(node.args, node.proc.typ.parameters):
|
|
128
|
|
129 if param.kind == 'value':
|
|
130 self.genexprcode(arg)
|
|
131 self.addCode( push(arg.reg) )
|
|
132 self.freereg( arg )
|
|
133 stacksize += 8
|
|
134 else:
|
|
135 Error('Parameter kind other than value')
|
|
136
|
|
137 elif type(node) is Assignment:
|
|
138 if node.lval.typ.isType(integer):
|
|
139 # TODO if node.rval is Constant of some datatype, move it to mem directly
|
|
140 self.genexprcode(node.rval) # Calculate the value that has to be stored.
|
104
|
141 print("TODO")
|
103
|
142 else:
|
|
143 Error('Assignments of other types not implemented')
|
|
144 # TODO if left and right are designators, do some sort of memcpy.
|
|
145
|
|
146 elif type(node) is IfStatement:
|
|
147 self.genexprcode(node.condition)
|
104
|
148 print("TODO IF")
|
103
|
149 if node.falsestatement:
|
|
150 # If with else clause
|
104
|
151 pass
|
103
|
152 else:
|
|
153 # If without else clause
|
104
|
154 pass
|
103
|
155
|
|
156 elif isinstance(node, WhileStatement):
|
|
157 self.genexprcode(node.condition)
|
|
158 self.gencode(node.dostatements)
|
|
159 elif type(node) is ForStatement:
|
|
160 # Initial load of iterator variable:
|
|
161 self.genexprcode(node.begin)
|
|
162 self.genexprcode(node.end)
|
|
163 self.gencode(node.statements)
|
|
164 Error('No implementation of FOR statement')
|
|
165
|
|
166 elif type(node) is AsmCode:
|
|
167 def processOperand(op):
|
|
168 if type(op) is list:
|
|
169 if type(op[0]) is Variable:
|
|
170 var = op[0]
|
|
171 if var.isLocal:
|
|
172 return ['rbp', var.offset]
|
|
173 else:
|
|
174 Error('Can only use local variables in inline assembler')
|
|
175 return op
|
|
176 for asmline in node.asmcode:
|
|
177 opcode, operands = asmline
|
|
178 operands = [processOperand(opx) for opx in operands]
|
|
179 print('assembling', opcode, *operands)
|
|
180 func,nargs = opcodes[opcode]
|
|
181 code = func(*operands)
|
|
182 self.addCode(code)
|
|
183
|
|
184 elif isinstance(node, EmptyStatement):
|
|
185 pass
|
|
186
|
|
187 elif type(node) is StringConstant:
|
|
188 self.strings.append(node)
|
|
189 self.data.append(node.value) # Add string to the data section
|
|
190
|
|
191 elif type(node) is Designator:
|
|
192 if len(node.selectors) > 0:
|
|
193 self.getreg(node)
|
|
194 # Load starting address
|
|
195 if node.obj.isLocal:
|
|
196 self.addCode( leareg64(node.reg, ['rbp', node.obj.offset]) )
|
|
197 else:
|
|
198 # Global variables need to be relocated...
|
|
199 self.addCode(leareg64(node.reg, ['RIP', 0]))
|
|
200 self.fixCode(self.rip - 4, imm32(node.obj.offset - self.rip))
|
|
201 # Loop over all designators..
|
|
202 for selector in node.selectors:
|
|
203 if type(selector) is Index:
|
|
204 # Deref an array index
|
|
205 self.genexprcode(selector.index)
|
|
206 self.freereg(selector)
|
|
207 elif type(selector) is Field:
|
|
208 print('Field')
|
|
209 Error('Field not implemented')
|
|
210 else:
|
|
211 Error('Unknown selector')
|
|
212 else:
|
|
213 Error('Can only gencode for designator with selectors')
|
|
214 else:
|
|
215 print('not generating code for {0}'.format(node))
|
|
216
|
104
|
217 def generateIr(self, context, ast):
|
103
|
218 """ ir generation front end """
|
104
|
219 # Create a new context for this code.
|
|
220 self.context = context
|
103
|
221 return self.gencode(ast)
|
|
222
|