changeset 158:9683a4cd848f

Added some functions for code generation
author Windel Bouwman
date Fri, 08 Mar 2013 16:52:44 +0100
parents 8f3924b6076e
children 5e1dd04cb61c
files python/c3/astnodes.py python/c3/codegenerator.py python/c3/parser.py python/ir/__init__.py python/ir/instruction.py python/ir/module.py python/ir/value.py python/testc3.py python/x86.py
diffstat 9 files changed, 161 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/python/c3/astnodes.py	Sun Mar 03 18:14:35 2013 +0100
+++ b/python/c3/astnodes.py	Fri Mar 08 16:52:44 2013 +0100
@@ -145,7 +145,8 @@
       return 'COMPOUND STATEMENT'
 
 class EmptyStatement(Node):
-   pass
+   def __repr__(self):
+      return 'NOP'
 
 class ReturnStatement(Node):
    def __init__(self, expr):
@@ -168,7 +169,7 @@
     return 'CALL {0} '.format(self.proc)
 
 class IfStatement(Node):
-   def __init__(self, condition, truestatement, falsestatement=None):
+   def __init__(self, condition, truestatement, falsestatement):
       self.condition = condition
       self.truestatement = truestatement
       self.falsestatement = falsestatement
--- a/python/c3/codegenerator.py	Sun Mar 03 18:14:35 2013 +0100
+++ b/python/c3/codegenerator.py	Fri Mar 08 16:52:44 2013 +0100
@@ -20,36 +20,73 @@
 def genFunction(m, fnc):
    ft = genType(fnc.typ)
    f = ir.Function(fnc.name, ft)
-   m.Globals.append(f)
+   m.Functions.append(f)
    bb = ir.BasicBlock()
    f.BasicBlocks.append(bb)
    genCode(bb, fnc.body)
+   bb.Instructions.append(ir.RetInstruction())
 
 def genCode(bb, code):
    if type(code) is astnodes.CompoundStatement:
       for s in code.statements:
          genCode(bb, s)
    elif type(code) is astnodes.Assignment:
-      genCode(bb, code.rval)
-      print('assign')
+      genExprCode(bb, code.rval)
+      # TODO: store
    elif type(code) is astnodes.IfStatement:
-      genCode(bb, code.condition)
+      genExprCode(bb, code.condition)
+      # TODO: implement IF.
+      t1, t2 = 1,2
+      b = ir.BranchInstruction(t1, t2)
+      bb.Instructions.append(b)
       genCode(bb, code.truestatement)
-      print('If!')
-   elif type(code) is astnodes.Binop:
-      genCode(bb, code.a)
-      genCode(bb, code.b)
-      a = 1
-      b = 2
-      if code.op == '+':
-         bb.Instructions.append(ir.AddInstruction(a, b))
+      genCode(bb, code.falsestatement)
+   elif type(code) is astnodes.ProcedureCall:
+      ins = ir.CallInstruction('f', [])
+      bb.Instructions.append(ins)
+   elif type(code) is astnodes.EmptyStatement:
+      pass
+   elif type(code) is astnodes.ReturnStatement:
+      bb.Instructions.append(ir.RetInstruction())
+   else:
+      print('Unknown stmt:', code)
+
+def NumGen():
+   a = 0
+   while True:
+      yield a
+      a = a + 1
+
+nums = NumGen()
+def unique():
+   return 'tmp{0}'.format(nums.__next__())
+
+def genExprCode(bb, code):
+   if type(code) is astnodes.Binop:
+      a = genExprCode(bb, code.a)
+      b = genExprCode(bb, code.b)
+      ops = {'+': 'fadd', '-': 'fsub', '*':'fmul', '/':'fdiv'}
+      if code.op in ops:
+         op = ops[code.op]
+         tmp = unique()
+         ins = ir.BinaryOperator(tmp, op, a, b)
+         bb.Instructions.append(ins)
+         return tmp
       else:
-         bb.Instructions.append(ir.BinaryOperator(code.op, a, b))
+         print('Unknown binop')
+         bb.Instructions.append(ir.BinaryOperator('unk2', code.op, a, b))
+         return 'unk2'
    elif type(code) is astnodes.Constant:
-      print('CST')
-      bb.Instructions.append(ir.ImmLoadInstruction(code.value))
+      tmp = unique()
+      bb.Instructions.append(ir.LoadInstruction(tmp, code.value))
+      return tmp
+   elif type(code) is astnodes.VariableUse:
+      tmp = unique()
+      ins = ir.LoadInstruction(tmp, code.target.name)
+      return tmp
    else:
