view python/codegenarm.py @ 274:ea93e0a7a31e

Move docs
author Windel Bouwman
date Wed, 04 Sep 2013 17:35:06 +0200
parents e64bae57cda8
children 6f2423df0675
line wrap: on
line source

import logging
import ir
from target import Label, Comment, Alignment, LabelRef, Imm32, DebugInfo
import cortexm3 as arm
from ppci import CompilerError
import flowgraph
import registerallocator
from instructionselector import InstructionSelector
import irmach


class ArmFrame(irmach.Frame):
    """
      Arm specific frame for functions.
    """
    pass


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 == '+':
            a = self.munchExpr(e.value1)
            b = self.munchExpr(e.value2)
            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('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)
            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)
            d = self.newTmp()
            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', dst=[d])
            return d
        elif isinstance(e, ir.Mem):
            # Load from memory
            loc = self.munchExpr(e.e)
            d = self.newTmp()
            self.emit('ldr %d0, [%s0]', src=[loc], 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
        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')
        else:
            raise NotImplementedError('Expr --> {}'.format(e))

    def munchStm(self, s):
        if 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])
        elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp):
            val = self.munchExpr(s.src)
            dreg = self.getTempReg(s.dst)
            self.emit('mov %d0, %s0', dst=[dreg], src=[val])
        elif isinstance(s, ir.Jump):
            tgt = self.targets[s.target]
            self.emit('jmp %l0', 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])
            # 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))


# TODO: this class could be target independent:
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 useUnused(self, inslist):
        # Use unused temporaries at the end of the list
        defTemps = []
        useTemps = []
        for i in inslist:
            for d in iter(i.dst):
                defTemps.append(d)
            for s in iter(i.src):
                useTemps.append(s)
        defTemps = set(defTemps)
        useTemps = set(useTemps)
        unUsed = defTemps - useTemps
        print('Unused:', unUsed)
        for uu in unUsed:
            inslist.append(irmach.AbstractInstruction('use %s0', src=[uu]))
        #print(useTemps)

    def allocFrame(self, f):
        """
            Do register allocation for a single stack frame.
        """
        ilist = f.instructions
        self.useUnused(ilist)
        cfg = flowgraph.FlowGraph(ilist)
        f.cfg = cfg
        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)
        # 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 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)

        # TODO: Peep-hole here
        # TODO: Materialize assembly
        return frames