changeset 239:63bb40758066

added check
author Windel Bouwman
date Mon, 22 Jul 2013 17:57:25 +0200
parents 90637d1bbfad
children 6259856841a0
files python/ir/basicblock.py python/ir/function.py python/ir/instruction.py python/ir/module.py python/transform.py python/zcc.py
diffstat 6 files changed, 176 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/python/ir/basicblock.py	Sat Jul 20 13:18:04 2013 +0200
+++ b/python/ir/basicblock.py	Mon Jul 22 17:57:25 2013 +0200
@@ -2,25 +2,27 @@
 class BasicBlock:
     """ Uninterrupted sequence of instructions. """
     def __init__(self, name):
-      self.name = name
-      self.instructions = []
+        self.name = name
+        self.instructions = []
+
     def __repr__(self):
-      return 'BasicBlock {0}'.format(self.name)
+        return 'BasicBlock {0}'.format(self.name)
+
     def addInstruction(self, i):
-      i.parent = self
-      self.instructions.append(i)
+        i.parent = self
+        self.instructions.append(i)
     addIns = addInstruction
 
     def replaceInstruction(self, i1, i2):
-      idx = self.instructions.index(i1)
-      i1.parent = None
-      i1.delete()
-      i2.parent = self
-      self.instructions[idx] = i2
+        idx = self.instructions.index(i1)
+        i1.parent = None
+        i1.delete()
+        i2.parent = self
+        self.instructions[idx] = i2
 
     def removeInstruction(self, i):
-      i.parent = None
-      self.instructions.remove(i)
+        i.parent = None
+        self.instructions.remove(i)
 
     def getInstructions(self):
         return self.instructions
@@ -34,14 +36,16 @@
     Instructions = property(getInstructions, setInstructions)
 
     def getLastIns(self):
-      return self.instructions[-1]
+        return self.instructions[-1]
     LastInstruction = property(getLastIns)
+
     @property
     def Empty(self):
-      return len(self.instructions) == 0
+        return len(self.instructions) == 0
+
     @property
     def FirstInstruction(self):
-      return self.instructions[0]
+        return self.instructions[0]
     FirstIns = FirstInstruction
 
     def getSuccessors(self):
@@ -52,10 +56,14 @@
     Successors = property(getSuccessors)
 
     def getPredecessors(self):
-      preds = []
-      for bb in self.parent.BasicBlocks:
-         if self in bb.Successors:
-            preds.append(bb)
-      return preds
+        preds = []
+        for bb in self.parent.BasicBlocks:
+            if self in bb.Successors:
+                preds.append(bb)
+        return preds
     Predecessors = property(getPredecessors)
 
+    def check(self):
+        for ins in self.Instructions:
+            ins.check()
+
--- a/python/ir/function.py	Sat Jul 20 13:18:04 2013 +0200
+++ b/python/ir/function.py	Mon Jul 22 17:57:25 2013 +0200
@@ -29,4 +29,6 @@
 
     BasicBlocks = property(getBBs)
 
-
+    def check(self):
+        for bb in self.BasicBlocks:
+            bb.check()
--- a/python/ir/instruction.py	Sat Jul 20 13:18:04 2013 +0200
+++ b/python/ir/instruction.py	Mon Jul 22 17:57:25 2013 +0200
@@ -5,58 +5,116 @@
 class Value:
     """ Temporary SSA value (value that is assigned only once! """
     def __init__(self, name):
-      # TODO: add typing? for now only handle integers
-      self.name = name
-      self.used_by = []
+        # TODO: add typing? for now only handle integers
+        self.name = name
+        self.used_by = []
+        self.Setter = None
 
     def __repr__(self):
         return '{0}'.format(self.name) # + str(self.IsUsed)
 
     @property
     def IsUsed(self):
-      return len(self.used_by) > 0
+        return len(self.used_by) > 0
+
+    def onlyUsedInBlock(self, bb):
+        for use in self.used_by:
+            ins = use
+            if ins.parent != bb:
+                return False
+        return True
+
 
 class Variable(Value):
     pass
 