-      print('Unknown:', code)
+      print('Unknown expr:', code)
+      return 'unk'
 
 def genType(t):
    return ir.Type()
--- a/python/c3/parser.py	Sun Mar 03 18:14:35 2013 +0100
+++ b/python/c3/parser.py	Fri Mar 08 16:52:44 2013 +0100
@@ -111,7 +111,7 @@
 
    # Statements:
    def parseAssignment(self, lval):
-      lval = astnodes.VariableUse(lval)
+      lval = self.sema.actOnVariableUse(lval)
       self.Consume('=')
       rval = self.parseExpression()
       self.Consume(';')
@@ -136,7 +136,7 @@
       if self.hasConsumed('else'):
          no = self.parseCompoundStatement()
          return astnodes.IfStatement(condition, yes, no)
-      return astnodes.IfStatement(condition, yes)
+      return astnodes.IfStatement(condition, yes, astnodes.EmptyStatement())
 
    def parseWhileStatement(self):
       self.Consume('while')
@@ -167,11 +167,11 @@
          return self.parseWhileStatement()
       elif self.Peak == '{':
          return self.parseCompoundStatement()
-      elif self.Peak == ';':
-         self.Consume(';')
+      elif self.hasConsumed(';'):
          return astnodes.EmptyStatement()
       elif self.Peak == 'var':
-         return self.parseVarDef()
+         self.parseVarDef()
+         return astnodes.EmptyStatement()
       elif self.Peak == 'return':
          return self.parseReturnStatement()
       elif self.Peak == 'ID':
--- a/python/ir/__init__.py	Sun Mar 03 18:14:35 2013 +0100
+++ b/python/ir/__init__.py	Fri Mar 08 16:52:44 2013 +0100
@@ -2,6 +2,7 @@
 from .value import Value
 from .module import Type, FunctionType
 from .module import i8, i16, i32, void
-from .instruction import AddInstruction, BinaryOperator, ImmLoadInstruction
+from .module import printIr
+from .instruction import *
 
 
--- a/python/ir/instruction.py	Sun Mar 03 18:14:35 2013 +0100
+++ b/python/ir/instruction.py	Fri Mar 08 16:52:44 2013 +0100
@@ -1,34 +1,44 @@
-
-def Enum(**enums):
-   return type('Enum', (), enums)
 
 class Instruction:
    """ Base class for all instructions. """
    pass
 
+# Function calling:
 class CallInstruction(Instruction):
    def __init__(self, callee, arguments):
       super().__init__()
       self.callee = callee
       self.arguments = arguments
+   def __repr__(self):
+      return 'CALL {0}'.format(self.callee)
 
-BinOps = Enum(Add=1, Sub=2, Mul=3)
+class RetInstruction(Instruction):
+   def __repr__(self):
+      return 'RET'
 
 class BinaryOperator(Instruction):
-   def __init__(self, operation, value1, value2):
+   def __init__(self, name, operation, value1, value2):
       assert value1
       assert value2
       #print('operation is in binops:', operation in BinOps)
       # Check types of the two operands:
+      self.name = name
       self.value1 = value1
       self.value2 = value2
       self.operation = operation
-
-class AddInstruction(BinaryOperator):
-   def __init__(self, a, b):
-      super().__init__('add', a, b)
+   def __repr__(self):
+      return '{0} = {1} {2}, {3}'.format(self.name, self.operation, self.value1, self.value2)
 
-class ImmLoadInstruction(Instruction):
-   def __init__(self, value):
+class LoadInstruction(Instruction):
+   def __init__(self, name, value):
       self.value = value
+      self.name = name
+   def __repr__(self):
+      return 'load {0} = {1}'.format(self.name, self.value)
 
+class BranchInstruction(Instruction):
+   def __init__(self, t1, t2):
+      self.t1 = t1
+      self.t2 = t2
+   def __repr__(self):
+      return 'BRANCH {0}'.format(self.t1)
--- a/python/ir/module.py	Sun Mar 03 18:14:35 2013 +0100
+++ b/python/ir/module.py	Fri Mar 08 16:52:44 2013 +0100
@@ -33,11 +33,12 @@
    def __init__(self, name):
       self.name = name
       self.functions = [] # Do functions come out of symbol table?
-      self.globals_ = [] # TODO: are globals in symbol table?
+      self.globs = [] # TODO: are globals in symbol table?
       self.symtable = SymbolTable()
-   Globals = property(lambda self: self.globals_)
+   Globals = property(lambda self: self.globs)
    Functions = property(lambda self: self.functions)
-   Identifier = property(lambda self: self.identifier)
+   def __repr__(self):
+      return 'IR-mod {0}'.format(self.name)
 
 class Argument:
    def __init__(self, argtype, name, function):
