changeset 323:e9fe6988497c

Used burg for generating expressions
author Windel Bouwman
date Thu, 30 Jan 2014 19:03:24 +0100
parents 44f336460c2a
children ed6d0adaa626
files python/ppci/codegen/graph.py python/ppci/codegen/registerallocator.py python/ppci/ir2tree.py python/ppci/irmach.py python/pyburg.py python/target/arm.brg python/target/armframe.py python/target/arminstructionselector.py python/tree.py python/yacc.py python/zcc.py test/grind.py test/testgraph.py
diffstat 13 files changed, 121 insertions(+), 141 deletions(-) [+]
line wrap: on
line diff
--- a/python/ppci/codegen/graph.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/python/ppci/codegen/graph.py	Thu Jan 30 19:03:24 2014 +0100
@@ -7,9 +7,12 @@
     def __init__(self):
         self.nodes = set()
         self.edges = set()
+        self.adj_map = {}
 
     def addNode(self, n):
         self.nodes.add(n)
+        if n not in self.adj_map:
+            self.adj_map[n] = set()
 
     def delNode(self, n):
         self.nodes.remove(n)
@@ -18,6 +21,8 @@
         """ Add an edge from n to m """
         self.edges.add((n, m))
         self.edges.add((m, n))
+        self.adj_map[n].add(m)
+        self.adj_map[m].add(n)
 
     def hasEdge(self, n, m):
         return (n, m) in self.edges
@@ -28,8 +33,7 @@
 
     def adjecent(self, n):
         """ Return all nodes with edges to n """
-        # TODO: this can be optimized for speed:
-        return set(m for m in self.nodes if self.hasEdge(n, m))
+        return self.adj_map[n] & self.nodes
 
     def to_dot(self, f):
         """ Generate graphviz dot representation """
@@ -57,21 +61,37 @@
 
 
 class DiGraph(Graph):
-    """
-        Directed graph.
-    """
+    """ Directed graph. """
+    def __init__(self):
+        super().__init__()
+        self.suc_map = {}
+        self.pre_map = {}
+
     def addEdge(self, n, m):
-        """ Add an edge from n to m """
+        """ Add a directed edge from n to m """
+        assert n in self.nodes
+        assert m in self.nodes
         self.edges.add((n, m))
+        self.suc_map[n].add(m)
+        self.pre_map[m].add(n)
+        self.adj_map[n].add(m)
+        self.adj_map[m].add(n)
+
+    def addNode(self, n):
+        super().addNode(n)
+        if n not in self.suc_map:
+            self.suc_map[n] = set()
+        if n not in self.pre_map:
+            self.pre_map[n] = set()
 
     def hasEdge(self, n, m):
         return (n, m) in self.edges
 
     def successors(self, n):
-        return set(m for m in self.nodes if self.hasEdge(n, m))
+        return self.suc_map[n] & self.nodes
 
     def predecessors(self, n):
-        return set(m for m in self.nodes if self.hasEdge(m, n))
+        return self.pre_map[n] & self.nodes
 
 
 class DiNode(Node):
--- a/python/ppci/codegen/registerallocator.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/python/ppci/codegen/registerallocator.py	Thu Jan 30 19:03:24 2014 +0100
@@ -165,7 +165,7 @@
                 n.color = self.color[n]
             else:
                 raise NotImplementedError('Spill required here!')
-        
+
     def ApplyColors(self):
         # Remove coalesced moves:
         for mv in self.coalescedMoves:
--- a/python/ppci/ir2tree.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/python/ppci/ir2tree.py	Thu Jan 30 19:03:24 2014 +0100
@@ -1,6 +1,8 @@
 from tree import Tree
 from . import ir
 
+""" Create a tree from ir code. """
+
 f_map = {}    # Mapping from types to tree creation functions
 
 def register(tp):
@@ -35,7 +37,9 @@
 
 @register(ir.Call)
 def call_to_tree(e):
-    return Tree('CALL')
+    t = Tree('CALL')
+    t.value = e
+    return t
 
 def makeTree(ir_node):
     """ Transform an ir node into a tree usable for matching """
--- a/python/ppci/irmach.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/python/ppci/irmach.py	Thu Jan 30 19:03:24 2014 +0100
@@ -11,7 +11,7 @@
 
 
 class Frame:
-    """ 
+    """
         Activation record abstraction. This class contains a flattened 
         function. Instructions are selected and scheduled at this stage.
         Frames differ per machine.
@@ -54,16 +54,12 @@
         """
             Substitutes source, dst and labels in the string
         """
