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)
+