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