-        x = str(self.assem)
-        for i, s in enumerate(self.src):
-            p = '%s{}'.format(i)
-            x = x.replace(p, str(s))
-        for i, d in enumerate(self.dst):
-            p = '%d{}'.format(i)
-            x = x.replace(p, str(d))
-        for i, j in enumerate(self.jumps):
-            p = '%l{}'.format(i)
-            x = x.replace(p, str(j))
+        if isinstance(self.assem, Instruction):
+            x = str(self.assem)
+        else:
+            cn = self.assem.__name__
+            x = '{}, def={}, use={}, other={}'
+            x = x.format(cn, self.dst, self.src, self.others)
         return x
 
 
--- a/python/pyburg.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/python/pyburg.py	Thu Jan 30 19:03:24 2014 +0100
@@ -245,8 +245,8 @@
         self.print('    def gen(self, tree):')
         self.print('        self.burm_label(tree)')
         self.print('        if not tree.state.has_goal("{}"):'.format(self.system.goal))
-        self.print('          raise Exception("Tree not covered")')
-        self.print('        self.apply_rules(tree, "{}")'.format(self.system.goal))
+        self.print('          raise Exception("Tree {} not covered".format(tree))')
+        self.print('        return self.apply_rules(tree, "{}")'.format(self.system.goal))
 
     def emit_record(self, rule, state_var):
         # TODO: check for rules fullfilled (by not using 999999)
--- a/python/target/arm.brg	Mon Jan 27 19:58:07 2014 +0100
+++ b/python/target/arm.brg	Thu Jan 30 19:03:24 2014 +0100
@@ -1,4 +1,5 @@
 
+from target.basetarget import Label, Comment, Alignment, LabelRef, DebugInfo, Nop
 from target.arminstructions import Orr, Lsl, Str2, Ldr2, Ldr3
 from target.arminstructions import B, Bl, Bgt, Blt, Beq, Bne
 from target.arminstructions import Mov2, Mov3
@@ -6,20 +7,26 @@
 
 %%
 
-%terminal ADDI32 SUBI32 ORI32 SHLI32
+%terminal ADDI32 SUBI32 MULI32
+%terminal ORI32 SHLI32
 %terminal CONSTI32 MEMI32 REGI32 CALL
+%terminal MOVI32
 
 %%
 
+
 reg: ADDI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Add, dst=[d], src=[$1, $2]); return d .)
 reg: SUBI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Sub, dst=[d], src=[$1, $2]); return d .)
-reg: ORI32(reg, reg)  2 (. d = self.newTmp(); self.emit(Orr, dst=[d], src=[$1, $2]); return d .)
-reg: SHLI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Lsl, dst=[d], src=[$1, $2]); return d .)
-reg: MULI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Mul, dst=[d], src=[$1, $2]); return d .)
+reg: ORI32(reg, reg)  2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Orr, dst=[], src=[d, $2]); return d .)
+reg: SHLI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Lsl, dst=[], src=[d, $2]); return d .)
+reg: MULI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Mul, dst=[d], src=[$2, d]); return d .)
 
-reg: CONSTI32         3 (. d = self.newTmp(); self.emit(Sub, dst=[d], src=[$$.value]); return d .)
-reg: MEMI32(reg)      4 (. d = self.newTmp(); self.emit(Ldr2, dst=[d], src=[$1]); return d .)
-reg: REGI32           1 (. pass .)
-reg: CALL             1 (. pass .)
+reg: CONSTI32         3 (. d = self.newTmp(); ln = LabelRef(self.selector.frame.addConstant($$.value)); self.emit(Ldr3, dst=[d], others=[ln]); return d .)
+reg: MEMI32(reg)      4 (. d = self.newTmp(); self.emit(Ldr2, dst=[d], src=[$1], others=[0]); return d .)
+reg: REGI32           1 (. return $$.value .)
+reg: CALL             1 (. return self.selector.munchCall($$.value) .)
 
 
+stmt: MOVI32(MEMI32(addr), reg) 3 (. self.emit(Str2, src=[$1, $2]) .)
+
+addr: reg 2 (. .)
--- a/python/target/armframe.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/python/target/armframe.py	Thu Jan 30 19:03:24 2014 +0100
@@ -61,16 +61,21 @@
         """ Returns prologue instruction sequence """
         pre = [
             Label(self.name),                     # Label indication function
-            Push({LR, R7}),
-            SubSp(SP, SP, Imm7(self.stacksize)),  # Reserve stack space
+            Push({LR, R7})
+            ]
+        if self.stacksize > 0:
+            pre.append(SubSp(SP, SP, Imm7(self.stacksize)))  # Reserve stack space
+        pre += [
             Mov2(R7, SP)                          # Setup frame pointer
             ]
         return pre
 
     def epilogue(self):
         """ Return epilogue sequence for a frame. Adjust frame pointer and add constant pool """