+
 class Use:
-   def __init__(self, user, val):
-      self.user = user
-      assert isinstance(val, Value)
-      self.val = val
-      self.val.used_by.append(self.user)
-   def delete(self):
-      self.val.used_by.remove(self.user)
+    def __init__(self, user, val):
+        self.user = user
+        assert isinstance(val, Value)
+        self.val = val
+        self.val.used_by.append(self.user)
+
+    def delete(self):
+        self.val.used_by.remove(self.user)
+
 
 class Instruction:
-   """ Base class for all instructions. """
-   def __init__(self):
-      # live variables at this node:
-      self.live_in = set()
-      self.live_out = set()
-      # What variables this instruction uses and defines:
-      self.defs = []
-      self.uses = []
-   def delete(self):
+    """ Base class for all instructions. """
+    def __init__(self):
+        # live variables at this node:
+        self.live_in = set()
+        self.live_out = set()
+        # What variables this instruction uses and defines:
+        self.defs = []
+        self.uses = []
+    def delete(self):
         while self.uses:
             use = self.uses.pop()
             use.delete()
-   def addUse(self, val):
-      self.uses.append(Use(self, val))
-   def addDef(self, v):
-      self.defs.append(v)
-   def getParent(self):
-      return self.parent
-   def setParent(self, p):
-      self.parent = p
-   Parent = property(getParent, setParent)
+        while self.defs:
+            d = self.defs.pop()
+            d.Setter = None
+
+    def addUse(self, val):
+        self.uses.append(Use(self, val))
+
+    def removeUse(self, val):
+        for u in self.uses:
+            if u.val is val:
+                theUse = u
+        theUse.delete()
+        self.uses.remove(theUse)
+
+    def addDef(self, v):
+        self.defs.append(v)
+        assert v.Setter == None
+        v.Setter = self
+
+    def removeDef(self, v):
+        assert v.Setter is self
+        v.Setter = None
+        self.defs.remove(v)
+
+    def getParent(self):
+        return self.parent
+
+    def setParent(self, p):
+        self.parent = p
+    Parent = property(getParent, setParent)
+
+    def replaceValue(self, old, new):
+        raise NotImplementedError()
+
+    @property
+    def Position(self):
+        return self.parent.Instructions.index(self)
+
+    def check(self):
+        # Check that the variables defined by this instruction 
+        # are only used in the same block
+        for v in self.defs:
+            assert v.Setter is self
+            for ub in v.used_by:
+                assert ub.parent == self.parent
+
+        # Check that variables used are defined earlier:
+        for u in self.uses:
+            v = u.val
+            assert self.Position > v.Setter.Position
+
+
+
 
 class Terminator(Instruction):
-   @property
-   def Targets(self):
-      return self.getTargets()
-   def changeTarget(self, tfrom, tto):
-      pass
+    @property
+    def Targets(self):
+        return self.getTargets()
+
+    def changeTarget(self, tfrom, tto):
+        pass
+
 
 # Function calling:
 class Call(Instruction):
@@ -112,7 +170,7 @@
       self.value = value
       self.addDef(target)
    def __repr__(self):
-      return '{0} = {1}'.format(self.target, self.value)
+      return '{} = {}'.format(self.target, self.value)
 
 # Data operations
 class BinaryOperator(Instruction):
@@ -129,10 +187,23 @@
       self.addUse(value1)
       self.addUse(value2)
       self.operation = operation
+
     def __repr__(self):
         a, b = self.value1, self.value2
         return '{} = {} {} {}'.format(self.result, a, self.operation, b)
 
+    def replaceValue(self, old, new):
+        if old is self.value1:
+            self.value1 = new
+        elif old is self.value2:
+            self.value2 = new
+        elif old is self.result:
+            self.result = new
+        else:
+            raise Exception()
+        self.removeUse(old)
+        self.addUse(new)
+
 # Memory functions:
 class Load(Instruction):
    def __init__(self, location, value):