@@ -57,6 +58,8 @@
    Arguments = property(lambda self: self.arguments)
    ReturnType = property(lambda self: self.functiontype.returnType)
    FunctionType = property(lambda self: self.functiontype)
+   def __repr__(self):
+      return 'FUNC {0}'.format(self.name)
    
 class BasicBlock:
    """ 
@@ -66,8 +69,20 @@
    def __init__(self):
       super().__init__()
       self.instructions = []
-      self.name = None
+      self.label = None
    def getInstructions(self):
       return self.instructions
    Instructions = property(getInstructions)
 
+def printIr(md):
+   print(md)
+   for g in md.Globals:
+      print(g)
+   for f in md.Functions:
+      print(f)
+      for bb in f.BasicBlocks:
+         print('{0}:'.format(bb))
+         for ins in bb.Instructions:
+            print(' {0}'.format(ins))
+      print()
+
--- a/python/ir/value.py	Sun Mar 03 18:14:35 2013 +0100
+++ b/python/ir/value.py	Fri Mar 08 16:52:44 2013 +0100
@@ -14,6 +14,8 @@
          return
       self.name = name
    Name = property(getName, setName)
+   def __repr__(self):
+      return 'VALUE {0}'.format(self.name)
 
 class Constant(Value):
    def __init__(self, value, vty):
--- a/python/testc3.py	Sun Mar 03 18:14:35 2013 +0100
+++ b/python/testc3.py	Fri Mar 08 16:52:44 2013 +0100
@@ -1,4 +1,5 @@
-import c3, time, ppci, x86
+import c3
+import time, ppci, x86, ir
 
 testsrc = """
 package test;
@@ -62,14 +63,8 @@
    al = c3.Analyzer(diag)
    cg = c3.CodeGenerator()
    x86gen = x86.X86CodeGen(diag)
-   t1 = time.time()
    p.parseSource(src)
-   t2 = time.time() 
-   print('parsetime: {0} [s]'.format(t2 - t1))
-   t2 = time.time() 
    tc.checkPackage(sema.mod)
-   t3 = time.time() 
-   print('checktime: {0} [s]'.format(t3 - t2))
    print('{0} errors'.format(len(diag.diags)))
 
    for d in diag.diags:
@@ -80,12 +75,18 @@
 
    ok = len(diag.diags) == 0
    if ok:
-      print('Generating code')
+      print('Generating ir-code')
       i = cg.gencode(sema.mod)
+      #ir.printIr(i)
+
+      print('generating x86 code')
 
-      print(i)
-      print(i.Globals)
       x86gen.genBin(i)
+
+      with open('dummydummy.asm', 'w') as f:
+         f.write('bits 64\n')
+         for a in x86gen.asm:
+            f.write(str(a) + '\n')
    else:
       print('Not generating code')
    
--- a/python/x86.py	Sun Mar 03 18:14:35 2013 +0100
+++ b/python/x86.py	Fri Mar 08 16:52:44 2013 +0100
@@ -1,9 +1,53 @@
 import ppci
+import ir
+
+class AsmLabel:
+   def __init__(self, lab):
+      self.lab = lab
+   def __repr__(self):
+      return '{0}:'.format(self.lab)
+
+class Op:
+   def __init__(self, op, a, b):
+      self.op = op
+      self.a = a
+      self.b = b
+   def __repr__(self):
+      return '{0} {1}, {2}'.format(self.op, self.a, self.b)
 
 class X86CodeGen:
    def __init__(self, diag):
       self.diag = diag
 
+   def emit(self, i):
+      self.asm.append(i)
+
    def genBin(self, i):
-      print(i)
+      self.asm = []
+      self.genModule(i)
 
+   def genModule(self, m):
+      for g in m.Globals:
+         self.emit(AsmLabel(g.name))
+         # Ignore types for now ..
+         self.emit('dw 0')
+      for f in m.Functions:
+         self.genFunction(f)
+   def genFunction(self, f):
+      self.emit('global {0}'.format(f.name))
+      self.emit(AsmLabel(f.name))
+      for bb in f.BasicBlocks:
+         self.genBB(bb)
+   def genBB(self, bb):
+      for i in bb.Instructions:
+         self.genIns(i)
+   def genIns(self, i):
+      if type(i) is ir.BinaryOperator:
+         if i.operation == 'fadd':
+            r = 'rax'
+            self.emit(Op('add', r, '11'))
+      elif type(i) is ir.RetInstruction:
+         self.emit('ret')
+      else:
+         print('Unknown ins', i)
+