Mercurial > lcfOS
diff python/codegenarm.py @ 269:5f8c04a8d26b
Towards better modularity
author | Windel Bouwman |
---|---|
date | Sun, 18 Aug 2013 17:43:18 +0200 |
parents | 5ec7580976d9 |
children | cdc76d183bcc |
line wrap: on
line diff
--- a/python/codegenarm.py Wed Aug 14 20:12:40 2013 +0200 +++ b/python/codegenarm.py Sun Aug 18 17:43:18 2013 +0200 @@ -3,40 +3,14 @@ from target import Label, Comment, Alignment, LabelRef, Imm32, DebugInfo import cortexm3 as arm from ppci import CompilerError -import irmach - - -class InstructionSelector: - def newTmp(self): - return 't999' - - def munchProgram(self, p): - assert isinstance(p, ir.Module) - self.result = [] - for f in p.Functions: - for bb in f.BasicBlocks: - for i in bb.Instructions: - self.munchStm(i) - return self.result - - def emit(self, *args, **kwargs): - """ Abstract instruction emitter """ - i = irmach.AbstractInstruction(*args, **kwargs) - self.result.append(i) - - def munchStm(self, s): - raise NotImplementedError() - - def munchExpr(self, e): - raise NotImplementedError() - - -class RegisterAllocator: - """ Target independent register allocator """ - pass +import graph +import flowgraph +import registerallocator +from instructionselector import InstructionSelector class ArmInstructionSelector(InstructionSelector): + """ Instruction selector for the arm architecture """ def munchExpr(self, e): if isinstance(e, ir.Alloc): return 0 @@ -46,11 +20,17 @@ d = self.newTmp() self.emit('add %d0, %s0, %s1', dst=[d], src=[a, b]) return d + elif isinstance(e, ir.Binop) and e.operation == '-': + a = self.munchExpr(e.value1) + b = self.munchExpr(e.value2) + d = self.newTmp() + self.emit('sub %d0, %s0, %s1', dst=[d], src=[a, b]) + return d elif isinstance(e, ir.Binop) and e.operation == '|': a = self.munchExpr(e.value1) b = self.munchExpr(e.value2) d = self.newTmp() - self.emit('orrrr %d0, %s0, %s1', dst=[d], src=[a, b]) + self.emit('or %d0, %s0, %s1', dst=[d], src=[a, b]) return d elif isinstance(e, ir.Binop) and e.operation == '<<': a = self.munchExpr(e.value1) @@ -62,14 +42,14 @@ a = self.munchExpr(e.value1) b = self.munchExpr(e.value2) d = self.newTmp() - self.emit('mylll %d0, %s0, %s1', dst=[d], src=[a, b]) + self.emit('mul %d0, %s0, %s1', dst=[d], src=[a, b]) return d elif isinstance(e, ir.Const): d = self.newTmp() if e.value < 256: self.emit('ldr %d0, {}'.format(e.value), dst=[d]) else: - self.emit('ldrpcrel TODO') + self.emit('ldrpcrel TODO', dst=[d]) return d elif isinstance(e, ir.Mem): # Load from memory @@ -78,7 +58,7 @@ self.emit('ldr %d0, [%s0]', src=[loc], dst=[d]) return d elif isinstance(e, ir.Temp): - return e + return self.getTempReg(e) else: raise NotImplementedError('--> {}'.format(e)) @@ -89,217 +69,48 @@ self.emit('str [%s0], %s1') elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp): val = self.munchExpr(s.src) - self.emit('str %d0, %s0', dst=[s.dst], src=[val]) + dreg = self.getTempReg(s.dst) + self.emit('mov %d0, %s0', dst=[dreg], src=[val]) elif isinstance(s, ir.Return): - self.emit('ret') + #etgt = self.targets[ + self.emit('jmp exit', jumps=[]) elif isinstance(s, ir.Jump): - self.emit('jmp {}'.format(s)) + tgt = self.targets[s.target] + self.emit('jmp {}'.format(s), jumps=[tgt]) elif isinstance(s, ir.CJump): - self.munchExpr(s.a) - self.munchExpr(s.b) - self.emit('jmp {}'.format(s)) + a = self.munchExpr(s.a) + b = self.munchExpr(s.b) + self.emit('cmp %s0, %s1', src=[a, b]) + ntgt = self.targets[s.lab_no] + ytgt = self.targets[s.lab_yes] + jmp_ins = self.makeIns('jmp {}'.format(s.lab_no), jumps=[ntgt]) + # Explicitely add fallthrough: + self.emit('jeq {}'.format(s.lab_yes), jumps=[ytgt, jmp_ins]) + self.emit2(jmp_ins) else: raise NotImplementedError('--> {}'.format(s)) class ArmCodeGenerator: def __init__(self, outs): + # TODO: schedule traces in better order. + # This is optional! self.ins_sel = ArmInstructionSelector() self.outs = outs self.outs.getSection('code').address = 0x08000000 self.outs.getSection('data').address = 0x20000000 - def generate(self, ircode): - self.ins_sel.munchProgram(ircode) + def generate(self, ircode, cfg_file=None, ig_file=None): + x = self.ins_sel.munchProgram(ircode) + cfg = flowgraph.FlowGraph(x) + if cfg_file: + cfg.to_dot(cfg_file) + ig = registerallocator.InterferenceGraph(cfg) + if ig_file: + ig.to_dot(ig_file) + + regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7'] + ra = registerallocator.RegisterAllocator() + ra.registerAllocate(ig, regs) -class ArmCodeGenerator_old: - """ - Simple code generator - Ad hoc implementation - """ - def __init__(self, out): - self.outs = out - self.logger = logging.getLogger('codegenarm') - - def emit(self, item): - self.outs.emit(item) - - def generate(self, ircode): - assert isinstance(ircode, ir.Module) - self.logger.info('Generating arm code for {}'.format(ircode.name)) - self.available_regs = {arm.r3, arm.r4, arm.r5, arm.r6, arm.r7} - self.regmap = {} - # TODO: get these from linker descriptor? - self.outs.getSection('code').address = 0x08000000 - self.outs.getSection('data').address = 0x20000000 - self.outs.selectSection('data') - - for gvar in ircode.Variables: - self.emit(Label(gvar.name)) - # TODO: use initial value: - self.dcd(0) - - self.imms = [] # list with immediates relative to PC. - self.outs.selectSection('code') - - # Manually inserted startup code: - self.dcd(0x20000678) # initial stack ptr - # TODO: use label here: - #self.emit(arm.dcd_ins(LabelRef('reset'))) # reset vector - self.dcd(0x08000009) # reset vector, lsb indicates thumb mode - self.emit(arm.bl_ins(LabelRef('main'))) - - self.emit(Label('reset')) - for f in ircode.Functions: - self.localVars = [] - # Add global variable addresses to immediate list: - for gvar in ircode.Variables: - pass #self.imms.append(( - - self.stack_frame = [] - self.emit(Label(f.name)) - # Save some registers: - self.emit(arm.push_ins(arm.RegisterSet({arm.r3, arm.r4, arm.r5, arm.r6,arm.r7,arm.lr}))) - for bb in f.BasicBlocks: - self.emit(Label(bb.name)) - for ins in bb.Instructions: - self.generateInstruction(ins) - - self.align() - while self.imms: - l, v = self.imms.pop() - self.emit(Label(l)) - self.dcd(v) - self.align() - self.outs.backpatch() - self.outs.backpatch() - codesize = self.outs.getSection('code').Size - self.logger.info('Generated {} bytes code'.format(codesize)) - - def dcd(self, x): - self.emit(arm.dcd_ins(Imm32(x))) - - def align(self): - self.outs.emit(Alignment(4)) - - # Helper functions: - def getStack(self, v): - off = self.stack_frame.index(v) - return off * 4 - - def addStack(self, v): - self.stack_frame.append(v) - return self.getStack(v) - - def getGlobal(self, r, g): - _global_address = g.name + '__global' - self.emit(arm.ldr_pcrel(r, LabelRef(_global_address))) - - def loadStack(self, reg, val): - self.emit(arm.ldr_sprel(reg, arm.MemSpRel(self.getStack(val)))) - - def getreg(self, v): - if not v in self.regmap: - self.regmap[v] = self.available_regs.pop() - return self.regmap[v] - - def freereg(self, v, ins): - if v.lastUse(ins): - r = self.regmap.pop(v) - assert r not in self.regmap.values() - self.available_regs.add(r) - - def comment(self, txt): - self.emit(Comment(txt)) - - def debugInfo(self, loc): - if loc: - self.emit(DebugInfo(loc)) - - def generateInstruction(self, ins): - self.comment(str(ins)) - if hasattr(ins, 'debugLoc'): - self.debugInfo(ins.debugLoc) - if type(ins) is ir.Branch: - tgt = LabelRef(ins.target.name) - self.emit(arm.b_ins(tgt)) - elif type(ins) is ir.ImmLoad: - lname = ins.target.name + '_ivalue' - r0 = self.getreg(ins.target) - self.emit(arm.ldr_pcrel(r0, LabelRef(lname))) - self.imms.append((lname, ins.value)) - elif type(ins) is ir.Store: - # Load value in r0: - r0 = self.getreg(ins.value) - # store in memory: - # TODO: split globals and locals?? - #self.getGlobal(arm.r1, ins.location) - # Horrible hack with localVars - if ins.location in self.localVars: - # The value was alloc'ed - self.emit(arm.str_sprel(r0, arm.MemSpRel(self.getStack(ins.location)))) - else: - r1 = self.getreg(ins.location) - self.emit(arm.storeimm5_ins(r0, arm.MemR8Rel(r1, 0))) - self.freereg(ins.location, ins) - self.freereg(ins.value, ins) - elif type(ins) is ir.Load: - # TODO: differ global and local?? - #self.getGlobal(arm.r0, ins.location) - r0 = self.getreg(ins.value) - if ins.location in self.localVars: - self.emit(arm.ldr_sprel(r0, arm.MemSpRel(self.getStack(ins.location)))) - else: - r2 = self.getreg(ins.location) - self.emit(arm.loadimm5_ins(r0, arm.MemR8Rel(r2, 0))) - self.freereg(ins.location, ins) - elif type(ins) is ir.BinaryOperator: - # Load operands: - r0 = self.getreg(ins.value1) - r1 = self.getreg(ins.value2) - r2 = self.getreg(ins.result) - # do operation: - if ins.operation == '+': - self.emit(arm.addregs_ins(r2, r0, r1)) - elif ins.operation == '<<': - self.emit(arm.movregreg_ins(r2, r0)) - self.emit(arm.lslregs_ins(r2, r1)) - elif ins.operation == '|': - self.emit(arm.movregreg_ins(r2, r0)) - self.emit(arm.orrregs_ins(r2, r1)) - else: - raise NotImplementedError('operation {} not implemented'.format(ins.operation)) - self.freereg(ins.value1, ins) - self.freereg(ins.value2, ins) - elif type(ins) is ir.Call: - # TODO: prep parameters: - self.emit(arm.bl_ins(LabelRef(ins.callee.name))) - elif type(ins) is ir.Return: - self.emit(arm.pop_ins(arm.RegisterSet({arm.r3, arm.r4, arm.r5, arm.r6, arm.r7, arm.pc}))) - elif type(ins) is ir.ConditionalBranch: - r0 = self.getreg(ins.a) - r1 = self.getreg(ins.b) - self.emit(arm.cmp_ins(r1, r0)) - tgt_yes = LabelRef(ins.lab1.name) - if ins.cond == '==': - self.emit(arm.beq_ins(tgt_yes)) - elif ins.cond == '<': - self.emit(arm.blt_ins(tgt_yes)) - elif ins.cond == '>': - self.emit(arm.bgt_ins(tgt_yes)) - else: - raise NotImplementedError('"{}" not covered'.format(ins.cond)) - tgt_no = LabelRef(ins.lab2.name) - self.emit(arm.b_ins(tgt_no)) - self.freereg(ins.a, ins) - self.freereg(ins.b, ins) - elif type(ins) is ir.Alloc: - # Local variables are added to stack - self.addStack(ins.value) - self.localVars.append(ins.value) - # load address into variable: - else: - raise NotImplementedError('IR "{}" not covered'.format(ins)) - -