changeset 205:d77cb5962cc5

Added some handcoded arm code generation
author Windel Bouwman
date Sun, 23 Jun 2013 18:23:18 +0200
parents de3a68f677a5
children 6c6bf8890d8a
files python/arm_cm3.py python/c3/codegenerator.py python/c3/lexer.py python/ir/basicblock.py python/ir/builder.py python/ir/function.py python/ir/instruction.py python/ir/module.py python/stm32f4/blink.c3 python/target.py python/testc3.py python/zcc.py
diffstat 12 files changed, 197 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/python/arm_cm3.py	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/arm_cm3.py	Sun Jun 23 18:23:18 2013 +0200
@@ -1,11 +1,15 @@
+import struct, types
 from target import Register, Instruction, Target
 from asmnodes import ASymbol, ANumber
 from ppci import CompilerError
-import struct, types
+import ir
 
 def u16(h):
     return struct.pack('<H', h)
 
+def u32(x):
+    return struct.pack('<I', x)
+
 armtarget = Target('arm')
 
 class ArmReg(Register):
@@ -33,6 +37,16 @@
                 r = regs[name]
                 return cls(r.num)
 
+class Label:
+    def __init__(self, name):
+        self.name = name
+
+    @classmethod
+    def Create(cls, vop):
+        if type(vop) is ASymbol:
+            name = vop.name
+            return cls(name)
+
 class Imm8:
     def __init__(self, imm):
         assert imm < 256
@@ -54,7 +68,13 @@
         if type(vop) is ANumber and vop.number < 8:
             return cls(vop.number)
 
+class RegisterSet:
+    def __init__(self, regs):
+        pass
+
 # 8 bit registers:
+r0 = ArmReg(0, 'r0')
+armtarget.registers.append(r0)
 r4 = ArmReg(4, 'r4')
 armtarget.registers.append(r4)
 r5 = ArmReg(5, 'r5')
@@ -71,7 +91,15 @@
 class ldr_ins(ArmInstruction):
     mnemonic = 'ldr'
     opcode = 1337
+    irpattern = 'todo'
 
+@armtarget.instruction
+class dcd_ins(ArmInstruction):
+    mnemonic = 'dcd'
+    def __init__(self, expr):
+        self.expr = expr
+    def encode(self):
+        return u32(self.expr)
 
 class Operand2:
     def __init__(self, expr):
@@ -85,9 +113,15 @@
     mnemonic = 'mov'
     opcode = 4 # 00100 Rd(3) imm8
     operands = (RegOp, Imm8)
+    irpattern = ir.ImmLoad
     def __init__(self, rd, imm):
         self.imm = imm.imm
         self.r = rd.num
+
+    @classmethod
+    def FromIr(cls, ir_ins):
+        pass
+
     def encode(self):
         rd = self.r
         opcode = self.opcode
@@ -121,6 +155,7 @@
     mnemonic = 'add'
     opcode = 3 # 00011
     operands = (RegOp, RegOp, Imm3)
+    irpattern = 3
     def __init__(self, rd, rn, imm3):
         self.rd = rd
         self.rn = rn
@@ -150,6 +185,36 @@
         return u16(h)
 
 @armtarget.instruction
+class jmp_ins(ArmInstruction):
+    operands = (Label)
+    mnemonic = 'jmp'
+    def __init__(self, target_label):
+        self.target = target_label
+    def fixUp(self):
+        pass
+    def encode(self):
+        h = 1337 # TODO
+        return u16(h)
+
+@armtarget.instruction
+class push_ins(ArmInstruction):
+    operands = (RegisterSet)
+    mnemonic = 'push'
+    def __init__(self, regs):
+        self.regs = regs
+    def encode(self):
+        return u16(0)
+
+@armtarget.instruction
+class pop_ins(ArmInstruction):
+    operands = (RegisterSet)
+    mnemonic = 'pop'
+    def __init__(self, regs):
+        self.regs = regs
+    def encode(self):
+        return u16(0)
+
+@armtarget.instruction
 class yield_ins(ArmInstruction):
     operands = ()
     mnemonic = 'yield'
--- a/python/c3/codegenerator.py	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/c3/codegenerator.py	Sun Jun 23 18:23:18 2013 +0200
@@ -23,7 +23,7 @@
             self.funcMap[s] = f
       for s in pkg.scope:
          if type(s) is astnodes.Variable:
-              v = self.builder.newTmp(s.name)
+              v = self.builder.newVariable(s.name)
               #self.builder.addIns(ir.Alloc(v))
               self.varMap[s] = v
          elif type(s) is astnodes.Function:
