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))