Mercurial > lcfOS
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 +