@@ -116,9 +116,9 @@
             raise NotImlementedError('Unknown condition {0}'.format(expr))
       elif type(expr) is astnodes.Literal:
          if expr.val:
-            self.builder.addIns(ir.BranchInstruction(bbtrue))
+            self.builder.addIns(ir.Branch(bbtrue))
          else:
-            self.builder.addIns(ir.BranchInstruction(bbfalse))
+            self.builder.addIns(ir.Branch(bbfalse))
       else:
          print('Unknown cond', expr)
    def genExprCode(self, expr):
--- a/python/c3/lexer.py	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/c3/lexer.py	Sun Jun 23 18:23:18 2013 +0200
@@ -28,7 +28,7 @@
        ('COMMENTS', r'//.*'),
        ('LONGCOMMENTBEGIN', r'\/\*'),
        ('LONGCOMMENTEND', r'\*\/'),
-       ('LEESTEKEN', r'==|[\.,=:;\-+*\[\]/\(\)]|>=|<=|<>|>|<|{|}'),
+       ('LEESTEKEN', r'==|[\.,=:;\-+*\[\]/\(\)]|>=|<=|<>|>|<|{|}|&|\^|\|'),
        ('STRING', r"'.*?'")
      ]
      tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec)
@@ -43,7 +43,7 @@
        if typ == 'NEWLINE':
          line_start = pos
          line += 1
-       elif typ == 'COMMENT':
+       elif typ == 'COMMENTS':
          pass
        elif typ == 'LONGCOMMENTBEGIN':
           incomment = True
@@ -73,9 +73,9 @@
        pos = mo.end()
        mo = gettok(s, pos)
      if pos != len(s):
-       col = pos - line_start
-       pos = line
-       raise CompilerError('Unexpected character {0}'.format(s[pos]), pos)
+         col = pos - line_start
+         loc = SourceLocation(line, col, 1)
+         raise CompilerError('Unexpected character "{0}"'.format(s[pos]), loc)
      loc = SourceLocation(line, 0, 0)
      yield Token('END', '', loc)
 
--- a/python/ir/basicblock.py	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/ir/basicblock.py	Sun Jun 23 18:23:18 2013 +0200
@@ -10,17 +10,21 @@
       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
+
    def removeInstruction(self, i):
       i.parent = None
       self.instructions.remove(i)
+
    def getInstructions(self):
-      return self.instructions
+        return self.instructions
+
    def setInstructions(self, ins):
       for i in self.instructions:
          i.parent = None
@@ -28,6 +32,7 @@
       for i in self.instructions:
          i.parent = self
    Instructions = property(getInstructions, setInstructions)
+
    def getLastIns(self):
       return self.instructions[-1]
    LastInstruction = property(getLastIns)
--- a/python/ir/builder.py	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/ir/builder.py	Sun Jun 23 18:23:18 2013 +0200
@@ -1,4 +1,4 @@
-from . import Value, BasicBlock, Function
+from . import Value, BasicBlock, Function, Variable
 
 class NameGenerator:
    def __init__(self, prefix):
@@ -41,16 +41,26 @@
       bb = self.newBBint()
       self.fn.addBB(bb)
       return bb
+
    def setModule(self, m):
       self.m = m
+
    def newFunction(self, name):
       f = Function(name)
       self.m.addFunc(f)
       return f
+
+   def newVariable(self, name):
+        v = Variable(name)
+        self.m.addVariable(v)
+        return v
+
    def setFunction(self, f):
       self.fn = f
+
    def setBB(self, bb):
       self.bb = bb
+
    def addIns(self, i):
       if not self.bb:
             raise Exception('No basic block')
--- a/python/ir/function.py	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/ir/function.py	Sun Jun 23 18:23:18 2013 +0200
@@ -5,14 +5,19 @@
       self.name = name
       self.bbs = []
       self.entry = None
+
    def __repr__(self):
       return 'Function {0}'.format(self.name)
+
    def addBB(self, bb):
       self.bbs.append(bb)
       bb.parent = self
+   addBasicBlock = addBB
+
    def removeBasicBlock(self, bb):
       self.bbs.remove(bb)
       bb.parent = None
+
    def getBBs(self):
       return self.bbs
    BasicBlocks = property(getBBs)
--- a/python/ir/instruction.py	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/ir/instruction.py	Sun Jun 23 18:23:18 2013 +0200
@@ -1,6 +1,7 @@
 from .basicblock import BasicBlock
 from .function import Function
 
