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