view python/ir/module.py @ 171:3eb9b9e2958d

Improved IR code
author Windel Bouwman
date Wed, 03 Apr 2013 22:20:20 +0200
parents 4348da5ca307
children 5a7d37d615ee
line wrap: on
line source

# IR-Structures:
from .instruction import *
from .basicblock import BasicBlock

class Module:
   """ Main container for a piece of code. """
   def __init__(self, name):
      self.name = name
      self.bbs = []
   def __repr__(self):
      return 'IR-module [{0}]'.format(self.name)
   def getInstructions(self):
      ins = []
      for bb in self.bbs:
         ins += bb.Instructions
      return ins
   Instructions = property(getInstructions)
   def addBB(self, bb):
      self.bbs.append(bb)
   def getBBs(self):
      return self.bbs
   BasicBlocks = property(getBBs)
   def dump(self):
      print(self)
      for i in self.Instructions:
         print(i, 'live vars:', list(i.live_in), 'uses', list(i.uses), 'defs', list(i.defs))
      print('END')
   def dumpgv(self, outf):
      outf.write('digraph G \n{\n')
      for i in self.Instructions:
         outf.write('{0} [label="{1}"];\n'.format(id(i), i))
         for succ in i.succ:
            outf.write('"{0}" -> "{1}" [label="{2}"];\n'.format(id(i), id(succ), succ.live_in))
      outf.write('}\n')

   # Analysis functions:
   def check(self):
      """ 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 Value, "use must be Value, not {0}".format(type(t))
   def analyze(self):
      # Determine pred and succ:
      def link(a, b):
         a.succ.add(b)
         b.pred.add(a)
      for bb in self.bbs:
         if not bb.Empty:
            if len(bb.Instructions) > 1:
               for i1, i2 in zip(bb.Instructions[:-1], bb.Instructions[1:]):
                  link(i1, i2)
            else:
               print('Only 1 long!', bb, bb.Instructions)
            if type(bb.LastIns) is ConditionalBranch:
               link(bb.LastIns, bb.LastIns.lab1.FirstIns)
               link(bb.LastIns, bb.LastIns.lab2.FirstIns)
            if type(bb.LastIns) is Branch:
               link(bb.LastIns, bb.LastIns.target.FirstIns)
         else:
            print('Empty!', bb)
      # We now have cfg

      # Determine liveness:
      for i in self.Instructions:
         i.live_in = set()
         i.live_out = set()
      for z in range(50):
         # TODO iterate until converge
         for i in self.Instructions:
            lo_mk = i.live_out.difference(i.defs)
            i.live_in = i.uses.union(lo_mk)
            lo = set()
            for s in i.succ:
               lo = lo.union(s.live_in)
            i.live_out = lo
   def constantProp(self):
      """ Constant propagation. Pre-calculate constant values """
      for i in self.Instructions:
         if type(i) is ImmLoad:
            i.target.constval = i.value
         elif type(i) is BinaryOperator:
            a = i.value1
            b = i.value2
            if i.value1.constval and i.value2.constval:
               op = i.operation
               if op == '+':
                  i.result.constval = a + b
               else:
                  raise NotImplementedError(op)
            else:
               i.result.constval = None

   def registerAllocate(self, regs):
      print(regs)
      allVals = []
      # construct interference:
      for i in self.Instructions:
         for v in i.live_in:
            allVals.append(v)
            for v2 in i.live_in:
               if v != v2:
                  v.interferes.add(v2)
      # assign random registers:
      print(allVals)
      regs = set(regs)
      for v in allVals:
         takenregs = set([iv.reg for iv in v.interferes])
         r2 = list(regs.difference(takenregs))
         # Pick next available:
         v.reg = r2[0]