+
 class Value:
    """ Temporary SSA value (value that is assigned only once! """
    def __init__(self, name):
@@ -13,10 +14,13 @@
    def IsUsed(self):
       return len(self.used_by) > 0
 
+class Variable(Value):
+    pass
+
 class Use:
    def __init__(self, user, val):
       self.user = user
-      assert type(val) is Value
+      assert isinstance(val, Value)
       self.val = val
       self.val.used_by.append(self.user)
    def delete(self):
@@ -130,7 +134,7 @@
    def __init__(self, location, value):
       super().__init__()
       assert type(value) is Value
-      assert type(location) is Value, "Location must be a value"
+      assert isinstance(location, Value), "Location must be a value"
       self.value = value
       self.addDef(value)
       self.location = location
@@ -142,7 +146,7 @@
    def __init__(self, location, value):
       super().__init__()
       assert type(value) is Value
-      assert type(location) is Value, "Location must be a value"
+      assert isinstance(location, Value), "Location must be a value"
       self.location = location
       self.value = value
       self.addUse(value)
--- a/python/ir/module.py	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/ir/module.py	Sun Jun 23 18:23:18 2013 +0200
@@ -7,34 +7,51 @@
    def __init__(self, name):
       self.name = name
       self.funcs = []
+      self.variables = []
+
    def __repr__(self):
       return 'IR-module [{0}]'.format(self.name)
+
    def getInstructions(self):
       ins = []
       for bb in self.BasicBlocks:
          ins += bb.Instructions
       return ins
    Instructions = property(getInstructions)
+
    def getBBs(self):
       bbs = []
       for f in self.Functions:
          bbs += f.BasicBlocks
       return bbs
+
    BasicBlocks = property(getBBs)
    def addFunc(self, f):
       self.funcs.append(f)
-   def getFuncs(self):
+   addFunction = addFunc
+
+   def addVariable(self, v):
+        self.variables.append(v)
+
+   def getVariables(self):
+        return self.variables
+   Variables = property(getVariables)
+
+   def getFunctions(self):
       return self.funcs
-   Functions = property(getFuncs)
+   Functions = property(getFunctions)
+
    def dump(self):
       print(self)
+      for v in self.Variables:
+            print('   ', v)
       for fn in self.Functions:
          print(fn)
          for bb in fn.BasicBlocks:
             print('   ', bb)
             for ins in bb.Instructions:
                print('      ', ins)
-      print('END')
+
    def dumpgv(self, outf):
       outf.write('digraph G \n{\n')
       for f in self.Functions:
--- a/python/stm32f4/blink.c3	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/stm32f4/blink.c3	Sun Jun 23 18:23:18 2013 +0200
@@ -39,7 +39,7 @@
 	TIM2->CR1 |= TIM_CR1_ARPE | TIM_CR1_CEN;
 	TIM2->EGR = 1;
 	
-	while(1);
     */
+    while(true) {}
 }
 
--- a/python/target.py	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/target.py	Sun Jun 23 18:23:18 2013 +0200
@@ -16,7 +16,7 @@
 
 class Instruction:
     def encode(self):
-        raise NotImplementedError('TODO')
+        raise NotImplementedError('Instruction {0} has no encode yet, TODO'.format(type(self)))
 
 class Target:
     def __init__(self, name, desc=''):
--- a/python/testc3.py	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/testc3.py	Sun Jun 23 18:23:18 2013 +0200
@@ -56,28 +56,6 @@
 
 """
 
-testsrc2 = """
-package test2;
-
-function void tst()
-{
-   var int a, b;
-   a = 2 * 33 - 12;
-   b = a * 2 + 13;
-   a = b + a;
-   if (a > b and b == 3)
-   {
-      var int x = a;
-      x = b * 2 - a;
-      a = x*x;
-   }
-   else
-   {
-      a = b + a;
-   }
-}
-
-"""
 
 def c3compile(src, diag):
    # Structures:
@@ -101,6 +79,11 @@
    c3compile(testsrc, diag)
 
 class testLexer(unittest.TestCase):
+    def testUnexpectedCharacter(self):
+        snippet = """ var s \u6c34 """
+        with self.assertRaises(ppci.CompilerError):
+            list(c3.lexer.tokenize(snippet))
+
     def testBlockComment(self):
         snippet = """
           /* Demo */
