# HG changeset patch # User Windel Bouwman # Date 1361525628 -3600 # Node ID 4e79484a9d477808dc5b4ae312b1b4d9e32cd02d # Parent 91af0e40f8682176e766bc50c22c9a290fa307f3 Moved core to ir folder diff -r 91af0e40f868 -r 4e79484a9d47 python/ir/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ir/__init__.py Fri Feb 22 10:33:48 2013 +0100 @@ -0,0 +1,14 @@ +from .instruction import BinaryOperator +from .function import Function +from .value import Value, Constant +from .bitreader import BitcodeReader, BitcodeWriter +from .errors import CompilerException +from .module import Module +from .llvmtype import FunctionType, i8, i16, i32, void +from .context import Context +from .asmwriter import AsmWriter +from .basicblock import BasicBlock +from .irbuilder import IRBuilder + +version='0.0.1' + diff -r 91af0e40f868 -r 4e79484a9d47 python/ir/asmwriter.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ir/asmwriter.py Fri Feb 22 10:33:48 2013 +0100 @@ -0,0 +1,43 @@ + +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 91af0e40f868 -r 4e79484a9d47 python/ir/basicblock.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ir/basicblock.py Fri Feb 22 10:33:48 2013 +0100 @@ -0,0 +1,15 @@ +from .value import Value + +class BasicBlock(Value): + """ + A basic block represents a sequence of instructions without + jumps and branches. + """ + def __init__(self): + super().__init__() + self.instructions = [] + self.name = None + def getInstructions(self): + return self.instructions + Instructions = property(getInstructions) + diff -r 91af0e40f868 -r 4e79484a9d47 python/ir/bitreader.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ir/bitreader.py Fri Feb 22 10:33:48 2013 +0100 @@ -0,0 +1,134 @@ +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(' 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(' len(lines): - afterrow = len(lines) - - # print preceding source lines: - for r in range(prerow, e.row): - printLine(r, lines[r-1]) - # print source line containing error: - printLine(e.row, lines[e.row-1]) - print(' '*(len(str(e.row)+':')+e.col-1) + '^ Error: {0}'.format(e.msg)) - # print trailing source line: - for r in range(e.row+1, afterrow+1): - printLine(r, lines[r-1]) diff -r 91af0e40f868 -r 4e79484a9d47 python/ppci/core/function.py --- a/python/ppci/core/function.py Fri Feb 22 10:31:58 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ - -class Argument: - def __init__(self, argtype, name, function): - self.t = argtype - self.name = name - self.function = function - -class Function(GlobalValue): - def __init__(self, functiontype, name, module): - super().__init__() - self.functiontype = functiontype - self.name = name - self.module = module - - self.module.Functions.append(self) - self.basicblocks = [] - self.arguments = [] - # Construct formal arguments depending on function type - - BasicBlocks = property(lambda self: self.basicblocks) - Arguments = property(lambda self: self.arguments) - ReturnType = property(lambda self: self.functiontype.returnType) - FunctionType = property(lambda self: self.functiontype) - diff -r 91af0e40f868 -r 4e79484a9d47 python/ppci/core/instruction.py --- a/python/ppci/core/instruction.py Fri Feb 22 10:31:58 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ - -from .value import Value - -def Enum(**enums): - return type('Enum', (), enums) - -class Instruction(Value): - """ Base class for all instructions. """ - pass - -class CallInstruction(Instruction): - def __init__(self, callee, arguments): - super().__init__() - self.callee = callee - self.arguments = arguments - -BinOps = Enum(Add=1, Sub=2, Mul=3) - -class BinaryOperator(Instruction): - def __init__(self, operation, value1, value2): - assert value1 - assert value2 - print('operation is in binops:', operation in BinOps) - # Check types of the two operands: - self.value1 = value1 - self.value2 = value2 - self.operation = operation - -class LoadInstruction(Instruction): - def __init__(self, ptr, name, insertBefore): - self.setName(name) - diff -r 91af0e40f868 -r 4e79484a9d47 python/ppci/core/llvmtype.py --- a/python/ppci/core/llvmtype.py Fri Feb 22 10:31:58 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ - -def Enum(**enums): - return type('Enum', (), enums) - -typeID = Enum(Void=0, Double=3, Integer=10, Function=11, Struct=12, Array=13, Pointer=14, Vector=15) - -class llvmType: - def __init__(self, tid): - self.tid = tid - -class IntegerType(llvmType): - def __init__(self, bits): - super().__init__(typeID.Integer) - self.bits = bits - -class FunctionType(llvmType): - def __init__(self, resultType, parameterTypes): - super().__init__(typeID.Function) - assert type(parameterTypes) is list - self.resultType = resultType - self.returnType = resultType - self.parameterTypes = parameterTypes - -# Default types: -i8 = IntegerType(8) -i16 = IntegerType(16) -i32 = IntegerType(32) -void = llvmType(typeID.Void) - - diff -r 91af0e40f868 -r 4e79484a9d47 python/ppci/core/module.py --- a/python/ppci/core/module.py Fri Feb 22 10:31:58 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -from .value import Value -from .symboltable import SymbolTable - -class Module(Value): - """ - Main container for a piece of code. Contains globals and functions. - """ - def __init__(self, identifier=None): - self.identifier = identifier - self.functions = [] # Do functions come out of symbol table? - self.globals_ = [] # TODO: are globals in symbol table? - self.symtable = SymbolTable() - - Globals = property(lambda self: self.globals_) - Functions = property(lambda self: self.functions) - Identifier = property(lambda self: self.identifier) - diff -r 91af0e40f868 -r 4e79484a9d47 python/ppci/core/symboltable.py --- a/python/ppci/core/symboltable.py Fri Feb 22 10:31:58 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ - -class SymbolTable: - """ Holds a table of symbols for a module or function """ - def __init__(self): - self.symbols = {} - - diff -r 91af0e40f868 -r 4e79484a9d47 python/ppci/core/value.py --- a/python/ppci/core/value.py Fri Feb 22 10:31:58 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ - -class Value: - def __init__(self, vty=None): - self.valueType = vty - self.name = None - def getContext(self): - return self.valueType.context - def dump(self): - print(self) - - def getName(self): - return self.name - def setName(self, name): - if not self.name and not name: - return - self.name = name - - if self.st: - pass - else: - pass - Name = property(getName, setName) - -class Constant(Value): - def __init__(self, value, vty): - super().__init__(vty) - self.value = value - print('new constant value: ', value) - diff -r 91af0e40f868 -r 4e79484a9d47 python/ppci/errors.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/ppci/errors.py Fri Feb 22 10:33:48 2013 +0100 @@ -0,0 +1,47 @@ +""" Error handling routines """ + +class CompilerException(Exception): + def __init__(self, msg, row=0, col=0, filename=None): + self.msg = msg + self.row = row + self.col = col + self.filename = filename + def __repr__(self): + return self.msg + def __str__(self): + return self.msg + +class ErrorNode: + def __init__(self, row, col, msg): + self.row, self.col = row,col + self.msg = msg + +def Error(msg, node=None): + if node is None: + raise CompilerException(msg) + else: + raise CompilerException(msg, node.row, node.col) + +def printError(source, e): + def printLine(row, txt): + print(str(row)+':'+txt) + if e.row == 0: + print('Error: {0}'.format(e.msg)) + else: + lines = source.split('\n') + prerow = e.row - 3 + if prerow < 1: + prerow = 1 + afterrow = e.row + 3 + if afterrow > len(lines): + afterrow = len(lines) + + # print preceding source lines: + for r in range(prerow, e.row): + printLine(r, lines[r-1]) + # print source line containing error: + printLine(e.row, lines[e.row-1]) + print(' '*(len(str(e.row)+':')+e.col-1) + '^ Error: {0}'.format(e.msg)) + # print trailing source line: + for r in range(e.row+1, afterrow+1): + printLine(r, lines[r-1])