-        post = [
-            AddSp(SP, SP, Imm7(self.stacksize)),
+        post = []
+        if self.stacksize > 0:
+            post.append(AddSp(SP, SP, Imm7(self.stacksize)))
+        post += [
             Pop({PC, R7}),
             Alignment(4)   # Align at 4 bytes
             ]
--- a/python/target/arminstructionselector.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/python/target/arminstructionselector.py	Thu Jan 30 19:03:24 2014 +0100
@@ -15,116 +15,41 @@
 spec_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'arm.brg')
 arm_matcher = pyburg.load_as_module(spec_file)
 
+
 class ArmMatcher(arm_matcher.Matcher):
-    def __init__(self):
+    """ Matcher that derives from a burg spec generated matcher """
+    def __init__(self, selector):
         super().__init__()
-
-    def newTmp(self):
-        pass
-
-    def emit(self, *args, **kwargs):
-        pass
+        self.newTmp = selector.newTmp
+        self.emit = selector.emit
+        self.selector = selector
 
 
 class ArmInstructionSelector(InstructionSelector):
     """ Instruction selector for the arm architecture """
     def __init__(self):
         super().__init__()
-        self.matcher = ArmMatcher()
+        self.matcher = ArmMatcher(self)
 
     def munchExpr(self, e):
-        #t = makeTree(e)
-        #print(t)
-        #return self.matcher.gen(t)
+        # Use BURG system here:
+        t = makeTree(e)
+        return self.matcher.gen(t)
 
-        # TODO: below is obsolete:
-        if isinstance(e, ir.Binop) and e.operation == '+' and \
-            isinstance(e.b, ir.Const) and e.b.value < 8:
-            a = self.munchExpr(e.a)
-            d = self.newTmp()
-            c = Imm3(e.b.value)
-            self.emit(Add2, others=[c], dst=[d], src=[a])
-            return d
-        elif isinstance(e, ir.Binop) and e.operation == '+':
-            a = self.munchExpr(e.a)
-            b = self.munchExpr(e.b)
-            d = self.newTmp()
-            self.emit(Add, dst=[d], src=[a, b])
-            return d
-        elif isinstance(e, ir.Binop) and e.operation == '-' and \
-            isinstance(e.b, ir.Const) and e.b.value < 8:
-            a = self.munchExpr(e.a)
-            d = self.newTmp()
-            c = Imm3(e.b.value)
-            self.emit(Sub2, others=[c], dst=[d], src=[a])
-            return d
-        elif isinstance(e, ir.Binop) and e.operation == '-':
-            a = self.munchExpr(e.a)
-            b = self.munchExpr(e.b)
-            d = self.newTmp()
-            self.emit(Sub, dst=[d], src=[a, b])
-            return d
-        elif isinstance(e, ir.Binop) and e.operation == '|':
-            a = self.munchExpr(e.a)
-            b = self.munchExpr(e.b)
-            d = self.newTmp()
-            self.move(d, a)
-            self.emit(Orr, dst=[], src=[d, b])
-            return d
-        elif isinstance(e, ir.Binop) and e.operation == '<<':
-            a = self.munchExpr(e.a)
-            b = self.munchExpr(e.b)
-            d = self.newTmp()
-            self.move(d, a)
-            self.emit(Lsl, dst=[], src=[d, b]) # TODO: is d a source variable?
-            return d
-        elif isinstance(e, ir.Binop) and e.operation == '*':
-            a = self.munchExpr(e.a)
-            b = self.munchExpr(e.b)
-            d = self.newTmp()
-            self.move(d, a)
-            # this mul instruction has operands swapped:
-            self.emit(Mul, dst=[d], src=[b, d])
-            return d
-        elif isinstance(e, ir.Const) and e.value < 256:
-            d = self.newTmp()
-            self.emit(Mov3, others=[Imm8(e.value)], dst=[d])
-            return d
-        elif isinstance(e, ir.Const) and e.value < (2**31):
-            d = self.newTmp()
-            ln = LabelRef(self.frame.addConstant(e.value))
-            self.emit(Ldr3, others=[ln], dst=[d])
-            return d
-        elif isinstance(e, ir.Mem) and isinstance(e.e, ir.Binop) and \
-                e.e.operation == '+' and isinstance(e.e.b, ir.Const):
-            base = self.munchExpr(e.e.a)
-            d = self.newTmp()
-            c = e.e.b.value
-            self.emit(Ldr2, others=[c], src=[base], dst=[d])
-            return d
-        elif isinstance(e, ir.Mem):
-            # Load from memory
-            base = self.munchExpr(e.e)
-            d = self.newTmp()
-            self.emit(Ldr2, others=[0], src=[base], dst=[d])
-            return d
-        elif isinstance(e, ir.Temp):
-            return e
-        elif isinstance(e, ir.Call):
-            # Move arguments into proper locations:
-            reguses = []
-            for i, a in enumerate(e.arguments):
-                loc = self.frame.argLoc(i)
-                m = ir.Move(loc, a)
-                self.munchStm(m)
-                if isinstance(loc, ir.Temp):
-                    reguses.append(loc)
-            self.emit(Bl(LabelRef(e.f)), src=reguses, dst=[self.frame.rv])
-            d = self.newTmp()
-            self.move(d, self.frame.rv)
-            return d
-        else:
-            raise NotImplementedError('Expr --> {}'.format(e))
+    def munchCall(self, e):
+        """ Generate code for call sequence """
+        # Move arguments into proper locations:
+        reguses = []
+        for i, a in enumerate(e.arguments):
+            loc = self.frame.argLoc(i)
+            m = ir.Move(loc, a)
+            self.munchStm(m)
+            if isinstance(loc, ir.Temp):
+                reguses.append(loc)
+        self.emit(Bl(LabelRef(e.f)), src=reguses, dst=[self.frame.rv])
+        d = self.newTmp()
+        self.move(d, self.frame.rv)
+        return d
 
     def munchStm(self, s):
         if isinstance(s, ir.Terminator):
