255
|
1 import logging
|
211
|
2 import ir
|
249
|
3 from target import Label, Comment, Alignment, LabelRef, Imm32, DebugInfo
|
218
|
4 import cortexm3 as arm
|
211
|
5 from ppci import CompilerError
|
269
|
6 import flowgraph
|
|
7 import registerallocator
|
|
8 from instructionselector import InstructionSelector
|
272
|
9 import irmach
|
262
|
10
|
274
|
11
|
|
12 class ArmFrame(irmach.Frame):
|
|
13 """
|
|
14 Arm specific frame for functions.
|
|
15 """
|
|
16 pass
|
|
17
|
|
18
|
268
|
19 class ArmInstructionSelector(InstructionSelector):
|
269
|
20 """ Instruction selector for the arm architecture """
|
274
|
21 def newFrame(self, name):
|
|
22 return ArmFrame(name)
|
|
23
|
268
|
24 def munchExpr(self, e):
|
|
25 if isinstance(e, ir.Alloc):
|
|
26 return 0
|
|
27 elif isinstance(e, ir.Binop) and e.operation == '+':
|
|
28 a = self.munchExpr(e.value1)
|
|
29 b = self.munchExpr(e.value2)
|
|
30 d = self.newTmp()
|
|
31 self.emit('add %d0, %s0, %s1', dst=[d], src=[a, b])
|
|
32 return d
|
269
|
33 elif isinstance(e, ir.Binop) and e.operation == '-':
|
|
34 a = self.munchExpr(e.value1)
|
|
35 b = self.munchExpr(e.value2)
|
|
36 d = self.newTmp()
|
|
37 self.emit('sub %d0, %s0, %s1', dst=[d], src=[a, b])
|
|
38 return d
|
268
|
39 elif isinstance(e, ir.Binop) and e.operation == '|':
|
|
40 a = self.munchExpr(e.value1)
|
|
41 b = self.munchExpr(e.value2)
|
|
42 d = self.newTmp()
|
269
|
43 self.emit('or %d0, %s0, %s1', dst=[d], src=[a, b])
|
268
|
44 return d
|
|
45 elif isinstance(e, ir.Binop) and e.operation == '<<':
|
|
46 a = self.munchExpr(e.value1)
|
|
47 b = self.munchExpr(e.value2)
|
|
48 d = self.newTmp()
|
|
49 self.emit('lsl %d0, %s0, %s1', dst=[d], src=[a, b])
|
|
50 return d
|
|
51 elif isinstance(e, ir.Binop) and e.operation == '*':
|
|
52 a = self.munchExpr(e.value1)
|
|
53 b = self.munchExpr(e.value2)
|
|
54 d = self.newTmp()
|
269
|
55 self.emit('mul %d0, %s0, %s1', dst=[d], src=[a, b])
|
268
|
56 return d
|
|
57 elif isinstance(e, ir.Const):
|
|
58 d = self.newTmp()
|
|
59 if e.value < 256:
|
|
60 self.emit('ldr %d0, {}'.format(e.value), dst=[d])
|
|
61 else:
|
269
|
62 self.emit('ldrpcrel TODO', dst=[d])
|
268
|
63 return d
|
|
64 elif isinstance(e, ir.Mem):
|
|
65 # Load from memory
|
|
66 loc = self.munchExpr(e.e)
|
|
67 d = self.newTmp()
|
|
68 self.emit('ldr %d0, [%s0]', src=[loc], dst=[d])
|
|
69 return d
|
|
70 elif isinstance(e, ir.Temp):
|
269
|
71 return self.getTempReg(e)
|
274
|
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
|
272
|
77 elif isinstance(e, ir.Call):
|
|
78 args = [self.munchExpr(a) for a in e.arguments]
|
274
|
79 frame_size = 222 # TODO: determine frame size?
|
|
80 self.emit('add sp, sp, {}'.format(frame_size))
|
272
|
81 # TODO: save frame
|
|
82 for a in args:
|
|
83 self.emit('push %s0', src=[a])
|
|
84 self.emit('bl {}'.format(e.f.name))
|
|
85 self.emit('sub sp, sp, 22')
|
268
|
86 else:
|
272
|
87 raise NotImplementedError('Expr --> {}'.format(e))
|
268
|
88
|
|
89 def munchStm(self, s):
|
|
90 if isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem):
|
|
91 memloc = self.munchExpr(s.dst.e)
|
|
92 val = self.munchExpr(s.src)
|
274
|
93 self.emit('str [%s0], %s1', src=[memloc, val])
|
268
|
94 elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp):
|
|
95 val = self.munchExpr(s.src)
|
269
|
96 dreg = self.getTempReg(s.dst)
|
|
97 self.emit('mov %d0, %s0', dst=[dreg], src=[val])
|
268
|
98 elif isinstance(s, ir.Jump):
|
269
|
99 tgt = self.targets[s.target]
|
274
|
100 self.emit('jmp %l0', jumps=[tgt])
|
268
|
101 elif isinstance(s, ir.CJump):
|
269
|
102 a = self.munchExpr(s.a)
|
|
103 b = self.munchExpr(s.b)
|
|
104 self.emit('cmp %s0, %s1', src=[a, b])
|
|
105 ntgt = self.targets[s.lab_no]
|
|
106 ytgt = self.targets[s.lab_yes]
|
274
|
107 jmp_ins = self.makeIns('jmp %l0', jumps=[ntgt])
|
269
|
108 # Explicitely add fallthrough:
|
274
|
109 self.emit('jeq %l0', jumps=[ytgt, jmp_ins])
|
269
|
110 self.emit2(jmp_ins)
|
274
|
111 elif isinstance(s, ir.Terminator):
|
|
112 pass
|
268
|
113 else:
|
274
|
114 raise NotImplementedError('Stmt --> {}'.format(s))
|
268
|
115
|
|
116
|
274
|
117 # TODO: this class could be target independent:
|
211
|
118 class ArmCodeGenerator:
|
268
|
119 def __init__(self, outs):
|
269
|
120 # TODO: schedule traces in better order.
|
|
121 # This is optional!
|
268
|
122 self.ins_sel = ArmInstructionSelector()
|
|
123 self.outs = outs
|
|
124 self.outs.getSection('code').address = 0x08000000
|
|
125 self.outs.getSection('data').address = 0x20000000
|
|
126
|
270
|
127 def useUnused(self, inslist):
|
|
128 # Use unused temporaries at the end of the list
|
|
129 defTemps = []
|
272
|
130 useTemps = []
|
|
131 for i in inslist:
|
|
132 for d in iter(i.dst):
|
|
133 defTemps.append(d)
|
|
134 for s in iter(i.src):
|
|
135 useTemps.append(s)
|
|
136 defTemps = set(defTemps)
|
|
137 useTemps = set(useTemps)
|
|
138 unUsed = defTemps - useTemps
|
274
|
139 print('Unused:', unUsed)
|
272
|
140 for uu in unUsed:
|
|
141 inslist.append(irmach.AbstractInstruction('use %s0', src=[uu]))
|
|
142 #print(useTemps)
|
270
|
143
|
274
|
144 def allocFrame(self, f):
|
|
145 """
|
|
146 Do register allocation for a single stack frame.
|
|
147 """
|
|
148 ilist = f.instructions
|
|
149 self.useUnused(ilist)
|
|
150 cfg = flowgraph.FlowGraph(ilist)
|
|
151 f.cfg = cfg
|
269
|
152 ig = registerallocator.InterferenceGraph(cfg)
|
274
|
153 f.ig = ig
|
269
|
154
|
|
155 regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7']
|
|
156 ra = registerallocator.RegisterAllocator()
|
270
|
157 regMap = ra.registerAllocate(ig, regs)
|
272
|
158 #print(regMap)
|
|
159 # Use allocated registers:
|
274
|
160 for i in ilist:
|
270
|
161 i.src = tuple(regMap[t] for t in i.src)
|
|
162 i.dst = tuple(regMap[t] for t in i.dst)
|
272
|
163 #print(i)
|
274
|
164
|
|
165 def generate(self, ircode):
|
|
166 # Munch program into a bunch of frames. One frame per function.
|
|
167 # Each frame has a flat list of abstract instructions.
|
|
168 frames = self.ins_sel.munchProgram(ircode)
|
|
169 self.frames = frames
|
|
170 for f in frames:
|
|
171 self.allocFrame(f)
|
|
172
|
|
173 # TODO: Peep-hole here
|
|
174 # TODO: Materialize assembly
|
|
175 return frames
|
268
|
176
|
|
177
|