# HG changeset patch # User Windel Bouwman # Date 1364574797 -3600 # Node ID 4348da5ca307ceb78a737994aa8fe4d2a76832b2 # Parent ee0d30533daed03f7a0d6f5a0a938407a6c4280e Cleanup of ir dir diff -r ee0d30533dae -r 4348da5ca307 python/c3/codegenerator.py --- a/python/c3/codegenerator.py Sat Mar 23 18:34:41 2013 +0100 +++ b/python/c3/codegenerator.py Fri Mar 29 17:33:17 2013 +0100 @@ -1,103 +1,95 @@ import ir from . import astnodes -def genModule(pkg): - m = ir.Module(pkg.name) - for s in pkg.scope: - if type(s) is astnodes.Variable: - genGlobal(m, s) - elif type(s) is astnodes.Function: - genFunction(m, s) - else: - print(s) - return m - -def genGlobal(m, var): - v = ir.Value() - v.name = var.name - m.Globals.append(v) - -def genFunction(m, fnc): - ft = genType(fnc.typ) - f = ir.Function(fnc.name, ft) - m.Functions.append(f) - bb = ir.BasicBlock() - f.BasicBlocks.append(bb) - genCode(bb, fnc.body) - bb.Instructions.append(ir.RetInstruction()) - -def genCode(bb, code): - if type(code) is astnodes.CompoundStatement: - for s in code.statements: - genCode(bb, s) - elif type(code) is astnodes.Assignment: - genExprCode(bb, code.rval) - # TODO: store - elif type(code) is astnodes.IfStatement: - genExprCode(bb, code.condition) - # TODO: implement IF. - t1, t2 = 1, 2 - b = ir.BranchInstruction(t1, t2) - bb.Instructions.append(b) - genCode(bb, code.truestatement) - genCode(bb, code.falsestatement) - elif type(code) is astnodes.FunctionCall: - ins = ir.CallInstruction('f', []) - bb.Instructions.append(ins) - elif type(code) is astnodes.EmptyStatement: - pass - elif type(code) is astnodes.ReturnStatement: - bb.Instructions.append(ir.RetInstruction()) - else: - print('Unknown stmt:', code) - def NumGen(): a = 0 while True: yield a a = a + 1 -nums = NumGen() -def unique(): - return 'tmp{0}'.format(nums.__next__()) +class NameGenerator: + def __init__(self, prefix): + self.prefix = prefix + self.nums = NumGen() + def gen(self): + return '{0}{1}'.format(self.prefix, self.nums.__next__()) + +class CodeGenerator: + """ Generates intermediate code from a package """ + def gencode(self, pkg): + assert type(pkg) is astnodes.Package + self.m = ir.Module(pkg.name) + self.newTmp = NameGenerator('t').gen + self.newLab = NameGenerator('lab').gen + self.genModule(pkg) + return self.m + + # Helpers: + def addIns(self, i): + self.m.Instructions.append(i) + # inner helpers: + def genModule(self, pkg): + for s in pkg.scope: + if type(s) is astnodes.Variable: + # TODO + pass + elif type(s) is astnodes.Function: + # TODO: handle arguments + # TODO handle return? + self.addIns(ir.LabelInstruction(s.name)) + self.genCode(s.body) + self.addIns(ir.RetInstruction()) + else: + print(s) -def genExprCode(bb, code): - if type(code) is astnodes.Binop: - a = genExprCode(bb, code.a) - b = genExprCode(bb, code.b) - ops = {'+': 'fadd', '-': 'fsub', '*':'fmul', '/':'fdiv'} - if code.op in ops: - op = ops[code.op] + def genCode(self, code): + if type(code) is astnodes.CompoundStatement: + for s in code.statements: + self.genCode(s) + elif type(code) is astnodes.Assignment: + re = self.genExprCode(code.rval) + self.addIns(ir.StoreInstruction(code.lval, re)) + elif type(code) is astnodes.IfStatement: + cr = self.genExprCode(code.condition) + t1, t2, te = self.newLab(), self.newLab(), self.newLab() + self.addIns(ir.IfInstruction(cr, t1, t2)) + self.addIns(ir.LabelInstruction(t1)) + self.genCode(code.truestatement) + self.addIns(ir.BranchInstruction(te)) + self.addIns(ir.LabelInstruction(t2)) + self.genCode(code.falsestatement) + self.addIns(ir.LabelInstruction(te)) + elif type(code) is astnodes.FunctionCall: + pass + elif type(code) is astnodes.EmptyStatement: + pass + elif type(code) is astnodes.ReturnStatement: + pass + else: + print('Unknown stmt:', code) + + def genExprCode(self, expr): + if type(expr) is astnodes.Binop: + ra = self.genExprCode(expr.a) + rb = self.genExprCode(expr.b) + ops = ['+', '-', '*', '/', 'and', 'or'] + if expr.op in ops: + op = expr.op + tmp = self.newTmp() + ins = ir.BinaryOperator(tmp, op, ra, rb) + self.addIns(ins) + return tmp + else: + print('Unknown binop {0}'.format(expr)) + elif type(expr) is astnodes.Constant: tmp = unique() - ins = ir.BinaryOperator(tmp, op, a, b) - bb.Instructions.append(ins) + elif type(expr) is astnodes.VariableUse: + tmp = self.newTmp() + elif type(expr) is astnodes.Literal: + tmp = self.newTmp() + ins = ir.MoveInstruction(tmp, expr.val) + self.addIns(ins) return tmp else: - print('Unknown binop {0}'.format(code)) - bb.Instructions.append(ir.BinaryOperator('unk2', code.op, a, b)) - return 'unk2' - elif type(code) is astnodes.Constant: - tmp = unique() - bb.Instructions.append(ir.LoadInstruction(tmp, code.value)) - return tmp - elif type(code) is astnodes.VariableUse: - tmp = unique() - ins = ir.LoadInstruction(tmp, code.target.name) - return tmp - elif type(code) is astnodes.Literal: - tmp = unique() - ins = ir.LoadInstruction(tmp, code.val) - return tmp - else: - print('Unknown expr:', code) - return 'unk' + print('Unknown expr:', code) -def genType(t): - return ir.Type() - -class CodeGenerator: - """ Generates intermediate code """ - def gencode(self, ast): - assert type(ast) is astnodes.Package - return genModule(ast) - diff -r ee0d30533dae -r 4348da5ca307 python/c3/typecheck.py --- a/python/c3/typecheck.py Sat Mar 23 18:34:41 2013 +0100 +++ b/python/c3/typecheck.py Fri Mar 29 17:33:17 2013 +0100 @@ -61,12 +61,16 @@ elif type(sym) is Binop: if sym.op in ['+', '-', '*', '/']: if equalTypes(sym.a.typ, sym.b.typ): - sym.typ = sym.a.typ + if equalTypes(sym.a.typ, intType): + sym.typ = sym.a.typ + else: + self.diag.error('Can only add integers', sym.loc) + sym.typ = intType else: # assume void here? TODO: throw exception! sym.typ = intType self.diag.error('Types unequal', sym.loc) - elif sym.op in ['>', '<']: + elif sym.op in ['>', '<', '==', '<=', '>=']: sym.typ = boolType if not equalTypes(sym.a.typ, sym.b.typ): self.diag.error('Types unequal', sym.loc) diff -r ee0d30533dae -r 4348da5ca307 python/ir/__init__.py --- a/python/ir/__init__.py Sat Mar 23 18:34:41 2013 +0100 +++ b/python/ir/__init__.py Fri Mar 29 17:33:17 2013 +0100 @@ -1,8 +1,3 @@ -from .module import Module, Function, BasicBlock -from .value import Value -from .module import Type, FunctionType -from .module import i8, i16, i32, void -from .module import printIr +from .module import Module from .instruction import * - diff -r ee0d30533dae -r 4348da5ca307 python/ir/asmwriter.py --- a/python/ir/asmwriter.py Sat Mar 23 18:34:41 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ - -from . import llvmtype -from .instruction import BinaryOperator -#typeNames[VoidType] = 'void' - -class AsmWriter: - def __init__(self): - self.typeNames = {} - self.typeNames[llvmtype.typeID.Void] = 'void' - def printModule(self, module): - if module.Identifier: - print('; ModuleID = {0}'.format(module.Identifier)) - # Print functions: - for f in module.Functions: - self.printFunction(f) - def printFunction(self, f): - # TODO: if definition: - - t = self.strType(f.ReturnType.tid) - args = '()' - print('define {0} {1}{2}'.format(t, f.name, args)) - print('{') - for bb in f.BasicBlocks: - print('basic block!') - self.printBasicBlock(bb) - print('}') - - def strType(self, t): - return self.typeNames[t] - - def printBasicBlock(self, bb): - if bb.Name: - # print label - print('{0}:'.format(bb.Name)) - for instr in bb.Instructions: - self.printInstruction(instr) - def printInstruction(self, i): - print('Instruction!') - if isinstance(i, BinaryOperator): - print(i.operation, i.value1.Name, i.value2.Name) - else: - print(i) - diff -r ee0d30533dae -r 4348da5ca307 python/ir/bitreader.py --- a/python/ir/bitreader.py Sat Mar 23 18:34:41 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -from .errors import CompilerException -from .module import Module -import struct - -def enum(**enums): - return type('Enum', (), enums) - -BitCodes = enum(END_BLOCK=0, ENTER_SUBBLOCK=1) - -class BitstreamReader: - def __init__(self, f): - self.f = f - # Initialize the bitreader: - self.bitsInCurrent = 32 - self.curWord = self.getWord() - self.curCodeSize = 2 - def getWord(self): - bts = self.f.read(4) - return struct.unpack(' 32: - raise CompilerException("Cannot read more than 32 bits") - if self.bitsInCurrent >= numbits: - # numbits inside the current word: - R = self.curWord & ((1 << numbits) - 1) - self.curWord = self.curWord >> numbits - self.bitsInCurrent -= numbits - return R - R = self.curWord - self.curWord = self.getWord() - bitsLeft = numbits - self.bitsInCurrent - - # Add remaining bits: - R |= (self.curWord & (0xFFFFFFFF >> (32 - bitsLeft))) << self.bitsInCurrent - - # Update curword and bits in current: - self.curWord = self.curWord >> bitsLeft - self.bitsInCurrent = 32 - bitsLeft - return R - def ReadVBR(self, numbits): - """ Read variable bits, checking for the last bit is zero. """ - piece = self.Read(numbits) - if (piece & (1 << (numbits - 1))) == 0: - return piece - result = 0 - nextbit = 0 - while True: - mask = (1 << (numbits - 1)) - 1 - result |= ( piece & mask ) << nextbit - if (piece & (1 << (numbits - 1))) == 0: - return result - nextbit += numbits - 1 - piece = self.Read(numbits) - def ReadCode(self): - """ Read the code depending on the current code size """ - return self.Read(self.curCodeSize) - def ReadSubBlockId(self): - return self.ReadVBR(8) - def EnterSubBlock(self, blockId): - pass - -BLOCKINFO_BLOCKID = 0 -FIRST_APPLICATION_BLOCKID = 8 -MODULE_BLOCKID = FIRST_APPLICATION_BLOCKID - -class BitcodeReader: - def __init__(self, f): - self.stream = BitstreamReader(f) - def parseModule(self): - for bitsig in [ord('B'), ord('C')]: - if self.stream.Read(8) != bitsig: - raise CompilerException('Invalid bitcode signature') - for bitsig in [0x0, 0xC, 0xE, 0xD]: - if self.stream.Read(4) != bitsig: - raise CompilerException('Invalid bitcode signature') - while True: - code = self.stream.ReadCode() - if code != BitCodes.ENTER_SUBBLOCK: - raise CompilerException('Invalid record at toplevel') - blockId = self.stream.ReadSubBlockId() - if blockId == MODULE_BLOCKID: - print('module block') - pass - else: - print('Block id:', blockId) - raise - return Module() - -class BitstreamWriter: - def __init__(self, f): - self.f = f - self.u32 = 0 - self.curpos = 0 - def Emit1(self, val): - self.Emit(val, 1) - def Emit(self, val, numbits): - """ Emits value using numbits bits """ - if numbits == 1: - if val != 0: - self.u32 |= (0x1 << self.curpos) - self.curpos += 1 - if self.curpos == 32: - self.writeWord() - elif numbits > 1: - for i in range(numbits): - if val & (1 << i) != 0: - self.Emit1(1) - else: - self.Emit1(0) - def writeWord(self): - bts = struct.pack(' b and b == 3) + { + var int x = a; + x = b * 2 - a; + a = x*x; + } + else + { + a = b + a; + } +} + +""" + def c3compile(src, diag): # Structures: builder = c3.Builder(diag) @@ -176,6 +199,13 @@ } """ self.builder.build(snippet) + def test2(self): + # testsrc2 is valid code: + self.diag.clear() + ir = self.builder.build(testsrc2) + print(self.diag.diags) + assert ir + ir.dump() if __name__ == '__main__': do()