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