Mercurial > lcfOS
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 |