# HG changeset patch # User Windel Bouwman # Date 1385901418 -3600 # Node ID 9417caea2eb3c34a3036b408380728b8e56a40f1 # Parent 917eab04b8b794838e99c825bd699bb5175921b1 Directorized some backend files diff -r 917eab04b8b7 -r 9417caea2eb3 kernel/kernel.c3 --- a/kernel/kernel.c3 Thu Nov 28 21:10:32 2013 +0100 +++ b/kernel/kernel.c3 Sun Dec 01 13:36:58 2013 +0100 @@ -12,9 +12,9 @@ memory:init(); - Process proc = new process:Process(); + //Process proc = new process:Process(); - scheduler:queue(proc); + //scheduler:queue(proc); } diff -r 917eab04b8b7 -r 9417caea2eb3 kernel/make.py --- a/kernel/make.py Thu Nov 28 21:10:32 2013 +0100 +++ b/kernel/make.py Sun Dec 01 13:36:58 2013 +0100 @@ -5,7 +5,7 @@ sys.path.insert(0, os.path.join('..', 'python')) import zcc -arglist = ['memory.c3', 'kernel.c3', 'syscall.c3'] +arglist = ['memory.c3', 'kernel.c3', 'syscall.c3', 'process.c3', 'schedule.c3'] arglist += ['--target', 'arm'] arglist += ['--dumpasm'] arglist += ['--log', 'debug'] diff -r 917eab04b8b7 -r 9417caea2eb3 kernel/memory.c3 --- a/kernel/memory.c3 Thu Nov 28 21:10:32 2013 +0100 +++ b/kernel/memory.c3 Sun Dec 01 13:36:58 2013 +0100 @@ -2,11 +2,11 @@ import process; -var uint8_t* ptr; +var u8* ptr; -function uint8_t* Alloc(int size) +function u8* Alloc(int size) { - ptr += size; + ptr = ptr + size; return ptr; } diff -r 917eab04b8b7 -r 9417caea2eb3 kernel/process.c3 --- a/kernel/process.c3 Thu Nov 28 21:10:32 2013 +0100 +++ b/kernel/process.c3 Sun Dec 01 13:36:58 2013 +0100 @@ -3,19 +3,19 @@ import kernel; // process type definition: -typedef struct { +type struct { int id; int status; } process_t; // Or, use this list structure: -List procs; +// List procs; // init is the root of all processes: var process_t* init = 0; var int next_pid = 0; -public function void init() +function void init() { next_pid = 0; init = Create(); @@ -24,7 +24,7 @@ /* Create a new process. */ -public func process_t* Create() +function process_t* Create() { process_t* p = memory.Alloc(sizeof(process_t)); p->id = next_pid; diff -r 917eab04b8b7 -r 9417caea2eb3 kernel/schedule.c3 --- a/kernel/schedule.c3 Thu Nov 28 21:10:32 2013 +0100 +++ b/kernel/schedule.c3 Sun Dec 01 13:36:58 2013 +0100 @@ -1,7 +1,7 @@ -module schedule.c3; +module scheduler; -func void executeNext() +function void executeNext() { process_t *old; diff -r 917eab04b8b7 -r 9417caea2eb3 python/asm.py diff -r 917eab04b8b7 -r 9417caea2eb3 python/c3/parser.py --- a/python/c3/parser.py Thu Nov 28 21:10:32 2013 +0100 +++ b/python/c3/parser.py Sun Dec 01 13:36:58 2013 +0100 @@ -1,6 +1,14 @@ import logging from .lexer import Lexer -from . import astnodes +from .astnodes import FieldRef, Literal, TypeCast, Unop, Binop +from .astnodes import Assignment, ExpressionStatement, CompoundStatement +from .astnodes import ReturnStatement, WhileStatement, IfStatement +from .astnodes import FunctionType, Function, FormalParameter +from .astnodes import StructureType, DefinedType, PointerType +from .astnodes import Constant, Variable +from .astnodes import StructField, Deref +from .astnodes import Package, ImportDesignator +from .astnodes import Designator, VariableUse, FunctionCall from ppci import CompilerError @@ -67,7 +75,7 @@ self.Consume('module') name = self.Consume('ID') self.Consume(';') - self.mod = astnodes.Package(name.val, name.loc) + self.mod = Package(name.val, name.loc) self.currentPart = self.mod while self.Peak != 'END': self.parseTopLevel() @@ -92,9 +100,9 @@ name = self.Consume('ID') if self.hasConsumed(':'): name2 = self.Consume('ID') - return astnodes.ImportDesignator(name.val, name2.val, name.loc) + return ImportDesignator(name.val, name2.val, name.loc) else: - return astnodes.Designator(name.val, name.loc) + return Designator(name.val, name.loc) # Type system def parseTypeSpec(self): @@ -107,18 +115,18 @@ while self.Peak != '}': mem_t = self.parseTypeSpec() mem_n = self.Consume('ID').val - mems.append(astnodes.StructField(mem_n, mem_t)) + mems.append(StructField(mem_n, mem_t)) while self.hasConsumed(','): mem_n = self.Consume('ID').val - mems.append(astnodes.StructField(mem_n, mem_t)) + mems.append(StructField(mem_n, mem_t)) self.Consume(';') self.Consume('}') - theT = astnodes.StructureType(mems) + theT = StructureType(mems) else: theT = self.parseDesignator() # Check for pointer suffix: while self.hasConsumed('*'): - theT = astnodes.PointerType(theT) + theT = PointerType(theT) return theT def parseTypeDef(self): @@ -126,7 +134,7 @@ newtype = self.parseTypeSpec() typename = self.Consume('ID') self.Consume(';') - df = astnodes.DefinedType(typename.val, newtype, typename.loc) + df = DefinedType(typename.val, newtype, typename.loc) self.addDeclaration(df) # Variable declarations: @@ -135,7 +143,7 @@ t = self.parseTypeSpec() def parseVar(): name = self.Consume('ID') - v = astnodes.Variable(name.val, t) + v = Variable(name.val, t) v.loc = name.loc if self.hasConsumed('='): v.ival = self.Expression() @@ -152,7 +160,7 @@ name = self.Consume('ID') self.Consume('=') val = self.Expression() - c = astnodes.Constant(name.val, t, val) + c = Constant(name.val, t, val) c.loc = name.loc parseConst() while self.hasConsumed(','): @@ -164,7 +172,7 @@ loc = self.Consume('function').loc returntype = self.parseTypeSpec() fname = self.Consume('ID').val - f = astnodes.Function(fname, loc) + f = Function(fname, loc) self.addDeclaration(f) savePart = self.currentPart self.currentPart = f @@ -174,7 +182,7 @@ def parseParameter(): typ = self.parseTypeSpec() name = self.Consume('ID') - param = astnodes.FormalParameter(name.val, typ) + param = FormalParameter(name.val, typ) param.loc = name.loc self.addDeclaration(param) parameters.append(param) @@ -183,7 +191,7 @@ parseParameter() self.Consume(')') paramtypes = [p.typ for p in parameters] - f.typ = astnodes.FunctionType(paramtypes, returntype) + f.typ = FunctionType(paramtypes, returntype) f.body = self.parseCompoundStatement() self.currentPart = savePart @@ -199,7 +207,7 @@ no = self.parseCompoundStatement() else: no = None - return astnodes.IfStatement(condition, yes, no, loc) + return IfStatement(condition, yes, no, loc) def parseWhileStatement(self): loc = self.Consume('while').loc @@ -207,16 +215,16 @@ condition = self.Expression() self.Consume(')') statements = self.parseCompoundStatement() - return astnodes.WhileStatement(condition, statements, loc) + return WhileStatement(condition, statements, loc) def parseReturnStatement(self): loc = self.Consume('return').loc if self.Peak == ';': - expr = astnodes.Literal(0, loc) + expr = Literal(0, loc) else: expr = self.Expression() self.Consume(';') - return astnodes.ReturnStatement(expr, loc) + return ReturnStatement(expr, loc) def parseCompoundStatement(self): self.Consume('{') @@ -226,7 +234,7 @@ if s is None: continue statements.append(s) - return astnodes.CompoundStatement(statements) + return CompoundStatement(statements) def Statement(self): # Determine statement type based on the pending token: @@ -251,9 +259,9 @@ # We enter assignment mode here. loc = self.Consume('=').loc rhs = self.Expression() - return astnodes.Assignment(x, rhs, loc) + return Assignment(x, rhs, loc) else: - return astnodes.ExpressionStatement(x, x.loc) + return ExpressionStatement(x, x.loc) # Expression section: # We not implement these C constructs: @@ -266,7 +274,7 @@ while self.Peak == 'or': loc = self.Consume('or').loc e2 = self.LogicalAndExpression() - exp = astnodes.Binop(exp, 'or', e2, loc) + exp = Binop(exp, 'or', e2, loc) return exp def LogicalAndExpression(self): @@ -274,7 +282,7 @@ while self.Peak == 'and': loc = self.Consume('and').loc o2 = self.EqualityExpression() - o = astnodes.Binop(o, 'and', o2, loc) + o = Binop(o, 'and', o2, loc) return o def EqualityExpression(self): @@ -282,7 +290,7 @@ while self.Peak in ['<', '==', '>']: op = self.Consume(self.Peak) ee2 = self.SimpleExpression() - ee = astnodes.Binop(ee, op.typ, ee2, op.loc) + ee = Binop(ee, op.typ, ee2, op.loc) return ee def SimpleExpression(self): @@ -291,7 +299,7 @@ while self.Peak in ['>>', '<<']: op = self.Consume(self.Peak) e2 = self.AddExpression() - e = astnodes.Binop(e, op.typ, e2, op.loc) + e = Binop(e, op.typ, e2, op.loc) return e def AddExpression(self): @@ -299,7 +307,7 @@ while self.Peak in ['+', '-']: op = self.Consume(self.Peak) e2 = self.Term() - e = astnodes.Binop(e, op.typ, e2, op.loc) + e = Binop(e, op.typ, e2, op.loc) return e def Term(self): @@ -307,7 +315,7 @@ while self.Peak in ['*', '/']: op = self.Consume(self.Peak) t2 = self.BitwiseOr() - t = astnodes.Binop(t, op.typ, t2, op.loc) + t = Binop(t, op.typ, t2, op.loc) return t def BitwiseOr(self): @@ -315,7 +323,7 @@ while self.Peak in ['|']: op = self.Consume(self.Peak) b = self.BitwiseAnd() - a = astnodes.Binop(a, op.typ, b, op.loc) + a = Binop(a, op.typ, b, op.loc) return a def BitwiseAnd(self): @@ -323,7 +331,7 @@ while self.Peak in ['&']: op = self.Consume(self.Peak) b = self.CastExpression() - a = astnodes.Binop(a, op.typ, b, op.loc) + a = Binop(a, op.typ, b, op.loc) return a # Domain of unary expressions: @@ -341,7 +349,7 @@ self.Consume('(') ce = self.Expression() self.Consume(')') - return astnodes.TypeCast(t, ce, loc) + return TypeCast(t, ce, loc) else: return self.UnaryExpression() @@ -350,9 +358,9 @@ op = self.Consume(self.Peak) ce = self.CastExpression() if op.val == '*': - return astnodes.Deref(ce, op.loc) + return Deref(ce, op.loc) else: - return astnodes.Unop(op.typ, ce, op.loc) + return Unop(op.typ, ce, op.loc) else: return self.PostFixExpression() @@ -369,14 +377,14 @@ while self.hasConsumed(','): args.append(self.Expression()) self.Consume(')') - pfe = astnodes.FunctionCall(pfe, args, pfe.loc) + pfe = FunctionCall(pfe, args, pfe.loc) elif self.hasConsumed('->'): field = self.Consume('ID') - pfe = astnodes.Deref(pfe, pfe.loc) - pfe = astnodes.FieldRef(pfe, field.val, field.loc) + pfe = Deref(pfe, pfe.loc) + pfe = FieldRef(pfe, field.val, field.loc) elif self.hasConsumed('.'): field = self.Consume('ID') - pfe = astnodes.FieldRef(pfe, field.val, field.loc) + pfe = FieldRef(pfe, field.val, field.loc) else: raise Exception() return pfe @@ -388,17 +396,17 @@ return e elif self.Peak == 'NUMBER': val = self.Consume('NUMBER') - return astnodes.Literal(val.val, val.loc) + return Literal(val.val, val.loc) elif self.Peak == 'REAL': val = self.Consume('REAL') - return astnodes.Literal(val.val, val.loc) + return Literal(val.val, val.loc) elif self.Peak == 'true': val = self.Consume('true') - return astnodes.Literal(True, val.loc) + return Literal(True, val.loc) elif self.Peak == 'false': val = self.Consume('false') - return astnodes.Literal(False, val.loc) + return Literal(False, val.loc) elif self.Peak == 'ID': d = self.parseDesignator() - return astnodes.VariableUse(d, d.loc) + return VariableUse(d, d.loc) self.Error('Expected NUM, ID or (expr), got {0}'.format(self.Peak)) diff -r 917eab04b8b7 -r 9417caea2eb3 python/canon.py --- a/python/canon.py Thu Nov 28 21:10:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -import ir -from itertools import chain - -def make(function, frame): - """ - Create canonicalized version of the IR-code. This means: - - Calls out of expressions. - - Other things? - """ - # Change the tree. This modifies the IR-tree! - # Move all parameters into registers - parmoves = [] - for p in function.arguments: - pt = newTemp() - frame.parMap[p] = pt - parmoves.append(ir.Move(pt, frame.argLoc(p.num))) - function.entry.instructions = parmoves + function.entry.instructions - - for block in function.Blocks: - for stmt in block.instructions: - rewriteStmt(stmt, frame) - linearize(block) - # TODO: schedule here? - -# Visit all nodes with some function: -# TODO: rewrite into visitor. - -# Rewrite rewrites call instructions into Eseq instructions. - -def rewriteStmt(stmt, frame): - if isinstance(stmt, ir.Jump): - pass - elif isinstance(stmt, ir.CJump): - stmt.a = rewriteExp(stmt.a, frame) - stmt.b = rewriteExp(stmt.b, frame) - elif isinstance(stmt, ir.Move): - stmt.src = rewriteExp(stmt.src, frame) - stmt.dst = rewriteExp(stmt.dst, frame) - elif isinstance(stmt, ir.Terminator): - pass - elif isinstance(stmt, ir.Exp): - stmt.e = rewriteExp(stmt.e, frame) - else: - raise NotImplementedError('STMT NI: {}'.format(stmt)) - -newTemp = ir.NamedClassGenerator('canon_reg', ir.Temp).gen - -def rewriteExp(exp, frame): - if isinstance(exp, ir.Binop): - exp.a = rewriteExp(exp.a, frame) - exp.b = rewriteExp(exp.b, frame) - return exp - elif isinstance(exp, ir.Const): - return exp - elif isinstance(exp, ir.Temp): - return exp - elif isinstance(exp, ir.Parameter): - return frame.parMap[exp] - elif isinstance(exp, ir.LocalVariable): - offset = frame.allocVar(exp) - return ir.Add(frame.fp, ir.Const(offset)) - elif isinstance(exp, ir.Mem): - exp.e = rewriteExp(exp.e, frame) - return exp - elif isinstance(exp, ir.Call): - exp.arguments = [rewriteExp(p, frame) for p in exp.arguments] - # Rewrite call into eseq: - t = newTemp() - return ir.Eseq(ir.Move(t, exp), t) - else: - raise NotImplementedError('NI: {}'.format(exp)) - -# The flatten functions pull out seq instructions to the sequence list. - -def flattenExp(exp): - if isinstance(exp, ir.Binop): - exp.a, sa = flattenExp(exp.a) - exp.b, sb = flattenExp(exp.b) - return exp, sa + sb - elif isinstance(exp, ir.Temp): - return exp, [] - elif isinstance(exp, ir.Const): - return exp, [] - elif isinstance(exp, ir.Mem): - exp.e, s = flattenExp(exp.e) - return exp, s - elif isinstance(exp, ir.Eseq): - s = flattenStmt(exp.stmt) - exp.e, se = flattenExp(exp.e) - return exp.e, s + se - elif isinstance(exp, ir.Call): - sp = [] - p = [] - for p_, sp_ in (flattenExp(p) for p in exp.arguments): - p.append(p_) - sp.extend(sp_) - exp.arguments = p - return exp, sp - else: - raise NotImplementedError('NI: {}'.format(exp)) - -def flattenStmt(stmt): - if isinstance(stmt, ir.Jump): - return [stmt] - elif isinstance(stmt, ir.CJump): - stmt.a, sa = flattenExp(stmt.a) - stmt.b, sb = flattenExp(stmt.b) - return sa + sb + [stmt] - elif isinstance(stmt, ir.Move): - stmt.dst, sd = flattenExp(stmt.dst) - stmt.src, ss = flattenExp(stmt.src) - return sd + ss + [stmt] - elif isinstance(stmt, ir.Terminator): - return [stmt] - elif isinstance(stmt, ir.Exp): - stmt.e, se = flattenExp(stmt.e) - return se + [stmt] - else: - raise NotImplementedError('STMT NI: {}'.format(stmt)) - - -def linearize(block): - """ - Move seq instructions to top and flatten these in an instruction list - """ - i = list(flattenStmt(s) for s in block.instructions) - block.instructions = list(chain.from_iterable(i)) - diff -r 917eab04b8b7 -r 9417caea2eb3 python/codegen.py --- a/python/codegen.py Thu Nov 28 21:10:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -import ir -from target import Target -from ppci import CompilerError -import transform -import canon -import registerallocator - - -class CodeGenerator: - """ Generic code generator """ - def __init__(self, target): - # TODO: schedule traces in better order. - # This is optional! - assert isinstance(target, Target), target - self.target = target - self.ins_sel = target.ins_sel - self.ra = registerallocator.RegisterAllocator() - - def generateFunc(self, irfunc, outs): - """ Generate code for one function into a frame """ - # Cleanup function: - transform.removeEmptyBlocks(irfunc) - - # Create a frame for this function: - frame = self.target.FrameClass(irfunc.name) - - # Canonicalize the intermediate language: - canon.make(irfunc, frame) - self.ins_sel.munchFunction(irfunc, frame) - - # Do register allocation: - self.ra.allocFrame(frame) - # TODO: Peep-hole here? - - # Add label and return and stack adjustment: - frame.EntryExitGlue3() - - # Materialize assembly - # Materialize the register allocated instructions into a stream of - # real instructions. - frame.lower_to(outs) - return frame - - def generate(self, ircode, outs): - assert isinstance(ircode, ir.Module) - outs.selectSection('code') - - # Munch program into a bunch of frames. One frame per function. - # Each frame has a flat list of abstract instructions. - # Generate code for all functions: - self.frames = [self.generateFunc(func, outs) for func in ircode.Functions] - return self.frames diff -r 917eab04b8b7 -r 9417caea2eb3 python/codegen/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/codegen/__init__.py Sun Dec 01 13:36:58 2013 +0100 @@ -0,0 +1,1 @@ +from .codegen import CodeGenerator diff -r 917eab04b8b7 -r 9417caea2eb3 python/codegen/canon.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/codegen/canon.py Sun Dec 01 13:36:58 2013 +0100 @@ -0,0 +1,128 @@ +import ir +from itertools import chain + +def make(function, frame): + """ + Create canonicalized version of the IR-code. This means: + - Calls out of expressions. + - Other things? + """ + # Change the tree. This modifies the IR-tree! + # Move all parameters into registers + parmoves = [] + for p in function.arguments: + pt = newTemp() + frame.parMap[p] = pt + parmoves.append(ir.Move(pt, frame.argLoc(p.num))) + function.entry.instructions = parmoves + function.entry.instructions + + for block in function.Blocks: + for stmt in block.instructions: + rewriteStmt(stmt, frame) + linearize(block) + # TODO: schedule here? + +# Visit all nodes with some function: +# TODO: rewrite into visitor. + +# Rewrite rewrites call instructions into Eseq instructions. + +def rewriteStmt(stmt, frame): + if isinstance(stmt, ir.Jump): + pass + elif isinstance(stmt, ir.CJump): + stmt.a = rewriteExp(stmt.a, frame) + stmt.b = rewriteExp(stmt.b, frame) + elif isinstance(stmt, ir.Move): + stmt.src = rewriteExp(stmt.src, frame) + stmt.dst = rewriteExp(stmt.dst, frame) + elif isinstance(stmt, ir.Terminator): + pass + elif isinstance(stmt, ir.Exp): + stmt.e = rewriteExp(stmt.e, frame) + else: + raise NotImplementedError('STMT NI: {}'.format(stmt)) + +newTemp = ir.NamedClassGenerator('canon_reg', ir.Temp).gen + +def rewriteExp(exp, frame): + if isinstance(exp, ir.Binop): + exp.a = rewriteExp(exp.a, frame) + exp.b = rewriteExp(exp.b, frame) + return exp + elif isinstance(exp, ir.Const): + return exp + elif isinstance(exp, ir.Temp): + return exp + elif isinstance(exp, ir.Parameter): + return frame.parMap[exp] + elif isinstance(exp, ir.LocalVariable): + offset = frame.allocVar(exp) + return ir.Add(frame.fp, ir.Const(offset)) + elif isinstance(exp, ir.Mem): + exp.e = rewriteExp(exp.e, frame) + return exp + elif isinstance(exp, ir.Call): + exp.arguments = [rewriteExp(p, frame) for p in exp.arguments] + # Rewrite call into eseq: + t = newTemp() + return ir.Eseq(ir.Move(t, exp), t) + else: + raise NotImplementedError('NI: {}'.format(exp)) + +# The flatten functions pull out seq instructions to the sequence list. + +def flattenExp(exp): + if isinstance(exp, ir.Binop): + exp.a, sa = flattenExp(exp.a) + exp.b, sb = flattenExp(exp.b) + return exp, sa + sb + elif isinstance(exp, ir.Temp): + return exp, [] + elif isinstance(exp, ir.Const): + return exp, [] + elif isinstance(exp, ir.Mem): + exp.e, s = flattenExp(exp.e) + return exp, s + elif isinstance(exp, ir.Eseq): + s = flattenStmt(exp.stmt) + exp.e, se = flattenExp(exp.e) + return exp.e, s + se + elif isinstance(exp, ir.Call): + sp = [] + p = [] + for p_, sp_ in (flattenExp(p) for p in exp.arguments): + p.append(p_) + sp.extend(sp_) + exp.arguments = p + return exp, sp + else: + raise NotImplementedError('NI: {}'.format(exp)) + +def flattenStmt(stmt): + if isinstance(stmt, ir.Jump): + return [stmt] + elif isinstance(stmt, ir.CJump): + stmt.a, sa = flattenExp(stmt.a) + stmt.b, sb = flattenExp(stmt.b) + return sa + sb + [stmt] + elif isinstance(stmt, ir.Move): + stmt.dst, sd = flattenExp(stmt.dst) + stmt.src, ss = flattenExp(stmt.src) + return sd + ss + [stmt] + elif isinstance(stmt, ir.Terminator): + return [stmt] + elif isinstance(stmt, ir.Exp): + stmt.e, se = flattenExp(stmt.e) + return se + [stmt] + else: + raise NotImplementedError('STMT NI: {}'.format(stmt)) + + +def linearize(block): + """ + Move seq instructions to top and flatten these in an instruction list + """ + i = list(flattenStmt(s) for s in block.instructions) + block.instructions = list(chain.from_iterable(i)) + diff -r 917eab04b8b7 -r 9417caea2eb3 python/codegen/codegen.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/codegen/codegen.py Sun Dec 01 13:36:58 2013 +0100 @@ -0,0 +1,48 @@ +import ir +from target import Target +from ppci import CompilerError +from .canon import make as canonicalize +from .registerallocator import RegisterAllocator + + +class CodeGenerator: + """ Generic code generator """ + def __init__(self, target): + # TODO: schedule traces in better order. + # This is optional! + assert isinstance(target, Target), target + self.target = target + self.ins_sel = target.ins_sel + self.ra = RegisterAllocator() + + def generateFunc(self, irfunc, outs): + """ Generate code for one function into a frame """ + # Create a frame for this function: + frame = self.target.FrameClass(irfunc.name) + + # Canonicalize the intermediate language: + canonicalize(irfunc, frame) + self.ins_sel.munchFunction(irfunc, frame) + + # Do register allocation: + self.ra.allocFrame(frame) + # TODO: Peep-hole here? + + # Add label and return and stack adjustment: + frame.EntryExitGlue3() + + # Materialize the register allocated instructions into a stream of + # real instructions. + frame.lower_to(outs) + return frame + + def generate(self, ircode, outs): + """ Generate code into output stream """ + assert isinstance(ircode, ir.Module) + outs.selectSection('code') + + # Munch program into a bunch of frames. One frame per function. + # Each frame has a flat list of abstract instructions. + # Generate code for all functions: + self.frames = [self.generateFunc(f, outs) for f in ircode.Functions] + return self.frames diff -r 917eab04b8b7 -r 9417caea2eb3 python/codegen/dag.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/codegen/dag.py Sun Dec 01 13:36:58 2013 +0100 @@ -0,0 +1,59 @@ + +# Instruction selection with DAG (Directed Acyclic Graph) +class DagLeaf: + def __init__(self, v): + self.v = v + +class DagNode: + def __init__(self, name): + self.name = name + self.children = [] + def __repr__(self): + return str(self.name) + +class Dag: + def __init__(self, bb): + self.mapping = {} + self.buildFromBB(bb) + + def buildFromBB(self, bb): + for ins in bb.Instructions: + if type(ins) is ir.BinaryOperator: + if not ins.value1 in self.mapping: + self.mapping[ins.value1] = DagNode(ins.value1) + if not ins.value2 in self.mapping: + self.mapping[ins.value2] = DagNode(ins.value2) + # look for op with left and right operand the same: + N = None + lnode = self.mapping[ins.value1] + rnode = self.mapping[ins.value2] + for node in self.mapping.values(): + if node.name == ins.operation: + if node.children[0] == lnode and node.children[1] == rnode: + N = node + break + if not N: + # Create a node. + N = DagNode(ins.operation) + N.children.append(lnode) + N.children.append(rnode) + self.mapping[ins.result] = N + else: + pass + + def dumpgv(self, outf): + outf.write('subgraph {0} {{\n'.format(id(self))) + for node in self.mapping.values(): + outf.write('{0} [label="{1}"];\n'.format(id(node), node.name)) + for c in node.children: + outf.write('{0} -> {1};\n'.format(id(node), id(c))) + outf.write('label="dag"}\n') + +def insSelect(mod): + """ Create DAG from ir-code """ + for bb in mod.BasicBlocks: + print(bb) + dag = Dag(bb) + print(dag.mapping) + bb.dag = dag + diff -r 917eab04b8b7 -r 9417caea2eb3 python/codegen/flowgraph.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/codegen/flowgraph.py Sun Dec 01 13:36:58 2013 +0100 @@ -0,0 +1,46 @@ +from .graph import DiGraph, DiNode + + +class FlowGraphNode(DiNode): + """ A node in the flow graph """ + def __init__(self, g, ins): + super().__init__(g) + self.ins = ins + self.uses = set(ins.src) + self.defs = set(ins.dst) + self.live_in = set() + self.live_out = set() + + def __repr__(self): + r = '{}'.format(self.ins) + if self.uses: + r += ' uses:' + ', '.join(str(u) for u in self.uses) + if self.defs: + r += ' defs:' + ', '.join(str(d) for d in self.defs) + return r + + +class FlowGraph(DiGraph): + def __init__(self, instrs): + """ Create a flowgraph from a list of abstract instructions """ + super().__init__() + self._map = {} + # Add nodes: + for ins in instrs: + n = FlowGraphNode(self, ins) + self._map[ins] = n + self.addNode(n) + + # Make edges: + prev = None + for ins in instrs: + n = self._map[ins] + if prev: + self.addEdge(prev, n) + if ins.jumps: + prev = None + for j in ins.jumps: + to_n = self._map[j] + self.addEdge(n, to_n) + else: + prev = n diff -r 917eab04b8b7 -r 9417caea2eb3 python/codegen/graph.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/codegen/graph.py Sun Dec 01 13:36:58 2013 +0100 @@ -0,0 +1,84 @@ + +class Graph: + """ + Generic graph base class. + Can dump to graphiz dot format for example! + """ + def __init__(self): + self.nodes = set() + self.edges = set() + + def addNode(self, n): + self.nodes.add(n) + + def delNode(self, n): + self.nodes.remove(n) + + def addEdge(self, n, m): + """ Add an edge from n to m """ + self.edges.add((n, m)) + self.edges.add((m, n)) + + def hasEdge(self, n, m): + return (n, m) in self.edges + + def delEdge(self, n, m): + self.edges.remove((n, m)) + self.edges.remove((m, n)) + + def adjecent(self, n): + """ Return all nodes with edges to n """ + # TODO: this can be optimized for speed: + return set(m for m in self.nodes if self.hasEdge(n, m)) + + def to_dot(self, f): + """ Generate graphviz dot representation """ + for n in self.nodes: + print('{} [label="{}" shape=box3d];'.format(id(n), n), file=f) + for n, m in self.edges: + print('{} -> {};'.format(id(n), id(m)), file=f) + + +class Node: + """ + Node in a graph. + """ + def __init__(self, g): + self.g = g + self.addDegree = 0 # Hack to increase degree + + @property + def Adjecent(self): + return self.g.adjecent(self) + + @property + def Degree(self): + return len(self.Adjecent) + self.addDegree + + +class DiGraph(Graph): + """ + Directed graph. + """ + def addEdge(self, n, m): + """ Add an edge from n to m """ + self.edges.add((n, m)) + + def hasEdge(self, n, m): + return (n, m) in self.edges + + def successors(self, n): + return set(m for m in self.nodes if self.hasEdge(n, m)) + + def predecessors(self, n): + return set(m for m in self.nodes if self.hasEdge(m, n)) + + +class DiNode(Node): + @property + def Succ(self): + return self.g.successors(self) + + @property + def Pred(self): + return self.g.predecessors(self) diff -r 917eab04b8b7 -r 9417caea2eb3 python/codegen/interferencegraph.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/codegen/interferencegraph.py Sun Dec 01 13:36:58 2013 +0100 @@ -0,0 +1,89 @@ +from .graph import Graph, Node + + +class InterferenceGraphNode(Node): + def __init__(self, g, varname): + super().__init__(g) + self.temps = [varname] + self.moves = set() + self.color = None + + def __repr__(self): + return '{}({})'.format(self.temps, self.color) + + +class InterferenceGraph(Graph): + """ + Interference graph. + """ + def __init__(self, flowgraph): + """ Create a new interference graph from a flowgraph """ + super().__init__() + # Calculate liveness in CFG: + ### + # Liveness: + # in[n] = use[n] UNION (out[n] - def[n]) + # out[n] = for s in n.succ in union in[s] + ### + for n in flowgraph.nodes: + n.live_in = set() + n.live_out = set() + + # Dataflow fixed point iteration: + change = True + while change: + change = False + for n in flowgraph.nodes: + _in = n.live_in + _out = n.live_out + n.live_in = n.uses | (n.live_out - n.defs) + if n.Succ: + n.live_out = set.union(*(s.live_in for s in n.Succ)) + else: + n.live_out = set() + change = change or (_in != n.live_in) or (_out != n.live_out) + + # Construct interference graph: + for n in flowgraph.nodes: + for tmp in n.live_out: + n1 = self.getNode(tmp) + for tmp2 in (n.live_out - {tmp}): + n2 = self.getNode(tmp2) + self.addEdge(n1, n2) + + def to_dot(self, f): + """ Generate graphviz dot representation """ + for n in self.nodes: + print('{} [label="{}" shape=box3d];'.format(id(n), n), file=f) + for n, m in self.edges: + print('{} -> {};'.format(id(n), id(m)), file=f) + + def to_txt(self): + for node in self.nodes: + print('{} interferes: {}'.format(node, node.Adjecent)) + + def getNode(self, tmp): + # Linear search + # TODO: can be improved for speed! + for n in self.nodes: + if tmp in n.temps: + return n + n = InterferenceGraphNode(self, tmp) + self.addNode(n) + return n + + def Combine(self, n, m): + """ Combine n and m into n """ + n.temps.extend(m.temps) + n.moves.update(m.moves) + # Reroute all edges: + e1 = [e for e in self.edges if e[0] is m] + e2 = [e for e in self.edges if e[1] is m] + for e in e1: + self.edges.remove(e) + self.addEdge(n, e[1]) + for e in e2: + self.edges.remove(e) + self.addEdge(n, e[0]) + # Remove node m: + self.delNode(m) diff -r 917eab04b8b7 -r 9417caea2eb3 python/codegen/registerallocator.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/codegen/registerallocator.py Sun Dec 01 13:36:58 2013 +0100 @@ -0,0 +1,200 @@ +from .flowgraph import FlowGraph +from .interferencegraph import InterferenceGraph + +# Nifty first function: +first = lambda x: next(iter(x)) + +class RegisterAllocator: + """ + Target independent register allocator. + + Algorithm is iterated register coalescing by Appel and George. + + Chaitin's algorithm: remove all nodes with less than K neighbours. + These nodes can be colored when added back. + + The process consists of the following steps: + - build interference graph from the instruction list + - remove low degree non move related nodes. + - (optional) coalesc registers to remove redundant moves + - (optional) spill registers + - select registers + """ + + def InitData(self, f): + self.f = f + # Register information: + self.regs = set(f.regs) + self.K = len(self.regs) + + # Move related sets: + self.coalescedMoves = set() + self.constrainedMoves = set() + self.frozenMoves = set() + self.activeMoves = set() + self.worklistMoves = set() + + def printLive(self): + print('Liveness:') + for i in self.f.instructions: + cfgn = self.f.cfg._map[i] + print(i, cfgn.live_in) + + def Build(self): + """ 1. Construct interference graph from instruction list """ + self.f.cfg = FlowGraph(self.f.instructions) + self.f.ig = InterferenceGraph(self.f.cfg) + + self.Node = self.f.ig.getNode + + # Divide nodes into pre-colored and initial: + pre_tmp = list(self.f.tempMap.keys()) + self.precolored = set(self.Node(tmp) for tmp in pre_tmp) + self.workSet = set(self.f.ig.nodes - self.precolored) + + for n in self.precolored: + n.addDegree = 100 + len(self.f.ig.nodes) + self.K + + # Initialize color map: + self.color = {} + for tmp, c in self.f.tempMap.items(): + self.color[self.Node(tmp)] = c + + self.moves = [i for i in self.f.instructions if i.ismove] + for mv in self.moves: + self.Node(mv.src[0]).moves.add(mv) + self.Node(mv.dst[0]).moves.add(mv) + + def NodeMoves(self, n): + return n.moves & (self.activeMoves | self.worklistMoves) + + def MoveRelated(self, n): + return bool(self.NodeMoves(n)) + + @property + def SpillWorkSet(self): + c = lambda n: n.Degree >= self.K + return set(filter(c, self.workSet)) + + @property + def FreezeWorkSet(self): + c = lambda n: n.Degree < self.K and self.MoveRelated(n) + return set(filter(c, self.workSet)) + + @property + def SimplifyWorkSet(self): + c = lambda n: n.Degree < self.K and not self.MoveRelated(n) + return set(filter(c, self.workSet)) + + def makeWorkList(self): + """ Divide initial nodes into worklists """ + self.selectStack = [] + + # Fill initial move set: + for m in self.moves: + self.worklistMoves.add(m) + + def Simplify(self): + """ 2. Remove nodes from the graph """ + n = first(self.SimplifyWorkSet) + self.workSet.remove(n) + self.selectStack.append(n) + # Pop out of graph: + self.f.ig.delNode(n) + + def EnableMoves(self, nodes): + for n in nodes: + for m in self.NodeMoves(n): + if m in self.activeMoves: + self.activeMoves.remove(m) + self.worklistMoves.add(m) + + def Coalesc(self): + """ Coalesc conservative. """ + m = first(self.worklistMoves) + x = self.Node(m.dst[0]) + y = self.Node(m.src[0]) + u, v = (y, x) if y in self.precolored else (x, y) + self.worklistMoves.remove(m) + if u is v: + self.coalescedMoves.add(m) + elif v in self.precolored or self.f.ig.hasEdge(u, v): + self.constrainedMoves.add(m) + elif u not in self.precolored and self.Conservative(u, v): + self.coalescedMoves.add(m) + self.workSet.remove(v) + self.f.ig.Combine(u, v) + else: + self.activeMoves.add(m) + + def Conservative(self, u, v): + """ Briggs conservative criteria for coalesc """ + nodes = u.Adjecent | v.Adjecent + c = lambda n: n.Degree >= self.K + k = len(list(filter(c, nodes))) + return k < self.K + + def Freeze(self): + """ Give up coalescing on some node """ + u = first(self.FreezeWorkSet) + self.freezeMoves(u) + + def freezeMoves(self, u): + """ Freeze moves for node u """ + for m in self.NodeMoves(u): + if m in self.activeMoves: + self.activeMoves.remove(m) + else: + sekf.worklistMoves.remove(m) + self.frozenMoves.add(m) + # Check other part of the move for still being move related: + v = m.src[0] if u is m.dst[0] else m.dst[0] + + def SelectSpill(self): + # TODO + pass + + def AssignColors(self): + """ Add nodes back to the graph to color it. """ + # Add nodes back to the graph: + while self.selectStack: + n = self.selectStack.pop(-1) + self.f.ig.addNode(n) + takenregs = set(self.color[m] for m in n.Adjecent) + okColors = self.regs - takenregs + if okColors: + self.color[n] = first(okColors) + n.color = self.color[n] + else: + raise NotImplementedError('Spill required here!') + + def ApplyColors(self): + # Remove coalesced moves: + for mv in self.coalescedMoves: + self.f.instructions.remove(mv) + + # Use allocated registers: + lookup = lambda t: self.color[self.Node(t)] + for i in self.f.instructions: + i.src = tuple(map(lookup, i.src)) + i.dst = tuple(map(lookup, i.dst)) + + def allocFrame(self, f): + """ Do iterated register allocation for a single stack frame. """ + self.InitData(f) + self.Build() + self.makeWorkList() + while True: + if self.SimplifyWorkSet: + self.Simplify() + elif self.worklistMoves: + self.Coalesc() + elif self.FreezeWorkSet: + self.Freeze() + elif self.SpillWorkSet: + raise NotImplementedError('Spill not implemented') + else: + break # Done! + self.AssignColors() + self.ApplyColors() + diff -r 917eab04b8b7 -r 9417caea2eb3 python/dag.py --- a/python/dag.py Thu Nov 28 21:10:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ - -# Instruction selection with DAG (Directed Acyclic Graph) -class DagLeaf: - def __init__(self, v): - self.v = v - -class DagNode: - def __init__(self, name): - self.name = name - self.children = [] - def __repr__(self): - return str(self.name) - -class Dag: - def __init__(self, bb): - self.mapping = {} - self.buildFromBB(bb) - - def buildFromBB(self, bb): - for ins in bb.Instructions: - if type(ins) is ir.BinaryOperator: - if not ins.value1 in self.mapping: - self.mapping[ins.value1] = DagNode(ins.value1) - if not ins.value2 in self.mapping: - self.mapping[ins.value2] = DagNode(ins.value2) - # look for op with left and right operand the same: - N = None - lnode = self.mapping[ins.value1] - rnode = self.mapping[ins.value2] - for node in self.mapping.values(): - if node.name == ins.operation: - if node.children[0] == lnode and node.children[1] == rnode: - N = node - break - if not N: - # Create a node. - N = DagNode(ins.operation) - N.children.append(lnode) - N.children.append(rnode) - self.mapping[ins.result] = N - else: - pass - - def dumpgv(self, outf): - outf.write('subgraph {0} {{\n'.format(id(self))) - for node in self.mapping.values(): - outf.write('{0} [label="{1}"];\n'.format(id(node), node.name)) - for c in node.children: - outf.write('{0} -> {1};\n'.format(id(node), id(c))) - outf.write('label="dag"}\n') - -def insSelect(mod): - """ Create DAG from ir-code """ - for bb in mod.BasicBlocks: - print(bb) - dag = Dag(bb) - print(dag.mapping) - bb.dag = dag - diff -r 917eab04b8b7 -r 9417caea2eb3 python/flowgraph.py --- a/python/flowgraph.py Thu Nov 28 21:10:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -import graph - - -class FlowGraphNode(graph.DiNode): - """ A node in the flow graph """ - def __init__(self, g, ins): - super().__init__(g) - self.ins = ins - self.uses = set(ins.src) - self.defs = set(ins.dst) - self.live_in = set() - self.live_out = set() - - def __repr__(self): - r = '{}'.format(self.ins) - if self.uses: - r += ' uses:' + ', '.join(str(u) for u in self.uses) - if self.defs: - r += ' defs:' + ', '.join(str(d) for d in self.defs) - return r - - -class FlowGraph(graph.DiGraph): - def __init__(self, instrs): - """ Create a flowgraph from a list of abstract instructions """ - super().__init__() - self._map = {} - # Add nodes: - for ins in instrs: - n = FlowGraphNode(self, ins) - self._map[ins] = n - self.addNode(n) - - # Make edges: - prev = None - for ins in instrs: - n = self._map[ins] - if prev: - self.addEdge(prev, n) - if ins.jumps: - prev = None - for j in ins.jumps: - to_n = self._map[j] - self.addEdge(n, to_n) - else: - prev = n - - diff -r 917eab04b8b7 -r 9417caea2eb3 python/graph.py --- a/python/graph.py Thu Nov 28 21:10:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ - -class Graph: - """ - Generic graph base class. - Can dump to graphiz dot format for example! - """ - def __init__(self): - self.nodes = set() - self.edges = set() - - def addNode(self, n): - self.nodes.add(n) - - def delNode(self, n): - self.nodes.remove(n) - - def addEdge(self, n, m): - """ Add an edge from n to m """ - self.edges.add((n, m)) - self.edges.add((m, n)) - - def hasEdge(self, n, m): - return (n, m) in self.edges - - def delEdge(self, n, m): - self.edges.remove((n, m)) - self.edges.remove((m, n)) - - def adjecent(self, n): - """ Return all nodes with edges to n """ - # TODO: this can be optimized for speed: - return set(m for m in self.nodes if self.hasEdge(n, m)) - - def to_dot(self, f): - """ Generate graphviz dot representation """ - for node in self.nodes: - print('{} [label="{}" shape=box3d];'.format(id(node), node), file=f) - for n, m in self.edges: - print('{} -> {};'.format(id(n), id(m)), file=f) - - -class Node: - """ - Node in a graph. - """ - def __init__(self, g): - self.g = g - self.addDegree = 0 # Hack to increase degree - - @property - def Adjecent(self): - return self.g.adjecent(self) - - @property - def Degree(self): - return len(self.Adjecent) + self.addDegree - - -class DiGraph(Graph): - """ - Directed graph. - """ - def addEdge(self, n, m): - """ Add an edge from n to m """ - self.edges.add((n, m)) - - def hasEdge(self, n, m): - return (n, m) in self.edges - - def successors(self, n): - return set(m for m in self.nodes if self.hasEdge(n, m)) - - def predecessors(self, n): - return set(m for m in self.nodes if self.hasEdge(m, n)) - - -class DiNode(Node): - @property - def Succ(self): - return self.g.successors(self) - - @property - def Pred(self): - return self.g.predecessors(self) - diff -r 917eab04b8b7 -r 9417caea2eb3 python/interferencegraph.py --- a/python/interferencegraph.py Thu Nov 28 21:10:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -import graph - - -class InterferenceGraphNode(graph.Node): - def __init__(self, g, varname): - super().__init__(g) - self.temps = [varname] - self.moves = set() - self.color = None - - def __repr__(self): - return '{}({})'.format(self.temps, self.color) - - -class InterferenceGraph(graph.Graph): - """ - Interference graph. - """ - def __init__(self, flowgraph): - """ - Create a new interference graph from a flowgraph - """ - super().__init__() - # Calculate liveness in CFG: - ### - # Liveness: - # in[n] = use[n] UNION (out[n] - def[n]) - # out[n] = for s in n.succ in union in[s] - ### - for n in flowgraph.nodes: - n.live_in = set() - n.live_out = set() - - # Dataflow fixed point iteration: - change = True - while change: - change = False - for n in flowgraph.nodes: - _in = n.live_in - _out = n.live_out - n.live_in = n.uses | (n.live_out - n.defs) - if n.Succ: - n.live_out = set.union(*(s.live_in for s in n.Succ)) - else: - n.live_out = set() - change = change or (_in != n.live_in) or (_out != n.live_out) - - # Construct interference graph: - for n in flowgraph.nodes: - for tmp in n.live_out: - n1 = self.getNode(tmp) - for tmp2 in (n.live_out - {tmp}): - n2 = self.getNode(tmp2) - self.addEdge(n1, n2) - - def to_dot(self, f): - """ Generate graphviz dot representation """ - for node in self.nodes: - print('{} [label="{}" shape=box3d];'.format(id(node), node), file=f) - for n, m in self.edges: - print('{} -> {};'.format(id(n), id(m)), file=f) - - def to_txt(self): - for node in self.nodes: - print('{} interferes: {}'.format(node, node.Adjecent)) - - def getNode(self, tmp): - # Linear search - # TODO: can be improved for speed! - for n in self.nodes: - if tmp in n.temps: - return n - n = InterferenceGraphNode(self, tmp) - self.addNode(n) - return n - - def Combine(self, n, m): - """ Combine n and m into n """ - n.temps.extend(m.temps) - n.moves.update(m.moves) - # Reroute all edges: - e1 = [e for e in self.edges if e[0] is m] - e2 = [e for e in self.edges if e[1] is m] - for e in e1: - self.edges.remove(e) - self.addEdge(n, e[1]) - for e in e2: - self.edges.remove(e) - self.addEdge(n, e[0]) - # Remove node m: - self.delNode(m) - diff -r 917eab04b8b7 -r 9417caea2eb3 python/mem2reg.py --- a/python/mem2reg.py Thu Nov 28 21:10:32 2013 +0100 +++ b/python/mem2reg.py Sun Dec 01 13:36:58 2013 +0100 @@ -68,4 +68,3 @@ for i in allocs: if isAllocPromotable(i): self.promote(i) - diff -r 917eab04b8b7 -r 9417caea2eb3 python/outstream.py --- a/python/outstream.py Thu Nov 28 21:10:32 2013 +0100 +++ b/python/outstream.py Sun Dec 01 13:36:58 2013 +0100 @@ -90,9 +90,11 @@ else: print(' 0x{0:08x} 0x{1} {2}'.format(addr, insword, asm)) + class TextOutputStream(OutputStream): pass + class BinOutputStream(OutputStream): @property @@ -105,5 +107,3 @@ self.backpatch() section = self.sections[list(self.sections.keys())[0]] return section.to_bytes() - - diff -r 917eab04b8b7 -r 9417caea2eb3 python/ppci/errors.py --- a/python/ppci/errors.py Thu Nov 28 21:10:32 2013 +0100 +++ b/python/ppci/errors.py Sun Dec 01 13:36:58 2013 +0100 @@ -6,6 +6,7 @@ import logging from . import SourceLocation + class CompilerError(Exception): def __init__(self, msg, loc=None): self.msg = msg @@ -33,7 +34,7 @@ self.sources[name] = src def addDiag(self, d): - self.logger.warning(str(d.msg)) + #self.logger.warning(str(d.msg)) self.diags.append(d) def error(self, msg, loc): diff -r 917eab04b8b7 -r 9417caea2eb3 python/registerallocator.py --- a/python/registerallocator.py Thu Nov 28 21:10:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -from flowgraph import FlowGraph -from interferencegraph import InterferenceGraph - -# Nifty first function: -first = lambda x: next(iter(x)) - -class RegisterAllocator: - """ - Target independent register allocator. - - Algorithm is iterated register coalescing by Appel and George. - - Chaitin's algorithm: remove all nodes with less than K neighbours. - These nodes can be colored when added back. - - The process consists of the following steps: - - build interference graph from the instruction list - - remove low degree non move related nodes. - - (optional) coalesc registers to remove redundant moves - - (optional) spill registers - - select registers - """ - - def InitData(self, f): - self.f = f - # Register information: - self.regs = set(f.regs) - self.K = len(self.regs) - - # Move related sets: - self.coalescedMoves = set() - self.constrainedMoves = set() - self.frozenMoves = set() - self.activeMoves = set() - self.worklistMoves = set() - - def printLive(self): - print('Liveness:') - for i in self.f.instructions: - cfgn = self.f.cfg._map[i] - print(i, cfgn.live_in) - - def Build(self): - """ 1. Construct interference graph from instruction list """ - self.f.cfg = FlowGraph(self.f.instructions) - self.f.ig = InterferenceGraph(self.f.cfg) - - self.Node = self.f.ig.getNode - - # Divide nodes into pre-colored and initial: - pre_tmp = list(self.f.tempMap.keys()) - self.precolored = set(self.Node(tmp) for tmp in pre_tmp) - self.workSet = set(self.f.ig.nodes - self.precolored) - - for n in self.precolored: - n.addDegree = 100 + len(self.f.ig.nodes) + self.K - - # Initialize color map: - self.color = {} - for tmp, c in self.f.tempMap.items(): - self.color[self.Node(tmp)] = c - - self.moves = [i for i in self.f.instructions if i.ismove] - for mv in self.moves: - self.Node(mv.src[0]).moves.add(mv) - self.Node(mv.dst[0]).moves.add(mv) - - def NodeMoves(self, n): - return n.moves & (self.activeMoves | self.worklistMoves) - - def MoveRelated(self, n): - return bool(self.NodeMoves(n)) - - @property - def SpillWorkSet(self): - c = lambda n: n.Degree >= self.K - return set(filter(c, self.workSet)) - - @property - def FreezeWorkSet(self): - c = lambda n: n.Degree < self.K and self.MoveRelated(n) - return set(filter(c, self.workSet)) - - @property - def SimplifyWorkSet(self): - c = lambda n: n.Degree < self.K and not self.MoveRelated(n) - return set(filter(c, self.workSet)) - - def makeWorkList(self): - """ Divide initial nodes into worklists """ - self.selectStack = [] - - # Fill initial move set: - for m in self.moves: - self.worklistMoves.add(m) - - def Simplify(self): - """ 2. Remove nodes from the graph """ - n = first(self.SimplifyWorkSet) - self.workSet.remove(n) - self.selectStack.append(n) - # Pop out of graph: - self.f.ig.delNode(n) - - def EnableMoves(self, nodes): - for n in nodes: - for m in self.NodeMoves(n): - if m in self.activeMoves: - self.activeMoves.remove(m) - self.worklistMoves.add(m) - - def Coalesc(self): - """ Coalesc conservative. """ - m = first(self.worklistMoves) - x = self.Node(m.dst[0]) - y = self.Node(m.src[0]) - u, v = (y, x) if y in self.precolored else (x, y) - self.worklistMoves.remove(m) - if u is v: - self.coalescedMoves.add(m) - elif v in self.precolored or self.f.ig.hasEdge(u, v): - self.constrainedMoves.add(m) - elif u not in self.precolored and self.Conservative(u, v): - self.coalescedMoves.add(m) - self.workSet.remove(v) - self.f.ig.Combine(u, v) - else: - self.activeMoves.add(m) - - def Conservative(self, u, v): - """ Briggs conservative criteria for coalesc """ - nodes = u.Adjecent | v.Adjecent - c = lambda n: n.Degree >= self.K - k = len(list(filter(c, nodes))) - return k < self.K - - def Freeze(self): - """ Give up coalescing on some node """ - u = first(self.FreezeWorkSet) - self.freezeMoves(u) - - def freezeMoves(self, u): - """ Freeze moves for node u """ - for m in self.NodeMoves(u): - if m in self.activeMoves: - self.activeMoves.remove(m) - else: - sekf.worklistMoves.remove(m) - self.frozenMoves.add(m) - # Check other part of the move for still being move related: - v = m.src[0] if u is m.dst[0] else m.dst[0] - - def SelectSpill(self): - # TODO - pass - - def AssignColors(self): - """ Add nodes back to the graph to color it. """ - # Add nodes back to the graph: - while self.selectStack: - n = self.selectStack.pop(-1) - self.f.ig.addNode(n) - takenregs = set(self.color[m] for m in n.Adjecent) - okColors = self.regs - takenregs - if okColors: - self.color[n] = first(okColors) - n.color = self.color[n] - else: - raise NotImplementedError('Spill required here!') - - def ApplyColors(self): - # Remove coalesced moves: - for mv in self.coalescedMoves: - self.f.instructions.remove(mv) - - # Use allocated registers: - lookup = lambda t: self.color[self.Node(t)] - for i in self.f.instructions: - i.src = tuple(map(lookup, i.src)) - i.dst = tuple(map(lookup, i.dst)) - - def allocFrame(self, f): - """ Do iterated register allocation for a single stack frame. """ - self.InitData(f) - self.Build() - self.makeWorkList() - while True: - if self.SimplifyWorkSet: - self.Simplify() - elif self.worklistMoves: - self.Coalesc() - elif self.FreezeWorkSet: - self.Freeze() - elif self.SpillWorkSet: - raise NotImplementedError('Spill not implemented') - else: - break # Done! - self.AssignColors() - self.ApplyColors() - diff -r 917eab04b8b7 -r 9417caea2eb3 python/transform.py --- a/python/transform.py Thu Nov 28 21:10:32 2013 +0100 +++ b/python/transform.py Sun Dec 01 13:36:58 2013 +0100 @@ -140,6 +140,3 @@ pred.LastInstruction.changeTarget(b, tgt) logging.debug('Removing empty block: {}'.format(b)) f.removeBlock(b) - - - diff -r 917eab04b8b7 -r 9417caea2eb3 python/zcc.py --- a/python/zcc.py Thu Nov 28 21:10:32 2013 +0100 +++ b/python/zcc.py Sun Dec 01 13:36:58 2013 +0100 @@ -32,7 +32,7 @@ parser.add_argument('source', type=argparse.FileType('r'), \ help='the source file to build', nargs="+") parser.add_argument('-i', '--imp', type=argparse.FileType('r'), \ - help='Possible import module', action='append') + help='Possible import module', action='append', default=[]) parser.add_argument('--dumpir', action='store_true', help="Dump IR-code") parser.add_argument('--dumpasm', action='store_true', help="Dump ASM-code") @@ -80,15 +80,11 @@ def main(args): logging.basicConfig(format=logformat, level=args.log) - src = args.source - imps = args.imp - if not imps: - imps = [] tg = targets[args.target] diag = ppci.DiagnosticsManager() outs = outstream.TextOutputStream() - res = zcc(src, imps, tg, outs, diag, dumpir=args.dumpir) + res = zcc(args.source, args.imp, tg, outs, diag, dumpir=args.dumpir) if not res: diag.printErrors() return 1 diff -r 917eab04b8b7 -r 9417caea2eb3 test/runtests.sh --- a/test/runtests.sh Thu Nov 28 21:10:32 2013 +0100 +++ b/test/runtests.sh Sun Dec 01 13:36:58 2013 +0100 @@ -5,7 +5,7 @@ if [ $1 == "loop" ]; then DIR=.. while :; do - python -m unittest -v + python -m unittest cd gui #python -m unittest -v cd .. diff -r 917eab04b8b7 -r 9417caea2eb3 test/testgraph.py --- a/test/testgraph.py Thu Nov 28 21:10:32 2013 +0100 +++ b/test/testgraph.py Sun Dec 01 13:36:58 2013 +0100 @@ -1,9 +1,9 @@ #!/usr/bin/python import unittest -import graph -import interferencegraph -import flowgraph +from codegen.graph import Graph, Node +from codegen.interferencegraph import InterferenceGraph +from codegen.flowgraph import FlowGraph import ir from irmach import AbstractInstruction as AI from target import Nop @@ -11,10 +11,10 @@ class GraphTestCase(unittest.TestCase): def testEdge(self): - g = graph.Graph() - n1 = graph.Node(g) + g = Graph() + n1 = Node(g) g.addNode(n1) - n2 = graph.Node(g) + n2 = Node(g) g.addNode(n2) g.addEdge(n1, n2) self.assertTrue(g.hasEdge(n2, n1)) @@ -23,12 +23,12 @@ g.delNode(n2) def testDegree(self): - g = graph.Graph() - n1 = graph.Node(g) + g = Graph() + n1 = Node(g) g.addNode(n1) - n2 = graph.Node(g) + n2 = Node(g) g.addNode(n2) - n3 = graph.Node(g) + n3 = Node(g) g.addNode(n3) g.addEdge(n1, n2) g.addEdge(n1, n3) @@ -54,8 +54,8 @@ instrs.append(AI(Nop, dst=[t1])) instrs.append(AI(Nop, dst=[t2])) instrs.append(AI(Nop, dst=[t3])) - cfg = flowgraph.FlowGraph(instrs) - ig = interferencegraph.InterferenceGraph(cfg) + cfg = FlowGraph(instrs) + ig = InterferenceGraph(cfg) def testCombine(self): t1 = ir.Temp('t1') @@ -70,8 +70,8 @@ instrs.append(AI(Nop, src=[t4])) instrs.append(AI(Nop, src=[t1])) instrs.append(AI(Nop, src=[t2])) - cfg = flowgraph.FlowGraph(instrs) - ig = interferencegraph.InterferenceGraph(cfg) + cfg = FlowGraph(instrs) + ig = InterferenceGraph(cfg) ig.Combine(ig.getNode(t4), ig.getNode(t3)) self.assertIs(ig.getNode(t4), ig.getNode(t3)) diff -r 917eab04b8b7 -r 9417caea2eb3 test/testregalloc.py --- a/test/testregalloc.py Thu Nov 28 21:10:32 2013 +0100 +++ b/test/testregalloc.py Sun Dec 01 13:36:58 2013 +0100 @@ -2,14 +2,14 @@ import os import sys from irmach import AbstractInstruction as makeIns, Frame -import registerallocator +from codegen.registerallocator import RegisterAllocator import ir from target import Nop class RegAllocTestCase(unittest.TestCase): def setUp(self): - self.ra = registerallocator.RegisterAllocator() + self.ra = RegisterAllocator() def testRegAlloc(self): f = Frame('tst')