view python/ir/instruction.py @ 219:1fa3e0050b49

Expanded ad hoc code generator
author Windel Bouwman
date Sat, 06 Jul 2013 12:38:09 +0200
parents 07bfea4c1ed7
children 848c4b15fd0b
line wrap: on
line source

from .basicblock import BasicBlock
from .function import Function


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 = []
   def __repr__(self):
      return '{0}'.format(self.name) # + str(self.IsUsed)
   @property
   def IsUsed(self):
      return len(self.used_by) > 0

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)

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

class Terminator(Instruction):
   @property
   def Targets(self):
      return self.getTargets()
   def changeTarget(self, tfrom, tto):
      pass

# Function calling:
class Call(Instruction):
   def __init__(self, callee, arguments, result=None):
      super().__init__()
      self.callee = callee
      assert type(callee) is Function
      self.arguments = arguments
      for arg in arguments:
         assert type(arg) is Value
         self.addUse(arg)
      self.result = result
      if result:
         assert type(result) is Value
         self.addDef(result)
   def __repr__(self):
      if self.result:
         pfx = '{0} = '.format(self.result)
      else:
         pfx = ''
      args = ','.join([str(arg) for arg in self.arguments])
      return pfx + '{0}({1})'.format(self.callee.name, args)

class Return(Terminator):
   def __init__(self, value=None):
      super().__init__()
      self.value = value
      if value:
         self.addUse(value)
   def __repr__(self):
      if self.value:
         return 'Return {0}'.format(self.value)
      else:
         return 'Return'
   def getTargets(self):
      return []

class Alloc(Instruction):
   """ Allocates space on the stack """
   def __init__(self, value):
      super().__init__()
      self.value = value
      self.addDef(value)
   def __repr__(self):
      return '{0} = alloc'.format(self.value)

class ImmLoad(Instruction):
   def __init__(self, target, value):
      super().__init__()
      assert type(target) is Value
      self.target = target
      self.value = value
      self.addDef(target)
   def __repr__(self):
      return '{0} = {1}'.format(self.target, self.value)

# Data operations
class BinaryOperator(Instruction):
   def __init__(self, result, operation, value1, value2):
      super().__init__()
      #print('operation is in binops:', operation in BinOps)
      # Check types of the two operands:
      assert type(value1) is Value
      assert type(value2) is Value
      self.result = result
      self.addDef(result)
      self.value1 = value1
      self.value2 = value2
      self.addUse(value1)
      self.addUse(value2)
      self.operation = operation
   def __repr__(self):
      return '{0} = {2} {1} {3}'.format(self.result, self.operation, self.value1, self.value2)

# Memory functions:
class Load(Instruction):
   def __init__(self, location, value):
      super().__init__()
      assert type(value) is Value
      assert isinstance(location, Value), "Location must be a value"
      self.value = value
      self.addDef(value)
      self.location = location
      self.addUse(self.location)
   def __repr__(self):
      return '{1} = [{0}]'.format(self.location, self.value)

class Store(Instruction):
   def __init__(self, location, value):
      super().__init__()
      assert type(value) is Value
      assert isinstance(location, Value), "Location must be a value"
      self.location = location
      self.value = value
      self.addUse(value)
      self.addUse(location)
   def __repr__(self):
      return '[{0}] = {1}'.format(self.location, self.value)

# Branching:
class Branch(Terminator):
    def __init__(self, target):
      super().__init__()
      assert type(target) is BasicBlock
      self.target = target
    def __repr__(self):
        return 'BRANCH {0}'.format(self.target)
    def getTargets(self):
        return [self.target]
    def changeTarget(self, tfrom, tto):
        assert tfrom is self.target
        self.target = tto

class ConditionalBranch(Terminator):
   def __init__(self, a, cond, b, lab1, lab2):
      super().__init__()
      self.a = a
      assert type(a) is Value
      self.cond = cond
      self.b = b
      self.addUse(a)
      self.addUse(b)
      assert type(b) is Value
      assert type(lab1) is BasicBlock
      self.lab1 = lab1
      assert type(lab2) is BasicBlock
      self.lab2 = lab2
   def __repr__(self):
      return 'IF {0} {1} {2} THEN {3} ELSE {4}'.format(self.a, self.cond, self.b, self.lab1, self.lab2)
   def getTargets(self):
      return [self.lab1, self.lab2]
   def changeTarget(self, tfrom, tto):
      assert tfrom is self.lab1 or tfrom is self.lab2
      if tfrom is self.lab1:
         self.lab1 = tto
      elif tfrom is self.lab2:
         self.lab2 = tto

class PhiNode(Instruction):
   def __init__(self):
      super().__init__()
      self.incBB = []
   def addIncoming(self, bb):
      self.incBB.append(bb)