Mercurial > lcfOS
comparison python/ppci/c3/codegenerator.py @ 300:158068af716c
yafm
author | Windel Bouwman |
---|---|
date | Tue, 03 Dec 2013 18:00:22 +0100 |
parents | python/c3/codegenerator.py@a747a45dcd78 |
children | 6753763d3bec |
comparison
equal
deleted
inserted
replaced
299:674789d9ff37 | 300:158068af716c |
---|---|
1 import logging | |
2 import ir | |
3 from . import astnodes | |
4 from .scope import boolType, intType | |
5 from ppci import CompilerError | |
6 from .analyse import theType | |
7 | |
8 | |
9 class CodeGenerator(ir.Builder): | |
10 """ | |
11 Generates intermediate (IR) code from a package. The entry function is | |
12 'genModule'. The main task of this part is to rewrite complex control | |
13 structures, such as while and for loops into simple conditional | |
14 jump statements. Also complex conditional statements are simplified. | |
15 Such as 'and' and 'or' statements are rewritten in conditional jumps. | |
16 And structured datatypes are rewritten. | |
17 """ | |
18 def __init__(self): | |
19 self.logger = logging.getLogger('c3cgen') | |
20 | |
21 def gencode(self, pkg): | |
22 self.prepare() | |
23 assert type(pkg) is astnodes.Package | |
24 self.logger.info('Generating ir-code for {}'.format(pkg.name)) | |
25 self.varMap = {} # Maps variables to storage locations. | |
26 self.funcMap = {} | |
27 self.m = ir.Module(pkg.name) | |
28 self.genModule(pkg) | |
29 return self.m | |
30 | |
31 # inner helpers: | |
32 def genModule(self, pkg): | |
33 # Take care of forward declarations: | |
34 for s in pkg.innerScope.Functions: | |
35 f = self.newFunction(s.name) | |
36 self.funcMap[s] = f | |
37 for v in pkg.innerScope.Variables: | |
38 self.varMap[v] = self.newTemp() | |
39 for s in pkg.innerScope.Functions: | |
40 self.genFunction(s) | |
41 | |
42 def genFunction(self, fn): | |
43 # TODO: handle arguments | |
44 f = self.funcMap[fn] | |
45 f.return_value = self.newTemp() | |
46 # TODO reserve room for stack, this can be done at later point? | |
47 self.setFunction(f) | |
48 l2 = self.newBlock() | |
49 self.emit(ir.Jump(l2)) | |
50 self.setBlock(l2) | |
51 # generate room for locals: | |
52 | |
53 for sym in fn.innerScope: | |
54 # TODO: handle parameters different | |
55 if sym.isParameter: | |
56 v = ir.Parameter(sym.name) | |
57 f.addParameter(v) | |
58 elif sym.isLocal: | |
59 v = ir.LocalVariable(sym.name) | |
60 f.addLocal(v) | |
61 else: | |
62 #v = self.newTemp() | |
63 raise NotImplementedError('{}'.format(sym)) | |
64 # TODO: make this ssa here?? | |
65 self.varMap[sym] = v | |
66 | |
67 self.genCode(fn.body) | |
68 # Set the default return value to zero: | |
69 # TBD: this may not be required? | |
70 self.emit(ir.Move(f.return_value, ir.Const(0))) | |
71 self.emit(ir.Jump(f.epiloog)) | |
72 self.setFunction(None) | |
73 | |
74 def genCode(self, code): | |
75 assert isinstance(code, astnodes.Statement) | |
76 self.setLoc(code.loc) | |
77 if type(code) is astnodes.CompoundStatement: | |
78 for s in code.statements: | |
79 self.genCode(s) | |
80 elif type(code) is astnodes.Assignment: | |
81 rval = self.genExprCode(code.rval) | |
82 lval = self.genExprCode(code.lval) | |
83 self.emit(ir.Move(lval, rval)) | |
84 elif type(code) is astnodes.ExpressionStatement: | |
85 self.emit(ir.Exp(self.genExprCode(code.ex))) | |
86 elif type(code) is astnodes.IfStatement: | |
87 bbtrue = self.newBlock() | |
88 bbfalse = self.newBlock() | |
89 te = self.newBlock() | |
90 self.genCondCode(code.condition, bbtrue, bbfalse) | |
91 self.setBlock(bbtrue) | |
92 self.genCode(code.truestatement) | |
93 self.emit(ir.Jump(te)) | |
94 self.setBlock(bbfalse) | |
95 if code.falsestatement: | |
96 self.genCode(code.falsestatement) | |
97 self.emit(ir.Jump(te)) | |
98 self.setBlock(te) | |
99 elif type(code) is astnodes.ReturnStatement: | |
100 if code.expr: | |
101 re = self.genExprCode(code.expr) | |
102 self.emit(ir.Move(self.fn.return_value, re)) | |
103 self.emit(ir.Jump(self.fn.epiloog)) | |
104 b = self.newBlock() | |
105 self.setBlock(b) | |
106 else: | |
107 self.builder.addIns(ir.Return()) | |
108 elif type(code) is astnodes.WhileStatement: | |
109 bbdo = self.newBlock() | |
110 bbtest = self.newBlock() | |
111 te = self.newBlock() | |
112 self.emit(ir.Jump(bbtest)) | |
113 self.setBlock(bbtest) | |
114 self.genCondCode(code.condition, bbdo, te) | |
115 self.setBlock(bbdo) | |
116 self.genCode(code.statement) | |
117 self.emit(ir.Jump(bbtest)) | |
118 self.setBlock(te) | |
119 else: | |
120 raise NotImplementedError('Unknown stmt {}'.format(code)) | |
121 | |
122 def genCondCode(self, expr, bbtrue, bbfalse): | |
123 # Implement sequential logical operators | |
124 assert expr.typ == boolType | |
125 if type(expr) is astnodes.Binop: | |
126 if expr.op == 'or': | |
127 l2 = self.newBlock() | |
128 self.genCondCode(expr.a, bbtrue, l2) | |
129 self.setBlock(l2) | |
130 self.genCondCode(expr.b, bbtrue, bbfalse) | |
131 elif expr.op == 'and': | |
132 l2 = self.newBlock() | |
133 self.genCondCode(expr.a, l2, bbfalse) | |
134 self.setBlock(l2) | |
135 self.genCondCode(expr.b, bbtrue, bbfalse) | |
136 elif expr.op in ['==', '>', '<']: | |
137 ta = self.genExprCode(expr.a) | |
138 tb = self.genExprCode(expr.b) | |
139 self.emit(ir.CJump(ta, expr.op, tb, bbtrue, bbfalse)) | |
140 else: | |
141 raise NotImplementedError('Unknown condition {}'.format(expr)) | |
142 elif type(expr) is astnodes.Literal: | |
143 if expr.val: | |
144 self.emit(ir.Jump(bbtrue)) | |
145 else: | |
146 self.emit(ir.Jump(bbfalse)) | |
147 else: | |
148 raise NotImplementedError('Unknown cond {}'.format(expr)) | |
149 | |
150 def genExprCode(self, expr): | |
151 assert isinstance(expr, astnodes.Expression) | |
152 if type(expr) is astnodes.Binop and expr.op in ir.Binop.ops: | |
153 ra = self.genExprCode(expr.a) | |
154 rb = self.genExprCode(expr.b) | |
155 return ir.Binop(ra, expr.op, rb) | |
156 elif type(expr) is astnodes.Unop and expr.op == '&': | |
157 ra = self.genExprCode(expr.a) | |
158 assert type(ra) is ir.Mem | |
159 return ra.e | |
160 elif type(expr) is astnodes.VariableUse: | |
161 # This returns the dereferenced variable. | |
162 if expr.target.isParameter: | |
163 # TODO: now parameters are handled different. Not nice? | |
164 return self.varMap[expr.target] | |
165 else: | |
166 return ir.Mem(self.varMap[expr.target]) | |
167 elif type(expr) is astnodes.Deref: | |
168 # dereference pointer type: | |
169 addr = self.genExprCode(expr.ptr) | |
170 return ir.Mem(addr) | |
171 elif type(expr) is astnodes.FieldRef: | |
172 base = self.genExprCode(expr.base) | |
173 assert type(base) is ir.Mem, type(base) | |
174 base = base.e | |
175 bt = theType(expr.base.typ) | |
176 offset = ir.Const(bt.fieldOffset(expr.field)) | |
177 return ir.Mem(ir.Add(base, offset)) | |
178 elif type(expr) is astnodes.Literal: | |
179 return ir.Const(expr.val) | |
180 elif type(expr) is astnodes.TypeCast: | |
181 # TODO: improve this mess: | |
182 ar = self.genExprCode(expr.a) | |
183 tt = theType(expr.to_type) | |
184 if isinstance(tt, astnodes.PointerType): | |
185 if expr.a.typ is intType: | |
186 return ar | |
187 elif isinstance(expr.a.typ, astnodes.PointerType): | |
188 return ar | |
189 else: | |
190 raise Exception() | |
191 else: | |
192 raise NotImplementedError("not implemented") | |
193 elif type(expr) is astnodes.FunctionCall: | |
194 args = [self.genExprCode(e) for e in expr.args] | |
195 fn = self.funcMap[expr.proc] | |
196 return ir.Call(fn, args) | |
197 else: | |
198 raise NotImplementedError('Unknown expr {}'.format(expr)) |