view python/codegenarm.py @ 270:cdc76d183bcc

first register allocator
author Windel Bouwman
date Mon, 19 Aug 2013 21:14:28 +0200
parents 5f8c04a8d26b
children e64bae57cda8
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


class ArmInstructionSelector(InstructionSelector):
    """ Instruction selector for the arm architecture """
    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)
        else:
            raise NotImplementedError('--> {}'.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')
        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.Return):
            #etgt = self.targets[
            self.emit('jmp exit', jumps=[])
        elif isinstance(s, ir.Jump):
            tgt = self.targets[s.target]
            self.emit('jmp {}'.format(s), 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 {}'.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 useUnused(self, inslist):
        # Use unused temporaries at the end of the list
        defTemps = []
        for d in (i.dst for i in inslist):
            print(d)
            defTemps.append(d)
        useTemps = [d for d in ([i.src] for i in inslist)]
        print(defTemps)
        print(useTemps)

    def generate(self, ircode, cfg_file=None, ig_file=None):
        ir2 = self.ins_sel.munchProgram(ircode)
        self.useUnused(ir2)
        cfg = flowgraph.FlowGraph(ir2)
        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()
        regMap = ra.registerAllocate(ig, regs)
        print(regMap)
        for i in ir2:
            i.src = tuple(regMap[t] for t in i.src)
            i.dst = tuple(regMap[t] for t in i.dst)
            print(i)