Mercurial > lcfOS
diff python/codegenarm.py @ 275:6f2423df0675
Fixed serve arm-as
author | Windel Bouwman |
---|---|
date | Sat, 14 Sep 2013 17:29:10 +0200 |
parents | ea93e0a7a31e |
children | 56d37ed4b4d2 |
line wrap: on
line diff
--- a/python/codegenarm.py Wed Sep 04 17:35:06 2013 +0200 +++ b/python/codegenarm.py Sat Sep 14 17:29:10 2013 +0200 @@ -7,109 +7,179 @@ import registerallocator from instructionselector import InstructionSelector import irmach - +from irmach import makeIns +import canon +import asm class ArmFrame(irmach.Frame): """ Arm specific frame for functions. """ - pass + def __init__(self, name): + # We use r7 as frame pointer. + super().__init__(name) + self.regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6'] + self.rv = ir.Temp('special_RV') + self.p1 = ir.Temp('special_P1') + self.p2 = ir.Temp('special_P2') + self.p3 = ir.Temp('special_P3') + self.p4 = ir.Temp('special_P4') + self.fp = ir.Temp('special_FP') + # Pre-colored registers: + self.tempMap = {} + self.tempMap[self.rv] = 'r0' + self.tempMap[self.p1] = 'r1' + self.tempMap[self.p2] = 'r2' + self.tempMap[self.p3] = 'r3' + self.tempMap[self.p4] = 'r4' + self.tempMap[self.fp] = 'r7' + self.locVars = {} + self.parMap = {} + + def argLoc(self, pos): + """ + Gets the function parameter location in IR-code format. + """ + if pos == 0: + return self.p1 + elif pos == 1: + return self.p2 + elif pos == 2: + return self.p3 + elif pos == 3: + return self.p4 + else: + raise NotImplementedError('No more than 4 parameters implemented') + + def allocVar(self, lvar): + if lvar not in self.locVars: + self.locVars[lvar] = self.stacksize + self.stacksize = self.stacksize + 4 + return self.locVars[lvar] + + def EntryExitGlue3(self): + """ + Add code for the prologue and the epilogue. Add a label, the + return instruction and the stack pointer adjustment for the frame. + """ + self.instructions.insert(0, makeIns('{}:'.format(self.name))) + self.instructions.insert(1, makeIns('push {lr, r7}')) + self.instructions.insert(2, makeIns('mov r7, sp')) + self.instructions.insert(3, makeIns('add sp, sp, {}'.format(self.stacksize))) + self.instructions.append(makeIns('sub sp, sp, {}'.format(self.stacksize))) + self.instructions.append(makeIns('pop {pc,r7}')) class ArmInstructionSelector(InstructionSelector): """ Instruction selector for the arm architecture """ - def newFrame(self, name): - return ArmFrame(name) - def munchExpr(self, e): if isinstance(e, ir.Alloc): return 0 + elif isinstance(e, ir.Binop) and e.operation == '+' and isinstance(e.b, ir.Const) and e.b.value < 8: + a = self.munchExpr(e.a) + d = self.newTmp() + self.emit('add %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a]) + return d elif isinstance(e, ir.Binop) and e.operation == '+': - a = self.munchExpr(e.value1) - b = self.munchExpr(e.value2) + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) d = self.newTmp() self.emit('add %d0, %s0, %s1', dst=[d], src=[a, b]) return d + elif isinstance(e, ir.Binop) and e.operation == '-' and isinstance(e.b, ir.Const) and e.b.value < 8: + a = self.munchExpr(e.a) + d = self.newTmp() + self.emit('sub %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a]) + return d elif isinstance(e, ir.Binop) and e.operation == '-': - a = self.munchExpr(e.value1) - b = self.munchExpr(e.value2) + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) 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) + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) d = self.newTmp() 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) - b = self.munchExpr(e.value2) + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) d = self.newTmp() self.emit('lsl %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) + a = self.munchExpr(e.a) + b = self.munchExpr(e.b) d = self.newTmp() self.emit('mul %d0, %s0, %s1', dst=[d], src=[a, b]) return d - elif isinstance(e, ir.Const): + elif isinstance(e, ir.Const) and e.value < 256: d = self.newTmp() - if e.value < 256: - self.emit('ldr %d0, {}'.format(e.value), dst=[d]) - else: - self.emit('ldrpcrel TODO', dst=[d]) + self.emit('mov %d0, {}'.format(e.value), dst=[d]) + return d + elif isinstance(e, ir.Mem) and isinstance(e.e, ir.Binop) and \ + e.e.operation == '+' and isinstance(e.e.b, ir.Const): + base = self.munchExpr(e.e.a) + d = self.newTmp() + self.emit('ldr %d0, [%s0 + {}]'.format(e.e.b.value), src=[base], dst=[d]) return d elif isinstance(e, ir.Mem): # Load from memory - loc = self.munchExpr(e.e) + base = self.munchExpr(e.e) d = self.newTmp() - self.emit('ldr %d0, [%s0]', src=[loc], dst=[d]) + self.emit('ldr %d0, [%s0]', src=[base], dst=[d]) return d elif isinstance(e, ir.Temp): - return self.getTempReg(e) - elif isinstance(e, ir.Parameter): - offset = 1337 # TODO: determine offset in frame?? - d = self.newTmp() - self.emit('ldr %d0, [sp + {}]'.format(offset), dst=[d]) - return d + return e elif isinstance(e, ir.Call): - args = [self.munchExpr(a) for a in e.arguments] - frame_size = 222 # TODO: determine frame size? - self.emit('add sp, sp, {}'.format(frame_size)) - # TODO: save frame - for a in args: - self.emit('push %s0', src=[a]) - self.emit('bl {}'.format(e.f.name)) - self.emit('sub sp, sp, 22') + # Move arguments into proper locations: + reguses = [] + for i, a in enumerate(e.arguments): + loc = self.frame.argLoc(i) + m = ir.Move(loc, a) + self.munchStm(m) + if isinstance(loc, ir.Temp): + reguses.append(loc) + self.emit('bl {}'.format(e.f.name), src=reguses, dst=[self.frame.rv]) + d = self.newTmp() + self.move(d, self.frame.rv) + return d else: raise NotImplementedError('Expr --> {}'.format(e)) def munchStm(self, s): - if isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): + if isinstance(s, ir.Terminator): + pass + elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem) and isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and isinstance(s.dst.e.a, ir.Temp) and isinstance(s.dst.e.b, ir.Const): + val = self.munchExpr(s.src) + self.emit('str %s1, [%s0 + {}]'.format(s.dst.e.b.value), src=[s.dst.e.a, val]) + elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): memloc = self.munchExpr(s.dst.e) val = self.munchExpr(s.src) - self.emit('str [%s0], %s1', src=[memloc, val]) + self.emit('str %s1, [%s0]', src=[memloc, val]) elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp): val = self.munchExpr(s.src) - dreg = self.getTempReg(s.dst) + dreg = s.dst self.emit('mov %d0, %s0', dst=[dreg], src=[val]) + elif isinstance(s, ir.Exp): + # Generate expression code and discard the result. + x = self.munchExpr(s.e) + self.emit('mov r0, r0', src=[x]) elif isinstance(s, ir.Jump): tgt = self.targets[s.target] - self.emit('jmp %l0', jumps=[tgt]) + self.emit('b {}'.format(s.target.name), jumps=[tgt]) elif isinstance(s, ir.CJump): 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 %l0', jumps=[ntgt]) + jmp_ins = makeIns('jmp {}'.format(s.lab_no.name), jumps=[ntgt]) # Explicitely add fallthrough: self.emit('jeq %l0', jumps=[ytgt, jmp_ins]) self.emit2(jmp_ins) - elif isinstance(s, ir.Terminator): - pass else: raise NotImplementedError('Stmt --> {}'.format(s)) @@ -136,7 +206,7 @@ defTemps = set(defTemps) useTemps = set(useTemps) unUsed = defTemps - useTemps - print('Unused:', unUsed) + assert not unUsed for uu in unUsed: inslist.append(irmach.AbstractInstruction('use %s0', src=[uu])) #print(useTemps) @@ -152,26 +222,49 @@ ig = registerallocator.InterferenceGraph(cfg) f.ig = ig - regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7'] ra = registerallocator.RegisterAllocator() - regMap = ra.registerAllocate(ig, regs) - #print(regMap) + regMap = ra.registerAllocate(ig, f.regs, f.tempMap) # Use allocated registers: for i in ilist: i.src = tuple(regMap[t] for t in i.src) i.dst = tuple(regMap[t] for t in i.dst) - #print(i) + + def generateFunc(self, irfunc): + # Create a frame for this function: + frame = ArmFrame(irfunc.name) + # Canonicalize the intermediate language: + canon.make(irfunc, frame) + # print('after canonicalize:') + # irfunc.dump() + self.ins_sel.munchFunction(irfunc, frame) + # print('Selected instructions:') + #for i in frame.instructions: + # print(i) + + # Do register allocation: + self.allocFrame(frame) + # TODO: Peep-hole here? + + # Add label and return and stack adjustment: + frame.EntryExitGlue3() + return frame def generate(self, ircode): # Munch program into a bunch of frames. One frame per function. # Each frame has a flat list of abstract instructions. - frames = self.ins_sel.munchProgram(ircode) - self.frames = frames - for f in frames: - self.allocFrame(f) + # Generate code for all functions: + self.frames = [self.generateFunc(func) for func in ircode.Functions] - # TODO: Peep-hole here - # TODO: Materialize assembly - return frames + # Materialize assembly + # Reparse the register allocated instructions into a stream of + # real instructions. + # TODO: this is ugly via string representations. This could be + # another interface? + assembler = asm.Assembler(target=arm.armtarget, stream=self.outs) + self.outs.selectSection('code') + for frame in self.frames: + for i in frame.instructions: + assembler.assemble_line(str(i)) + return self.frames