--- a/python/ir/module.py	Sat Jul 20 13:18:04 2013 +0200
+++ b/python/ir/module.py	Mon Jul 22 17:57:25 2013 +0200
@@ -78,10 +78,13 @@
 
    # Analysis functions:
    def check(self):
-      """ Perform sanity check on module """
-      for i in self.Instructions:
+        """ Perform sanity check on module """
+        for i in self.Instructions:
          for t in i.defs:
             assert type(t) is Value, "def must be Value, not {0}".format(type(t))
          for t in i.uses:
             assert type(t) is Use, "use must be Value, not {0}".format(type(t))
+        for f in self.Functions:
+            f.check()
+            
 
--- a/python/transform.py	Sat Jul 20 13:18:04 2013 +0200
+++ b/python/transform.py	Mon Jul 22 17:57:25 2013 +0200
@@ -51,6 +51,7 @@
                vr = None
                return
             self.constMap[i.result] = vr
+            i.removeDef(i.result)
             i2 = ImmLoad(i.result, vr)
             i.Parent.replaceInstruction(i, i2)
 
@@ -97,6 +98,27 @@
          return False
       bb.Instructions = list(filter(instructionUsed, bb.Instructions))
 
+
+class SameImmLoadDeletePass(BasicBlockPass):
+    def onBasicBlock(self, bb):
+        constMap = {}
+        imms = filter(lambda i: isinstance(i, ImmLoad), bb.Instructions)
+        for ins in list(imms):
+            if ins.value in constMap:
+                # remove this immload and update all references to the target
+                t_old = ins.target
+                if not t_old.onlyUsedInBlock(bb):
+                    continue
+                # update all references:
+                t_new = constMap[ins.value]
+                print('Replace {} with {}'.format(t_old, t_new))
+                for use in t_old.used_by:
+                    use.replaceValue(t_old, t_new)
+                bb.removeInstruction(ins)
+            else:
+                constMap[ins.value] = ins.target
+            
+
 def isAllocPromotable(allocinst):
    # Check if alloc value is only used by load and store operations.
    assert type(allocinst) is Alloc
@@ -109,21 +131,20 @@
 
 class CleanPass(FunctionPass):
     def onFunction(self, f):
-      bbs = list(f.BasicBlocks)
-      for bb in bbs:
+        bbs = list(f.BasicBlocks)
+        for bb in bbs:
          # TODO: determine check for 'empty'
 
          # If a block only contains a branch, it can be removed:
-         if len(bb.Instructions) == 1:
+         if len(bb.Instructions) == 1 and type(bb.LastInstruction) is Branch:
             # This block is empty.
             # find predecessors of this block and replace this block reference with the jumped reference.
             ins = bb.LastInstruction
-            if type(ins) is Branch:
-                preds = bb.Predecessors
-                if bb in preds:
+            preds = bb.Predecessors
+            if bb in preds:
                     # Do not remove if preceeded by itself
                     pass
-                else:
+            else:
                     for pred in bb.Predecessors:
                           pred.LastInstruction.changeTarget(bb, ins.target)
                     f.removeBasicBlock(bb)
--- a/python/zcc.py	Sat Jul 20 13:18:04 2013 +0200
+++ b/python/zcc.py	Mon Jul 22 17:57:25 2013 +0200
@@ -3,7 +3,7 @@
 import sys, argparse
 import c3, ppci, codegen
 import codegenarm
-from transform import CleanPass
+from transform import CleanPass, SameImmLoadDeletePass
 import outstream
 
 # Parse arguments:
@@ -26,8 +26,13 @@
         sys.exit(1)
 
     # Optimization passes:
+    ircode.check()
     cp = CleanPass()
     cp.run(ircode)
+    ircode.check()
+    sidp = SameImmLoadDeletePass()
+    sidp.run(ircode)
+    ircode.check()
 
     if args.dumpir:
         ircode.dump()