# HG changeset patch # User Windel Bouwman # Date 1377964734 -7200 # Node ID e64bae57cda889b4b4294e07f04b8feb4a8f7e66 # Parent cf7d5fb7d9c8cfea836b111f24730cdb63bab012 refactor ir diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/c3/analyse.py --- a/python/c3/analyse.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/c3/analyse.py Sat Aug 31 17:58:54 2013 +0200 @@ -110,7 +110,7 @@ raise Exception('Error resolving type {} {}'.format(t, type(t))) def findRefs(self, sym): - if type(sym) in [Variable, Constant]: + if type(sym) in [Constant] or isinstance(sym, Variable): sym.typ = self.resolveType(sym.typ, sym.scope) elif type(sym) is TypeCast: sym.to_type = self.resolveType(sym.to_type, sym.scope) diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/c3/astnodes.py --- a/python/c3/astnodes.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/c3/astnodes.py Sat Aug 31 17:58:54 2013 +0200 @@ -42,14 +42,17 @@ """ class Type(Node): - def isType(self, b): - return isType(self, b) + def isType(self, b): + return isType(self, b) + class BaseType(Type): - def __init__(self, name): - self.name = name - def __repr__(self): - return '{}'.format(self.name) + def __init__(self, name): + self.name = name + + def __repr__(self): + return '{}'.format(self.name) + class FunctionType(Type): def __init__(self, parametertypes, returntype): @@ -59,6 +62,7 @@ params = ', '.join([str(v) for v in self.parametertypes]) return '{1} f({0})'.format(params, self.returntype) + class PointerType(Type): def __init__(self, ptype): assert isinstance(ptype, Type) or isinstance(ptype, Designator) @@ -102,6 +106,7 @@ def __repr__(self): return 'STRUCT' + class DefinedType(Type): def __init__(self, name, typ, loc): assert isinstance(name, str) @@ -116,32 +121,51 @@ # Variables, parameters, local variables, constants: class Symbol(Node): def __init__(self, name): - self.name = name - self.refs = [] + self.name = name + self.refs = [] + def addRef(self, r): - self.refs.append(r) + self.refs.append(r) + @property def References(self): - return self.refs + return self.refs + class Constant(Symbol): def __init__(self, name, typ, value): - super().__init__(name) - self.typ = typ - self.value = value + super().__init__(name) + self.typ = typ + self.value = value + def __repr__(self): - return 'CONSTANT {0} = {1}'.format(self.name, self.value) + return 'CONSTANT {0} = {1}'.format(self.name, self.value) + class Variable(Symbol): - def __init__(self, name, typ): - super().__init__(name) - self.typ = typ - self.ival = None - self.isLocal = False - self.isReadOnly = False - self.isParameter = False - def __repr__(self): - return 'Var {} [{}]'.format(self.name, self.typ) + def __init__(self, name, typ): + super().__init__(name) + self.typ = typ + self.ival = None + self.isLocal = False + self.isReadOnly = False + self.isParameter = False + + def __repr__(self): + return 'Var {} [{}]'.format(self.name, self.typ) + + +class LocalVariable(Variable): + def __init__(self, name, typ): + super().__init__(name, typ) + self.isLocal = True + + +class FormalParameter(Variable): + def __init__(self, name, typ): + super().__init__(name, typ) + self.isParameter = True + # Procedure types class Function(Symbol): diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/c3/builder.py --- a/python/c3/builder.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/c3/builder.py Sat Aug 31 17:58:54 2013 +0200 @@ -10,6 +10,7 @@ Reports errors to the diagnostics system """ def __init__(self, diag): + self.pack_dir = None self.logger = logging.getLogger('c3') self.diag = diag self.parser = Parser(diag) @@ -24,11 +25,17 @@ return self.packages[pname] else: # Try to lookup package from file - fns = glob.glob('./*/{}.c3'.format(pname)) + fns = glob.glob('./**/{}.c3'.format(pname)) if fns: with open(fns[0]) as f: src = f.read() self.build(src) + if self.pack_dir: + fns = glob.glob('{}/{}.c3'.format(self.pack_dir, pname)) + if fns: + with open(fns[0]) as f: + src = f.read() + self.build(src) if pname in self.packages: return self.packages[pname] @@ -48,8 +55,9 @@ self.packages[pkg.name] = pkg return pkg - def build(self, src): + def build(self, src, pack_dir=None): """ Create IR-code from sources """ + self.pack_dir = pack_dir pkg = self.parse(src) # Only return ircode when everything is OK diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/c3/codegenerator.py --- a/python/c3/codegenerator.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/c3/codegenerator.py Sat Aug 31 17:58:54 2013 +0200 @@ -27,19 +27,16 @@ for s in pkg.innerScope.Functions: f = self.newFunction(s.name) self.funcMap[s] = f - for s in pkg.innerScope: - if type(s) is astnodes.Variable: - #v = self.builder.newTmp(s.name) - self.varMap[s] = self.newTemp() - pass - elif type(s) is astnodes.Function: - self.genFunction(s) - else: - raise NotImplementedError(str(s)) + for v in pkg.innerScope.Variables: + #print(v) + self.varMap[v] = self.newTemp() + for s in pkg.innerScope.Functions: + self.genFunction(s) def genFunction(self, fn): # TODO: handle arguments f = self.funcMap[fn] + f.return_value = self.newTemp() # TODO reserve room for stack, this can be done at later point? self.setFunction(f) l2 = self.newBlock() @@ -49,14 +46,21 @@ for sym in fn.innerScope: # TODO: handle parameters different + if sym.isParameter: + print('param', sym) + ir.Parameter(sym.name) + if sym.isLocal: + print('local', sym) + v = self.newTemp() # TODO: make this ssa here?? self.varMap[sym] = v self.genCode(fn.body) - # TODO handle return? + # Set the default return value to zero: + # TBD: this may not be required? + self.emit(ir.Move(f.return_value, ir.Const(0))) self.emit(ir.Jump(f.epiloog)) - #self.emit(ir.Return(ir.Const(0))) self.setFunction(None) def genCode(self, code): @@ -87,7 +91,8 @@ elif type(code) is astnodes.ReturnStatement: if code.expr: re = self.genExprCode(code.expr) - self.emit(ir.Return(re)) + self.emit(ir.Move(self.fn.return_value, re)) + self.emit(ir.Jump(self.fn.epiloog)) else: self.builder.addIns(ir.Return()) elif type(code) is astnodes.WhileStatement: diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/c3/parser.py --- a/python/c3/parser.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/c3/parser.py Sat Aug 31 17:58:54 2013 +0200 @@ -124,19 +124,19 @@ # Variable declarations: def parseVarDef(self): - self.Consume('var') - t = self.parseTypeSpec() - def parseVar(): - name = self.Consume('ID') - v = astnodes.Variable(name.val, t) - v.loc = name.loc - if self.hasConsumed('='): - v.ival = self.Expression() - self.addDeclaration(v) - parseVar() - while self.hasConsumed(','): - parseVar() - self.Consume(';') + self.Consume('var') + t = self.parseTypeSpec() + def parseVar(): + name = self.Consume('ID') + v = astnodes.Variable(name.val, t) + v.loc = name.loc + if self.hasConsumed('='): + v.ival = self.Expression() + self.addDeclaration(v) + parseVar() + while self.hasConsumed(','): + parseVar() + self.Consume(';') def parseConstDef(self): self.Consume('const') @@ -164,17 +164,17 @@ self.Consume('(') parameters = [] if not self.hasConsumed(')'): - def parseParameter(): - typ = self.parseTypeSpec() - name = self.Consume('ID') - param = astnodes.Variable(name.val, typ) - param.loc = name.loc - self.addDeclaration(param) - parameters.append(param) - parseParameter() - while self.hasConsumed(','): + def parseParameter(): + typ = self.parseTypeSpec() + name = self.Consume('ID') + param = astnodes.FormalParameter(name.val, typ) + param.loc = name.loc + self.addDeclaration(param) + parameters.append(param) parseParameter() - self.Consume(')') + while self.hasConsumed(','): + parseParameter() + self.Consume(')') paramtypes = [p.typ for p in parameters] f.typ = astnodes.FunctionType(paramtypes, returntype) f.body = self.parseCompoundStatement() @@ -183,16 +183,16 @@ # Statements: def parseIfStatement(self): - loc = self.Consume('if').loc - self.Consume('(') - condition = self.Expression() - self.Consume(')') - yes = self.parseCompoundStatement() - if self.hasConsumed('else'): - no = self.parseCompoundStatement() - else: - no = None - return astnodes.IfStatement(condition, yes, no, loc) + loc = self.Consume('if').loc + self.Consume('(') + condition = self.Expression() + self.Consume(')') + yes = self.parseCompoundStatement() + if self.hasConsumed('else'): + no = self.parseCompoundStatement() + else: + no = None + return astnodes.IfStatement(condition, yes, no, loc) def parseWhileStatement(self): loc = self.Consume('while').loc diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/c3/scope.py --- a/python/c3/scope.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/c3/scope.py Sat Aug 31 17:58:54 2013 +0200 @@ -7,8 +7,8 @@ self.parent = parent def __iter__(self): - # Iterate in a deterministic manner: - return iter(self.Constants + self.Variables + self.Functions) + # Iterate in a deterministic manner: + return iter(self.Constants + self.Variables + self.Functions) @property def Syms(self): @@ -21,33 +21,34 @@ @property def Variables(self): - return [s for s in self.Syms if type(s) is astnodes.Variable] + return [s for s in self.Syms if isinstance(s, astnodes.Variable)] @property def Functions(self): return [s for s in self.Syms if type(s) is astnodes.Function] def getSymbol(self, name): - if name in self.symbols: - return self.symbols[name] - # Look for symbol: - if self.parent: - return self.parent.getSymbol(name) - raise CompilerException("Symbol {0} not found".format(name), name.loc) + if name in self.symbols: + return self.symbols[name] + # Look for symbol: + if self.parent: + return self.parent.getSymbol(name) + raise CompilerException("Symbol {0} not found".format(name), name.loc) def hasSymbol(self, name): - if name in self.symbols: - return True - if self.parent: - return self.parent.hasSymbol(name) - return False + if name in self.symbols: + return True + if self.parent: + return self.parent.hasSymbol(name) + return False def addSymbol(self, sym): - self.symbols[sym.name] = sym + self.symbols[sym.name] = sym def __repr__(self): return 'Scope with {} symbols'.format(len(self.symbols)) + # buildin types: intType = astnodes.BaseType('int') intType.bytesize = 4 diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/c3/typecheck.py --- a/python/c3/typecheck.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/c3/typecheck.py Sat Aug 31 17:58:54 2013 +0200 @@ -33,7 +33,7 @@ return False return True else: - raise Exception('Type compare not implemented') + raise Exception('Type compare for {} not implemented'.format(type(a))) return False def canCast(fromT, toT): @@ -99,7 +99,7 @@ sym.typ = sym.proc.typ.returntype elif type(sym) is VariableUse: sym.lvalue = True - if type(sym.target) is Variable: + if isinstance(sym.target, Variable): sym.typ = sym.target.typ else: print('warning {} has no target, defaulting to int'.format(sym)) @@ -172,7 +172,7 @@ self.error('Must be {0}'.format(boolType), sym.b.loc) else: raise Exception('Unknown binop {0}'.format(sym.op)) - elif type(sym) is Variable: + elif isinstance(sym, Variable): # check initial value type: # TODO pass diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/c3/visitor.py --- a/python/c3/visitor.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/c3/visitor.py Sat Aug 31 17:58:54 2013 +0200 @@ -54,7 +54,7 @@ self.do(node.ptr) elif type(node) is Constant: self.do(node.value) - elif type(node) in [VariableUse, Variable, Literal, FunctionType, DefinedType]: + elif type(node) in [VariableUse, Variable, Literal, FunctionType, DefinedType, FormalParameter, LocalVariable]: # Those nodes do not have child nodes. pass elif type(node) is WhileStatement: diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/c3/wishes/coro.c3 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/c3/wishes/coro.c3 Sat Aug 31 17:58:54 2013 +0200 @@ -0,0 +1,91 @@ +module coro; + +/* + Some co-routines doing some work. + + This example demonstrates how to write co-operating + routines in a nice way. +*/ + +int regbank[10]; + +function i2c_write(int address, int d) +{ + regbank[2] = address; + regbank[0] |= 0x1; // Issue go command + while (regbank[1] != 0) + { + yield; + } + + // Wait while busy: + while (regbank[1] != 11) + { + yield; + } +} + +function int i2c_read(int address) +{ + regbank[2] = address; + regbank[0] |= 0x1; // Issue go command + while (regbank[1] != 0) + { + yield; + } + + // Wait while busy: + while (regbank[1] != 11) + { + yield; + } +} + +function void eeprom_set(int address, int v) +{ + i2c_write(address, v); + i2c_read(address); +} + +function int calcX(int y) +{ + var int x; + x = 2; + x = x + 2 + 9 * y; + return x; +} + +var int counter = 0; + +task task1() +{ + start task3; + var int a = 200; + while (a > 0) + { + yield; + } +} + +task task2() +{ + while(true) + { + yield; + } +} + +task task3() +{ + eeprom_set(99, 1); + yield; +} + +task main() +{ + start task1; + start task2; + await task1; + await task2; +} + diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/codegenarm.py --- a/python/codegenarm.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/codegenarm.py Sat Aug 31 17:58:54 2013 +0200 @@ -6,7 +6,7 @@ import flowgraph import registerallocator from instructionselector import InstructionSelector - +import irmach class ArmInstructionSelector(InstructionSelector): """ Instruction selector for the arm architecture """ @@ -58,8 +58,16 @@ return d elif isinstance(e, ir.Temp): return self.getTempReg(e) + elif isinstance(e, ir.Call): + args = [self.munchExpr(a) for a in e.arguments] + self.emit('add sp, sp, 22') + # TODO: save frame + for a in args: + self.emit('push %s0', src=[a]) + self.emit('bl {}'.format(e.f.name)) + self.emit('sub sp, sp, 22') else: - raise NotImplementedError('--> {}'.format(e)) + raise NotImplementedError('Expr --> {}'.format(e)) def munchStm(self, s): if isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): @@ -70,9 +78,6 @@ val = self.munchExpr(s.src) dreg = self.getTempReg(s.dst) self.emit('mov %d0, %s0', dst=[dreg], src=[val]) - elif isinstance(s, ir.Return): - #etgt = self.targets[ - self.emit('jmp exit', jumps=[]) elif isinstance(s, ir.Jump): tgt = self.targets[s.target] self.emit('jmp {}'.format(s), jumps=[tgt]) @@ -102,12 +107,19 @@ def useUnused(self, inslist): # Use unused temporaries at the end of the list defTemps = [] - for d in (i.dst for i in inslist): - print(d) - defTemps.append(d) - useTemps = [d for d in ([i.src] for i in inslist)] - print(defTemps) - print(useTemps) + useTemps = [] + for i in inslist: + for d in iter(i.dst): + defTemps.append(d) + for s in iter(i.src): + useTemps.append(s) + defTemps = set(defTemps) + useTemps = set(useTemps) + unUsed = defTemps - useTemps + #print('Unused:', unUsed) + for uu in unUsed: + inslist.append(irmach.AbstractInstruction('use %s0', src=[uu])) + #print(useTemps) def generate(self, ircode, cfg_file=None, ig_file=None): ir2 = self.ins_sel.munchProgram(ircode) @@ -122,11 +134,13 @@ regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7'] ra = registerallocator.RegisterAllocator() regMap = ra.registerAllocate(ig, regs) - print(regMap) + #print(regMap) + # Use allocated registers: for i in ir2: i.src = tuple(regMap[t] for t in i.src) i.dst = tuple(regMap[t] for t in i.dst) - print(i) + #print(i) + return ir2 diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/doc/design.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/doc/design.rst Sat Aug 31 17:58:54 2013 +0200 @@ -0,0 +1,93 @@ + += processes / threads = + +Processes are completely seperated and fully pre-emptive. +This means a process can be unscheduled at any moment. + +Threads are co-operative. This means they yield control +voluntary. This means that mutexes and locks are not required. +This is done with the built-in language feature called tasks. + +If some heavy duty task must be performed, either way spawn +a new process, or yield frequently from this hard labour. + += tasks = + +Consider the following:: + +-- +function int insanemath(int a) +{ + while (a > 0) + { + a = a -1; + resume agent1; + } + return a - 1; +} + +task agent1() +{ + start agent2; +} + +task agent2() +{ + insanemath(55); + insanemath(44); +} + +task main() +{ + start agent1; + join agent1; +} +-- + +Say to tasks are running in concurrent / parallel. + + + +Stack layout for tasks. +|| +|| +\/ ++---------+ +| return address +| locals +| ++------ +| return address +| locals +| ++--- + +Assembly code for the functions above: + +.code +insanemath: +L1: +load r0, sp - 4 +cmp r0, 0 +jl L2 +dec r0 +store r0, sp - 4 +jmp L1 +L2: +ret + +agent1: +hlt? + +agent2: +hlt? + +main: +jmp agent1 + +.data +agent1_task: +dd 0 +agent2_task: +dd 0 + diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/ir/__init__.py --- a/python/ir/__init__.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/ir/__init__.py Sat Aug 31 17:58:54 2013 +0200 @@ -1,5 +1,4 @@ -from .module import * +from .module import Module, Function, Block from .instruction import * -from .function import Function, Block from .builder import Builder diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/ir/function.py --- a/python/ir/function.py Tue Aug 20 18:56:02 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ - -class Function: - def __init__(self, name): - self.name = name - self.entry = Block('{}_entry'.format(name)) - self.epiloog = Block('{}_epilog'.format(name)) - - def __repr__(self): - return 'Function {0}'.format(self.name) - - def addBB(self, bb): - self.bbs.append(bb) - bb.parent = self - addBasicBlock = addBB - - def removeBasicBlock(self, bb): - self.bbs.remove(bb) - bb.parent = None - - def getBBs(self): - bbs = [self.entry] - worklist = [self.entry] - while worklist: - b = worklist.pop() - for sb in b.Successors: - if sb not in bbs: - bbs.append(sb) - worklist.append(sb) - bbs.remove(self.entry) - if self.epiloog in bbs: - bbs.remove(self.epiloog) - bbs.insert(0, self.entry) - bbs.append(self.epiloog) - return bbs - - def findBasicBlock(self, name): - for bb in self.bbs: - if bb.name == name: - return bb - raise KeyError(name) - - BasicBlocks = property(getBBs) - - @property - def Entry(self): - return self.entry - - def check(self): - pass - - def call(self, *args): - varmap = {} - bb = self.Entry - ip = 0 - while True: - i = bb.Instructions[ip] - ip += 1 - return - - -class Block: - """ - Uninterrupted sequence of instructions with a label at the start. - """ - def __init__(self, name): - self.name = name - self.instructions = [] - - def __repr__(self): - return 'Block {0}'.format(self.name) - - def addInstruction(self, i): - i.parent = self - self.instructions.append(i) - - def replaceInstruction(self, i1, i2): - idx = self.instructions.index(i1) - i1.parent = None - i1.delete() - i2.parent = self - self.instructions[idx] = i2 - - def removeInstruction(self, i): - i.parent = None - i.delete() - self.instructions.remove(i) - - def getInstructions(self): - return self.instructions - Instructions = property(getInstructions) - - def getLastIns(self): - return self.instructions[-1] - LastInstruction = property(getLastIns) - - @property - def Empty(self): - return len(self.instructions) == 0 - - @property - def FirstInstruction(self): - return self.instructions[0] - - def getSuccessors(self): - if not self.Empty: - return self.LastInstruction.Targets - return [] - Successors = property(getSuccessors) - - def getPredecessors(self): - preds = [] - for bb in self.parent.BasicBlocks: - if self in bb.Successors: - preds.append(bb) - return preds - Predecessors = property(getPredecessors) - - def precedes(self, other): - raise NotImplementedError() - - def check(self): - pass diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/ir/instruction.py --- a/python/ir/instruction.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/ir/instruction.py Sat Aug 31 17:58:54 2013 +0200 @@ -1,4 +1,4 @@ -from .function import Function +from .module import Function class Expression: pass @@ -39,6 +39,7 @@ def Add(a, b): + """ Convenience call """ return Binop(a, '+', b) @@ -51,6 +52,26 @@ return 'Alloc' +class Variable(Expression): + def __init__(self, offset): + self.offset = offset + + def __repr__(self): + return 'Variable' + + +class LocalVariable(Variable): + pass + + +class GlobalVariable(Variable): + pass + + +class Parameter(Variable): + pass + + class Temp(Expression): """ Temporary storage, same as register """ def __init__(self, name): @@ -120,15 +141,4 @@ return 'IF {} {} {} THEN {} ELSE {}'.format(self.a, self.cond, self.b, self.lab_yes, self.lab_no) -class Return(Statement): - def __init__(self, value): - self.value = value - self.Targets = [] # TODO: Do this in another way - def __repr__(self): - if self.value: - return 'ret {0}'.format(self.value) - else: - return 'ret' - - diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/ir/module.py --- a/python/ir/module.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/ir/module.py Sat Aug 31 17:58:54 2013 +0200 @@ -1,6 +1,5 @@ # IR-Structures: -from .instruction import * -from .function import Block + class Module: """ Main container for a piece of code. """ @@ -68,5 +67,129 @@ """ Perform sanity check on module """ for f in self.Functions: f.check() - + + +class Function: + def __init__(self, name): + self.name = name + self.entry = Block('{}_entry'.format(name)) + self.epiloog = Block('{}_epilog'.format(name)) + self.arguments = [] + + def __repr__(self): + return 'Function {0}'.format(self.name) + + def addBB(self, bb): + self.bbs.append(bb) + bb.parent = self + addBasicBlock = addBB + + def removeBasicBlock(self, bb): + self.bbs.remove(bb) + bb.parent = None + + def getBBs(self): + bbs = [self.entry] + worklist = [self.entry] + while worklist: + b = worklist.pop() + for sb in b.Successors: + if sb not in bbs: + bbs.append(sb) + worklist.append(sb) + bbs.remove(self.entry) + if self.epiloog in bbs: + bbs.remove(self.epiloog) + bbs.insert(0, self.entry) + bbs.append(self.epiloog) + return bbs + + def findBasicBlock(self, name): + for bb in self.bbs: + if bb.name == name: + return bb + raise KeyError(name) + + BasicBlocks = property(getBBs) + + @property + def Entry(self): + return self.entry + + def check(self): + pass + + def call(self, *args): + varmap = {} + bb = self.Entry + ip = 0 + while True: + i = bb.Instructions[ip] + ip += 1 + return + +class Block: + """ + Uninterrupted sequence of instructions with a label at the start. + """ + def __init__(self, name): + self.name = name + self.instructions = [] + + def __repr__(self): + return 'Block {0}'.format(self.name) + + def addInstruction(self, i): + i.parent = self + self.instructions.append(i) + + def replaceInstruction(self, i1, i2): + idx = self.instructions.index(i1) + i1.parent = None + i1.delete() + i2.parent = self + self.instructions[idx] = i2 + + def removeInstruction(self, i): + i.parent = None + i.delete() + self.instructions.remove(i) + + def getInstructions(self): + return self.instructions + Instructions = property(getInstructions) + + def getLastIns(self): + return self.instructions[-1] + LastInstruction = property(getLastIns) + + @property + def Empty(self): + return len(self.instructions) == 0 + + @property + def FirstInstruction(self): + return self.instructions[0] + + def getSuccessors(self): + if not self.Empty: + return self.LastInstruction.Targets + return [] + Successors = property(getSuccessors) + + def getPredecessors(self): + preds = [] + for bb in self.parent.BasicBlocks: + if self in bb.Successors: + preds.append(bb) + return preds + Predecessors = property(getPredecessors) + + def precedes(self, other): + raise NotImplementedError() + + def check(self): + pass + + diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/tcodegen.py --- a/python/tcodegen.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/tcodegen.py Sat Aug 31 17:58:54 2013 +0200 @@ -11,6 +11,15 @@ testsrc = """ package test2; +var int phaa, foo, bar; + +function int insanemath(int a, int b) +{ + var int c; + c = a + b + 1; + return c; +} + function void tesssst(int henkie) { var int a, b, cee; @@ -22,7 +31,7 @@ if (cee + a > b and b - a+b== 3*6-b) { var int x = a; - x = b - a; + x = b - a + insanemath(3, 4); a = x * (x + a); } else @@ -43,7 +52,9 @@ cga = codegenarm.ArmCodeGenerator(outs) cfg_file = open('cfg.gv', 'w') ig_file = open('ig.gv', 'w') - cga.generate(ir, cfg_file=cfg_file, ig_file=ig_file) + ir2 = cga.generate(ir, cfg_file=cfg_file, ig_file=ig_file) cfg_file.close() ig_file.close() + for i in ir2: + print(i) diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/testc3.py --- a/python/testc3.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/testc3.py Sat Aug 31 17:58:54 2013 +0200 @@ -105,23 +105,13 @@ self.assertSequenceEqual(rows, actualErrors) self.assertFalse(ircode) - def expectOK(self, snippet): - ircode = self.builder.build(snippet) + def expectOK(self, snippet, pack_dir=None): + ircode = self.builder.build(snippet, pack_dir=pack_dir) if not ircode: self.diag.printErrors(snippet) self.assertTrue(ircode) return ircode - def expectIR(self, snippet, ir_out): - ircode = self.builder.build(snippet) - if not ircode: - self.diag.printErrors(snippet) - self.assertTrue(ircode) - actual_ins = [str(i) for i in ircode.Instructions] - expected_ins = [i.strip() for i in ir_out.split('\n')] - self.assertSequenceEqual(expected_ins, actual_ins) - return ircode - def testPackage(self): p1 = """package p1; type int A; @@ -408,7 +398,7 @@ for filename in example_filenames: with open(filename, 'r') as f: src = f.read() - self.expectOK(src) + self.expectOK(src, pack_dir='./c3/examples') def test2(self): # testsrc2 is valid code: diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/testcg.py --- a/python/testcg.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/testcg.py Sat Aug 31 17:58:54 2013 +0200 @@ -8,7 +8,7 @@ m = ir.Module('tst') f = ir.Function('tst') m.addFunction(f) - return m, f.entry + return m, f, f.entry class testCodeGeneration(unittest.TestCase): @@ -16,9 +16,9 @@ self.cg = codegen.CodeGenerator(arm.armtarget) def testFunction(self): - m, bb = genTestFunction() + m, f, bb = genTestFunction() bb.addInstruction(ir.Const(123)) - bb.addInstruction(ir.Return(ir.Const(0))) + bb.addInstruction(ir.Jump(f.epiloog)) m.check() obj = self.cg.generate(m) self.assertTrue(obj) @@ -28,9 +28,9 @@ def testStack(self): s = outstream.OutputStream() cg = codegenarm.ArmCodeGenerator(s) - m, bb = genTestFunction() + m, f, bb = genTestFunction() bb.addInstruction(ir.Move(ir.Mem(ir.Const(1)), ir.Const(22))) - bb.addInstruction(ir.Return(ir.Const(0))) + bb.addInstruction(ir.Jump(f.epiloog)) m.check() cg.generate(m) #s.dump() diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/testhexfile.py --- a/python/testhexfile.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/testhexfile.py Sat Aug 31 17:58:54 2013 +0200 @@ -28,11 +28,13 @@ hf.addRegion(0xFFFE, bytes.fromhex('aabbcc')) self.saveload(hf) + @unittest.skip def testSave4(self): hf = HexFile() hf.addRegion(0xF000, bytes.fromhex('ab')*0x10000) self.saveload(hf) + @unittest.skip def testSave5(self): hf = HexFile() hf.addRegion(0xF003, bytes.fromhex('ab')*0x10000) diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/testir.py --- a/python/testir.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/testir.py Sat Aug 31 17:58:54 2013 +0200 @@ -5,6 +5,7 @@ import ir, x86, transform import optimize + class IrCodeTestCase(unittest.TestCase): def setUp(self): self.b = ir.Builder() @@ -16,12 +17,13 @@ self.b.setFunction(f) bb = self.b.newBlock() self.b.setBlock(bb) - self.b.emit(ir.Return(ir.Const(0))) + self.b.emit(ir.Exp(ir.Const(0))) self.m.check() # Run interpreter: # r = self.m.getFunction('add').call(1, 2) #self.assertEqual(3, r) + class ConstantFolderTestCase(unittest.TestCase): def setUp(self): self.b = ir.Builder() diff -r cf7d5fb7d9c8 -r e64bae57cda8 python/zcc.py --- a/python/zcc.py Tue Aug 20 18:56:02 2013 +0200 +++ b/python/zcc.py Sat Aug 31 17:58:54 2013 +0200 @@ -21,15 +21,16 @@ parser.add_argument('--dumpir', action='store_true', help="Dump IR-code") parser.add_argument('--dumpasm', action='store_true', help="Dump ASM-code") parser.add_argument('--optimize', action='store_true', help="Optimize") +parser.add_argument('--package_dir', help="Look in this directory for packages") parser.add_argument('-o', '--output', help='Output file', metavar='filename') parser.add_argument('--hexfile', help='Output hexfile', type=argparse.FileType('w')) parser.add_argument('--log', help='Log level (INFO,DEBUG)', type=logLevel) -def zcc(src, outs, diag, dumpir=False, do_optimize=False): +def zcc(src, outs, diag, dumpir=False, do_optimize=False, pack_dir=None): logging.info('Zcc started') # Front end: c3b = c3.Builder(diag) - ircode = c3b.build(src) + ircode = c3b.build(src, pack_dir=pack_dir) if not ircode: return @@ -55,7 +56,7 @@ outs = outstream.TextOutputStream() # Invoke compiler: - res = zcc(src, outs, diag, dumpir=args.dumpir, do_optimize=args.optimize) + res = zcc(src, outs, diag, dumpir=args.dumpir, do_optimize=args.optimize, pack_dir=args.package_dir) if not res: diag.printErrors(src) sys.exit(1)