diff python/codegenarm.py @ 280:02385f62f250

Rework from str interface to Instruction interface
author Windel Bouwman
date Sat, 02 Nov 2013 10:03:26 +0100
parents 2ccd57b1d78c
children
line wrap: on
line diff
--- a/python/codegenarm.py	Sat Oct 12 09:56:23 2013 +0200
+++ b/python/codegenarm.py	Sat Nov 02 10:03:26 2013 +0100
@@ -1,13 +1,15 @@
 import logging
 import ir
-from target import Label, Comment, Alignment, LabelRef, Imm32, DebugInfo
+from target import Label, Comment, Alignment, LabelRef, Imm32, DebugInfo, Nop
+from target import Imm3
 import cortexm3 as arm
 from ppci import CompilerError
 import registerallocator
 from instructionselector import InstructionSelector
 import irmach
-from irmach import makeIns
+from irmach import AbstractInstruction as makeIns
 import canon
+import transform
 import asm
 
 class ArmFrame(irmach.Frame):
@@ -17,7 +19,7 @@
     def __init__(self, name):
         # We use r7 as frame pointer.
         super().__init__(name)
-        self.regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6']
+        self.regs = [arm.r0, arm.r1, arm.r2, arm.r3, arm.r4, arm.r5, arm.r6]
         self.rv = ir.Temp('special_RV')
         self.p1 = ir.Temp('special_P1')
         self.p2 = ir.Temp('special_P2')
@@ -26,12 +28,12 @@
         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.tempMap[self.rv] = arm.r0
+        self.tempMap[self.p1] = arm.r1
+        self.tempMap[self.p2] = arm.r2
+        self.tempMap[self.p3] = arm.r3
+        self.tempMap[self.p4] = arm.r4
+        self.tempMap[self.fp] = arm.r7
         self.locVars = {}
         self.parMap = {}
         # Literal pool:
@@ -68,20 +70,20 @@
             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(0, makeIns(arm.Label(self.name)))
+        self.instructions.insert(1, makeIns(arm.push_ins(arm.RegisterSet({arm.lr, arm.r7}))))
         # Reserve stack space for locals:
-        self.instructions.insert(2, makeIns('sub sp, sp, {}'.format(self.stacksize)))
+        self.instructions.insert(2, makeIns(arm.subspsp_ins(arm.sp, arm.sp, arm.Imm7(self.stacksize))))
         # Setup frame pointer:
-        self.instructions.insert(3, makeIns('mov r7, sp'))
+        self.instructions.insert(3, makeIns(arm.movregreg_ext_ins(arm.r7, arm.sp)))
         # Stack grows downwards
-        self.instructions.append(makeIns('add sp, sp, {}'.format(self.stacksize)))
-        self.instructions.append(makeIns('pop {pc,r7}'))
+        self.instructions.append(makeIns(arm.addspsp_ins(arm.sp, arm.sp, arm.Imm7(self.stacksize))))
+        self.instructions.append(makeIns(arm.pop_ins(arm.RegisterSet({arm.pc, arm.r7}))))
         # Add constant literals:
-        self.instructions.append(makeIns('align 4')) # Align at 4 bytes
+        self.instructions.append(makeIns(Alignment(4))) # Align at 4 bytes
         for ln, v in self.constants:
-            self.instructions.append(makeIns('{}:'.format(ln)))
-            self.instructions.append(makeIns('dcd {}'.format(v)))
+            self.instructions.append(makeIns(arm.Label(ln)))
+            self.instructions.append(makeIns(arm.dcd_ins(v)))
 
 
 class ArmInstructionSelector(InstructionSelector):
@@ -94,39 +96,41 @@
             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])
+            c = Imm3(e.b.value)
+            self.emit(arm.addregregimm3_ins, others=[c], dst=[d], src=[a])
             return d
         elif isinstance(e, ir.Binop) and e.operation == '+':
             a = self.munchExpr(e.a)
             b = self.munchExpr(e.b)
             d = self.newTmp()
-            self.emit('add %d0, %s0, %s1', dst=[d], src=[a, b])
+            self.emit(arm.addregs_ins, 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])
+            c = Imm3(e.b.value)
+            self.emit(arm.subregregimm3_ins, others=[c], dst=[d], src=[a])
             return d
         elif isinstance(e, ir.Binop) and e.operation == '-':
             a = self.munchExpr(e.a)
             b = self.munchExpr(e.b)
             d = self.newTmp()
-            self.emit('sub %d0, %s0, %s1', dst=[d], src=[a, b])
+            self.emit(arm.subregs_ins, dst=[d], src=[a, b])
             return d
         elif isinstance(e, ir.Binop) and e.operation == '|':
             a = self.munchExpr(e.a)
             b = self.munchExpr(e.b)
             d = self.newTmp()
             self.move(d, a)
-            self.emit('orr %s1, %s0', dst=[], src=[b, d])
+            self.emit(arm.orrregs_ins, dst=[], src=[b, d])
             return d
         elif isinstance(e, ir.Binop) and e.operation == '<<':
             a = self.munchExpr(e.a)
             b = self.munchExpr(e.b)
             d = self.newTmp()
             self.move(d, a)
-            self.emit('lsl %s1, %s0', dst=[], src=[b, d]) # TODO: is d a source variable?
+            self.emit(arm.lslregs_ins, dst=[], src=[b, d]) # TODO: is d a source variable?
             return d
         elif isinstance(e, ir.Binop) and e.operation == '*':
             a = self.munchExpr(e.a)
@@ -134,29 +138,29 @@
             d = self.newTmp()
             self.move(d, a)
             # this mul instruction has operands swapped:
-            self.emit('mul %s0, %d0', dst=[d], src=[b, d])
+            self.emit(arm.mulregreg_ins, dst=[d], src=[b, d])
             return d
         elif isinstance(e, ir.Const) and e.value < 256:
             d = self.newTmp()
-            self.emit('mov %d0, {}'.format(e.value), dst=[d])
+            self.emit(arm.mov_imm8_ins, others=[arm.Imm8(e.value)], dst=[d])
             return d
         elif isinstance(e, ir.Const) and e.value < (2**31):
             d = self.newTmp()
-            ln = self.frame.addConstant(e.value)
-            self.emit('ldr %d0, {}'.format(ln), dst=[d])
+            ln = LabelRef(self.frame.addConstant(e.value))
+            self.emit(arm.ldr_pcrel, others=[ln], 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()
             c = e.e.b.value
-            self.emit('ldr %d0, [%s0 + {}]'.format(c), src=[base], dst=[d])
+            self.emit(arm.loadimm5_ins, others=[c], src=[base], dst=[d])
             return d
         elif isinstance(e, ir.Mem):
             # Load from memory
             base = self.munchExpr(e.e)
             d = self.newTmp()
-            self.emit('ldr %d0, [%s0]', src=[base], dst=[d])
+            self.emit(arm.loadimm5_ins, others=[0], src=[base], dst=[d])
             return d
         elif isinstance(e, ir.Temp):
             return e
@@ -169,7 +173,7 @@
                 self.munchStm(m)
                 if isinstance(loc, ir.Temp):
                     reguses.append(loc)
-            self.emit('bl {}'.format(e.f.name), src=reguses, dst=[self.frame.rv])
+            self.emit(arm.bl_ins(LabelRef(e.f.name)), src=reguses, dst=[self.frame.rv])
             d = self.newTmp()
             self.move(d, self.frame.rv)
             return d
@@ -185,35 +189,39 @@
             a = self.munchExpr(s.dst.e.a)
             val = self.munchExpr(s.src)
             c = s.dst.e.b.value
-            self.emit('str %s1, [%s0 + {}]'.format(c), src=[a, val])
+            self.emit(arm.storeimm5_ins, others=[c], src=[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 %s1, [%s0]', src=[memloc, val])
+            self.emit(arm.storeimm5_ins, others=[0], src=[memloc, val])
         elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp):
             val = self.munchExpr(s.src)
             dreg = s.dst
-            self.emit('mov %d0, %s0', dst=[dreg], src=[val])
+            self.move(dreg, val)
         elif isinstance(s, ir.Exp):
             # Generate expression code and discard the result.
             x = self.munchExpr(s.e)
-            self.emit('nop', src=[x])
+            self.emit(Nop(), src=[x])
         elif isinstance(s, ir.Jump):
             tgt = self.targets[s.target]
-            self.emit('b {}'.format(s.target.name), jumps=[tgt])
+            self.emit(arm.b_ins(LabelRef(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])
+            self.emit(arm.cmp_ins, src=[a, b])
             ntgt = self.targets[s.lab_no]
             ytgt = self.targets[s.lab_yes]
-            jmp_ins = makeIns('b {}'.format(s.lab_no.name), jumps=[ntgt])
-            # Explicitely add fallthrough:
-            self.emit('beq {}'.format(s.lab_yes.name), jumps=[ytgt, jmp_ins])
+            jmp_ins = makeIns(arm.b_ins(LabelRef(s.lab_no.name)), jumps=[ntgt])
+            opnames = {'<': arm.blt_ins, '>':arm.bgt_ins, '==':arm.beq_ins}
+            op = opnames[s.cond](LabelRef(s.lab_yes.name))
+            self.emit(op, jumps=[ytgt, jmp_ins]) # Explicitely add fallthrough
             self.emit2(jmp_ins)
         else:
             raise NotImplementedError('Stmt --> {}'.format(s))
 
+    def move(self, dst, src):
+        self.emit(arm.movregreg_ext_ins, src=[src], dst=[dst])
+
 
 # TODO: this class could be target independent:
 class ArmCodeGenerator:
@@ -227,47 +235,45 @@
         self.outs.getSection('data').address = 0x20000000
 
     def generateFunc(self, irfunc):
+        """ Generate code for one function into a frame """
+        # Cleanup function:
+        transform.removeEmptyBlocks(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.ra.allocFrame(frame)
         # TODO: Peep-hole here?
 
+        # Can we materialize here??
+
         # Add label and return and stack adjustment:
         frame.EntryExitGlue3()
+
+        # Materialize assembly
+        # Materialize the register allocated instructions into a stream of
+        # real instructions.
+        frame.lower_to(self.outs)
         return frame
 
     def generate(self, ircode):
+        self.outs.selectSection('code')
+        # assembly glue to make it work:
+        # TODO: this must be in source code, not in compiler
+        self.outs.emit(arm.dcd_ins(Imm32(0x20000678))) # initial SP
+        self.outs.emit(arm.dcd_ins(Imm32(0x08000009))) # reset vector
+        self.outs.emit(arm.b_ins(LabelRef('main')))
+
         # Munch program into a bunch of frames. One frame per function.
         # Each frame has a flat list of abstract instructions.
         # Generate code for all functions:
         self.frames = [self.generateFunc(func) for func in ircode.Functions]
 
-        # 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')
-        # assembly glue to make it work:
-        self.outs.emit(arm.dcd_ins(Imm32(0x20000678))) # initial SP
-        self.outs.emit(arm.dcd_ins(Imm32(0x08000009))) # reset vector
-        self.outs.emit(arm.b_ins(LabelRef('main')))
-        for frame in self.frames:
-            for i in frame.instructions:
-                assembler.assemble_line(str(i))
-
         # TODO: fixup references, do this in another way?
         self.outs.backpatch()
         self.outs.backpatch()