comparison 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
comparison
equal deleted inserted replaced
279:2ccd57b1d78c 280:02385f62f250
1 import logging 1 import logging
2 import ir 2 import ir
3 from target import Label, Comment, Alignment, LabelRef, Imm32, DebugInfo 3 from target import Label, Comment, Alignment, LabelRef, Imm32, DebugInfo, Nop
4 from target import Imm3
4 import cortexm3 as arm 5 import cortexm3 as arm
5 from ppci import CompilerError 6 from ppci import CompilerError
6 import registerallocator 7 import registerallocator
7 from instructionselector import InstructionSelector 8 from instructionselector import InstructionSelector
8 import irmach 9 import irmach
9 from irmach import makeIns 10 from irmach import AbstractInstruction as makeIns
10 import canon 11 import canon
12 import transform
11 import asm 13 import asm
12 14
13 class ArmFrame(irmach.Frame): 15 class ArmFrame(irmach.Frame):
14 """ 16 """
15 Arm specific frame for functions. 17 Arm specific frame for functions.
16 """ 18 """
17 def __init__(self, name): 19 def __init__(self, name):
18 # We use r7 as frame pointer. 20 # We use r7 as frame pointer.
19 super().__init__(name) 21 super().__init__(name)
20 self.regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6'] 22 self.regs = [arm.r0, arm.r1, arm.r2, arm.r3, arm.r4, arm.r5, arm.r6]
21 self.rv = ir.Temp('special_RV') 23 self.rv = ir.Temp('special_RV')
22 self.p1 = ir.Temp('special_P1') 24 self.p1 = ir.Temp('special_P1')
23 self.p2 = ir.Temp('special_P2') 25 self.p2 = ir.Temp('special_P2')
24 self.p3 = ir.Temp('special_P3') 26 self.p3 = ir.Temp('special_P3')
25 self.p4 = ir.Temp('special_P4') 27 self.p4 = ir.Temp('special_P4')
26 self.fp = ir.Temp('special_FP') 28 self.fp = ir.Temp('special_FP')
27 # Pre-colored registers: 29 # Pre-colored registers:
28 self.tempMap = {} 30 self.tempMap = {}
29 self.tempMap[self.rv] = 'r0' 31 self.tempMap[self.rv] = arm.r0
30 self.tempMap[self.p1] = 'r1' 32 self.tempMap[self.p1] = arm.r1
31 self.tempMap[self.p2] = 'r2' 33 self.tempMap[self.p2] = arm.r2
32 self.tempMap[self.p3] = 'r3' 34 self.tempMap[self.p3] = arm.r3
33 self.tempMap[self.p4] = 'r4' 35 self.tempMap[self.p4] = arm.r4
34 self.tempMap[self.fp] = 'r7' 36 self.tempMap[self.fp] = arm.r7
35 self.locVars = {} 37 self.locVars = {}
36 self.parMap = {} 38 self.parMap = {}
37 # Literal pool: 39 # Literal pool:
38 self.constants = [] 40 self.constants = []
39 41
66 def EntryExitGlue3(self): 68 def EntryExitGlue3(self):
67 """ 69 """
68 Add code for the prologue and the epilogue. Add a label, the 70 Add code for the prologue and the epilogue. Add a label, the
69 return instruction and the stack pointer adjustment for the frame. 71 return instruction and the stack pointer adjustment for the frame.
70 """ 72 """
71 self.instructions.insert(0, makeIns('{}:'.format(self.name))) 73 self.instructions.insert(0, makeIns(arm.Label(self.name)))
72 self.instructions.insert(1, makeIns('push {lr, r7}')) 74 self.instructions.insert(1, makeIns(arm.push_ins(arm.RegisterSet({arm.lr, arm.r7}))))
73 # Reserve stack space for locals: 75 # Reserve stack space for locals:
74 self.instructions.insert(2, makeIns('sub sp, sp, {}'.format(self.stacksize))) 76 self.instructions.insert(2, makeIns(arm.subspsp_ins(arm.sp, arm.sp, arm.Imm7(self.stacksize))))
75 # Setup frame pointer: 77 # Setup frame pointer:
76 self.instructions.insert(3, makeIns('mov r7, sp')) 78 self.instructions.insert(3, makeIns(arm.movregreg_ext_ins(arm.r7, arm.sp)))
77 # Stack grows downwards 79 # Stack grows downwards
78 self.instructions.append(makeIns('add sp, sp, {}'.format(self.stacksize))) 80 self.instructions.append(makeIns(arm.addspsp_ins(arm.sp, arm.sp, arm.Imm7(self.stacksize))))
79 self.instructions.append(makeIns('pop {pc,r7}')) 81 self.instructions.append(makeIns(arm.pop_ins(arm.RegisterSet({arm.pc, arm.r7}))))
80 # Add constant literals: 82 # Add constant literals:
81 self.instructions.append(makeIns('align 4')) # Align at 4 bytes 83 self.instructions.append(makeIns(Alignment(4))) # Align at 4 bytes
82 for ln, v in self.constants: 84 for ln, v in self.constants:
83 self.instructions.append(makeIns('{}:'.format(ln))) 85 self.instructions.append(makeIns(arm.Label(ln)))
84 self.instructions.append(makeIns('dcd {}'.format(v))) 86 self.instructions.append(makeIns(arm.dcd_ins(v)))
85 87
86 88
87 class ArmInstructionSelector(InstructionSelector): 89 class ArmInstructionSelector(InstructionSelector):
88 90
89 """ Instruction selector for the arm architecture """ 91 """ Instruction selector for the arm architecture """
92 return 0 94 return 0
93 elif isinstance(e, ir.Binop) and e.operation == '+' and \ 95 elif isinstance(e, ir.Binop) and e.operation == '+' and \
94 isinstance(e.b, ir.Const) and e.b.value < 8: 96 isinstance(e.b, ir.Const) and e.b.value < 8:
95 a = self.munchExpr(e.a) 97 a = self.munchExpr(e.a)
96 d = self.newTmp() 98 d = self.newTmp()
97 self.emit('add %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a]) 99 c = Imm3(e.b.value)
100 self.emit(arm.addregregimm3_ins, others=[c], dst=[d], src=[a])
98 return d 101 return d
99 elif isinstance(e, ir.Binop) and e.operation == '+': 102 elif isinstance(e, ir.Binop) and e.operation == '+':
100 a = self.munchExpr(e.a) 103 a = self.munchExpr(e.a)
101 b = self.munchExpr(e.b) 104 b = self.munchExpr(e.b)
102 d = self.newTmp() 105 d = self.newTmp()
103 self.emit('add %d0, %s0, %s1', dst=[d], src=[a, b]) 106 self.emit(arm.addregs_ins, dst=[d], src=[a, b])
104 return d 107 return d
105 elif isinstance(e, ir.Binop) and e.operation == '-' and \ 108 elif isinstance(e, ir.Binop) and e.operation == '-' and \
106 isinstance(e.b, ir.Const) and e.b.value < 8: 109 isinstance(e.b, ir.Const) and e.b.value < 8:
107 a = self.munchExpr(e.a) 110 a = self.munchExpr(e.a)
108 d = self.newTmp() 111 d = self.newTmp()
109 self.emit('sub %d0, %s0, {}'.format(e.b.value), dst=[d], src=[a]) 112 c = Imm3(e.b.value)
113 self.emit(arm.subregregimm3_ins, others=[c], dst=[d], src=[a])
110 return d 114 return d
111 elif isinstance(e, ir.Binop) and e.operation == '-': 115 elif isinstance(e, ir.Binop) and e.operation == '-':
112 a = self.munchExpr(e.a) 116 a = self.munchExpr(e.a)
113 b = self.munchExpr(e.b) 117 b = self.munchExpr(e.b)
114 d = self.newTmp() 118 d = self.newTmp()
115 self.emit('sub %d0, %s0, %s1', dst=[d], src=[a, b]) 119 self.emit(arm.subregs_ins, dst=[d], src=[a, b])
116 return d 120 return d
117 elif isinstance(e, ir.Binop) and e.operation == '|': 121 elif isinstance(e, ir.Binop) and e.operation == '|':
118 a = self.munchExpr(e.a) 122 a = self.munchExpr(e.a)
119 b = self.munchExpr(e.b) 123 b = self.munchExpr(e.b)
120 d = self.newTmp() 124 d = self.newTmp()
121 self.move(d, a) 125 self.move(d, a)
122 self.emit('orr %s1, %s0', dst=[], src=[b, d]) 126 self.emit(arm.orrregs_ins, dst=[], src=[b, d])
123 return d 127 return d
124 elif isinstance(e, ir.Binop) and e.operation == '<<': 128 elif isinstance(e, ir.Binop) and e.operation == '<<':
125 a = self.munchExpr(e.a) 129 a = self.munchExpr(e.a)
126 b = self.munchExpr(e.b) 130 b = self.munchExpr(e.b)
127 d = self.newTmp() 131 d = self.newTmp()
128 self.move(d, a) 132 self.move(d, a)
129 self.emit('lsl %s1, %s0', dst=[], src=[b, d]) # TODO: is d a source variable? 133 self.emit(arm.lslregs_ins, dst=[], src=[b, d]) # TODO: is d a source variable?
130 return d 134 return d
131 elif isinstance(e, ir.Binop) and e.operation == '*': 135 elif isinstance(e, ir.Binop) and e.operation == '*':
132 a = self.munchExpr(e.a) 136 a = self.munchExpr(e.a)
133 b = self.munchExpr(e.b) 137 b = self.munchExpr(e.b)
134 d = self.newTmp() 138 d = self.newTmp()
135 self.move(d, a) 139 self.move(d, a)
136 # this mul instruction has operands swapped: 140 # this mul instruction has operands swapped:
137 self.emit('mul %s0, %d0', dst=[d], src=[b, d]) 141 self.emit(arm.mulregreg_ins, dst=[d], src=[b, d])
138 return d 142 return d
139 elif isinstance(e, ir.Const) and e.value < 256: 143 elif isinstance(e, ir.Const) and e.value < 256:
140 d = self.newTmp() 144 d = self.newTmp()
141 self.emit('mov %d0, {}'.format(e.value), dst=[d]) 145 self.emit(arm.mov_imm8_ins, others=[arm.Imm8(e.value)], dst=[d])
142 return d 146 return d
143 elif isinstance(e, ir.Const) and e.value < (2**31): 147 elif isinstance(e, ir.Const) and e.value < (2**31):
144 d = self.newTmp() 148 d = self.newTmp()
145 ln = self.frame.addConstant(e.value) 149 ln = LabelRef(self.frame.addConstant(e.value))
146 self.emit('ldr %d0, {}'.format(ln), dst=[d]) 150 self.emit(arm.ldr_pcrel, others=[ln], dst=[d])
147 return d 151 return d
148 elif isinstance(e, ir.Mem) and isinstance(e.e, ir.Binop) and \ 152 elif isinstance(e, ir.Mem) and isinstance(e.e, ir.Binop) and \
149 e.e.operation == '+' and isinstance(e.e.b, ir.Const): 153 e.e.operation == '+' and isinstance(e.e.b, ir.Const):
150 base = self.munchExpr(e.e.a) 154 base = self.munchExpr(e.e.a)
151 d = self.newTmp() 155 d = self.newTmp()
152 c = e.e.b.value 156 c = e.e.b.value
153 self.emit('ldr %d0, [%s0 + {}]'.format(c), src=[base], dst=[d]) 157 self.emit(arm.loadimm5_ins, others=[c], src=[base], dst=[d])
154 return d 158 return d
155 elif isinstance(e, ir.Mem): 159 elif isinstance(e, ir.Mem):
156 # Load from memory 160 # Load from memory
157 base = self.munchExpr(e.e) 161 base = self.munchExpr(e.e)
158 d = self.newTmp() 162 d = self.newTmp()
159 self.emit('ldr %d0, [%s0]', src=[base], dst=[d]) 163 self.emit(arm.loadimm5_ins, others=[0], src=[base], dst=[d])
160 return d 164 return d
161 elif isinstance(e, ir.Temp): 165 elif isinstance(e, ir.Temp):
162 return e 166 return e
163 elif isinstance(e, ir.Call): 167 elif isinstance(e, ir.Call):
164 # Move arguments into proper locations: 168 # Move arguments into proper locations:
167 loc = self.frame.argLoc(i) 171 loc = self.frame.argLoc(i)
168 m = ir.Move(loc, a) 172 m = ir.Move(loc, a)
169 self.munchStm(m) 173 self.munchStm(m)
170 if isinstance(loc, ir.Temp): 174 if isinstance(loc, ir.Temp):
171 reguses.append(loc) 175 reguses.append(loc)
172 self.emit('bl {}'.format(e.f.name), src=reguses, dst=[self.frame.rv]) 176 self.emit(arm.bl_ins(LabelRef(e.f.name)), src=reguses, dst=[self.frame.rv])
173 d = self.newTmp() 177 d = self.newTmp()
174 self.move(d, self.frame.rv) 178 self.move(d, self.frame.rv)
175 return d 179 return d
176 else: 180 else:
177 raise NotImplementedError('Expr --> {}'.format(e)) 181 raise NotImplementedError('Expr --> {}'.format(e))
183 isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and \ 187 isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and \
184 isinstance(s.dst.e.b, ir.Const): 188 isinstance(s.dst.e.b, ir.Const):
185 a = self.munchExpr(s.dst.e.a) 189 a = self.munchExpr(s.dst.e.a)
186 val = self.munchExpr(s.src) 190 val = self.munchExpr(s.src)
187 c = s.dst.e.b.value 191 c = s.dst.e.b.value
188 self.emit('str %s1, [%s0 + {}]'.format(c), src=[a, val]) 192 self.emit(arm.storeimm5_ins, others=[c], src=[a, val])
189 elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem): 193 elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem):
190 memloc = self.munchExpr(s.dst.e) 194 memloc = self.munchExpr(s.dst.e)
191 val = self.munchExpr(s.src) 195 val = self.munchExpr(s.src)
192 self.emit('str %s1, [%s0]', src=[memloc, val]) 196 self.emit(arm.storeimm5_ins, others=[0], src=[memloc, val])
193 elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp): 197 elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp):
194 val = self.munchExpr(s.src) 198 val = self.munchExpr(s.src)
195 dreg = s.dst 199 dreg = s.dst
196 self.emit('mov %d0, %s0', dst=[dreg], src=[val]) 200 self.move(dreg, val)
197 elif isinstance(s, ir.Exp): 201 elif isinstance(s, ir.Exp):
198 # Generate expression code and discard the result. 202 # Generate expression code and discard the result.
199 x = self.munchExpr(s.e) 203 x = self.munchExpr(s.e)
200 self.emit('nop', src=[x]) 204 self.emit(Nop(), src=[x])
201 elif isinstance(s, ir.Jump): 205 elif isinstance(s, ir.Jump):
202 tgt = self.targets[s.target] 206 tgt = self.targets[s.target]
203 self.emit('b {}'.format(s.target.name), jumps=[tgt]) 207 self.emit(arm.b_ins(LabelRef(s.target.name)), jumps=[tgt])
204 elif isinstance(s, ir.CJump): 208 elif isinstance(s, ir.CJump):
205 a = self.munchExpr(s.a) 209 a = self.munchExpr(s.a)
206 b = self.munchExpr(s.b) 210 b = self.munchExpr(s.b)
207 self.emit('cmp %s0, %s1', src=[a, b]) 211 self.emit(arm.cmp_ins, src=[a, b])
208 ntgt = self.targets[s.lab_no] 212 ntgt = self.targets[s.lab_no]
209 ytgt = self.targets[s.lab_yes] 213 ytgt = self.targets[s.lab_yes]
210 jmp_ins = makeIns('b {}'.format(s.lab_no.name), jumps=[ntgt]) 214 jmp_ins = makeIns(arm.b_ins(LabelRef(s.lab_no.name)), jumps=[ntgt])
211 # Explicitely add fallthrough: 215 opnames = {'<': arm.blt_ins, '>':arm.bgt_ins, '==':arm.beq_ins}
212 self.emit('beq {}'.format(s.lab_yes.name), jumps=[ytgt, jmp_ins]) 216 op = opnames[s.cond](LabelRef(s.lab_yes.name))
217 self.emit(op, jumps=[ytgt, jmp_ins]) # Explicitely add fallthrough
213 self.emit2(jmp_ins) 218 self.emit2(jmp_ins)
214 else: 219 else:
215 raise NotImplementedError('Stmt --> {}'.format(s)) 220 raise NotImplementedError('Stmt --> {}'.format(s))
221
222 def move(self, dst, src):
223 self.emit(arm.movregreg_ext_ins, src=[src], dst=[dst])
216 224
217 225
218 # TODO: this class could be target independent: 226 # TODO: this class could be target independent:
219 class ArmCodeGenerator: 227 class ArmCodeGenerator:
220 def __init__(self, outs): 228 def __init__(self, outs):
225 self.outs = outs 233 self.outs = outs
226 self.outs.getSection('code').address = 0x08000000 234 self.outs.getSection('code').address = 0x08000000
227 self.outs.getSection('data').address = 0x20000000 235 self.outs.getSection('data').address = 0x20000000
228 236
229 def generateFunc(self, irfunc): 237 def generateFunc(self, irfunc):
238 """ Generate code for one function into a frame """
239 # Cleanup function:
240 transform.removeEmptyBlocks(irfunc)
241
230 # Create a frame for this function: 242 # Create a frame for this function:
231 frame = ArmFrame(irfunc.name) 243 frame = ArmFrame(irfunc.name)
232 244
233 # Canonicalize the intermediate language: 245 # Canonicalize the intermediate language:
234 canon.make(irfunc, frame) 246 canon.make(irfunc, frame)
235 print('after canonicalize:')
236 irfunc.dump()
237 self.ins_sel.munchFunction(irfunc, frame) 247 self.ins_sel.munchFunction(irfunc, frame)
238 print('Selected instructions:')
239 for i in frame.instructions:
240 print(i)
241 248
242 # Do register allocation: 249 # Do register allocation:
243 self.ra.allocFrame(frame) 250 self.ra.allocFrame(frame)
244 # TODO: Peep-hole here? 251 # TODO: Peep-hole here?
245 252
253 # Can we materialize here??
254
246 # Add label and return and stack adjustment: 255 # Add label and return and stack adjustment:
247 frame.EntryExitGlue3() 256 frame.EntryExitGlue3()
257
258 # Materialize assembly
259 # Materialize the register allocated instructions into a stream of
260 # real instructions.
261 frame.lower_to(self.outs)
248 return frame 262 return frame
249 263
250 def generate(self, ircode): 264 def generate(self, ircode):
265 self.outs.selectSection('code')
266 # assembly glue to make it work:
267 # TODO: this must be in source code, not in compiler
268 self.outs.emit(arm.dcd_ins(Imm32(0x20000678))) # initial SP
269 self.outs.emit(arm.dcd_ins(Imm32(0x08000009))) # reset vector
270 self.outs.emit(arm.b_ins(LabelRef('main')))
271
251 # Munch program into a bunch of frames. One frame per function. 272 # Munch program into a bunch of frames. One frame per function.
252 # Each frame has a flat list of abstract instructions. 273 # Each frame has a flat list of abstract instructions.
253 # Generate code for all functions: 274 # Generate code for all functions:
254 self.frames = [self.generateFunc(func) for func in ircode.Functions] 275 self.frames = [self.generateFunc(func) for func in ircode.Functions]
255 276
256 # Materialize assembly
257 # Reparse the register allocated instructions into a stream of
258 # real instructions.
259 # TODO: this is ugly via string representations. This could be
260 # another interface?
261 assembler = asm.Assembler(target=arm.armtarget, stream=self.outs)
262 self.outs.selectSection('code')
263 # assembly glue to make it work:
264 self.outs.emit(arm.dcd_ins(Imm32(0x20000678))) # initial SP
265 self.outs.emit(arm.dcd_ins(Imm32(0x08000009))) # reset vector
266 self.outs.emit(arm.b_ins(LabelRef('main')))
267 for frame in self.frames:
268 for i in frame.instructions:
269 assembler.assemble_line(str(i))
270
271 # TODO: fixup references, do this in another way? 277 # TODO: fixup references, do this in another way?
272 self.outs.backpatch() 278 self.outs.backpatch()
273 self.outs.backpatch() 279 self.outs.backpatch()
274 return self.frames 280 return self.frames
275 281