pavone@185
|
1 {
|
pavone@185
|
2 //commutative ops
|
pavone@185
|
3 _add <- 0
|
pavone@185
|
4 _and <- 1
|
pavone@185
|
5 _or <- 2
|
pavone@185
|
6 _xor <- 3
|
pavone@185
|
7 //non-commutative ops
|
pavone@185
|
8 _sub <- 4
|
pavone@185
|
9 _cmp <- 5
|
pavone@185
|
10 _not <- 6
|
pavone@185
|
11 _sl <- 7
|
pavone@185
|
12 _asr <- 8
|
pavone@185
|
13 _lsr <- 9
|
pavone@185
|
14 _rol <- 10
|
pavone@185
|
15 _ror <- 11
|
pavone@185
|
16 _mov <- 12
|
pavone@185
|
17 _call <- 13
|
pavone@185
|
18 _ret <- 14
|
pavone@185
|
19 _skipif <- 15
|
pavone@195
|
20 _save <- 16
|
pavone@185
|
21
|
pavone@185
|
22 _names <- #[
|
pavone@185
|
23 "add"
|
pavone@185
|
24 "and"
|
pavone@185
|
25 "or"
|
pavone@185
|
26 "xor"
|
pavone@185
|
27 "sub"
|
pavone@185
|
28 "cmp"
|
pavone@185
|
29 "not"
|
pavone@185
|
30 "sl"
|
pavone@185
|
31 "asr"
|
pavone@185
|
32 "lsr"
|
pavone@185
|
33 "rol"
|
pavone@185
|
34 "ror"
|
pavone@185
|
35 "mov"
|
pavone@185
|
36 "call"
|
pavone@185
|
37 "ret"
|
pavone@185
|
38 "skipIf"
|
pavone@195
|
39 "save"
|
pavone@185
|
40 ]
|
pavone@185
|
41
|
pavone@185
|
42 op3:a:b:out:size <- :_opcode :_ina :_inb :_out :_size {
|
pavone@185
|
43 #{
|
pavone@185
|
44 opcode <- { _opcode }
|
pavone@185
|
45 ina <- { _ina }
|
pavone@185
|
46 inb <- { _inb }
|
pavone@185
|
47 commutative? <- { _opcode < _sub }
|
pavone@185
|
48 out <- { _out }
|
pavone@185
|
49 size <- { _size }
|
pavone@185
|
50 numops <- { 3 }
|
pavone@185
|
51 name <- { _names get: _opcode }
|
pavone@185
|
52 string <- { name . " " . (string: _ina) . " " . (string: _inb) . " " . (string: _out) . " " . (string: _size) }
|
pavone@189
|
53 recordUsage:at <- :tracker :address {
|
pavone@189
|
54 if: (not: (_ina isInteger?)) {
|
pavone@189
|
55 _ina recordUsage: tracker at: 0 | address withSize: _size
|
pavone@189
|
56 }
|
pavone@189
|
57 _inb recordUsage: tracker at: 0 | address withSize: _size
|
pavone@189
|
58 _out recordUsage: tracker at: 1 | address withSize: _size
|
pavone@189
|
59 }
|
pavone@200
|
60 assignRegs:at:withSource:andUsage <- :assignments :at :regSrc :usage {
|
pavone@194
|
61 newa <- if: (not: (_ina isInteger?)) {
|
pavone@194
|
62 _ina assign: assignments withSource: regSrc
|
pavone@194
|
63 } else: { _ina }
|
pavone@194
|
64 newb <- _inb assign: assignments withSource: regSrc
|
pavone@194
|
65 newout <- _out assign: assignments withSource: regSrc
|
pavone@194
|
66 op3: _opcode a: newa b: newb out: newout size: _size
|
pavone@194
|
67 }
|
pavone@185
|
68 }
|
pavone@185
|
69 }
|
pavone@185
|
70 op2:in:out:size <- :_opcode :_in :_out :_size {
|
pavone@185
|
71 #{
|
pavone@185
|
72 opcode <- { _opcode }
|
pavone@185
|
73 in <- { _in }
|
pavone@185
|
74 out <- { _out }
|
pavone@185
|
75 size <- { _size }
|
pavone@185
|
76 numops <- { 2 }
|
pavone@185
|
77 name <- { _names get: _opcode }
|
pavone@185
|
78 string <- { name . " " . (string: _in) . " " . (string: _out) . " " . (string: _size) }
|
pavone@189
|
79 recordUsage:at <- :tracker :address {
|
pavone@189
|
80 if: (not: (_in isInteger?)) {
|
pavone@189
|
81 _in recordUsage: tracker at: 0 | address withSize: _size
|
pavone@189
|
82 }
|
pavone@189
|
83 _out recordUsage: tracker at: 1 | address withSize: _size
|
pavone@189
|
84 }
|
pavone@200
|
85 assignRegs:at:withSource:andUsage <- :assignments :at :regSrc :usage {
|
pavone@194
|
86 newin <- if: (not: (_in isInteger?)) {
|
pavone@194
|
87 _in assign: assignments withSource: regSrc
|
pavone@194
|
88 } else: { _in }
|
pavone@194
|
89 newout <- _out assign: assignments withSource: regSrc
|
pavone@194
|
90 op2: _opcode in: newin out: newout size: _size
|
pavone@194
|
91 }
|
pavone@185
|
92 }
|
pavone@185
|
93 }
|
pavone@185
|
94 op1:arg:size <- :_opcode :_arg :_size {
|
pavone@185
|
95 #{
|
pavone@185
|
96 opcode <- { _opcode }
|
pavone@185
|
97 arg <- { _arg }
|
pavone@185
|
98 size <- { _size }
|
pavone@185
|
99 numops <- { 1 }
|
pavone@185
|
100 name <- { _names get: _opcode }
|
pavone@185
|
101 string <- { name . " " . (string: _arg) . " " . (string: _size) }
|
pavone@189
|
102 recordUsage:at <- :tracker :address {
|
pavone@189
|
103 if: (not: (_arg isInteger?)) {
|
pavone@189
|
104 _arg recordUsage: tracker at: address withSize: _size
|
pavone@189
|
105 }
|
pavone@189
|
106 }
|
pavone@200
|
107 assignRegs:at:withSource:andUsage <- :assignments :at :regSrc :usage {
|
pavone@194
|
108 newarg <- if: (not: (_arg isInteger?)) {
|
pavone@194
|
109 _arg assign: assignments withSource: regSrc
|
pavone@194
|
110 } else: { _arg }
|
pavone@194
|
111 op1: _opcode arg: newarg size: _size
|
pavone@194
|
112 }
|
pavone@185
|
113 }
|
pavone@185
|
114 }
|
pavone@185
|
115
|
pavone@185
|
116 _sizenames <- #["b" "w" "l" "q"]
|
pavone@193
|
117 _size <- :_bytes {
|
pavone@185
|
118 #{
|
pavone@193
|
119 bytes <- { _bytes }
|
pavone@193
|
120 string <- {
|
pavone@193
|
121 idx <- if: _bytes = 8 { 3 } else: { _bytes / 2}
|
pavone@193
|
122 _sizenames get: idx
|
pavone@193
|
123 }
|
pavone@185
|
124 = <- :other {
|
pavone@193
|
125 _bytes = (other bytes)
|
pavone@185
|
126 }
|
pavone@185
|
127 <= <- :other {
|
pavone@193
|
128 _bytes <= (other bytes)
|
pavone@185
|
129 }
|
pavone@185
|
130 >= <- :other {
|
pavone@193
|
131 _bytes >= (other bytes)
|
pavone@185
|
132 }
|
pavone@185
|
133 > <- :other {
|
pavone@193
|
134 _bytes > (other bytes)
|
pavone@185
|
135 }
|
pavone@185
|
136 < <- :other {
|
pavone@193
|
137 _bytes < (other bytes)
|
pavone@185
|
138 }
|
pavone@185
|
139 }
|
pavone@185
|
140 }
|
pavone@193
|
141 byte <- _size: 1
|
pavone@193
|
142 word <- _size: 2
|
pavone@193
|
143 long <- _size: 4
|
pavone@193
|
144 quad <- _size: 8
|
pavone@185
|
145
|
pavone@185
|
146 _retr <- #{
|
pavone@185
|
147 isInteger? <- { false }
|
pavone@185
|
148 register? <- { true }
|
pavone@185
|
149 argument? <- { false }
|
pavone@185
|
150 return? <- { true }
|
pavone@185
|
151 string <- { "retr" }
|
pavone@185
|
152 = <- :other {
|
pavone@185
|
153 (not: (other isInteger?)) && (other register?) && (other return?)
|
pavone@185
|
154 }
|
pavone@189
|
155 != <- :other {
|
pavone@189
|
156 not: self = other
|
pavone@189
|
157 }
|
pavone@189
|
158 recordUsage:at:withSize <- :tracker :address :size {
|
pavone@189
|
159 //TODO: Figure out what tracking is necessary here
|
pavone@189
|
160 }
|
pavone@194
|
161 assign:withSource <- :assignments :regSrc {
|
pavone@194
|
162 regSrc allocRet
|
pavone@194
|
163 }
|
pavone@185
|
164 }
|
pavone@185
|
165
|
pavone@185
|
166 _condnames <- #[
|
pavone@185
|
167 "eq"
|
pavone@185
|
168 "neq"
|
pavone@185
|
169 "ge"
|
pavone@185
|
170 "le"
|
pavone@185
|
171 "gr"
|
pavone@185
|
172 "ls"
|
pavone@185
|
173 "uge"
|
pavone@185
|
174 "ule"
|
pavone@185
|
175 "ugr"
|
pavone@185
|
176 "uls"
|
pavone@185
|
177 ]
|
pavone@185
|
178 condition <- :num {
|
pavone@185
|
179 #{
|
pavone@185
|
180 cc <- { num }
|
pavone@185
|
181 string <- { _condnames get: num }
|
pavone@185
|
182 = <- :other { num = (other cc) }
|
pavone@185
|
183 }
|
pavone@185
|
184 }
|
pavone@185
|
185 _eq <- condition: 0
|
pavone@185
|
186 _neq <- condition: 1
|
pavone@185
|
187 _ge <- condition: 2
|
pavone@185
|
188 _le <- condition: 3
|
pavone@185
|
189 _gr <- condition: 4
|
pavone@185
|
190 _ls <- condition: 5
|
pavone@185
|
191 _uge <- condition: 6
|
pavone@185
|
192 _ule <- condition: 7
|
pavone@185
|
193 _ugr <- condition: 8
|
pavone@185
|
194 _uls <- condition: 9
|
pavone@185
|
195
|
pavone@185
|
196 #{
|
pavone@185
|
197 b <- { byte }
|
pavone@185
|
198 w <- { word }
|
pavone@185
|
199 l <- { long }
|
pavone@185
|
200 q <- { quad }
|
pavone@185
|
201
|
pavone@185
|
202 eq <- { _eq }
|
pavone@185
|
203 neq <- { _neq }
|
pavone@185
|
204
|
pavone@185
|
205 //signed conditions
|
pavone@185
|
206 ge <- { _ge }
|
pavone@185
|
207 le <- { _le }
|
pavone@185
|
208 gr <- { _gr }
|
pavone@185
|
209 ls <- { _ls }
|
pavone@185
|
210
|
pavone@185
|
211 //unsigned conditions
|
pavone@185
|
212 uge <- { _uge }
|
pavone@185
|
213 ule <- { _ule }
|
pavone@185
|
214 ugr <- { _ugr }
|
pavone@185
|
215 uls <- { _uls }
|
pavone@185
|
216
|
pavone@185
|
217
|
pavone@185
|
218 reg <- :num {
|
pavone@185
|
219 #{
|
pavone@185
|
220 isInteger? <- { false }
|
pavone@185
|
221 register? <- { true }
|
pavone@185
|
222 argument? <- { false }
|
pavone@185
|
223 return? <- { false }
|
pavone@185
|
224 regnum <- { num }
|
pavone@185
|
225 string <- { "r" . (string: num) }
|
pavone@185
|
226 = <- :other {
|
pavone@185
|
227 (not: (other isInteger?)) && (other register?) && (not: (other argument?)) && (not: (other return?)) && num = (other regnum)
|
pavone@185
|
228 }
|
pavone@189
|
229 != <- :other {
|
pavone@189
|
230 not: self = other
|
pavone@189
|
231 }
|
pavone@189
|
232 recordUsage:at:withSize <- :tracker :address :size {
|
pavone@189
|
233 tracker reg: self usedAt: address withSize: size
|
pavone@189
|
234 }
|
pavone@194
|
235 assign:withSource <- :assignments :regSrc {
|
pavone@194
|
236 assignments get: self
|
pavone@194
|
237 }
|
pavone@185
|
238 }
|
pavone@185
|
239 }
|
pavone@185
|
240 arg <- :num {
|
pavone@185
|
241 #{
|
pavone@185
|
242 isInteger? <- { false }
|
pavone@185
|
243 register? <- { true }
|
pavone@185
|
244 argument? <- { true }
|
pavone@185
|
245 return? <- { false }
|
pavone@185
|
246 argnum <- { num }
|
pavone@185
|
247 string <- { "a" . (string: num) }
|
pavone@185
|
248 = <- :other {
|
pavone@185
|
249 (not: (other isInteger?)) && (other register?) && (other argument?) && num = (other regnum)
|
pavone@185
|
250 }
|
pavone@189
|
251 != <- :other {
|
pavone@189
|
252 not: self = other
|
pavone@189
|
253 }
|
pavone@189
|
254 recordUsage:at:withSize <- :tracker :address :size {
|
pavone@189
|
255 tracker arg: self usedAt: address withSize: size
|
pavone@189
|
256 }
|
pavone@194
|
257 assign:withSource <- :assignments :regSrc {
|
pavone@194
|
258 regSrc allocArg: num
|
pavone@194
|
259 }
|
pavone@185
|
260 }
|
pavone@185
|
261 }
|
pavone@185
|
262 retr <- { _retr }
|
pavone@185
|
263
|
pavone@189
|
264 base:offset <- :_base :_offset {
|
pavone@189
|
265 #{
|
pavone@189
|
266 base <- { _base }
|
pavone@189
|
267 offset <- { _offset }
|
pavone@189
|
268 string <- {
|
pavone@189
|
269 start <- if: _offset = 0 { "" } else: { (string: _offset) }
|
pavone@189
|
270 start . "[" . (string: _base) . "]"
|
pavone@189
|
271 }
|
pavone@189
|
272 recordUsage:at:withSize <- :tracker :address :size {
|
pavone@189
|
273 _base recordUsage: tracker at: address withSize: size
|
pavone@189
|
274 }
|
pavone@189
|
275 }
|
pavone@189
|
276 }
|
pavone@189
|
277
|
pavone@185
|
278 add <- :ina inb out size {
|
pavone@185
|
279 op3: _add a: ina b: inb out: out size: size
|
pavone@185
|
280 }
|
pavone@185
|
281
|
pavone@185
|
282 sub <- :ina inb out size {
|
pavone@185
|
283 op3: _sub a: ina b: inb out: out size: size
|
pavone@185
|
284 }
|
pavone@185
|
285
|
pavone@185
|
286 cmp <- :ina inb out size {
|
pavone@185
|
287 op3: _cmp a: ina b: inb out: out size: size
|
pavone@185
|
288 }
|
pavone@185
|
289
|
pavone@185
|
290 and <- :ina inb out size {
|
pavone@185
|
291 op3: _and a: ina b: inb out: out size: size
|
pavone@185
|
292 }
|
pavone@185
|
293
|
pavone@185
|
294 or <- :ina inb out size {
|
pavone@185
|
295 op3: _or a: ina b: inb out: out size: size
|
pavone@185
|
296 }
|
pavone@185
|
297
|
pavone@185
|
298 xor <- :ina inb out size {
|
pavone@185
|
299 op3: _xor a: ina b: inb out: out size: size
|
pavone@185
|
300 }
|
pavone@185
|
301
|
pavone@185
|
302 bnot <- :in out size {
|
pavone@185
|
303 op2: _not in: in out: out size: size
|
pavone@185
|
304 }
|
pavone@185
|
305
|
pavone@185
|
306 sl <- :shift in out size {
|
pavone@185
|
307 op3: _sl a: shift b: in out: out size: size
|
pavone@185
|
308 }
|
pavone@185
|
309
|
pavone@185
|
310 asr <- :shift in out size {
|
pavone@185
|
311 op3: _asr a: shift b: in out: out size: size
|
pavone@185
|
312 }
|
pavone@185
|
313
|
pavone@185
|
314 lsr <- :shift in out size {
|
pavone@185
|
315 op3: _lsr a: shift b: in out: out size: size
|
pavone@185
|
316 }
|
pavone@185
|
317
|
pavone@185
|
318 rol <- :rot in out size {
|
pavone@185
|
319 op3: _rol a: rot b: in out: out size: size
|
pavone@185
|
320 }
|
pavone@185
|
321
|
pavone@185
|
322 ror <- :rot in out size {
|
pavone@185
|
323 op3: _ror a: rot b: in out: out size: size
|
pavone@185
|
324 }
|
pavone@185
|
325
|
pavone@185
|
326 mov <- :in out size {
|
pavone@185
|
327 op2: _mov in: in out: out size: size
|
pavone@185
|
328 }
|
pavone@185
|
329
|
pavone@185
|
330 call:withArgs <- :_target :_args {
|
pavone@185
|
331 #{
|
pavone@185
|
332 opcode <- { _call }
|
pavone@185
|
333 target <- { _target }
|
pavone@185
|
334 args <- { _args }
|
pavone@185
|
335 numops <- { 0 }
|
pavone@185
|
336 name <- { _names get: _call }
|
pavone@185
|
337 string <- {
|
pavone@185
|
338 argstr <- _args map: :el {
|
pavone@185
|
339 string: el
|
pavone@185
|
340 }
|
pavone@185
|
341 name . " " . (string: _target) . " " . (argstr join: " ")
|
pavone@185
|
342 }
|
pavone@189
|
343 recordUsage:at <- :tracker :address {
|
pavone@189
|
344 if: (not: (_target isString?)) {
|
pavone@189
|
345 //TODO: use size l for 32-bit targets or an abstract pointer size
|
pavone@189
|
346 _target recordUsage: tracker at: address withSize: q
|
pavone@189
|
347 }
|
pavone@189
|
348 foreach: _args :_ arg {
|
pavone@189
|
349 //TODO: have some mechanism for properly expressing sizes of arguments
|
pavone@189
|
350 arg recordUsage: tracker at: address withSize: q
|
pavone@189
|
351 }
|
pavone@189
|
352 }
|
pavone@200
|
353 assignRegs:at:withSource:andUsage <- :assignments :address :regSrc :usage {
|
pavone@194
|
354 newtarget <- if: (_target isString?) { _target } else: {
|
pavone@194
|
355 _target assign: assignments withSource: regSrc
|
pavone@194
|
356 }
|
pavone@194
|
357 newargs <- _args map: :arg {
|
pavone@194
|
358 if: (arg isInteger?) { arg } else: {
|
pavone@194
|
359 arg assign: assignments withSource: regSrc
|
pavone@194
|
360 }
|
pavone@194
|
361 }
|
pavone@200
|
362 newcall <- call: newtarget withArgs: newargs
|
pavone@200
|
363 regSrc returnAll
|
pavone@200
|
364 raddress <- address reverse
|
pavone@200
|
365 foreach: (usage liveArgsAt: raddress) :_ arg {
|
pavone@200
|
366 regSrc allocArg: (arg num)
|
pavone@200
|
367 }
|
pavone@200
|
368 foreach: (usage liveRegsAt: raddress) :_ reg {
|
pavone@200
|
369 regSrc allocSpecific: (assignments get: reg)
|
pavone@200
|
370 }
|
pavone@200
|
371 tosave <- regSrc needSaveForCall
|
pavone@200
|
372 if: (tosave length) > 0 {
|
pavone@200
|
373 save: tosave #[newcall]
|
pavone@200
|
374 } else: {
|
pavone@200
|
375 newcall
|
pavone@200
|
376 }
|
pavone@194
|
377 }
|
pavone@185
|
378 }
|
pavone@185
|
379 }
|
pavone@185
|
380
|
pavone@185
|
381 return <- :val size {
|
pavone@185
|
382 op1: _ret arg: val size: size
|
pavone@185
|
383 }
|
pavone@185
|
384 skipIf <- :_cond _toskip {
|
pavone@185
|
385 #{
|
pavone@185
|
386 opcode <- { _skipif }
|
pavone@185
|
387 toskip <- { _toskip }
|
pavone@185
|
388 cond <- { _cond }
|
pavone@185
|
389 numops <- { 0 }
|
pavone@185
|
390 name <- { _names get: _skipif }
|
pavone@185
|
391 string <- {
|
pavone@185
|
392 block <- (_toskip map: :el { string: el }) join: "\n\t"
|
pavone@185
|
393 if: (_toskip length) > 0 {
|
pavone@185
|
394 block <- "\n\t" . block . "\n"
|
pavone@185
|
395 }
|
pavone@185
|
396 name . " " . (string: _cond) . " {" . block . "}"
|
pavone@185
|
397 }
|
pavone@189
|
398 recordUsage:at <- :tracker :address {
|
pavone@189
|
399 foreach: _toskip :idx inst {
|
pavone@189
|
400 inst recordUsage: tracker at: idx | address
|
pavone@189
|
401 }
|
pavone@189
|
402 }
|
pavone@200
|
403 assignRegs:at:withSource:andUsage <- :assignments :address :regSrc :usage {
|
pavone@200
|
404 newskip <- #[]
|
pavone@200
|
405 foreach: _toskip :idx inst {
|
pavone@200
|
406 newskip append: (inst assignRegs: assignments at: idx | address withSource: regSrc andUsage: usage)
|
pavone@194
|
407 }
|
pavone@194
|
408 skipIf: _cond newskip
|
pavone@194
|
409 }
|
pavone@200
|
410 to2OpInst <- {
|
pavone@200
|
411 skipIf: _cond (to2Op: _toskip)
|
pavone@200
|
412 }
|
pavone@185
|
413 }
|
pavone@185
|
414 }
|
pavone@203
|
415 save <- :regs :_scope{
|
pavone@195
|
416 #{
|
pavone@195
|
417 opcode <- { _save }
|
pavone@195
|
418 numops <- { 0 }
|
pavone@195
|
419 name <- { _names get: _save }
|
pavone@203
|
420 tosave <- { regs }
|
pavone@203
|
421 scope <- { _scope }
|
pavone@195
|
422 string <- {
|
pavone@203
|
423 block <- _scope join: "\n\t"
|
pavone@203
|
424 if: (_scope length) > 0 {
|
pavone@195
|
425 block <- "\n\t" . block . "\n"
|
pavone@195
|
426 }
|
pavone@195
|
427 name . " " . (regs join: " ") . " {" . block . "}"
|
pavone@195
|
428 }
|
pavone@200
|
429 to2OpInst <- {
|
pavone@203
|
430 save: regs (to2Op: _scope)
|
pavone@200
|
431 }
|
pavone@195
|
432 }
|
pavone@195
|
433 }
|
pavone@185
|
434
|
pavone@189
|
435 allocRegs:withSource <- :instarr:regSrc {
|
pavone@189
|
436 _regMap <- dict linear
|
pavone@189
|
437 _argMap <- dict linear
|
pavone@189
|
438
|
pavone@189
|
439 _usageTracker <- :_firstUsage {
|
pavone@189
|
440 #{
|
pavone@189
|
441 firstUsage <- _firstUsage
|
pavone@189
|
442 lastUsage <- _firstUsage
|
pavone@189
|
443 useCount <- 0
|
pavone@189
|
444 maxSize <- byte
|
pavone@189
|
445 usedAt:withSize <- :address :size {
|
pavone@189
|
446 useCount <- useCount + 1
|
pavone@189
|
447 lastUsage <- address
|
pavone@189
|
448 if: size > maxSize {
|
pavone@189
|
449 maxSize <- size
|
pavone@189
|
450 }
|
pavone@189
|
451 }
|
pavone@189
|
452 string <- {
|
pavone@189
|
453 "Uses: " . useCount . ", FirstUse: " . (firstUsage join: ":") . ", Last Use: " . (lastUsage join: ":") . ", Max Size: " . maxSize
|
pavone@189
|
454 }
|
pavone@189
|
455 }
|
pavone@189
|
456 }
|
pavone@189
|
457
|
pavone@189
|
458 _maxUses <- 0
|
pavone@200
|
459 liveFrom:to <- :regs :from :to {
|
pavone@200
|
460 live <- #[]
|
pavone@200
|
461 foreach: regs :reg usage {
|
pavone@200
|
462 if: ((usage lastUsage) addrGreatEq: from) && ((usage firstUsage) addrLessEq: to) {
|
pavone@200
|
463 live append: reg
|
pavone@200
|
464 }
|
pavone@200
|
465 }
|
pavone@200
|
466 live
|
pavone@200
|
467 }
|
pavone@189
|
468 regUsage <- #{
|
pavone@189
|
469 reg:usedAt:withSize <- :reg :address :size {
|
pavone@193
|
470 raddress <- address reverse
|
pavone@189
|
471 usage <- _regMap get: reg elseSet: {
|
pavone@193
|
472 _usageTracker: raddress
|
pavone@189
|
473 }
|
pavone@193
|
474 usage usedAt: raddress withSize: size
|
pavone@189
|
475 if: (usage useCount) > _maxUses {
|
pavone@189
|
476 _maxUses <- usage useCount
|
pavone@189
|
477 }
|
pavone@189
|
478 }
|
pavone@189
|
479 arg:usedAt:withSize <- :arg :address :size {
|
pavone@193
|
480 raddress <- address reverse
|
pavone@189
|
481 usage <- _argMap get: arg elseSet: {
|
pavone@189
|
482 _usageTracker: [0 0]
|
pavone@189
|
483 }
|
pavone@193
|
484 usage usedAt: raddress withSize: size
|
pavone@189
|
485 }
|
pavone@200
|
486
|
pavone@200
|
487 liveRegsAt <- :address {
|
pavone@200
|
488 _regMap liveFrom: address to: address
|
pavone@200
|
489 }
|
pavone@200
|
490 liveArgsAt <- :address {
|
pavone@200
|
491 _argMap liveFrom: address to: address
|
pavone@200
|
492 }
|
pavone@200
|
493
|
pavone@189
|
494 print <- {
|
pavone@189
|
495 foreach: _regMap :reg usage {
|
pavone@189
|
496 print: (string: reg) . " | " . (string: usage) . "\n"
|
pavone@189
|
497 }
|
pavone@189
|
498 foreach: _argMap :arg usage {
|
pavone@189
|
499 print: (string: arg) . " | " . (string: usage) . "\n"
|
pavone@189
|
500 }
|
pavone@189
|
501 }
|
pavone@189
|
502 }
|
pavone@189
|
503 foreach: instarr :idx inst {
|
pavone@189
|
504 inst recordUsage: regUsage at: [idx]
|
pavone@189
|
505 }
|
pavone@189
|
506 print: regUsage
|
pavone@193
|
507
|
pavone@193
|
508 addrLessEq <- :left :right {
|
pavone@193
|
509 lesseq <- true
|
pavone@193
|
510 while: { lesseq && (not: (left empty?)) && (not: (right empty?)) } do: {
|
pavone@193
|
511 if: (left value) > (right value) {
|
pavone@193
|
512 lesseq <- false
|
pavone@193
|
513 } else: {
|
pavone@193
|
514 if: (left value) < (right value) {
|
pavone@193
|
515 left <- []
|
pavone@193
|
516 } else: {
|
pavone@193
|
517 left <- left tail
|
pavone@193
|
518 right <- right tail
|
pavone@193
|
519 }
|
pavone@193
|
520 }
|
pavone@193
|
521 }
|
pavone@193
|
522 lesseq
|
pavone@193
|
523 }
|
pavone@193
|
524
|
pavone@193
|
525 addrGreatEq <- :left :right {
|
pavone@193
|
526 greateq <- true
|
pavone@193
|
527 while: { greateq && (not: (left empty?)) && (not: (right empty?)) } do: {
|
pavone@193
|
528 if: (left value) < (right value) {
|
pavone@193
|
529 greateq <- false
|
pavone@193
|
530 } else: {
|
pavone@193
|
531 if: (left value) > (right value) {
|
pavone@193
|
532 left <- []
|
pavone@193
|
533 } else: {
|
pavone@193
|
534 left <- left tail
|
pavone@193
|
535 right <- right tail
|
pavone@193
|
536 }
|
pavone@193
|
537 }
|
pavone@193
|
538 }
|
pavone@193
|
539 greateq
|
pavone@193
|
540 }
|
pavone@193
|
541
|
pavone@193
|
542 _assignments <- dict linear
|
pavone@193
|
543 curuses <- _maxUses
|
pavone@193
|
544 while: { curuses > 0 && (_assignments length) < (_regMap length) } do: {
|
pavone@193
|
545 foreach: _regMap :reg usage {
|
pavone@193
|
546 if: (usage useCount) = curuses {
|
pavone@193
|
547 liveArgs <- _argMap liveFrom: (usage firstUsage) to: (usage lastUsage)
|
pavone@193
|
548 foreach: liveArgs :_ arg {
|
pavone@193
|
549 regSrc allocArg: (arg num)
|
pavone@193
|
550 }
|
pavone@193
|
551
|
pavone@193
|
552 liveRegs <- _regMap liveFrom: (usage firstUsage) to: (usage lastUsage)
|
pavone@193
|
553 print: (string: reg) . " | Live: " . (liveRegs join: ", ") . ", Live Args: " . (liveArgs join: ", ") . "\n"
|
pavone@193
|
554 foreach: liveRegs :_ reg {
|
pavone@193
|
555 if: (_assignments contains?: reg) {
|
pavone@193
|
556 regSrc allocSpecific: (_assignments get: reg)
|
pavone@193
|
557 }
|
pavone@193
|
558 }
|
pavone@193
|
559 _assignments set: reg (regSrc alloc: (usage maxSize))
|
pavone@193
|
560
|
pavone@193
|
561 regSrc returnAll
|
pavone@193
|
562 }
|
pavone@193
|
563 }
|
pavone@193
|
564 curuses <- curuses - 1
|
pavone@193
|
565 }
|
pavone@193
|
566 print: "\n\nAssignments:\n\n"
|
pavone@193
|
567 foreach: _assignments :reg assign {
|
pavone@193
|
568 print: (string: reg) . " = " . assign . "\n"
|
pavone@193
|
569 }
|
pavone@194
|
570
|
pavone@200
|
571 withassign <- #[]
|
pavone@200
|
572 foreach: instarr :idx inst {
|
pavone@200
|
573 withassign append: (inst assignRegs: _assignments at: [idx] withSource: regSrc andUsage: regUsage)
|
pavone@194
|
574 }
|
pavone@195
|
575 psave <- regSrc needSaveProlog
|
pavone@195
|
576 if: (psave length) > 0 {
|
pavone@195
|
577 withassign <- #[save: psave withassign]
|
pavone@195
|
578 }
|
pavone@195
|
579 withassign
|
pavone@189
|
580 }
|
pavone@189
|
581
|
pavone@185
|
582 //used to convert IL to a format suitable for a 2-operand architecture
|
pavone@185
|
583 //should be run after register allocation (I think....)
|
pavone@185
|
584 to2Op <- :instarr {
|
pavone@185
|
585 instarr fold: #[] with: :newarr inst {
|
pavone@185
|
586 if: (inst numops) = 3 {
|
pavone@185
|
587 if: (inst inb) = (inst out) {
|
pavone@185
|
588 newarr append: (op2: (inst opcode) in: (inst ina) out: (inst out) size: (inst size))
|
pavone@185
|
589 } else: {
|
pavone@185
|
590 if: (inst commutative?) && (inst ina) = (inst out) {
|
pavone@185
|
591 newarr append: (op2: (inst opcode) in: (inst inb) out: (inst out) size: (inst size))
|
pavone@185
|
592 } else: {
|
pavone@185
|
593 newarr append: (mov: (inst inb) (inst out) (inst size))
|
pavone@185
|
594 newarr append: (op2: (inst opcode) in: (inst ina) out: (inst out) size: (inst size))
|
pavone@185
|
595 }
|
pavone@185
|
596 }
|
pavone@185
|
597 } else: {
|
pavone@185
|
598 if: (inst numops) = 2 && (inst opcode) != _mov {
|
pavone@185
|
599 if: (inst in) != (inst out) {
|
pavone@185
|
600 newarr append: (mov: (inst in) (inst out) (inst size))
|
pavone@185
|
601 }
|
pavone@185
|
602 newarr append: (op1: (inst opcode) val: (inst out) size: (inst size))
|
pavone@185
|
603 } else: {
|
pavone@200
|
604 if: (inst opcode) = _skipif || (inst opcode) = _save {
|
pavone@200
|
605 newarr append: (inst to2OpInst)
|
pavone@200
|
606 } else: {
|
pavone@200
|
607 newarr append: inst
|
pavone@200
|
608 }
|
pavone@185
|
609 }
|
pavone@185
|
610 }
|
pavone@185
|
611 }
|
pavone@185
|
612 }
|
pavone@185
|
613
|
pavone@203
|
614 toBackend <- :program :backend {
|
pavone@203
|
615 prepped <- program map: :fun {
|
pavone@203
|
616 backend adjustIL: fun
|
pavone@203
|
617 }
|
pavone@203
|
618 labels <- prepped map: :_ {
|
pavone@203
|
619 backend label
|
pavone@203
|
620 }
|
pavone@203
|
621 outprog <- #[]
|
pavone@203
|
622 foreach: prepped :name instarr {
|
pavone@203
|
623 outprog append: (labels get: name)
|
pavone@203
|
624 foreach: instarr :_ inst {
|
pavone@203
|
625 backend convertIL: inst to: outprog withLabels: labels
|
pavone@203
|
626 }
|
pavone@203
|
627 }
|
pavone@203
|
628 outprog
|
pavone@203
|
629 }
|
pavone@203
|
630
|
pavone@185
|
631 main <- {
|
pavone@203
|
632 prog <- dict linear
|
pavone@203
|
633
|
pavone@185
|
634 fib <- #[
|
pavone@185
|
635 sub: 2 (arg: 0) (reg: 0) q
|
pavone@185
|
636 skipIf: ge #[
|
pavone@185
|
637 return: 1 q
|
pavone@185
|
638 ]
|
pavone@185
|
639 call: "fib" withArgs: #[reg: 0]
|
pavone@185
|
640 mov: retr (reg: 1) q
|
pavone@185
|
641 add: 1 (reg: 0) (reg: 2) q
|
pavone@185
|
642 call: "fib" withArgs: #[reg: 2]
|
pavone@185
|
643 add: retr (reg: 1) (reg: 3) q
|
pavone@185
|
644 return: (reg: 3) q
|
pavone@185
|
645 ]
|
pavone@185
|
646 print: "Original:\n\n"
|
pavone@185
|
647 foreach: fib :idx inst {
|
pavone@185
|
648 print: (string: inst) . "\n"
|
pavone@185
|
649 }
|
pavone@203
|
650 prog set: "fib" fib
|
pavone@203
|
651
|
pavone@203
|
652 mprog <- prog toBackend: x86
|
pavone@203
|
653 ba <- bytearray executableFromBytes: mprog
|
pavone@203
|
654 res <- ba runWithArg: 30u64
|
pavone@203
|
655 print: (string: res) . "\n"
|
pavone@203
|
656 0
|
pavone@185
|
657 }
|
pavone@185
|
658 }
|
pavone@185
|
659 }
|