comparison genasm.rhope @ 2:73e978d590c7

Adding WIP compiler code
author Mike Pavone <pavone@retrodev.com>
date Wed, 29 Apr 2009 02:58:03 -0400
parents
children 31f8182f3433
comparison
equal deleted inserted replaced
1:b3f71490858c 2:73e978d590c7
1 //Import extendlib.rhope
2 Escape Rhope Name[name:escaped]
3 {
4 escaped <- [[[[[[[[[name]Replace["_","__"]
5 ]Replace["@","_AT_"]
6 ]Replace[" ","_SP_"]
7 ]Replace[":","_CN_"]
8 ]Replace["?","_QN_"]
9 ]Replace["+","_PL_"]
10 ]Replace["-","_MN_"]
11 ]Replace["*","_TM_"]
12 ]Replace["/","_DV_"]
13 }
14
15 Blueprint Registers
16 {
17 Names
18 Can Data
19 Can Pointer
20 Available?
21 Need Save
22 Max Size
23 }
24
25 Set Yes[in:out]
26 {
27 out <- Yes
28 }
29
30 _Flip[dest,val,index:out]
31 {
32 out <- [dest]Set[val,index]
33 }
34 Flip[list,dest:out]
35 {
36 out <- Fold["_Flip", dest, list]
37 }
38
39 Registers[names, data, pointer, need save, max size:out]
40 {
41 out <- [[[[[[Build["Registers"]
42 ]Names << [names]
43 ]Can Data << [data]
44 ]Can Pointer << [pointer]
45 ]Available? << [ Map[names, "Set Yes"] ]
46 ]Need Save << [ Flip[need save, ()] ]
47 ]Max Size <<[max size]
48 }
49
50 Name@Registers[regs,num:out]
51 {
52 out <- [[regs]Names >>]Index[num]
53 }
54
55 Allocate Helper@Registers[regs, try, current:found, not found]
56 {
57 reg <- [try]Index[current]
58 If[[[regs]Available? >>]Index[reg]]
59 {
60 found <- Val[reg]
61 }{
62 [try]Next[current]
63 {
64 found, not found <- [regs]Allocate Helper[try, ~]
65 }{
66 not found <- Yes
67 }
68 }
69 }
70
71 Allocate Reg@Registers[regs,try:next regs,found,need save?,not found]
72 {
73 [try]First
74 {
75 found, not found <- [regs]Allocate Helper[try, ~]
76 {
77 next regs <- [regs]Available? << [ [[regs]Available? >>]Set[~, No] ]
78 [[regs]Need Save >>]Index[~]
79 {
80 need save? <- Yes
81 }{
82 need save? <- No
83 }
84 }
85 }{
86 not found <- Yes
87 }
88 }
89
90 Free Reg@Registers[regs,num:out]
91 {
92 out <- [regs]Available? <<[ [[regs]Available? >>]Set[num, Yes] ]
93 }
94
95 Processor Reg[func,type:next func,num,not found]
96 {
97 regs <- [func]Registers >>
98 If[[type] = ["pointer"]]
99 {
100 source <- [regs]Can Pointer >>
101 }{
102 source <- [regs]Can Data >>
103 }
104 next regs, reg num, need save?, not found <- [regs]Allocate Reg[source] {}
105 {
106 If[need save?]
107 {
108 next func <- [[func]Need Save << [ [[func]Need Save >>]Set[reg num, Yes] ]
109 ]Registers << [next regs]
110 }{
111 next func <- [func]Registers << [next regs]
112 }
113 num <- Val[reg num]
114 }
115 }
116
117 Processor Free Reg[func,num:out func]
118 {
119 out func <- [func]Registers <<[ [[func]Registers >>]Free Reg[num] ]
120 }
121
122 Processor Allocate[func,name,size,type:out func,out]
123 {
124 regs <- [func]Registers >>
125 If[[type] = ["pointer"]]
126 {
127 alloc size <- [func]Pointer Size
128 }{
129 alloc size <- size
130 }
131 If[[alloc size] > [[regs]Max Size >>]] {
132 stack alloc <- Val[alloc size]
133 }{
134 next func <- [func]Processor Reg[type] {}
135 {
136 location <- Register[~, alloc size]
137 }{
138 stack alloc <- Val[alloc size]
139 }
140 }
141 Val[stack alloc]
142 {
143 next func, location <- [func]Allocate Stack[alloc size]
144 }
145 out func <- [next func]Variables <<[ [[next func]Variables >>]Set[name, location] ]
146 out <- Val[location]
147 }
148
149 Blueprint Register
150 {
151 Number
152 Value Size
153 }
154 Register[num,size:out]
155 {
156 If[[size] = [3]]
157 {
158 value size <- 4
159 }{
160 value size <- size
161 }
162 out <- [[Build["Register"]]Number <<[num]]Value Size <<[value size]
163 }
164
165 In Memory?@Register[reg:out]
166 {
167 out <- No
168 }
169
170 =@Register[reg,other:out]
171 {
172 ,out <- If[[Type Of[reg]] = [Type Of[other]]]
173 {
174 out <- [[reg]Number >>] = [[other]Number >>]
175 }
176 }
177
178 Op ASM@Register[reg,func,regs,extra offset:out]
179 {
180 out <- [regs]Index[ [reg]Number >> ]
181 }
182
183 Size@Register[reg:out]
184 {
185 out <- [reg]Value Size >>
186 }
187
188 Blueprint Immediate
189 {
190 Value
191 }
192
193 Immediate[val:out]
194 {
195 out <- [Build["Immediate"]]Value <<[val]
196 }
197
198 In Memory?@Immediate[val:out]
199 {
200 out <- No
201 }
202
203 =@Immediate[val,other:out]
204 {
205 ,out <- If[[Type Of[val]] = [Type Of[other]]]
206 {
207 out <- [[val]Value >>] = [[other]Value >>]
208 }
209 }
210
211 Op ASM@Immediate[val,func,regs,extra offset:out]
212 {
213 out <- [val]Value >>
214 }
215
216 Size@Immediate[val:out]
217 {
218 out <- 4
219 }
220
221 Blueprint None
222 {
223 Dummy
224 }
225
226 None[:out]
227 {
228 out <- Build["None"]
229 }
230
231 In Memory?@None[none:out]
232 {
233 out <- No
234 }
235
236 Op ASM@None[none,func,regs,extra offset:out]
237 {
238 out <- ""
239 }
240
241 Size@None[none:out]
242 {
243 out <- 0
244 }
245
246 Blueprint Stack Location
247 {
248 Offset
249 Size
250 }
251
252 Stack Location[offset,size:out]
253 {
254 out <- [[Build["Stack Location"]]Offset <<[offset]]Size <<[size]
255 }
256
257 In Memory?@Stack Location[location:out]
258 {
259 out <- Yes
260 }
261
262 =@Stack Location[loc,other:out]
263 {
264 ,out <- If[[Type Of[loc]] = [Type Of[other]]]
265 {
266 out <- [[loc]Offset >>] = [[other]Offset >>]
267 }
268 }
269
270 Op ASM@Stack Location[loc,func,regs,extra offset:out]
271 {
272 offset <- [[[func]Stack Size >>] - [[loc]Offset >>]] - [[loc]Size >>]
273 If[[offset] > [0]]
274 {
275 toffset <- ["+"]Append[offset]
276 }{
277 toffset <- ""
278 }
279 out <- [["[esp"]Append[toffset]]Append["]"]
280 }
281
282 Size@Stack Location[loc:out]
283 {
284 out <- [loc]Size >>
285 }
286
287 Blueprint Pointer
288 {
289 Base
290 Offset
291 Target Size
292 }
293
294 Pointer[base,offset,size:out]
295 {
296 out <- [[[Build["Pointer"]]Base <<[base]]Offset <<[offset]]Target Size <<[size]
297 }
298
299 In Memory?@Pointer[location:out]
300 {
301 out <- Yes
302 }
303
304 =@Pointer[pointer,other:out]
305 {
306 ,out <- If[[Type Of[loc]] = [Type Of[other]]]
307 {
308 out <- [[loc]Storage >>] = [[other]Storage >>]
309 }
310 }
311
312 Op ASM@Pointer[pointer,func,regs,extra offset:out]
313 {
314 If[[Type Of[ [pointer]Offset >> ]] = ["None"]]
315 {
316 out <- [["["]Append[ [[pointer]Base >>]Op ASM[func,regs,extra offset] ]]Append["]"]
317 }{
318 out <- [[[["["
319 ]Append[ [[pointer]Base >>]Op ASM[func,regs,extra offset] ]
320 ]Append["+"]
321 ]Append[ [[pointer]Offset >>]Op ASM[func,regs,extra offset] ]
322 ]Append["]"]
323 }
324 }
325
326 Size@Pointer[pointer:out]
327 {
328 out <- [pointer]Target Size >>
329 }
330
331 Blueprint X86 Instruction
332 {
333 Name
334 Op1
335 Op2
336 Width
337 Extra Offset
338 }
339
340 X86 Instruction[name, op1, op2, width:out]
341 {
342 out <- [[[[[Build["X86 Instruction"]]Name << [name]]Op1 << [op1]]Op2 <<[op2]]Width <<[width]]Extra Offset <<[0]
343 }
344
345 CAppend[left,right:out]
346 {
347 If[[right] = [""]]
348 {
349 out <- ""
350 }{
351 out <- [left]Append[right]
352 }
353 }
354
355 Inst ASM@X86 Instruction[inst,func:out]
356 {
357 If[[[inst]Width >>] = [4]]
358 {
359 regs <- ("eax","ecx","edx","ebx","esi","edi","esp")
360 }{
361 If[[[inst]Width >>] = [2]]
362 {
363 regs <- ("ax","cx","dx","bx","si","di")
364 }{
365 regs <- ("al","cl","dl","bl","si","di")
366 }
367 }
368 out <- [[[inst]Name >>
369 ]Append[ [" "]CAppend[[[inst]Op1>>]Op ASM[func, regs, [inst]Extra Offset >>]] ]
370 ]Append[ [", "]CAppend[[[inst]Op2>>]Op ASM[func, regs, [inst]Extra Offset >>]] ]
371 }
372
373 Blueprint X86 Function
374 {
375 Name
376 Registers
377 Variables
378 Scratch
379 Need Save
380 Free Stack Locations
381 Stack Size
382 Param Size
383 Temp Stack
384 Convention
385 Instructions
386 }
387
388 X86 Function[name,params,convention:out]
389 {
390 [[[[[[[[[Build["X86 Function"]
391 ]Name << [name]
392 ]Registers << [Registers[("eax","ecx","edx","ebx","esi","edi"), (0,1,2,3,4,5), (0,1,2,3,4,5), (3,4,5), 4]]
393 ]Variables <<[New@Dictionary[]]
394 ]Need Save <<[()]
395 ]Free Stack Locations <<[()]
396 ]Stack Size <<[0]
397 ]Instructions <<[()]
398 ]Convention <<[convention]
399 ]Alloc Params[params, convention]
400 {
401 out <- [~]Param Size <<[ [~]Stack Size >> ]
402 }
403 }
404
405 Pointer Size@X86 Function[func:out]
406 {
407 out <- 4
408 }
409
410 Param Helper@X86 Function[func, param:out]
411 {
412 ,loc <- [func]Allocate Stack[4]
413 {
414 out <- [~]Variables << [ [[~]Variables >>]Set[param, loc] ]
415 }
416 }
417
418 Alloc Params@X86 Function[func,params,convention:out]
419 {
420 If[[convention] = ["fastcall"]]
421 {
422 [params]Index[0]
423 {
424 next func <- [[func]Registers <<[ [[func]Registers >>]Available? <<[ [[[func]Registers >>]Available? >>]Set[1, No] ]]
425 ]Variables <<[ [[func]Variables >>]Set[~, Register[1,4]] ]
426 [params]Index[1]
427 {
428 next func2 <- [[next func]Registers <<[ [[next func]Registers >>]Available? <<[ [[[next func]Registers >>]Available? >>]Set[2, No] ]]
429 ]Variables <<[ [[next func]Variables >>]Set[~, Register[2,4]] ]
430 [params]Index[2]
431 {
432 out <- _Fold[params, 2, next func2, "Param Helper"]
433 }{
434 out <- Val[next func2]
435 }
436 }{
437 out <- Val[next func]
438 }
439 }{
440 out <- func
441 }
442 }{
443 out <- Fold["Param Helper", func, params]
444 }
445 }
446
447 Add Instruction@X86 Function[func, inst:out]
448 {
449 out <- [func]Instructions << [ [[func]Instructions >>]Append[ [inst]Extra Offset <<[[func]Temp Stack >>] ] ]
450 }
451
452 Allocate Stack@X86 Function[func,size:func out,out]
453 {
454 out <- Stack Location[[func]Stack Size >>, size]
455 func out <- [func]Stack Size <<[ [[func]Stack Size >>]+[size] ]
456 }
457
458 Allocate Var@X86 Function[func,name,size,type:out func,out]
459 {
460 out func, out <- Processor Allocate[func,name,size,type]
461 }
462
463 Resolve@X86 Function[func,op:out,out func]
464 {
465 If[[Type Of[op]] = ["String"]]
466 {
467 out <- [[func]Variables >>]Index[op]
468 }{
469 out <- op
470 }
471 }
472
473 Allocate Scratch@X86 Function[func,size:out func,scratch]
474 {
475 out func,scratch <- Processor Reg[func,"data"] {} {}
476 {
477 //FIXME: need to use a reg that's not involved in the current op
478 //FIXME: Also, might need two scratch regs and both might be in use
479 ,stack inc <- [func]Save Reg[0]
480 {
481 out func <- [~]Scratch << [ [[~]Scratch >>]Set[0, Yes] ]
482 }
483 }
484 }
485
486 Free Scratch@X86 Function[func,scratch:out func]
487 {
488 [[func]Scratch >>]Index[scratch]
489 {
490 [func]Restore Reg[scratch]
491 {
492 out func <- [~]Scratch << [ [[~]Scratch >>]Remove[scratch] ]
493 }
494 }{
495 out func <- Processor Free Reg[func, scratch]
496 }
497 If[[scratch]Index[1]]
498 {
499
500 }{
501
502 }
503 }
504
505 Classify Op@X86 Function[func,op:class]
506 {
507 If[[op]In Memory?]
508 {
509 If[[Type Of[op]] = ["Pointer"]]
510 {
511 If[[[[op]Base >>]In Memory?] Or [[[op]Offset >>]In Memory?]]
512 {
513 class <- "u"
514 }{
515 class <- "m"
516 }
517 }{
518 class <- "m"
519 }
520 }{
521 class <- "r"
522 }
523 }
524
525 RegMem2Op@X86 Function[func,dest,notdest,op,size:out]
526 {
527 out <- [func]Add Instruction[X86 Instruction[op, dest, notdest, size]]
528 }
529
530 MemPointer2Op@X86 Function[func,dest,notdest,op,size:out]
531 {
532 ,scratch <- [func]Allocate Scratch[size]
533 {
534 out <- [[[~]Fetch[notdest,scratch]
535 ]Add Instruction[X86 Instruction[op, dest, scratch, size]]
536 ]Free Scratch[scratch]
537 }
538 }
539
540 //Make sure to map this to both r, (m or r) -> m and r, (m or r) -> r
541 RegMemToNotPointer@X86 Function[func,source1,source2,dest,op,size:out]
542 {
543 out <- [[func]Move[source2,dest]
544 ]Add Instruction[X86 Instruction[op, dest, source1, size]]
545 }
546
547 RegMemToPointer@X86 Function[func,source1,source2,dest,op,size:out]
548 {
549 ,scratch <- [func]Allocate Scratch[size]
550 {
551 spointer <- Pointer[scratch, None[], size]
552 out <- [[[[~]Calculate Address[dest, scratch]
553 ]Move[source2, spointer]
554 ]Add Instruction[X86 Instruction[op, spointer, source1, size]]
555 ]Free Scratch[scratch]
556 }
557 }
558
559 RegPointerToMem@X86 Function[func,source1,source2,dest,op,size:out]
560 {
561 ,scratch <- [func]Allocate Scratch[size]
562 {
563 spointer <- Pointer[scratch, None[], size]
564 out <- [[[[~]Calculate Address[source2, scratch]
565 ]Move[spointer, dest]
566 ]Add Instruction[X86 Instruction[op, dest, source1, size]]
567 ]Free Scratch[scratch]
568 }
569 }
570
571 RegPointerReg2Op@X86 Function[func,dest,notdest,op,size:out]
572 {
573 ,scratch <- [func]Allocate Scratch[size]
574 {
575 spointer <- Pointer[scratch, None[], size]
576 out <- [[[~]Calculate Address[notdest, scratch]
577 ]Add Instruction[X86 Instruction[op, dest, spointer, size]]
578 ]Free Scratch[scratch]
579 }
580 }
581
582 RegPointerPointer2Op@X86 Function[func,dest,notdest,op,size:out]
583 {
584 ,scratch <- [func]Allocate Scratch[size]
585 {
586 spointer <- Pointer[scratch, None[], size]
587 out <- [[[~]Calculate Address[dest, scratch]
588 ]Add Instruction[X86 Instruction[op, spointer, notdest, size]]
589 ]Free Scratch[scratch]
590 }
591 }
592
593 RegPointerToPointer@X86 Function[func,source1,source2,dest,op,size:out]
594 {
595 ,scratch <- [func]Allocate Scratch[size]
596 {
597 spointer <- Pointer[scratch, None[], size]
598 ,scratch2 <- [~]Allocate Scratch[size]
599 {
600 spointer2 <- Pointer[scratch2, None[], size]
601 out <- [[[[[[~]Calculate Address[source2, scratch]
602 ]Calculate Address[dest, scratch2]
603 ]Move[spointer2, spointer]
604 ]Add Instruction[X86 Instruction[op, spointer2, source1, size]]
605 ]Free Scratch[scratch2]
606 ]Free Scratch[scratch]
607 }
608 }
609 }
610
611 //If source1, source2 and dest are all pointers with register offsets, allocating a scratch register could
612 //become a problem unless I let ebp be used as a scratch register. Should be doable as long as thread local
613 //variables properly report ebp as a used register. Alternatively, one register could be reserved for scratch
614 //usage
615 MemPointerToMem@X86 Function[func,source1,source2,dest,op,size:out]
616 {
617 ,scratch <- [func]Allocate Scratch[size]
618 {
619 out <- [[[[~]Fetch[source2, scratch]
620 ]Add Instruction[X86 Instruction[op, scratch, source1, size]]
621 ]Move[scratch, dest]
622 ]Free Scratch[scratch]
623 }
624 }
625
626 MemPointerToPointer@X86 Function[func,source1,source2,dest,op,size:out]
627 {
628 ,scratch <- [func]Allocate Scratch[size]
629 {
630 ,scratch2 <- [~]Allocate Scratch[size]
631 {
632 spointer2 <- Pointer[scratch2, None[], size]
633 out <- [[[[[[~]Fetch[source2, scratch]
634 ]Add Instruction[X86 Instruction[op, scratch, source1, size]]
635 ]Calculate Address[dest, scratch2]
636 ]Move[scratch, spointer2]
637 ]Free Scratch[scratch2]
638 ]Free Scratch[scratch]
639 }
640 }
641 }
642
643 //This does almost the same thing as RegMemToNotPointer, depending on how I do the pattern matching I could maybe combine them
644 PointerMemToReg@X86 Function[func,source1,source2,dest,op,size:out]
645 {
646 out <- [[func]Fetch[source1,dest]
647 ]Add Instruction[X86 Instruction[op, dest, source2, size]]
648 }
649
650 PointerPointer2Op@X86 Function[func,dest,notdest,op,size:out]
651 {
652 ,scratch <- [func]Allocate Scratch[size]
653 {
654 spointer <- Pointer[scratch, None[], size]
655 ,scratch2 <- [~]Allocate Scratch[size]
656 {
657 out <- [[[[[[[~]Calculate Address[dest, scratch]
658 ]Fetch[notdest, scratch2]
659 ]Add Instruction[X86 Instruction[op, scratch, scratch2, size]]
660 ]Calculate Address[dest, scratch2]
661 ]Move[scratch, spointer2]
662 ]Free Scratch[scratch2]
663 ]Free Scratch[scratch]
664 }
665 }
666 }
667
668 PointerPointerToPointer@X86 Function[func,source1,source2,dest,op,size:out]
669 {
670 ,scratch <- [func]Allocate Scratch[size]
671 {
672 ,scratch2 <- [~]Allocate Scratch[size]
673 {
674 spointer2 <- Pointer[scratch2, None[], size]
675 out <- [[[[[[[~]Fetch[source1, scratch]
676 ]Calculate Address[source2, scratch2]
677 ]Add Instruction[X86 Instruction[op, scratch, spointer2, size]]
678 ]Calculate Address[dest, scratch2]
679 ]Move[scratch, spointer2]
680 ]Free Scratch[scratch2]
681 ]Free Scratch[scratch]
682 }
683 }
684 }
685
686 PointerPointerToMem@X86 Function[func,source1,souce2,dest,op,size:out]
687 {
688 ,scratch <- [func]Allocate Scratch[size]
689 {
690 spointer <- Pointer[scratch, None[], size]
691 out <- [[[[[~]Calculate Address[source1, scratch]
692 ]Move[dest, spointer]
693 ]Fetch[source2, scratch]
694 ]Add Instruction[X86 Instruction[op, dest, scratch, size]]
695 ]Free Scratch[scratch]
696 }
697 }
698
699 PointerPointerToReg@X86 Function[func,source1,souce2,dest,op,size:out]
700 {
701 ,scratch <- [func]Allocate Scratch[size]
702 {
703 spointer <- Pointer[scratch, None[], size]
704 out <- [[[[~]Fetch[source1, dest]
705 ]Calculate Address[source2, scratch]
706 ]Add Instruction[X86 Instruction[op, dest, scratch, size]]
707 ]Free Scratch[scratch]
708 }
709 }
710
711 2Op Associative@X86 Function[func,psource1,psource2,pdest,name:out func]
712 {
713 source1 <- [func]Resolve[psource1]
714 source2 <- [func]Resolve[psource2]
715 dest <- [func]Resolve[pdest]
716 dest class <- [func]Classify Op[dest]
717 width <- Min[Min[Min[[source1]Size,[source2]Size], [dest]Size], 4]
718 swapper <- (1,0)
719 sources <- [[()]Append[source1]Append[source2]
720 [sources]Find[dest]
721 {
722 source <- [swapper]Index[~]
723 source class <- [func]Classify Op[source]
724 If[[dest class] = ["u"]]
725 {
726 If[[source class] = ["r"]]
727 {
728 out func <- [func]RegPointerPointer2Op[dest,source,name,width]
729 }{
730 out func <- [func]PointerPointer2Op[dest,source,name,width]
731 }
732 }{
733 If[[dest class] = ["r"]]
734 {
735 If[[source class] = ["u"]]
736 {
737 out func <- [func]RegPointerReg2Op[dest,source,name,width]
738 }{
739 out func <- [func]RegMem2Op[dest,source,name,width]
740 }
741 }{
742 If[[source class] = ["r"]]
743 {
744 out func <- [func]RegMem2Op[dest,source,name,width]
745 }{
746 out func <- [func]MemPointer2Op[dest,source,name,width]
747 }
748 }
749 }
750 }{
751 sclasses <- Map[sources, ["Classify Op"]Set Input[0, func]]
752 first <- [sources]Index[found index]
753 other index <- [swapper]Index[found index]
754 other <- [sources]Index[other index]
755 other class <- [sclasses]Index[other index]
756 found index <- [sclasses]Find["r"]
757 {
758 If[[other class] = ["u"]]
759 {
760 If[[dest class] = ["m"]]
761 {
762 out func <- [func]RegPointerToMem[first,other,dest,name,width]
763 }{
764 If[[dest class] = ["u"]]
765 {
766 out func <- [func]RegPointerToPointer[first,other,dest,name,width]
767 }{
768 out func <- [func]PointerMemToReg[other,first,dest,name,width]
769 }
770 }
771 }{
772 If[[dest class] = ["u"]]
773 {
774 out func <- [func]RegMemToPointer[first,other,dest,name,width]
775 }{
776 out func <- [func]RegMemToNotPointer[first,other,dest,name,width]
777 }
778 }
779 }{
780 found index <- [sclasses]Find["m"]
781 {
782 If[[dest class] = ["r"]]
783 {
784 out func <- [func]PointerMemToReg[other,first,dest,name,width]
785 }{
786 If[[dest class] = ["m"]]
787 {
788 out func <- [func]MemPointerToMem[first,other,dest,name,width]
789 }{
790 out func <- [func]MemPointerToPointer[first,other,dest,name,width]
791 }
792 }
793 }{
794 If[[dest class] = ["r"]]
795 {
796 out func <- [func]PointerPointerToReg[first,other,dest,name,width]
797 }{
798 If[[dest class] = ["m"]]
799 {
800 out func <- [func]PointerPointerToMem[first,other,dest,name,width]
801 }{
802 out func <- [func]PointerPointerToPointer[first,other,dest,name,width]
803 }
804 }
805 }
806 }
807 }
808 }
809
810 2Op@X86 Function[func,psource1,psource2,pdest,name:out func]
811 {
812 source1 <- [func]Resolve[psource1]
813 source2 <- [func]Resolve[psource2]
814 dest <- [func]Resolve[pdest]
815 width <- Min[Min[Min[[source1]Size,[source2]Size], [dest]Size], 4]
816 If[[source1] = [dest]]
817 {
818 If[[[source1]In Memory?] And [[source2]In Memory?]]
819 {
820 ,scratch, stack inc <- [func]Allocate Scratch[width]
821 {
822 out func <- [[[~]Add Instruction[X86 Instruction["mov", [scratch]Index[0], source2, width, stack inc]]
823 ]Add Instruction[X86 Instruction[name, source1, [scratch]Index[0], width, stack inc]]
824 ]Free Scratch[scratch]
825 }
826 }{
827 out func <- [func]Add Instruction[X86 Instruction[name, dest, source2, width, 0]]
828 }
829 }{
830 If[[dest]In Memory?]
831 {
832 If[[source2]In Memory?]
833 {
834 ,scratch, stack inc <- [func]Allocate Scratch[width]
835 {
836 out func <- [[[[~]Add Instruction[X86 Instruction["mov", [scratch]Index[0], source1, width, stack inc]]
837 ]Add Instruction[X86 Instruction[name, [scratch]Index[0], source2, width, stack inc]]
838 ]Add Instruction[X86 Instruction["mov", dest, [scratch]Index[0], width, stack inc]]
839 ]Free Scratch[scratch]
840 }
841 }{
842 out func <- [[func]Move[source1,dest]
843 ]Add Instruction[X86 Instruction[name, dest, source2, width, 0]]
844 }
845 }{
846 out func <- [[func]Move[source1,dest]
847 ]Add Instruction[X86 Instruction[name, dest, source2, width, 0]]
848 }
849 }
850 }
851
852 Add@X86 Function[func,source1,source2,dest:out func]
853 {
854 out func <- [func]2Op Associative[source1,source2,dest,"add"]
855 }
856
857 Sub@X86 Function[func,source1,source2,dest:out func]
858 {
859 out func <- [func]2Op[source1,source2,dest,"sub"]
860 }
861
862 Move@X86 Function[func,psource,pdest:out func]
863 {
864 source <- [func]Resolve[psource]
865 dest <- [func]Resolve[pdest]
866 out func <- [func]Add Instruction[X86 Instruction["mov", dest, source, 4]]
867 }
868
869 Instruction ASM[current,instruction,func:out]
870 {
871 out <- [[[current]Append["\t"]]Append[ [instruction]Inst ASM[func] ]]Append["\n"]
872 }
873
874 Save Reg@X86 Function[func,reg:out]
875 {
876 out <- [[func]Add Instruction[X86 Instruction["push", Register[reg, 4], None[], 4]]
877 ]Temp Stack << [ [[func]Temp Stack >>]+[4] ]
878 }
879
880 Prolog Save@X86 Function[func,junk,reg:out]
881 {
882 out <- [[func]Add Instruction[X86 Instruction["push", Register[reg, 4], None[], 4]]
883 ]Stack Size << [ [[func]Stack Size >>]+[4] ]
884 }
885
886 Restore Reg@X86 Function[func,reg:out]
887 {
888 out <- [[func]Add Instruction[X86 Instruction["pop", Register[reg, 4], None[], 4]]
889 ]Temp Stack << [ [[func]Temp Stack >>]-[4] ]
890 }
891
892 Epilogue Restore@X86 Function[func,junk,reg:out]
893 {
894 out <- [func]Add Instruction[X86 Instruction["pop", Register[reg, 4], None[], 4]]
895 }
896
897 Finalize@X86 Function[func:out]
898 {
899 alloc stack <- [[func]Stack Size >>] - [[func]Param Size >>]
900
901 oldstream <- [func]Instructions >>
902
903 If[[alloc stack] > [0]]
904 {
905 start <- [()]Append[X86 Instruction["sub", Register[6, 4],Immediate[alloc stack], Register[6, 4], 4], func]
906 }{
907 start <- ()
908 }
909
910 If[[[func]Convention >>] = ["cdecl"]]
911 {
912 If[ [alloc stack] > [0] ]
913 {
914 retparam <- Immediate[alloc stack]
915 }{
916 retparam <- None[]
917 }
918 }{
919 retparam <- Immediate[[func]Stack Size >>]
920 }
921
922 [[func]Need Save >>]First
923 {
924 prolog <- Fold["Prolog Save", [func]Instructions << [start], [func]Need Save >>]
925 out <- [Reverse Fold["Epilogue Restore", body, [func]Need Save >>]]Add Instruction[X86 Instruction["ret", retparam, None[], 4]]
926 }{
927 prolog <- [func]Instructions <<[start]
928 out <- [body]Add Instruction[X86 Instruction["ret", retparam, None[], 4]]
929 }
930
931 body <- Fold["Add Instruction", prolog, oldstream]
932 }
933
934 Text@X86 Function[func:out]
935 {
936 name line <- [Escape Rhope Name[[func]Name >>]
937 ]Append[":\n"]
938
939 out <- Fold[["Instruction ASM"]Set Input[2, func], name line, [func]Instructions >>]
940 }