Mercurial > lcfOS
changeset 355:c2ddc8a36f5e
Enabled optimization
author | Windel Bouwman |
---|---|
date | Fri, 14 Mar 2014 10:30:13 +0100 |
parents | 5477e499b039 |
children | 52492b304adf |
files | kernel/arm.yaml kernel/io.c3 kernel/kernel.c3 kernel/thumb.yaml python/ppci/codegen/codegen.py python/ppci/codegen/dag.py python/ppci/ir2tree.py python/ppci/recipe.py python/ppci/transform.py python/zcc.py test/testc3.py test/testemulation.py test/testsamples.py |
diffstat | 13 files changed, 215 insertions(+), 139 deletions(-) [+] |
line wrap: on
line diff
--- a/kernel/arm.yaml Thu Mar 13 18:59:06 2014 +0100 +++ b/kernel/arm.yaml Fri Mar 14 10:30:13 2014 +0100 @@ -5,15 +5,13 @@ source: startup_a9.asm machine: arm - compile: - sources: [kernel.c3, syscall.c3, schedule.c3, 'arch/vexpressA9.c3'] + sources: [kernel.c3, syscall.c3, schedule.c3, 'arch/vexpressA9.c3', io.c3] includes: [memory.c3, process.c3] machine: arm - output: kernel.elf2 - compile: sources: [memory.c3, process.c3] - includes: [kernel.c3, syscall.c3, schedule.c3, 'arch/vexpressA9.c3'] + includes: [kernel.c3, syscall.c3, schedule.c3, 'arch/vexpressA9.c3', io.c3] machine: arm - output: kernel.elf2 layout: code: 0x60010000 data: 0x60020000
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/io.c3 Fri Mar 14 10:30:13 2014 +0100 @@ -0,0 +1,24 @@ +module io; +import arch; + +function void print(string txt) +{ + var int i; + i = 0; + + while (i < txt->len) + { + arch.putc(cast<int>(txt->txt[i])); + i = i + 1; + } +} + +function void print_int(int i) +{ + // int txt[20]; + while (i != 0) + { + arch.putc(1); + } +} +
--- a/kernel/kernel.c3 Thu Mar 13 18:59:06 2014 +0100 +++ b/kernel/kernel.c3 Fri Mar 14 10:30:13 2014 +0100 @@ -4,13 +4,14 @@ import process; import scheduler; import arch; +import io; // Main entry point of the kernel: function void start() { arch.init(); - print("Welcome to lcfos!"); + io.print("Welcome to lcfos!"); process.init(); //memory:init(); @@ -21,18 +22,6 @@ while(true) {} } -function void print(string txt) -{ - var int i; - i = 0; - - while (i < txt->len) - { - arch.putc(cast<int>(txt->txt[i])); - i = i + 1; - } -} - function void panic() { arch.halt();
--- a/kernel/thumb.yaml Thu Mar 13 18:59:06 2014 +0100 +++ b/kernel/thumb.yaml Fri Mar 14 10:30:13 2014 +0100 @@ -8,12 +8,10 @@ sources: [kernel.c3, syscall.c3, schedule.c3, 'arch/cortexm3.c3'] includes: [memory.c3, process.c3] machine: thumb - output: kernel.elf2 - compile: sources: [memory.c3, process.c3] includes: [kernel.c3, syscall.c3, schedule.c3, 'arch/cortexm3.c3'] machine: thumb - output: kernel.elf2 layout: code: 0x10000 data: 0x20000000
--- a/python/ppci/codegen/codegen.py Thu Mar 13 18:59:06 2014 +0100 +++ b/python/ppci/codegen/codegen.py Fri Mar 14 10:30:13 2014 +0100 @@ -1,5 +1,6 @@ from .. import ir from ..irutils import Verifier +from ..transform import RemoveAddZero from ..target import Target from .. import CompilerError from .canon import make as canonicalize @@ -27,6 +28,7 @@ # Canonicalize the intermediate language: canonicalize(irfunc, frame) + RemoveAddZero().run(irfunc) self.logger.debug('after canonicalize', extra={'irfunc': irfunc}) self.verifier.verify_function(irfunc) self.ins_sel.munchFunction(irfunc, frame)
--- a/python/ppci/codegen/dag.py Thu Mar 13 18:59:06 2014 +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 -
--- a/python/ppci/ir2tree.py Thu Mar 13 18:59:06 2014 +0100 +++ b/python/ppci/ir2tree.py Fri Mar 14 10:30:13 2014 +0100 @@ -30,7 +30,6 @@ if type(e.value) is bytes: t = Tree('CONSTDATA') t.value = e.value - print(t.value) return t elif type(e.value) is int: t = Tree('CONSTI32')
--- a/python/ppci/recipe.py Thu Mar 13 18:59:06 2014 +0100 +++ b/python/ppci/recipe.py Fri Mar 14 10:30:13 2014 +0100 @@ -12,19 +12,19 @@ class RecipeLoader: """ Loads a recipe into a runner from a dictionary or file """ - def __init__(self): + def __init__(self, runner): + self.runner = runner self.directive_handlers = {} for a in dir(self): if a.startswith('handle_'): f = getattr(self, a) self.directive_handlers[a[7:]] = f - def load_file(self, recipe_file, runner): - """ Loads a recipe dictionary into a task runner """ + def load_file(self, recipe_file): + """ Loads a recipe dictionary from file """ self.recipe_dir = os.path.abspath(os.path.dirname(recipe_file)) with open(recipe_file, 'r') as f: recipe = yaml.load(f) - self.runner = runner self.load_dict(recipe) def relpath(self, filename):
--- a/python/ppci/transform.py Thu Mar 13 18:59:06 2014 +0100 +++ b/python/ppci/transform.py Fri Mar 14 10:30:13 2014 +0100 @@ -10,12 +10,17 @@ def __init__(self): self.logger = logging.getLogger(str(self.__class__.__name__)) - def run(self, ir): + def run(self, ir_module): """ Main entry point for the pass """ self.logger.debug('Running pass {}'.format(self.__class__.__name__)) self.prepare() - for f in ir.Functions: - self.onFunction(f) + if isinstance(ir_module, ir.Module): + for f in ir_module.Functions: + self.onFunction(f) + elif isinstance(ir_module, ir.Function): + self.onFunction(ir_module) + else: + raise Exception() def onFunction(self, f): """ Override this virtual method """ @@ -117,11 +122,59 @@ self.logger.debug('removing {}'.format(i)) bb.removeInstruction(i) -class RemoveAddZero(InstructionPass): + +child_nodes = {} +child_nodes[ir.Binop] = ['a', 'b'] +child_nodes[ir.Const] = [] +child_nodes[ir.Temp] = [] +child_nodes[ir.Exp] = ['e'] +child_nodes[ir.Mem] = ['e'] +child_nodes[ir.Addr] = ['e'] +child_nodes[ir.LocalVariable] = [] +child_nodes[ir.Parameter] = [] +child_nodes[ir.Jump] = [] +child_nodes[ir.Terminator] = [] +child_nodes[ir.Call] = ['arguments'] +child_nodes[ir.CJump] = ['a', 'b'] +child_nodes[ir.Move] = ['src', 'dst'] + + +def apply_function(x, f): + """ Recursively apply function """ + # Handle list: + if type(x) is list: + for i in range(len(x)): + x[i] = apply_function(x[i], f) + return x + + # Normal node: + for child in child_nodes[type(x)]: + v = getattr(x, child) + v = apply_function(v, f) + assert not (v is None) + setattr(x, child, v) + # Apply function! + return f(x) + + +class ExpressionFixer(InstructionPass): def onInstruction(self, i): - if type(i) is ir.Binop: - print(i) - pass + apply_function(i, self.grok) + + +class RemoveAddZero(ExpressionFixer): + def grok(self, v): + if type(v) is ir.Binop: + if v.operation == '+': + if type(v.b) is ir.Const and v.b.value == 0: + self.logger.debug('Folding {} to {}'.format(v, v.a)) + return v.a + elif v.operation == '*': + if type(v.b) is ir.Const and v.b.value == 1: + self.logger.debug('Multiple 1 {} to {}'.format(v, v.a)) + return v.a + return v + class CleanPass(FunctionPass): def onFunction(self, f):
--- a/python/zcc.py Thu Mar 13 18:59:06 2014 +0100 +++ b/python/zcc.py Fri Mar 14 10:30:13 2014 +0100 @@ -70,8 +70,8 @@ output = ObjectFile() runner.add_task(Compile(args.source, args.imp, tg, output)) elif args.command == 'recipe': - recipe_loader = RecipeLoader() - recipe_loader.load_file(args.recipe_file, runner) + recipe_loader = RecipeLoader(runner) + recipe_loader.load_file(args.recipe_file) else: raise NotImplementedError('Invalid option')
--- a/test/testc3.py Thu Mar 13 18:59:06 2014 +0100 +++ b/test/testc3.py Fri Mar 14 10:30:13 2014 +0100 @@ -1,4 +1,5 @@ import unittest +import logging import io from ppci.c3 import Builder, Lexer from ppci.target import SimpleTarget @@ -44,6 +45,9 @@ self.diag = ppci.DiagnosticsManager() self.builder = Builder(self.diag, SimpleTarget()) self.diag.clear() + # Add a null logging handler to disable warning log messages: + nh = logging.NullHandler() + logging.getLogger().addHandler(nh) def makeFileList(self, snippet): """ Try to make a list with opened files """ @@ -382,6 +386,17 @@ """ self.expectErrors(snippet, [7]) + @unittest.skip('TODO') + def testArrayFail3(self): + snippet = """ + module testarray; + function void t() + { + int c[20]; + } + """ + self.expectErrors(snippet, [7]) + def testStructCall(self): snippet = """ module teststruct1;
--- a/test/testemulation.py Thu Mar 13 18:59:06 2014 +0100 +++ b/test/testemulation.py Fri Mar 14 10:30:13 2014 +0100 @@ -10,6 +10,51 @@ # Store testdir for safe switch back to directory: testdir = os.path.dirname(os.path.abspath(__file__)) +def runQemu(kernel, machine='lm3s811evb'): + """ Runs qemu on a given kernel file on some machine """ + args = ['qemu-system-arm', '-M', machine, '-m', '16M', + '-nographic', '-kernel', kernel, '-monitor', + 'unix:qemucontrol.sock,server', + '-serial', 'unix:qemuserial.sock,server'] + p = subprocess.Popen(args, stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) + + # Give process some time to boot: + time.sleep(0.5) + + # Connect to the control socket: + qemu_control = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + qemu_control.connect('qemucontrol.sock') + + time.sleep(0.5) + + # Now connect to the serial output: + qemu_serial = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + qemu_serial.connect('qemuserial.sock') + + time.sleep(0.5) + + qemu_serial.settimeout(0.2) + + # Receive all data: + data = bytearray() + for i in range(40): + try: + data += qemu_serial.recv(1) + except socket.timeout as e: + break + data = data.decode('ascii') + # print(data) + + # Send quit command: + qemu_control.send("quit\n".encode('ascii')) + p.wait(timeout=3) + qemu_control.close() + qemu_serial.close() + + # Check that output was correct: + return data + class EmulationTestCase(ZccBaseTestCase): """ Tests the compiler driver """ @@ -17,69 +62,25 @@ if 'TESTEMU' not in os.environ: self.skipTest('Not running emulation tests') - def runQemu(self, kernel, machine='lm3s811evb'): - args = ['qemu-system-arm', '-M', machine, '-m', '16M', - '-nographic', '-kernel', kernel, '-monitor', - 'unix:qemucontrol.sock,server', - '-serial', 'unix:qemuserial.sock,server'] - p = subprocess.Popen(args, stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL) - - # Give process some time to boot: - time.sleep(0.5) - - # Connect to the control socket: - qemu_control = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - qemu_control.connect('qemucontrol.sock') - - time.sleep(0.5) - - # Now connect to the serial output: - qemu_serial = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - qemu_serial.connect('qemuserial.sock') - - time.sleep(0.5) - - qemu_serial.settimeout(0.2) - - # Receive all data: - data = bytearray() - for i in range(40): - try: - data += qemu_serial.recv(1) - except socket.timeout as e: - break - data = data.decode('ascii') - # print(data) - - # Send quit command: - qemu_control.send("quit\n".encode('ascii')) - p.wait(timeout=3) - qemu_control.close() - qemu_serial.close() - - # Check that output was correct: - return data - def testM3Bare(self): """ Build bare m3 binary and emulate it """ recipe = os.path.join(testdir, 'm3_bare', 'recipe.yaml') self.buildRecipe(recipe) - data = self.runQemu('m3_bare/bare.bin') + data = runQemu('m3_bare/bare.bin') self.assertEqual('Hello worle', data) def testA9Bare(self): """ Build vexpress cortex-A9 binary and emulate it """ recipe = os.path.join(testdir, '..', 'examples', 'qemu_a9_hello', 'recipe.yaml') self.buildRecipe(recipe) - data = self.runQemu('../examples/qemu_a9_hello/hello.bin', machine='vexpress-a9') + data = runQemu('../examples/qemu_a9_hello/hello.bin', machine='vexpress-a9') self.assertEqual('Hello worle', data) def testKernelVexpressA9(self): """ Build vexpress cortex-A9 binary and emulate it """ recipe = os.path.join(testdir, '..', 'kernel', 'arm.yaml') self.buildRecipe(recipe) - data = self.runQemu('../kernel/kernel_arm.bin', machine='vexpress-a9') + data = runQemu('../kernel/kernel_arm.bin', machine='vexpress-a9') self.assertEqual('Welcome to lcfos!', data)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testsamples.py Fri Mar 14 10:30:13 2014 +0100 @@ -0,0 +1,56 @@ +import unittest +from testemulation import runQemu +from ppci.recipe import RecipeLoader +from ppci.tasks import TaskRunner + + +class TestSamples: + def testPrint(self): + snippet = """ + module testsample; + import io; + function void start() + { + io.print("Hello world"); + } + """ + self.do(snippet, "Hello world") + + def testForLoopPrint(self): + snippet = """ + module testsample; + import io; + function void start() + { + var int i; + for (i=0;i<10;i++) + { + io.print("A"); + } + } + """ + self.do(snippet, "AAAAAAAAAA") + + +class TestSamplesOnVexpress(unittest.TestCase, TestSamples): + def do(self, src, expected_output): + runner = TaskRunner() + recipe_loader = RecipeLoader(runner) + return + # TODO: improve recipe loading?? + recipe_loader.load_dict({ + 'link': { + 'inputs': [ + ], + 'layout': { + 'code': 0x60010000, + 'data': 0x60020000 + }, + 'output': 'tst.bin' + } + }) + runner.add_task(Compile()) + runner.run_tasks() + res = runQemu() + self.assertEqual(expected_output, res) +