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
|
268
|
11 class ArmInstructionSelector(InstructionSelector):
|
269
|
12 """ Instruction selector for the arm architecture """
|
268
|
13 def munchExpr(self, e):
|
|
14 if isinstance(e, ir.Alloc):
|
|
15 return 0
|
|
16 elif isinstance(e, ir.Binop) and e.operation == '+':
|
|
17 a = self.munchExpr(e.value1)
|
|
18 b = self.munchExpr(e.value2)
|
|
19 d = self.newTmp()
|
|
20 self.emit('add %d0, %s0, %s1', dst=[d], src=[a, b])
|
|
21 return d
|
269
|
22 elif isinstance(e, ir.Binop) and e.operation == '-':
|
|
23 a = self.munchExpr(e.value1)
|
|
24 b = self.munchExpr(e.value2)
|
|
25 d = self.newTmp()
|
|
26 self.emit('sub %d0, %s0, %s1', dst=[d], src=[a, b])
|
|
27 return d
|
268
|
28 elif isinstance(e, ir.Binop) and e.operation == '|':
|
|
29 a = self.munchExpr(e.value1)
|
|
30 b = self.munchExpr(e.value2)
|
|
31 d = self.newTmp()
|
269
|
32 self.emit('or %d0, %s0, %s1', dst=[d], src=[a, b])
|
268
|
33 return d
|
|
34 elif isinstance(e, ir.Binop) and e.operation == '<<':
|
|
35 a = self.munchExpr(e.value1)
|
|
36 b = self.munchExpr(e.value2)
|
|
37 d = self.newTmp()
|
|
38 self.emit('lsl %d0, %s0, %s1', dst=[d], src=[a, b])
|
|
39 return d
|
|
40 elif isinstance(e, ir.Binop) and e.operation == '*':
|
|
41 a = self.munchExpr(e.value1)
|
|
42 b = self.munchExpr(e.value2)
|
|
43 d = self.newTmp()
|
269
|
44 self.emit('mul %d0, %s0, %s1', dst=[d], src=[a, b])
|
268
|
45 return d
|
|
46 elif isinstance(e, ir.Const):
|
|
47 d = self.newTmp()
|
|
48 if e.value < 256:
|
|
49 self.emit('ldr %d0, {}'.format(e.value), dst=[d])
|
|
50 else:
|
269
|
51 self.emit('ldrpcrel TODO', dst=[d])
|
268
|
52 return d
|
|
53 elif isinstance(e, ir.Mem):
|
|
54 # Load from memory
|
|
55 loc = self.munchExpr(e.e)
|
|
56 d = self.newTmp()
|
|
57 self.emit('ldr %d0, [%s0]', src=[loc], dst=[d])
|
|
58 return d
|
|
59 elif isinstance(e, ir.Temp):
|
269
|
60 return self.getTempReg(e)
|
272
|
61 elif isinstance(e, ir.Call):
|
|
62 args = [self.munchExpr(a) for a in e.arguments]
|
|
63 self.emit('add sp, sp, 22')
|
|
64 # TODO: save frame
|
|
65 for a in args:
|
|
66 self.emit('push %s0', src=[a])
|
|
67 self.emit('bl {}'.format(e.f.name))
|
|
68 self.emit('sub sp, sp, 22')
|
268
|
69 else:
|
272
|
70 raise NotImplementedError('Expr --> {}'.format(e))
|
268
|
71
|
|
72 def munchStm(self, s):
|
|
73 if isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem):
|
|
74 memloc = self.munchExpr(s.dst.e)
|
|
75 val = self.munchExpr(s.src)
|
|
76 self.emit('str [%s0], %s1')
|
|
77 elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp):
|
|
78 val = self.munchExpr(s.src)
|
269
|
79 dreg = self.getTempReg(s.dst)
|
|
80 self.emit('mov %d0, %s0', dst=[dreg], src=[val])
|
268
|
81 elif isinstance(s, ir.Jump):
|
269
|
82 tgt = self.targets[s.target]
|
|
83 self.emit('jmp {}'.format(s), jumps=[tgt])
|
268
|
84 elif isinstance(s, ir.CJump):
|
269
|
85 a = self.munchExpr(s.a)
|
|
86 b = self.munchExpr(s.b)
|
|
87 self.emit('cmp %s0, %s1', src=[a, b])
|
|
88 ntgt = self.targets[s.lab_no]
|
|
89 ytgt = self.targets[s.lab_yes]
|
|
90 jmp_ins = self.makeIns('jmp {}'.format(s.lab_no), jumps=[ntgt])
|
|
91 # Explicitely add fallthrough:
|
|
92 self.emit('jeq {}'.format(s.lab_yes), jumps=[ytgt, jmp_ins])
|
|
93 self.emit2(jmp_ins)
|
268
|
94 else:
|
|
95 raise NotImplementedError('--> {}'.format(s))
|
|
96
|
|
97
|
211
|
98 class ArmCodeGenerator:
|
268
|
99 def __init__(self, outs):
|
269
|
100 # TODO: schedule traces in better order.
|
|
101 # This is optional!
|
268
|
102 self.ins_sel = ArmInstructionSelector()
|
|
103 self.outs = outs
|
|
104 self.outs.getSection('code').address = 0x08000000
|
|
105 self.outs.getSection('data').address = 0x20000000
|
|
106
|
270
|
107 def useUnused(self, inslist):
|
|
108 # Use unused temporaries at the end of the list
|
|
109 defTemps = []
|
272
|
110 useTemps = []
|
|
111 for i in inslist:
|
|
112 for d in iter(i.dst):
|
|
113 defTemps.append(d)
|
|
114 for s in iter(i.src):
|
|
115 useTemps.append(s)
|
|
116 defTemps = set(defTemps)
|
|
117 useTemps = set(useTemps)
|
|
118 unUsed = defTemps - useTemps
|
|
119 #print('Unused:', unUsed)
|
|
120 for uu in unUsed:
|
|
121 inslist.append(irmach.AbstractInstruction('use %s0', src=[uu]))
|
|
122 #print(useTemps)
|
270
|
123
|
269
|
124 def generate(self, ircode, cfg_file=None, ig_file=None):
|
270
|
125 ir2 = self.ins_sel.munchProgram(ircode)
|
|
126 self.useUnused(ir2)
|
|
127 cfg = flowgraph.FlowGraph(ir2)
|
269
|
128 if cfg_file:
|
|
129 cfg.to_dot(cfg_file)
|
|
130 ig = registerallocator.InterferenceGraph(cfg)
|
|
131 if ig_file:
|
|
132 ig.to_dot(ig_file)
|
|
133
|
|
134 regs = ['r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7']
|
|
135 ra = registerallocator.RegisterAllocator()
|
270
|
136 regMap = ra.registerAllocate(ig, regs)
|
272
|
137 #print(regMap)
|
|
138 # Use allocated registers:
|
270
|
139 for i in ir2:
|
|
140 i.src = tuple(regMap[t] for t in i.src)
|
|
141 i.dst = tuple(regMap[t] for t in i.dst)
|
272
|
142 #print(i)
|
|
143 return ir2
|
268
|
144
|
|
145
|
270
|
146
|