--- a/python/tree.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/python/tree.py	Thu Jan 30 19:03:24 2014 +0100
@@ -53,5 +53,5 @@
     def apply_rules(self, tree, goal):
         rule = tree.state.get_rule(goal)
         results = [self.apply_rules(kid_tree, kid_goal)
-         for kid_tree, kid_goal in zip(self.kids(tree, rule), self.nts(rule))]
-        self.pat_f[rule](tree, *results)
+          for kid_tree, kid_goal in zip(self.kids(tree, rule), self.nts(rule))]
+        return self.pat_f[rule](tree, *results)
--- a/python/yacc.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/python/yacc.py	Thu Jan 30 19:03:24 2014 +0100
@@ -41,6 +41,7 @@
 import datetime
 import types
 import io
+import logging
 from pyyacc import Grammar, print_grammar
 
 
@@ -201,12 +202,13 @@
 class XaccGenerator:
     """ Generator that writes generated parser to file """
     def __init__(self):
-        pass
+        self.logger = logging.getLogger('yacc')
 
     def generate(self, grammar, headers, output_file):
         self.output_file = output_file
         self.grammar = grammar
         self.headers = headers
+        self.logger.info('Generating parser for grammar {}'.format(grammar))
         self.action_table, self.goto_table = grammar.doGenerate()
         self.generate_python_script()
 
--- a/python/zcc.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/python/zcc.py	Thu Jan 30 19:03:24 2014 +0100
@@ -11,6 +11,7 @@
 import outstream
 from utils import HexFile
 import target
+from target.target_list import target_list
 from ppci import irutils
 import io
 from ppci.transform import CleanPass, RemoveAddZero
@@ -112,7 +113,7 @@
         return s
 
 
-targets = {t.name: t for t in target.target_list.target_list}
+targets = {t.name: t for t in target_list}
 targetnames = list(targets.keys())
 
 # Parse arguments:
--- a/test/grind.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/test/grind.py	Thu Jan 30 19:03:24 2014 +0100
@@ -6,9 +6,16 @@
 import sys
 import os
 
+p = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'python')
+sys.path.insert(0, p)
+
 if __name__ == '__main__':
     suite = unittest.TestLoader().discover('.')
     def runtests():
         unittest.TextTestRunner().run(suite)
     #s = cProfile.run('runtests()',sort='cumtime')
-    s = cProfile.run('runtests()',sort='tottime')
+    p = cProfile.Profile()
+    s = p.run('runtests()')
+    stats = pstats.Stats(p)
+    stats.sort_stats('tottime')
+    stats.print_stats(.1)
--- a/test/testgraph.py	Mon Jan 27 19:58:07 2014 +0100
+++ b/test/testgraph.py	Thu Jan 30 19:03:24 2014 +0100
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 
 import unittest
-from ppci.codegen.graph import Graph, Node
+from ppci.codegen.graph import Graph, Node, DiGraph, DiNode
 from ppci.codegen.interferencegraph import InterferenceGraph
 from ppci.codegen.flowgraph import FlowGraph
 from ppci import ir
@@ -39,7 +39,20 @@
 
 
 class DigraphTestCase(unittest.TestCase):
-    pass
+    def testSuccessor(self):
+        g = DiGraph()
+        a = DiNode(g)
+        b = DiNode(g)
+        c = DiNode(g)
+        g.addNode(a)
+        g.addNode(b)
+        g.addNode(c)
+        g.addEdge(a, b)
+        g.addEdge(b, c)
+        self.assertEqual({b}, a.Succ)
+        self.assertEqual({b}, c.Pred)
+        g.delNode(c)
+        self.assertEqual(set(), b.Succ)
 
 
 class InterferenceGraphTestCase(unittest.TestCase):