comparison 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
comparison
equal deleted inserted replaced
274:ea93e0a7a31e 275:6f2423df0675
5 from ppci import CompilerError 5 from ppci import CompilerError
6 import flowgraph 6 import flowgraph
7 import registerallocator 7 import registerallocator
8 from instructionselector import InstructionSelector 8 from instructionselector import InstructionSelector
9 import irmach 9 import irmach
10 10 from irmach import makeIns
11 import canon
12 import asm
11 13
12 class ArmFrame(irmach.Frame): 14 class ArmFrame(irmach.Frame):
13 """ 15 """
14 Arm specific frame for functions. 16 Arm specific frame for functions.
15 """ 17 """
16 pass 18 def __init__(self, name):
19 # We use r7 as frame pointer.
20 super().__init__(name)
21 self.regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6']
22 self.rv = ir.Temp('special_RV')
23 self.p1 = ir.Temp('special_P1')
24 self.p2 = ir.Temp('special_P2')
25 self.p3 = ir.Temp('special_P3')
26 self.p4 = ir.Temp('special_P4')
27 self.fp = ir.Temp('special_FP')
28 # Pre-colored registers:
29 self.tempMap = {}
30 self.tempMap[self.rv] = 'r0'
31 self.tempMap[self.p1] = 'r1'
32 self.tempMap[self.p2] = 'r2'
33 self.tempMap[self.p3] = 'r3'
34 self.tempMap[self.p4] = 'r4'
35 self.tempMap[self.fp] = 'r7'
36 self.locVars = {}
37 self.parMap = {}
38
39 def argLoc(self, pos):
40 """
41 Gets the function parameter location in IR-code format.
42 """
43 if pos == 0:
44 return self.p1
45 elif pos == 1:
46 return self.p2
47 elif pos == 2:
48 return self.p3
49 elif pos == 3:
50 return self.p4
51 else:
52 raise NotImplementedError('No more than 4 parameters implemented')
53
54 def allocVar(self, lvar):
55 if lvar not in self.locVars:
56 self.locVars[lvar] = self.stacksize
57 self.stacksize = self.stacksize + 4
58 return self.locVars[lvar]
59
60 def EntryExitGlue3(self):
61 """
62 Add code for the prologue and the epilogue. Add a label, the
63 return instruction and the stack pointer adjustment for the frame.
64 """
65 self.instructions.insert(0, makeIns('{}:'.format(self.name)))
66 self.instructions.insert(1, makeIns('push {lr, r7}'))
67 self.instructions.insert(2, makeIns('mov r7, sp'))
68 self.instructions.insert(3, makeIns('add sp, sp, {}'.format(self.stacksize)))
69 self.instructions.append(makeIns('sub sp, sp, {}'.format(self.stacksize)))
70 self.instructions.append(makeIns('pop {pc,r7}'))
17 71
18 72
19 class ArmInstructionSelector(InstructionSelector): 73 class ArmInstructionSelector(InstructionSelector):
20 """ Instruction selector for the arm architecture """ 74 """ Instruction selector for the arm architecture """
21 def newFrame(self, name):
22 return ArmFrame(name)
23
24 def munchExpr(self, e): 75 def munchExpr(self, e):
25 if isinstance(e, ir.Alloc): 76 if isinstance(e, ir.Alloc):
26 return 0 77 return 0
78 elif isinstance(e, ir.Binop) and e.operation == '+' and isinstance(e.b, ir.Const) and e.b.value < 8:
79 a = self.munchExpr(e.a)
80 d = self.newTmp()
81 self.emit('add %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a])
82 return d
27 elif isinstance(e, ir.Binop) and e.operation == '+': 83 elif isinstance(e, ir.Binop) and e.operation == '+':
28 a = self.munchExpr(e.value1) 84 a = self.munchExpr(e.a)
29 b = self.munchExpr(e.value2) 85 b = self.munchExpr(e.b)
30 d = self.newTmp() 86 d = self.newTmp()
31 self.emit('add %d0, %s0, %s1', dst=[d], src=[a, b]) 87 self.emit('add %d0, %s0, %s1', dst=[d], src=[a, b])
32 return d 88 return d
89 elif isinstance(e, ir.Binop) and e.operation == '-' and isinstance(e.b, ir.Const) and e.b.value < 8:
90 a = self.munchExpr(e.a)
91 d = self.newTmp()
92 self.emit('sub %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a])
93 return d
33 elif isinstance(e, ir.Binop) and e.operation == '-': 94 elif isinstance(e, ir.Binop) and e.operation == '-':
34 a = self.munchExpr(e.value1) 95 a = self.munchExpr(e.a)
35 b = self.munchExpr(e.value2) 96 b = self.munchExpr(e.b)
36 d = self.newTmp() 97 d = self.newTmp()
37 self.emit('sub %d0, %s0, %s1', dst=[d], src=[a, b]) 98 self.emit('sub %d0, %s0, %s1', dst=[d], src=[a, b])
38 return d 99 return d
39 elif isinstance(e, ir.Binop) and e.operation == '|': 100 elif isinstance(e, ir.Binop) and e.operation == '|':
40 a = self.munchExpr(e.value1) 101 a = self.munchExpr(e.a)
41 b = self.munchExpr(e.value2) 102 b = self.munchExpr(e.b)
42 d = self.newTmp() 103 d = self.newTmp()
43 self.emit('or %d0, %s0, %s1', dst=[d], src=[a, b]) 104 self.emit('or %d0, %s0, %s1', dst=[d], src=[a, b])
44 return d 105 return d
45 elif isinstance(e, ir.Binop) and e.operation == '<<': 106 elif isinstance(e, ir.Binop) and e.operation == '<<':
46 a = self.munchExpr(e.value1) 107 a = self.munchExpr(e.a)
47 b = self.munchExpr(e.value2) 108 b = self.munchExpr(e.b)
48 d = self.newTmp() 109 d = self.newTmp()
49 self.emit('lsl %d0, %s0, %s1', dst=[d], src=[a, b]) 110 self.emit('lsl %d0, %s0, %s1', dst=[d], src=[a, b])
50 return d 111 return d
51 elif isinstance(e, ir.Binop) and e.operation == '*': 112 elif isinstance(e, ir.Binop) and e.operation == '*':
52 a = self.munchExpr(e.value1) 113 a = self.munchExpr(e.a)
53 b = self.munchExpr(e.value2) 114 b = self.munchExpr(e.b)
54 d = self.newTmp() 115 d = self.newTmp()
55 self.emit('mul %d0, %s0, %s1', dst=[d], src=[a, b]) 116 self.emit('mul %d0, %s0, %s1', dst=[d], src=[a, b])
56 return d 117 return d
57 elif isinstance(e, ir.Const): 118 elif isinstance(e, ir.Const) and e.value < 256:
58 d = self.newTmp() 119 d = self.newTmp()
59 if e.value < 256: 120 self.emit('mov %d0, {}'.format(e.value), dst=[d])
60 self.emit('ldr %d0, {}'.format(e.value), dst=[d]) 121 return d
61 else: 122 elif isinstance(e, ir.Mem) and isinstance(e.e, ir.Binop) and \
62 self.emit('ldrpcrel TODO', dst=[d]) 123 e.e.operation == '+' and isinstance(e.e.b, ir.Const):
124 base = self.munchExpr(e.e.a)
125 d = self.newTmp()
126 self.emit('ldr %d0, [%s0 + {}]'.format(e.e.b.value), src=[base], dst=[d])
63 return d 127 return d
64 elif isinstance(e, ir.Mem): 128 elif isinstance(e, ir.Mem):
65 # Load from memory 129 # Load from memory
66 loc = self.munchExpr(e.e) 130 base = self.munchExpr(e.e)
67 d = self.newTmp() 131 d = self.newTmp()
68 self.emit('ldr %d0, [%s0]', src=[loc], dst=[d]) 132 self.emit('ldr %d0, [%s0]', src=[base], dst=[d])
69 return d 133 return d
70 elif isinstance(e, ir.Temp): 134 elif isinstance(e, ir.Temp):
71 return self.getTempReg(e) 135 return e
72 elif isinstance(e, ir.Parameter):
73 offset = 1337 # TODO: determine offset in frame??
74 d = self.newTmp()
75 self.emit('ldr %d0, [sp + {}]'.format(offset), dst=[d])
76 return d
77 elif isinstance(e, ir.Call): 136 elif isinstance(e, ir.Call):
78 args = [self.munchExpr(a) for a in e.arguments] 137 # Move arguments into proper locations:
79 frame_size = 222 # TODO: determine frame size? 138 reguses = []
80 self.emit('add sp, sp, {}'.format(frame_size)) 139 for i, a in enumerate(e.arguments):
81 # TODO: save frame 140 loc = self.frame.argLoc(i)
82 for a in args: 141 m = ir.Move(loc, a)
83 self.emit('push %s0', src=[a]) 142 self.munchStm(m)
84 self.emit('bl {}'.format(e.f.name)) 143 if isinstance(loc, ir.Temp):
85 self.emit('sub sp, sp, 22') 144 reguses.append(loc)
145 self.emit('bl {}'.format(e.f.name), src=reguses, dst=[self.frame.rv])
146 d = self.newTmp()
147 self.move(d, self.frame.rv)
148 return d
86 else: 149 else:
87 raise NotImplementedError('Expr --> {}'.format(e)) 150 raise NotImplementedError('Expr --> {}'.format(e))
88 151
89 def munchStm(self, s): 152 def munchStm(self, s):
90 if isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): 153 if isinstance(s, ir.Terminator):
154 pass
155 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):
156 val = self.munchExpr(s.src)
157 self.emit('str %s1, [%s0 + {}]'.format(s.dst.e.b.value), src=[s.dst.e.a, val])
158 elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem):
91 memloc = self.munchExpr(s.dst.e) 159 memloc = self.munchExpr(s.dst.e)
92 val = self.munchExpr(s.src) 160 val = self.munchExpr(s.src)
93 self.emit('str [%s0], %s1', src=[memloc, val]) 161 self.emit('str %s1, [%s0]', src=[memloc, val])
94 elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp): 162 elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp):
95 val = self.munchExpr(s.src) 163 val = self.munchExpr(s.src)
96 dreg = self.getTempReg(s.dst) 164 dreg = s.dst
97 self.emit('mov %d0, %s0', dst=[dreg], src=[val]) 165 self.emit('mov %d0, %s0', dst=[dreg], src=[val])
166 elif isinstance(s, ir.Exp):
167 # Generate expression code and discard the result.
168 x = self.munchExpr(s.e)
169 self.emit('mov r0, r0', src=[x])
98 elif isinstance(s, ir.Jump): 170 elif isinstance(s, ir.Jump):
99 tgt = self.targets[s.target] 171 tgt = self.targets[s.target]
100 self.emit('jmp %l0', jumps=[tgt]) 172 self.emit('b {}'.format(s.target.name), jumps=[tgt])
101 elif isinstance(s, ir.CJump): 173 elif isinstance(s, ir.CJump):
102 a = self.munchExpr(s.a) 174 a = self.munchExpr(s.a)
103 b = self.munchExpr(s.b) 175 b = self.munchExpr(s.b)
104 self.emit('cmp %s0, %s1', src=[a, b]) 176 self.emit('cmp %s0, %s1', src=[a, b])
105 ntgt = self.targets[s.lab_no] 177 ntgt = self.targets[s.lab_no]
106 ytgt = self.targets[s.lab_yes] 178 ytgt = self.targets[s.lab_yes]
107 jmp_ins = self.makeIns('jmp %l0', jumps=[ntgt]) 179 jmp_ins = makeIns('jmp {}'.format(s.lab_no.name), jumps=[ntgt])
108 # Explicitely add fallthrough: 180 # Explicitely add fallthrough:
109 self.emit('jeq %l0', jumps=[ytgt, jmp_ins]) 181 self.emit('jeq %l0', jumps=[ytgt, jmp_ins])
110 self.emit2(jmp_ins) 182 self.emit2(jmp_ins)
111 elif isinstance(s, ir.Terminator):
112 pass
113 else: 183 else:
114 raise NotImplementedError('Stmt --> {}'.format(s)) 184 raise NotImplementedError('Stmt --> {}'.format(s))
115 185
116 186
117 # TODO: this class could be target independent: 187 # TODO: this class could be target independent:
134 for s in iter(i.src): 204 for s in iter(i.src):
135 useTemps.append(s) 205 useTemps.append(s)
136 defTemps = set(defTemps) 206 defTemps = set(defTemps)
137 useTemps = set(useTemps) 207 useTemps = set(useTemps)
138 unUsed = defTemps - useTemps 208 unUsed = defTemps - useTemps
139 print('Unused:', unUsed) 209 assert not unUsed
140 for uu in unUsed: 210 for uu in unUsed:
141 inslist.append(irmach.AbstractInstruction('use %s0', src=[uu])) 211 inslist.append(irmach.AbstractInstruction('use %s0', src=[uu]))
142 #print(useTemps) 212 #print(useTemps)
143 213
144 def allocFrame(self, f): 214 def allocFrame(self, f):
150 cfg = flowgraph.FlowGraph(ilist) 220 cfg = flowgraph.FlowGraph(ilist)
151 f.cfg = cfg 221 f.cfg = cfg
152 ig = registerallocator.InterferenceGraph(cfg) 222 ig = registerallocator.InterferenceGraph(cfg)
153 f.ig = ig 223 f.ig = ig
154 224
155 regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7']
156 ra = registerallocator.RegisterAllocator() 225 ra = registerallocator.RegisterAllocator()
157 regMap = ra.registerAllocate(ig, regs) 226 regMap = ra.registerAllocate(ig, f.regs, f.tempMap)
158 #print(regMap)
159 # Use allocated registers: 227 # Use allocated registers:
160 for i in ilist: 228 for i in ilist:
161 i.src = tuple(regMap[t] for t in i.src) 229 i.src = tuple(regMap[t] for t in i.src)
162 i.dst = tuple(regMap[t] for t in i.dst) 230 i.dst = tuple(regMap[t] for t in i.dst)
163 #print(i) 231
232 def generateFunc(self, irfunc):
233 # Create a frame for this function:
234 frame = ArmFrame(irfunc.name)
235 # Canonicalize the intermediate language:
236 canon.make(irfunc, frame)
237 # print('after canonicalize:')
238 # irfunc.dump()
239 self.ins_sel.munchFunction(irfunc, frame)
240 # print('Selected instructions:')
241 #for i in frame.instructions:
242 # print(i)
243
244 # Do register allocation:
245 self.allocFrame(frame)
246 # TODO: Peep-hole here?
247
248 # Add label and return and stack adjustment:
249 frame.EntryExitGlue3()
250 return frame
164 251
165 def generate(self, ircode): 252 def generate(self, ircode):
166 # Munch program into a bunch of frames. One frame per function. 253 # Munch program into a bunch of frames. One frame per function.
167 # Each frame has a flat list of abstract instructions. 254 # Each frame has a flat list of abstract instructions.
168 frames = self.ins_sel.munchProgram(ircode) 255 # Generate code for all functions:
169 self.frames = frames 256 self.frames = [self.generateFunc(func) for func in ircode.Functions]
170 for f in frames: 257
171 self.allocFrame(f) 258 # Materialize assembly
172 259 # Reparse the register allocated instructions into a stream of
173 # TODO: Peep-hole here 260 # real instructions.
174 # TODO: Materialize assembly 261 # TODO: this is ugly via string representations. This could be
175 return frames 262 # another interface?
176 263 assembler = asm.Assembler(target=arm.armtarget, stream=self.outs)
177 264 self.outs.selectSection('code')
265 for frame in self.frames:
266 for i in frame.instructions:
267 assembler.assemble_line(str(i))
268
269 return self.frames
270