Mercurial > lcfOS
changeset 394:988f3fb861e4
c3 code generator rewrite
author | Windel Bouwman |
---|---|
date | Thu, 22 May 2014 08:14:12 +0200 |
parents | 6ae782a085e0 |
children | 3b0c495e3008 |
files | python/ppci/buildfunctions.py python/ppci/c3/astnodes.py python/ppci/c3/codegenerator.py python/ppci/c3/parser.py python/ppci/c3/scope.py python/ppci/codegen/canon.py python/ppci/ir.py python/ppci/ir2tree.py python/ppci/irutils.py python/ppci/target/token.py python/ppci/transform.py test/testir.py |
diffstat | 12 files changed, 289 insertions(+), 196 deletions(-) [+] |
line wrap: on
line diff
--- a/python/ppci/buildfunctions.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/buildfunctions.py Thu May 22 08:14:12 2014 +0200 @@ -14,7 +14,7 @@ from .linker import Linker from .layout import Layout, load_layout from .target.target_list import targets -from .outstream import BinaryAndLoggingStream +from .outstream import BinaryOutputStream from .objectfile import ObjectFile, load_object from . import DiagnosticsManager from .tasks import TaskError, TaskRunner @@ -91,7 +91,7 @@ output = ObjectFile() assembler = target.assembler logger.debug('Assembling into code section') - ostream = BinaryAndLoggingStream(output) + ostream = BinaryOutputStream(output) ostream.select_section('code') assembler.prepare() assembler.assemble(source, ostream) @@ -111,7 +111,7 @@ c3b = Builder(diag, target) cg = CodeGenerator(target) - output_stream = BinaryAndLoggingStream(output) + output_stream = BinaryOutputStream(output) for ircode in c3b.build(sources, includes): if not ircode:
--- a/python/ppci/c3/astnodes.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/c3/astnodes.py Thu May 22 08:14:12 2014 +0200 @@ -44,6 +44,10 @@ def Types(self): return self.innerScope.Types + @property + def Functions(self): + return self.innerScope.Functions + def __repr__(self): return 'MODULE {}'.format(self.name)
--- a/python/ppci/c3/codegenerator.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/c3/codegenerator.py Thu May 22 08:14:12 2014 +0200 @@ -13,7 +13,7 @@ self.loc = loc -class CodeGenerator(irutils.Builder): +class CodeGenerator: """ Generates intermediate (IR) code from a package. The entry function is 'genModule'. The main task of this part is to rewrite complex control @@ -26,11 +26,12 @@ """ def __init__(self, diag): self.logger = logging.getLogger('c3cgen') + self.builder = irutils.Builder() self.diag = diag def gencode(self, pkg): """ Generate code for a single module """ - self.prepare() + self.builder.prepare() assert type(pkg) is ast.Package self.pkg = pkg self.intType = pkg.scope['int'] @@ -39,24 +40,24 @@ self.logger.debug('Generating ir-code for {}'.format(pkg.name), extra={'c3_ast': pkg}) self.varMap = {} # Maps variables to storage locations. - self.m = ir.Module(pkg.name) + self.builder.m = ir.Module(pkg.name) try: for typ in pkg.Types: self.check_type(typ) # Only generate function if function contains a body: real_functions = list(filter( - lambda f: f.body, pkg.innerScope.Functions)) + lambda f: f.body, pkg.Functions)) for v in pkg.innerScope.Variables: - v2 = ir.GlobalVariable(v.name) + v2 = ir.GlobalVariable(v.name, ir.i32) self.varMap[v] = v2 if not v.isLocal: - self.m.add_variable(v2) + self.builder.m.add_variable(v2) for s in real_functions: self.gen_function(s) except SemanticError as e: self.error(e.msg, e.loc) if self.pkg.ok: - return self.m + return self.builder.m def error(self, msg, loc=None): self.pkg.ok = False @@ -64,133 +65,145 @@ def gen_function(self, fn): # TODO: handle arguments - f = self.newFunction(fn.name) - f.return_value = self.newTemp() - self.setFunction(f) - l2 = self.newBlock() - self.emit(ir.Jump(l2)) - self.setBlock(l2) + f = self.builder.new_function(fn.name) + f.return_value = self.builder.newTemp() + self.builder.setFunction(f) + l2 = self.builder.newBlock() + self.builder.emit(ir.Jump(l2)) + self.builder.setBlock(l2) # generate room for locals: for sym in fn.innerScope: self.check_type(sym.typ) if sym.isParameter: - p = ir.Parameter(sym.name) - variable = ir.LocalVariable(sym.name + '_copy') + p = ir.Parameter(sym.name, ir.i32) + variable = ir.LocalVariable(sym.name + '_copy', ir.i32) f.addParameter(p) f.addLocal(variable) # Move parameter into local copy: - self.emit(ir.Move(ir.Mem(variable), p)) + self.builder.emit(ir.Move(ir.Mem(variable), p)) elif sym.isLocal: - variable = ir.LocalVariable(sym.name) + variable = ir.LocalVariable(sym.name, ir.i32) f.addLocal(variable) elif isinstance(sym, ast.Variable): - variable = ir.LocalVariable(sym.name) + variable = ir.LocalVariable(sym.name, ir.i32) f.addLocal(variable) else: raise NotImplementedError('{}'.format(sym)) self.varMap[sym] = variable - self.genCode(fn.body) - self.emit(ir.Move(f.return_value, ir.Const(0))) - self.emit(ir.Jump(f.epiloog)) - self.setFunction(None) - - def genCode(self, code): - """ Wrapper around gen_stmt to catch errors """ - try: - self.gen_stmt(code) - except SemanticError as e: - self.error(e.msg, e.loc) + self.gen_stmt(fn.body) + self.builder.emit(ir.Move(f.return_value, ir.Const(0))) + self.builder.emit(ir.Jump(f.epiloog)) + self.builder.setFunction(None) def gen_stmt(self, code): """ Generate code for a statement """ - assert isinstance(code, ast.Statement) - self.setLoc(code.loc) - if type(code) is ast.Compound: - for s in code.statements: - self.genCode(s) - elif type(code) is ast.Empty: - pass - elif type(code) is ast.Assignment: - lval = self.gen_expr_code(code.lval) - rval = self.gen_expr_code(code.rval) - if not self.equal_types(code.lval.typ, code.rval.typ): - raise SemanticError('Cannot assign {} to {}' - .format(code.rval.typ, code.lval.typ), - code.loc) - if not code.lval.lvalue: - raise SemanticError('No valid lvalue {}'.format(code.lval), - code.lval.loc) - self.emit(ir.Move(lval, rval)) - elif type(code) is ast.ExpressionStatement: - self.emit(ir.Exp(self.gen_expr_code(code.ex))) - elif type(code) is ast.If: - bbtrue = self.newBlock() - bbfalse = self.newBlock() - te = self.newBlock() - self.gen_cond_code(code.condition, bbtrue, bbfalse) - self.setBlock(bbtrue) - self.genCode(code.truestatement) - self.emit(ir.Jump(te)) - self.setBlock(bbfalse) - self.genCode(code.falsestatement) - self.emit(ir.Jump(te)) - self.setBlock(te) - elif type(code) is ast.Return: - re = self.gen_expr_code(code.expr) - self.emit(ir.Move(self.fn.return_value, re)) - self.emit(ir.Jump(self.fn.epiloog)) - b = self.newBlock() - self.setBlock(b) - elif type(code) is ast.While: - bbdo = self.newBlock() - bbtest = self.newBlock() - te = self.newBlock() - self.emit(ir.Jump(bbtest)) - self.setBlock(bbtest) - self.gen_cond_code(code.condition, bbdo, te) - self.setBlock(bbdo) - self.genCode(code.statement) - self.emit(ir.Jump(bbtest)) - self.setBlock(te) - elif type(code) is ast.For: - bbdo = self.newBlock() - bbtest = self.newBlock() - te = self.newBlock() - self.genCode(code.init) - self.emit(ir.Jump(bbtest)) - self.setBlock(bbtest) - self.gen_cond_code(code.condition, bbdo, te) - self.setBlock(bbdo) - self.genCode(code.statement) - self.genCode(code.final) - self.emit(ir.Jump(bbtest)) - self.setBlock(te) - elif type(code) is ast.Switch: - raise NotImplementedError('Unknown stmt {}'.format(code)) - else: - raise NotImplementedError('Unknown stmt {}'.format(code)) + try: + assert isinstance(code, ast.Statement) + self.builder.setLoc(code.loc) + if type(code) is ast.Compound: + for s in code.statements: + self.gen_stmt(s) + elif type(code) is ast.Empty: + pass + elif type(code) is ast.Assignment: + self.gen_assignment_stmt(code) + elif type(code) is ast.ExpressionStatement: + self.builder.emit(ir.Exp(self.gen_expr_code(code.ex))) + elif type(code) is ast.If: + self.gen_if_stmt(code) + elif type(code) is ast.Return: + re = self.gen_expr_code(code.expr) + self.builder.emit(ir.Move(self.builder.fn.return_value, re)) + self.builder.emit(ir.Jump(self.builder.fn.epiloog)) + b = self.builder.newBlock() + self.builder.setBlock(b) + elif type(code) is ast.While: + self.gen_while(code) + elif type(code) is ast.For: + self.gen_for_stmt(code) + elif type(code) is ast.Switch: + raise NotImplementedError('Unknown stmt {}'.format(code)) + else: + raise NotImplementedError('Unknown stmt {}'.format(code)) + except SemanticError as e: + self.error(e.msg, e.loc) + + def gen_assignment_stmt(self, code): + """ Generate code for assignment statement """ + lval = self.gen_expr_code(code.lval) + rval = self.gen_expr_code(code.rval) + if not self.equal_types(code.lval.typ, code.rval.typ): + raise SemanticError('Cannot assign {} to {}' + .format(code.rval.typ, code.lval.typ), + code.loc) + if not code.lval.lvalue: + raise SemanticError('No valid lvalue {}'.format(code.lval), + code.lval.loc) + self.builder.emit(ir.Move(lval, rval)) + + def gen_if_stmt(self, code): + """ Generate code for if statement """ + true_block = self.builder.newBlock() + bbfalse = self.builder.newBlock() + te = self.builder.newBlock() + self.gen_cond_code(code.condition, true_block, bbfalse) + self.builder.setBlock(true_block) + self.gen_stmt(code.truestatement) + self.builder.emit(ir.Jump(te)) + self.builder.setBlock(bbfalse) + self.gen_stmt(code.falsestatement) + self.builder.emit(ir.Jump(te)) + self.builder.setBlock(te) + + def gen_while(self, code): + """ Generate code for while statement """ + bbdo = self.builder.newBlock() + test_block = self.builder.newBlock() + final_block = self.builder.newBlock() + self.builder.emit(ir.Jump(test_block)) + self.builder.setBlock(test_block) + self.gen_cond_code(code.condition, bbdo, final_block) + self.builder.setBlock(bbdo) + self.gen_stmt(code.statement) + self.builder.emit(ir.Jump(test_block)) + self.builder.setBlock(final_block) + + def gen_for_stmt(self, code): + """ Generate for statement code """ + bbdo = self.builder.newBlock() + test_block = self.builder.newBlock() + final_block = self.builder.newBlock() + self.gen_stmt(code.init) + self.builder.emit(ir.Jump(test_block)) + self.builder.setBlock(test_block) + self.gen_cond_code(code.condition, bbdo, final_block) + self.builder.setBlock(bbdo) + self.gen_stmt(code.statement) + self.gen_stmt(code.final) + self.builder.emit(ir.Jump(test_block)) + self.builder.setBlock(final_block) def gen_cond_code(self, expr, bbtrue, bbfalse): """ Generate conditional logic. Implement sequential logical operators. """ if type(expr) is ast.Binop: if expr.op == 'or': - l2 = self.newBlock() + l2 = self.builder.newBlock() self.gen_cond_code(expr.a, bbtrue, l2) if not self.equal_types(expr.a.typ, self.boolType): raise SemanticError('Must be boolean', expr.a.loc) - self.setBlock(l2) + self.builder.setBlock(l2) self.gen_cond_code(expr.b, bbtrue, bbfalse) if not self.equal_types(expr.b.typ, self.boolType): raise SemanticError('Must be boolean', expr.b.loc) elif expr.op == 'and': - l2 = self.newBlock() + l2 = self.builder.newBlock() self.gen_cond_code(expr.a, l2, bbfalse) if not self.equal_types(expr.a.typ, self.boolType): self.error('Must be boolean', expr.a.loc) - self.setBlock(l2) + self.builder.setBlock(l2) self.gen_cond_code(expr.b, bbtrue, bbfalse) if not self.equal_types(expr.b.typ, self.boolType): raise SemanticError('Must be boolean', expr.b.loc) @@ -201,16 +214,16 @@ raise SemanticError('Types unequal {} != {}' .format(expr.a.typ, expr.b.typ), expr.loc) - self.emit(ir.CJump(ta, expr.op, tb, bbtrue, bbfalse)) + self.builder.emit(ir.CJump(ta, expr.op, tb, bbtrue, bbfalse)) else: raise SemanticError('non-bool: {}'.format(expr.op), expr.loc) expr.typ = self.boolType elif type(expr) is ast.Literal: self.gen_expr_code(expr) if expr.val: - self.emit(ir.Jump(bbtrue)) + self.builder.emit(ir.Jump(bbtrue)) else: - self.emit(ir.Jump(bbfalse)) + self.builder.emit(ir.Jump(bbfalse)) else: raise NotImplementedError('Unknown cond {}'.format(expr)) @@ -237,7 +250,7 @@ raise SemanticError('Can only add integers', expr.loc) else: raise NotImplementedError("Cannot use equality as expressions") - return ir.Binop(ra, expr.op, rb) + return ir.Binop(ra, expr.op, rb, "op", ir.i32) elif type(expr) is ast.Unop: if expr.op == '&': ra = self.gen_expr_code(expr.a) @@ -274,61 +287,11 @@ else: raise SemanticError('Cannot deref non-pointer', expr.loc) elif type(expr) is ast.Member: - base = self.gen_expr_code(expr.base) - expr.lvalue = expr.base.lvalue - basetype = self.the_type(expr.base.typ) - if type(basetype) is ast.StructureType: - if basetype.hasField(expr.field): - expr.typ = basetype.fieldType(expr.field) - else: - raise SemanticError('{} does not contain field {}' - .format(basetype, expr.field), - expr.loc) - else: - raise SemanticError('Cannot select {} of non-structure type {}' - .format(expr.field, basetype), expr.loc) - - assert type(base) is ir.Mem, type(base) - bt = self.the_type(expr.base.typ) - offset = ir.Const(bt.fieldOffset(expr.field)) - return ir.Mem(ir.Add(base.e, offset)) + return self.gen_member_expr(expr) elif type(expr) is ast.Index: - """ Array indexing """ - base = self.gen_expr_code(expr.base) - idx = self.gen_expr_code(expr.i) - base_typ = self.the_type(expr.base.typ) - if not isinstance(base_typ, ast.ArrayType): - raise SemanticError('Cannot index non-array type {}' - .format(base_typ), - expr.base.loc) - idx_type = self.the_type(expr.i.typ) - if not self.equal_types(idx_type, self.intType): - raise SemanticError('Index must be int not {}' - .format(idx_type), expr.i.loc) - assert type(base) is ir.Mem - element_type = self.the_type(base_typ.element_type) - element_size = self.size_of(element_type) - expr.typ = base_typ.element_type - expr.lvalue = True - - return ir.Mem(ir.Add(base.e, ir.Mul(idx, ir.Const(element_size)))) + return self.gen_index_expr(expr) elif type(expr) is ast.Literal: - expr.lvalue = False - typemap = {int: 'int', - float: 'double', - bool: 'bool', - str: 'string'} - if type(expr.val) in typemap: - expr.typ = self.pkg.scope[typemap[type(expr.val)]] - else: - raise SemanticError('Unknown literal type {}' - .format(expr.val), expr.loc) - # Construct correct const value: - if type(expr.val) is str: - cval = self.pack_string(expr.val) - return ir.Addr(ir.Const(cval)) - else: - return ir.Const(expr.val) + return self.gen_literal_expr(expr) elif type(expr) is ast.TypeCast: return self.gen_type_cast(expr) elif type(expr) is ast.Sizeof: @@ -342,6 +305,69 @@ else: raise NotImplementedError('Unknown expr {}'.format(expr)) + def gen_member_expr(self, expr): + base = self.gen_expr_code(expr.base) + expr.lvalue = expr.base.lvalue + basetype = self.the_type(expr.base.typ) + if type(basetype) is ast.StructureType: + if basetype.hasField(expr.field): + expr.typ = basetype.fieldType(expr.field) + else: + raise SemanticError('{} does not contain field {}' + .format(basetype, expr.field), + expr.loc) + else: + raise SemanticError('Cannot select {} of non-structure type {}' + .format(expr.field, basetype), expr.loc) + + assert type(base) is ir.Mem, type(base) + bt = self.the_type(expr.base.typ) + offset = ir.Const(bt.fieldOffset(expr.field)) + addr = ir.Add(base.e, offset, "mem_addr", ir.i32) + return ir.Mem(addr) + + def gen_index_expr(self, expr): + """ Array indexing """ + base = self.gen_expr_code(expr.base) + idx = self.gen_expr_code(expr.i) + base_typ = self.the_type(expr.base.typ) + if not isinstance(base_typ, ast.ArrayType): + raise SemanticError('Cannot index non-array type {}' + .format(base_typ), + expr.base.loc) + idx_type = self.the_type(expr.i.typ) + if not self.equal_types(idx_type, self.intType): + raise SemanticError('Index must be int not {}' + .format(idx_type), expr.i.loc) + assert type(base) is ir.Mem + element_type = self.the_type(base_typ.element_type) + element_size = self.size_of(element_type) + expr.typ = base_typ.element_type + expr.lvalue = True + + offset = ir.Mul(idx, ir.Const(element_size), "element_offset", ir.i32) + addr = ir.Add(base.e, offset, "element_address", ir.i32) + return ir.Mem(addr) + + def gen_literal_expr(self, expr): + """ Generate code for literal """ + expr.lvalue = False + typemap = {int: 'int', + float: 'double', + bool: 'bool', + str: 'string'} + if type(expr.val) in typemap: + expr.typ = self.pkg.scope[typemap[type(expr.val)]] + else: + raise SemanticError('Unknown literal type {}' + .format(expr.val), expr.loc) + # Construct correct const value: + if type(expr.val) is str: + cval = self.pack_string(expr.val) + return ir.Addr(ir.Const(cval)) + else: + return ir.Const(expr.val) + def pack_string(self, txt): """ Pack a string using 4 bytes length followed by text data """ length = struct.pack('<I', len(txt))
--- a/python/ppci/c3/parser.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/c3/parser.py Thu May 22 08:14:12 2014 +0200 @@ -23,7 +23,7 @@ self.tokens = tokens self.token = self.tokens.__next__() try: - self.parsePackage() + self.parse_package() self.mod.ok = True # Valid until proven wrong :) return self.mod except CompilerError as e: @@ -68,26 +68,28 @@ self.mod.imports.append(name) self.Consume(';') - def parsePackage(self): + def parse_package(self): + """ Parse a package definition """ self.Consume('module') name = self.Consume('ID') self.Consume(';') self.mod = Package(name.val, name.loc) self.currentPart = self.mod while self.Peak != 'END': - self.parseTopLevel() + self.parse_top_level() self.Consume('END') - def parseTopLevel(self): + def parse_top_level(self): + """ Parse toplevel declaration """ if self.Peak == 'function': self.parse_function_def() elif self.Peak == 'var': - self.parseVarDef() + self.parse_variable_def() # TODO handle variable initialization elif self.Peak == 'const': self.parseConstDef() elif self.Peak == 'type': - self.parseTypeDef() + self.parse_type_def() elif self.Peak == 'import': self.parseImport() else: @@ -155,7 +157,7 @@ raise Exception() return theT - def parseTypeDef(self): + def parse_type_def(self): self.Consume('type') newtype = self.parse_type_spec() typename = self.Consume('ID') @@ -164,7 +166,8 @@ self.addDeclaration(df) # Variable declarations: - def parseVarDef(self): + def parse_variable_def(self): + """ Parse variable declaration """ self.Consume('var') t = self.parse_type_spec() for name in self.parseIdSequence(): @@ -172,7 +175,6 @@ v.loc = name.loc self.addDeclaration(v) self.Consume(';') - return Empty() def parseConstDef(self): self.Consume('const') @@ -234,7 +236,7 @@ self.Consume(')') return Switch(condition, loc) - def parseWhile(self): + def parse_while(self): loc = self.Consume('while').loc self.Consume('(') condition = self.Expression() @@ -275,7 +277,7 @@ if self.Peak == 'if': return self.parse_if() elif self.Peak == 'while': - return self.parseWhile() + return self.parse_while() elif self.Peak == 'for': return self.parse_for() elif self.Peak == 'switch': @@ -285,7 +287,8 @@ elif self.hasConsumed(';'): return Empty() elif self.Peak == 'var': - return self.parseVarDef() + self.parse_variable_def() + return Empty() elif self.Peak == 'return': return self.parseReturn() else: @@ -391,6 +394,7 @@ return self.UnaryExpression() def sizeof_expression(self): + """ Compiler internal function to determine size of a type """ loc = self.Consume('sizeof').loc self.Consume('(') typ = self.parse_type_spec()
--- a/python/ppci/c3/scope.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/c3/scope.py Thu May 22 08:14:12 2014 +0200 @@ -16,6 +16,7 @@ @property def Syms(self): + """ Get all the symbols defined in this scope """ syms = self.symbols.values() return sorted(syms, key=lambda v: v.name)
--- a/python/ppci/codegen/canon.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/codegen/canon.py Thu May 22 08:14:12 2014 +0200 @@ -60,7 +60,7 @@ return frame.parMap[exp] elif isinstance(exp, ir.LocalVariable): offset = frame.allocVar(exp) - return ir.Add(frame.fp, ir.Const(offset)) + return ir.Add(frame.fp, ir.Const(offset), "Offset", ir.i32) elif isinstance(exp, ir.GlobalVariable): #frame.load_global_address(ir.label_name(exp)) return exp
--- a/python/ppci/ir.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/ir.py Thu May 22 08:14:12 2014 +0200 @@ -4,7 +4,7 @@ def label_name(dut): - """ Function that returns the assembly code label name """ + """ Returns the assembly code label name """ if isinstance(dut, Block): f = dut.function return label_name(f) + '_' + dut.name @@ -16,6 +16,14 @@ raise NotImplementedError(str(dut)) +class Typ: + def __init__(self): + pass + + +i32 = Typ() +i8 = Typ() + class Module: """ Container unit for variables and functions. """ def __init__(self, name): @@ -46,14 +54,12 @@ Functions = property(get_functions) - def findFunction(self, name): + def find_function(self, name): for f in self.funcs: if f.name == name: return f raise KeyError(name) - getFunction = findFunction - class Function: """ Represents a function. """ @@ -195,9 +201,27 @@ # Instructions: class Value: - pass + """ A value has a type and a name """ + def __init__(self, name, ty): + assert isinstance(ty, Typ) + self.name = name + self.ty = ty + -class Expression: +class User(Value): + """ Value that uses other values """ + def __init__(self, name, ty): + super().__init__(name, ty) + # Create a collection to store the values this value uses. + # TODO: think of better naming.. + self.uses = set() + + def add_use(self, v): + assert isinstance(v, Value) + self.uses.add(v) + + +class Expression(User): """ Base class for an expression """ pass @@ -228,11 +252,14 @@ """ Generic binary operation """ ops = ['+', '-', '*', '/', '|', '&', '<<', '>>'] - def __init__(self, value1, operation, value2): + def __init__(self, a, operation, b, name, ty): + super().__init__(name, ty) assert operation in Binop.ops #assert type(value1) is type(value2) - self.a = value1 - self.b = value2 + assert isinstance(a, Value), str(a) + assert isinstance(b, Value), str(b) + self.a = a + self.b = b self.operation = operation def __repr__(self): @@ -240,9 +267,10 @@ return '({} {} {})'.format(a, self.operation, b) -def Add(a, b): +class Add(Binop): """ Add a and b """ - return Binop(a, '+', b) + def __init__(self, a, b, name, ty): + super().__init__(a, '+', b, name, ty) def Sub(a, b): @@ -250,9 +278,9 @@ return Binop(a, '-', b) -def Mul(a, b): +def Mul(a, b, name, ty): """ Multiply a by b """ - return Binop(a, '*', b) + return Binop(a, '*', b, name, ty) def Div(a, b): @@ -260,6 +288,16 @@ return Binop(a, '/', b) +def Phi(User): + """ Imaginary phi instruction to make SSA possible. """ + def __init__(self, name, ty): + super().__init__(name, ty) + self.inputs = [] + + def add_input(self, value, block): + self.inputs.append((value, block)) + + class Eseq(Expression): """ Sequence of instructions where the last is an expression """ def __init__(self, stmt, e): @@ -280,7 +318,8 @@ class Variable(Expression): - def __init__(self, name): + def __init__(self, name, ty): + super().__init__(name, ty) self.name = name def __repr__(self): @@ -320,6 +359,23 @@ return '[{}]'.format(self.e) +class Load(Value): + """ Load a value from memory """ + def __init__(self, address, name, ty): + super().__init__(name, ty) + assert isinstance(address, Value) + self.address = address + + def __repr__(self): + return 'load {}'.format(self.address) + + +class Store: + """ Store a value into memory """ + def __init__(self, address, value): + self.address = address + + class Addr(Expression): """ Address of label """ def __init__(self, e):
--- a/python/ppci/ir2tree.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/ir2tree.py Thu May 22 08:14:12 2014 +0200 @@ -13,6 +13,7 @@ return reg_f @register(ir.Binop) +@register(ir.Add) def binop_to_tree(e): names = {'+':'ADDI32', '-':'SUBI32', '|':'ORI32', '<<':'SHLI32', '*':'MULI32', '&':'ANDI32', '>>':'SHRI32'}
--- a/python/ppci/irutils.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/irutils.py Thu May 22 08:14:12 2014 +0200 @@ -210,7 +210,7 @@ def setModule(self, m): self.m = m - def newFunction(self, name): + def new_function(self, name): f = ir.Function(name) self.m.add_function(f) return f @@ -240,6 +240,7 @@ class Verifier: + """ Checks an ir module for correctness """ def verify(self, module): """ Verifies a module for some sanity """ assert isinstance(module, ir.Module)
--- a/python/ppci/target/token.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/target/token.py Thu May 22 08:14:12 2014 +0200 @@ -13,7 +13,6 @@ b = [] for i in range(bits): b.append(bool((1<<i) & v)) - #b.reverse() return b @@ -48,6 +47,7 @@ elif type(key) is slice: assert key.step is None bits = key.stop - key.start + assert value < (2**bits) value_bits = val2bit(value, bits) for i in range(key.start, key.stop): self.set_bit(i, value_bits[i - key.start])
--- a/python/ppci/transform.py Sat May 17 21:17:40 2014 +0200 +++ b/python/ppci/transform.py Thu May 22 08:14:12 2014 +0200 @@ -125,6 +125,7 @@ child_nodes = {} child_nodes[ir.Binop] = ['a', 'b'] +child_nodes[ir.Add] = ['a', 'b'] child_nodes[ir.Const] = [] child_nodes[ir.Temp] = [] child_nodes[ir.Exp] = ['e']
--- a/test/testir.py Sat May 17 21:17:40 2014 +0200 +++ b/test/testir.py Thu May 22 08:14:12 2014 +0200 @@ -1,5 +1,4 @@ import unittest -import os import sys import io import ppci @@ -10,7 +9,7 @@ class IrCodeTestCase(unittest.TestCase): def testAdd(self): - v = ir.Add(ir.Const(1), ir.Const(2)) + v = ir.Add(ir.Const(1), ir.Const(2), "add", ir.i32) class IrBuilderTestCase(unittest.TestCase): @@ -20,7 +19,7 @@ self.b.setModule(self.m) def testBuilder(self): - f = self.b.newFunction('add') + f = self.b.new_function('add') self.b.setFunction(f) bb = self.b.newBlock() self.b.emit(ir.Jump(bb)) @@ -65,23 +64,23 @@ self.b.setModule(self.m) def testBuilder(self): - f = self.b.newFunction('test') + f = self.b.new_function('test') self.b.setFunction(f) bb = self.b.newBlock() self.b.emit(ir.Jump(bb)) self.b.setBlock(bb) v1 = ir.Const(5) v2 = ir.Const(7) - v3 = ir.Add(v1, v2) + v3 = ir.Add(v1, v2, "add", ir.i32) self.b.emit(ir.Jump(f.epiloog)) self.cf.run(self.m) def testAdd0(self): - f = self.b.newFunction('test') + f = self.b.new_function('test') self.b.setFunction(f) self.b.setBlock(self.b.newBlock()) - v1 = ir.Const(0) - v3 = ir.Add(v1, ir.Const(0)) + v1 = ir.Const(12) + v3 = ir.Add(v1, ir.Const(0), "add", ir.i32) class TestWriter(unittest.TestCase):