@@ -108,6 +91,7 @@
         """
         toks = ['var', 'ID', 'ID', '=', 'NUMBER', ';', 'END']
         self.assertSequenceEqual([tok.typ for tok in c3.lexer.tokenize(snippet)], toks)
+
     def testBlockCommentMultiLine(self):
         snippet = """
           /* Demo
@@ -138,8 +122,8 @@
       self.diag.clear()
       ir = self.builder.build(snippet)
       assert len(self.diag.diags) == 2
-      assert self.diag.diags[0].loc.row == 5
-      assert self.diag.diags[1].loc.row == 6
+      self.assertEqual(5, self.diag.diags[0].loc.row)
+      self.assertEqual(6, self.diag.diags[1].loc.row)
 
    def testExpressions(self):
       snippet = """
@@ -161,17 +145,20 @@
       self.assertEqual(self.diag.diags[1].loc.row, 9)
       self.assertEqual(self.diag.diags[2].loc.row, 10)
       self.assertFalse(ircode)
+
    def testEmpty(self):
       snippet = """
       package A
       """
       ircode = self.builder.build(snippet)
       self.assertFalse(ircode)
+
    def testEmpty2(self):
       snippet = ""
       self.diag.clear()
       ircode = self.builder.build(snippet)
       self.assertFalse(ircode)
+
    def testRedefine(self):
       snippet = """
       package test;
@@ -184,6 +171,7 @@
       self.assertFalse(ircode)
       self.assertEqual(len(self.diag.diags), 1)
       self.assertEqual(self.diag.diags[0].loc.row, 5)
+
    def testWhile(self):
       snippet = """
       package tstwhile;
@@ -196,6 +184,14 @@
             i = i + 3;
             a = a + i;
          }
+
+         while(true)
+         {
+         }
+
+         while(false)
+         {
+         }
       }
       """
       ircode = self.builder.build(snippet)
@@ -228,11 +224,34 @@
       if not ircode:
         self.diag.printErrors(snippet)
       self.assertTrue(ircode)
+
    def test2(self):
-      # testsrc2 is valid code:
-      self.diag.clear()
-      ir = self.builder.build(testsrc2)
-      self.assertTrue(ir)
+        # testsrc2 is valid code:
+        testsrc2 = """
+        package test2;
+
+        function void tst()
+        {
+           var int a, b;
+           a = 2 * 33 - 12;
+           b = a * 2 + 13;
+           a = b + a;
+           if (a > b and b == 3)
+           {
+              var int x = a;
+              x = b * 2 - a;
+              a = x*x;
+           }
+           else
+           {
+              a = b + a;
+           }
+        }
+
+        """
+        self.diag.clear()
+        ir = self.builder.build(testsrc2)
+        self.assertTrue(ir)
 
 if __name__ == '__main__':
    do()
--- a/python/zcc.py	Fri Jun 21 15:01:08 2013 +0200
+++ b/python/zcc.py	Sun Jun 23 18:23:18 2013 +0200
@@ -1,13 +1,19 @@
 #!/usr/bin/python
 
 import sys, os, argparse
-import c3, ppci
+import c3, ppci, codegen
+import arm_cm3
+import codegenarm
+import outstream
 
+# Parse arguments:
 parser = argparse.ArgumentParser(description='lcfos Compiler')
 parser.add_argument('source', type=argparse.FileType('r'), help='the source file to build')
+parser.add_argument('-d', '--dumpir', action='store_true', help="Dump IR-code")
+parser.add_argument('-o', '--output', help='Output file', metavar='filename')
 args = parser.parse_args()
 
-# Building:
+# Front end:
 src = args.source.read()
 diag = ppci.DiagnosticsManager()
 c3b = c3.Builder(diag)
@@ -17,15 +23,23 @@
     diag.printErrors(src)
     sys.exit(1)
 
-# optionally run passes here:
-# TODO
+if args.dumpir:
+    ircode.dump()
+
+# Code generation:
+
+#cg = codegen.CodeGenerator(arm_cm3.armtarget)
+outs = outstream.TextOutputStream()
+cg = codegenarm.ArmCodeGenerator(outs)
+obj = cg.generate(ircode)
 
-print('stage 3: Code generation')
-asmWriter = core.AsmWriter()
-asmWriter.printModule(module)
+if args.dumpir:
+    outs.dump()
 
-# Generate code:
-bitcodeWriter = core.BitcodeWriter()
-with open(args.source + '.bc', 'wb') as f:
-   bitcodeWriter.WriteModuleToFile(module, f)
+if args.output:
+    output_filename = args.output
+else:
+    output_filename = 'lc.output'
 
+# TODO: store data
+