Mercurial > lcfOS
changeset 312:2c9768114877
Added cool logging formatter
author | Windel Bouwman |
---|---|
date | Mon, 16 Dec 2013 17:58:15 +0100 |
parents | ff665880a6b0 |
children | 04cf4d26a3bc |
files | kernel/make.py python/ppci/__init__.py python/ppci/c3/codegenerator.py python/ppci/codegen/codegen.py python/ppci/codegen/graph.py python/ppci/codegen/registerallocator.py python/ppci/common.py python/ppci/errors.py python/ppci/ir.py python/ppci/irutils.py python/zcc.py test/testzcc.py |
diffstat | 12 files changed, 217 insertions(+), 110 deletions(-) [+] |
line wrap: on
line diff
--- a/kernel/make.py Mon Dec 16 12:49:24 2013 +0100 +++ b/kernel/make.py Mon Dec 16 17:58:15 2013 +0100 @@ -2,7 +2,6 @@ import sys import os -import zcc def make_kernel(): arglist = ['memory.c3', 'kernel.c3', 'syscall.c3', 'process.c3'] @@ -16,4 +15,5 @@ if __name__ == '__main__': sys.path.insert(0, os.path.join('..', 'python')) + import zcc make_kernel()
--- a/python/ppci/__init__.py Mon Dec 16 12:49:24 2013 +0100 +++ b/python/ppci/__init__.py Mon Dec 16 17:58:15 2013 +0100 @@ -10,4 +10,4 @@ sys.exit(1) from .common import SourceLocation, SourceRange, Token -from .errors import CompilerError, DiagnosticsManager +from .common import CompilerError, DiagnosticsManager
--- a/python/ppci/c3/codegenerator.py Mon Dec 16 12:49:24 2013 +0100 +++ b/python/ppci/c3/codegenerator.py Mon Dec 16 17:58:15 2013 +0100 @@ -265,7 +265,7 @@ if type(expr.val) in typemap: expr.typ = self.pkg.scope[typemap[type(expr.val)]] else: - raise SemanticError('Unknown literal type {}'.format(expr.val)) + raise SemanticError('Unknown literal type {}'.format(expr.val), expr.loc) return ir.Const(expr.val) elif type(expr) is ast.TypeCast: return self.gen_type_cast(expr)
--- a/python/ppci/codegen/codegen.py Mon Dec 16 12:49:24 2013 +0100 +++ b/python/ppci/codegen/codegen.py Mon Dec 16 17:58:15 2013 +0100 @@ -1,8 +1,10 @@ from ..ir import Module +from ..irutils import Verifier from target import Target from ppci import CompilerError from .canon import make as canonicalize from .registerallocator import RegisterAllocator +import logging class CodeGenerator: @@ -11,21 +13,28 @@ # TODO: schedule traces in better order. # This is optional! assert isinstance(target, Target), target + self.logger = logging.getLogger('codegen') self.target = target self.ins_sel = target.ins_sel self.ra = RegisterAllocator() + self.verifier = Verifier() def generateFunc(self, irfunc, outs): """ Generate code for one function into a frame """ + self.logger.info('Generating code for {}'.format(irfunc.name)) # Create a frame for this function: frame = self.target.FrameClass(irfunc.name) # Canonicalize the intermediate language: canonicalize(irfunc, frame) + self.logger.info('after canonicalize', extra={'irfunc':irfunc}) + self.verifier.verify_function(irfunc) self.ins_sel.munchFunction(irfunc, frame) + self.logger.info('Selected instructions', extra={'ppci_frame':frame}) # Do register allocation: self.ra.allocFrame(frame) + self.logger.info('Registers allocated, now adding final glue') # TODO: Peep-hole here? # Add label and return and stack adjustment: @@ -34,6 +43,7 @@ # Materialize the register allocated instructions into a stream of # real instructions. frame.lower_to(outs) + self.logger.info('Instructions materialized') return frame def generate(self, ircode, outs):
--- a/python/ppci/codegen/graph.py Mon Dec 16 12:49:24 2013 +0100 +++ b/python/ppci/codegen/graph.py Mon Dec 16 17:58:15 2013 +0100 @@ -34,9 +34,9 @@ def to_dot(self, f): """ Generate graphviz dot representation """ for n in self.nodes: - print('{} [label="{}" shape=box3d];'.format(id(n), n), file=f) + print(' {} [label="{}" shape=box3d];'.format(id(n), n), file=f) for n, m in self.edges: - print('{} -> {};'.format(id(n), id(m)), file=f) + print(' {} -> {};'.format(id(n), id(m)), file=f) class Node:
--- a/python/ppci/codegen/registerallocator.py Mon Dec 16 12:49:24 2013 +0100 +++ b/python/ppci/codegen/registerallocator.py Mon Dec 16 17:58:15 2013 +0100 @@ -1,3 +1,4 @@ +import logging from .flowgraph import FlowGraph from .interferencegraph import InterferenceGraph @@ -21,6 +22,8 @@ - (optional) spill registers - select registers """ + def __init__(self): + self.logger = logging.getLogger('registerallocator') def InitData(self, f): self.f = f @@ -38,7 +41,9 @@ def Build(self): """ 1. Construct interference graph from instruction list """ self.f.cfg = FlowGraph(self.f.instructions) + self.logger.info('Constructed flowgraph', extra={'ra_cfg':self.f.cfg}) self.f.ig = InterferenceGraph(self.f.cfg) + self.logger.info('Constructed interferencegraph', extra={'ra_ig':self.f.ig}) self.Node = self.f.ig.getNode @@ -146,14 +151,12 @@ v = m.src[0] if u is m.dst[0] else m.dst[0] def SelectSpill(self): - # TODO - pass + raise NotImplementedError("Spill is not implemented") 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) + n = self.selectStack.pop(-1) # Start with the last added self.f.ig.addNode(n) takenregs = set(self.color[m] for m in n.Adjecent) okColors = self.regs - takenregs @@ -192,4 +195,3 @@ break # Done! self.AssignColors() self.ApplyColors() -
--- a/python/ppci/common.py Mon Dec 16 12:49:24 2013 +0100 +++ b/python/ppci/common.py Mon Dec 16 17:58:15 2013 +0100 @@ -1,5 +1,11 @@ from collections import namedtuple +import logging +""" + Error handling routines + Diagnostic utils + Source location structures +""" # Token is used in the lexical analyzer: class Token: @@ -27,3 +33,79 @@ SourceRange = namedtuple('SourceRange', ['p1', 'p2']) + + +class CompilerError(Exception): + def __init__(self, msg, loc=None): + self.msg = msg + self.loc = loc + if loc: + assert type(loc) is SourceLocation, \ + '{0} must be SourceLocation'.format(type(loc)) + self.row = loc.row + self.col = loc.col + else: + self.row = self.col = 0 + + def __repr__(self): + return '"{}"'.format(self.msg) + + +class DiagnosticsManager: + def __init__(self): + self.diags = [] + self.sources = {} + self.logger = logging.getLogger('diagnostics') + + def addSource(self, name, src): + self.logger.info('Adding source {}'.format(name)) + self.sources[name] = src + + def addDiag(self, d): + #self.logger.warning(str(d.msg)) + self.diags.append(d) + + def error(self, msg, loc): + self.addDiag(CompilerError(msg, loc)) + + def clear(self): + del self.diags[:] + self.sources.clear() + + def printErrors(self): + if len(self.diags) > 0: + print('{0} Errors'.format(len(self.diags))) + for d in self.diags: + self.printError(d) + + def printError(self, e): + def printLine(row, txt): + print(str(row)+':'+txt) + print('==============') + if not e.loc: + print('Error: {0}'.format(e)) + else: + if e.loc.filename not in self.sources: + print('Error: {0}'.format(e)) + return + print("File: {}".format(e.loc.filename)) + source = self.sources[e.loc.filename] + lines = source.split('\n') + ro, co = e.row, e.col + prerow = ro - 2 + if prerow < 1: + prerow = 1 + afterrow = ro + 3 + if afterrow > len(lines): + afterrow = len(lines) + + # print preceding source lines: + for r in range(prerow, ro): + printLine(r, lines[r-1]) + # print source line containing error: + printLine(ro, lines[ro-1]) + print(' '*(len(str(ro)+':')+co-1) + '^ Error: {0}'.format(e.msg)) + # print trailing source line: + for r in range(ro+1, afterrow+1): + printLine(r, lines[r-1]) + print('==============')
--- a/python/ppci/errors.py Mon Dec 16 12:49:24 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -""" - Error handling routines - Diagnostic utils -""" - -import logging -from . import SourceLocation - - -class CompilerError(Exception): - def __init__(self, msg, loc=None): - self.msg = msg - self.loc = loc - if loc: - assert type(loc) is SourceLocation, \ - '{0} must be SourceLocation'.format(type(loc)) - self.row = loc.row - self.col = loc.col - else: - self.row = self.col = 0 - - def __repr__(self): - return '"{}"'.format(self.msg) - - -class DiagnosticsManager: - def __init__(self): - self.diags = [] - self.sources = {} - self.logger = logging.getLogger('diagnostics') - - def addSource(self, name, src): - self.logger.info('Adding source {}'.format(name)) - self.sources[name] = src - - def addDiag(self, d): - #self.logger.warning(str(d.msg)) - self.diags.append(d) - - def error(self, msg, loc): - self.addDiag(CompilerError(msg, loc)) - - def clear(self): - del self.diags[:] - self.sources.clear() - - def printErrors(self): - if len(self.diags) > 0: - print('{0} Errors'.format(len(self.diags))) - for d in self.diags: - self.printError(d) - - def printError(self, e): - def printLine(row, txt): - print(str(row)+':'+txt) - print('==============') - if not e.loc: - print('Error: {0}'.format(e)) - else: - if e.loc.filename not in self.sources: - print('Error: {0}'.format(e)) - return - print("File: {}".format(e.loc.filename)) - source = self.sources[e.loc.filename] - lines = source.split('\n') - ro, co = e.row, e.col - prerow = ro - 2 - if prerow < 1: - prerow = 1 - afterrow = ro + 3 - if afterrow > len(lines): - afterrow = len(lines) - - # print preceding source lines: - for r in range(prerow, ro): - printLine(r, lines[r-1]) - # print source line containing error: - printLine(ro, lines[ro-1]) - print(' '*(len(str(ro)+':')+co-1) + '^ Error: {0}'.format(e.msg)) - # print trailing source line: - for r in range(ro+1, afterrow+1): - printLine(r, lines[r-1]) - print('==============')
--- a/python/ppci/ir.py Mon Dec 16 12:49:24 2013 +0100 +++ b/python/ppci/ir.py Mon Dec 16 17:58:15 2013 +0100 @@ -166,6 +166,7 @@ if not self.Empty: return self.LastInstruction.Targets return [] + Successors = property(getSuccessors) def getPredecessors(self): @@ -174,6 +175,7 @@ if self in bb.Successors: preds.append(bb) return preds + Predecessors = property(getPredecessors) def precedes(self, other): @@ -326,7 +328,9 @@ class Statement: """ Base class for all instructions. """ - pass + @property + def IsTerminator(self): + return isinstance(self, LastStatement) class Move(Statement):
--- a/python/ppci/irutils.py Mon Dec 16 12:49:24 2013 +0100 +++ b/python/ppci/irutils.py Mon Dec 16 17:58:15 2013 +0100 @@ -3,7 +3,6 @@ Some utilities for ir-code. """ import re -from .ir import Temp, Block, Function, Statement from . import ir def dumpgv(m, outf): @@ -25,18 +24,24 @@ class Writer: + def __init__(self, extra_indent=''): + self.extra_indent = extra_indent + def write(self, ir, f): """ Write ir-code to file f """ - print(ir, file=f) + print('{}{}'.format(self.extra_indent, ir), file=f) for v in ir.Variables: - print(str(v), file=f) - for fn in ir.Functions: - args = ','.join('i32 ' + str(a) for a in fn.arguments) - print('function i32 {}({})'.format(fn.name, args), file=f) - for bb in fn.Blocks: - print(' ' + str(bb), file=f) - for ins in bb.Instructions: - print(' ' + str(ins), file=f) + print('{}{}'.format(self.extra_indent, v), file=f) + for function in ir.Functions: + self.write_function(function, f) + + def write_function(self, fn, f): + args = ','.join('i32 ' + str(a) for a in fn.arguments) + print('{}function i32 {}({})'.format(self.extra_indent, fn.name, args), file=f) + for bb in fn.Blocks: + print('{} {}'.format(self.extra_indent, bb), file=f) + for ins in bb.Instructions: + print('{} {}'.format(self.extra_indent, ins), file=f) class IrParseException(Exception): @@ -194,8 +199,8 @@ self.prepare() def prepare(self): - self.newTemp = NamedClassGenerator('reg', Temp).gen - self.newBlock2 = NamedClassGenerator('block', Block).gen + self.newTemp = NamedClassGenerator('reg', ir.Temp).gen + self.newBlock2 = NamedClassGenerator('block', ir.Block).gen self.bb = None self.m = None self.fn = None @@ -206,7 +211,7 @@ self.m = m def newFunction(self, name): - f = Function(name) + f = ir.Function(name) self.m.add_function(f) return f @@ -227,8 +232,35 @@ self.loc = l def emit(self, i): - assert isinstance(i, Statement) + assert isinstance(i, ir.Statement) i.debugLoc = self.loc if not self.bb: raise Exception('No basic block') self.bb.addInstruction(i) + + +class Verifier: + def verify(self, module): + """ Verifies a module for some sanity """ + assert isinstance(module, ir.Module) + for f in module.Functions: + self.verify_function(f) + + def verify_function(self, function): + for b in function.Blocks: + self.verify_block_termination(b) + + # Now we can build a dominator tree + for b in function.Blocks: + self.verify_block(b) + + def verify_block_termination(self, block): + assert not block.Empty + assert block.LastInstruction.IsTerminator + + def verify_block(self, block): + for instruction in block.Instructions: + self.verify_instruction(instruction) + + def verify_instruction(self, instruction): + pass
--- a/python/zcc.py Mon Dec 16 12:49:24 2013 +0100 +++ b/python/zcc.py Mon Dec 16 17:58:15 2013 +0100 @@ -6,6 +6,7 @@ from ppci.c3 import Builder import ppci +from ppci.irutils import Verifier, Writer from ppci.codegen import CodeGenerator import outstream from utils import HexFile @@ -18,12 +19,64 @@ def logLevel(s): + """ Converts a string to a valid logging level """ numeric_level = getattr(logging, s.upper(), None) if not isinstance(numeric_level, int): raise ValueError('Invalid log level: {}'.format(s)) return numeric_level +class RstFormatter(logging.Formatter): + """ Formatter that tries to create an rst document """ + def __init__(self): + super().__init__(fmt=logformat) + + def format(self, record): + s = super().format(record) + if hasattr(record, 'ircode'): + f = io.StringIO() + print('', file=f) + print('', file=f) + print('.. code::', file=f) + print('', file=f) + Writer(' ').write(record.ircode, f) + print('', file=f) + s += '\n' + f.getvalue() + if hasattr(record, 'irfunc'): + f = io.StringIO() + print('', file=f) + print('', file=f) + print('.. code::', file=f) + print('', file=f) + Writer(' ').write_function(record.irfunc, f) + print('', file=f) + s += '\n' + f.getvalue() + if hasattr(record, 'ppci_frame'): + f = io.StringIO() + frame = record.ppci_frame + print('', file=f) + print('.. code::', file=f) + print('', file=f) + print(' {}'.format(frame.name), file=f) + for i in frame.instructions: + print(' {}'.format(i),file=f) + print('', file=f) + s += '\n' + f.getvalue() + if hasattr(record, 'ra_cfg'): + f = io.StringIO() + print('', file=f) + print('', file=f) + print('.. graphviz::', file=f) + print('', file=f) + print(' digraph G {', file=f) + cfg = record.ra_cfg + cfg.to_dot(f) + print(' }', file=f) + print('', file=f) + s += '\n' + f.getvalue() + return s + + target_list = [target.armtarget] targets = {t.name: t for t in target_list} targetnames = list(targets.keys()) @@ -67,6 +120,7 @@ if not ircode: return # Optimization passes, TODO + Verifier().verify(ircode) if dumpir: f = io.StringIO() @@ -74,7 +128,8 @@ print(f.getvalue()) # Code generation: - logging.info('Starting code generation for {}'.format(ircode)) + d = {'ircode':ircode} + logging.info('Starting code generation for {}'.format(ircode), extra=d) cg.generate(ircode, outs) # TODO: fixup references, do this in another way? outs.backpatch() @@ -84,6 +139,11 @@ def main(args): logging.basicConfig(format=logformat, level=args.log) + #logging.getLogger().addHandler(RstLogHandler()) + fh = logging.FileHandler('log.rst', mode='w') + fh.setFormatter(RstFormatter()) + logging.getLogger().addHandler(fh) + tg = targets[args.target] diag = ppci.DiagnosticsManager() outs = outstream.TextOutputStream()