comparison genasm.rhope @ 105:43cc42df26cc

Various compiler improvements
author Mike Pavone <pavone@retrodev.com>
date Tue, 24 Aug 2010 23:22:17 -0400
parents 31f8182f3433
children
comparison
equal deleted inserted replaced
103:7428aa5d6ade 105:43cc42df26cc
1 //Import extendlib.rhope
2 Import backendutils.rhope
3 1
4 Blueprint Registers 2 Blueprint Registers
5 { 3 {
6 Names 4 Names
7 Can Data 5 Can Data
315 Size@Pointer[pointer:out] 313 Size@Pointer[pointer:out]
316 { 314 {
317 out <- [pointer]Target Size >> 315 out <- [pointer]Target Size >>
318 } 316 }
319 317
320 Blueprint X86 Instruction
321 {
322 Name
323 Op1
324 Op2
325 Width
326 Extra Offset
327 }
328
329 X86 Instruction[name, op1, op2, width:out]
330 {
331 out <- [[[[[Build["X86 Instruction"]]Name << [name]]Op1 << [op1]]Op2 <<[op2]]Width <<[width]]Extra Offset <<[0]
332 }
333
334 CAppend[left,right:out] 318 CAppend[left,right:out]
335 { 319 {
336 If[[right] = [""]] 320 If[[right] = [""]]
337 { 321 {
338 out <- "" 322 out <- ""
339 }{ 323 }{
340 out <- [left]Append[right] 324 out <- [left]Append[right]
341 } 325 }
342 } 326 }
343 327
344 Inst ASM@X86 Instruction[inst,func:out]
345 {
346 If[[[inst]Width >>] = [4]]
347 {
348 regs <- ("eax","ecx","edx","ebx","esi","edi","esp")
349 }{
350 If[[[inst]Width >>] = [2]]
351 {
352 regs <- ("ax","cx","dx","bx","si","di")
353 }{
354 regs <- ("al","cl","dl","bl","si","di")
355 }
356 }
357 out <- [[[inst]Name >>
358 ]Append[ [" "]CAppend[[[inst]Op1>>]Op ASM[func, regs, [inst]Extra Offset >>]] ]
359 ]Append[ [", "]CAppend[[[inst]Op2>>]Op ASM[func, regs, [inst]Extra Offset >>]] ]
360 }
361
362 Blueprint X86 Function
363 {
364 Name
365 Registers
366 Variables
367 Scratch
368 Need Save
369 Free Stack Locations
370 Stack Size
371 Param Size
372 Temp Stack
373 Convention
374 Instructions
375 }
376
377 X86 Function[name,params,convention:out]
378 {
379 [[[[[[[[[Build["X86 Function"]
380 ]Name << [name]
381 ]Registers << [Registers[("eax","ecx","edx","ebx","esi","edi"), (0,1,2,3,4,5), (0,1,2,3,4,5), (3,4,5), 4]]
382 ]Variables <<[New@Dictionary[]]
383 ]Need Save <<[()]
384 ]Free Stack Locations <<[()]
385 ]Stack Size <<[0]
386 ]Instructions <<[()]
387 ]Convention <<[convention]
388 ]Alloc Params[params, convention]
389 {
390 out <- [~]Param Size <<[ [~]Stack Size >> ]
391 }
392 }
393
394 Pointer Size@X86 Function[func:out]
395 {
396 out <- 4
397 }
398
399 Param Helper@X86 Function[func, param:out]
400 {
401 ,loc <- [func]Allocate Stack[4]
402 {
403 out <- [~]Variables << [ [[~]Variables >>]Set[param, loc] ]
404 }
405 }
406
407 Alloc Params@X86 Function[func,params,convention:out]
408 {
409 If[[convention] = ["fastcall"]]
410 {
411 [params]Index[0]
412 {
413 next func <- [[func]Registers <<[ [[func]Registers >>]Available? <<[ [[[func]Registers >>]Available? >>]Set[1, No] ]]
414 ]Variables <<[ [[func]Variables >>]Set[~, Register[1,4]] ]
415 [params]Index[1]
416 {
417 next func2 <- [[next func]Registers <<[ [[next func]Registers >>]Available? <<[ [[[next func]Registers >>]Available? >>]Set[2, No] ]]
418 ]Variables <<[ [[next func]Variables >>]Set[~, Register[2,4]] ]
419 [params]Index[2]
420 {
421 out <- _Fold[params, 2, next func2, "Param Helper"]
422 }{
423 out <- Val[next func2]
424 }
425 }{
426 out <- Val[next func]
427 }
428 }{
429 out <- func
430 }
431 }{
432 out <- Fold["Param Helper", func, params]
433 }
434 }
435
436 Add Instruction@X86 Function[func, inst:out]
437 {
438 out <- [func]Instructions << [ [[func]Instructions >>]Append[ [inst]Extra Offset <<[[func]Temp Stack >>] ] ]
439 }
440
441 Allocate Stack@X86 Function[func,size:func out,out]
442 {
443 out <- Stack Location[[func]Stack Size >>, size]
444 func out <- [func]Stack Size <<[ [[func]Stack Size >>]+[size] ]
445 }
446
447 Allocate Var@X86 Function[func,name,size,type:out func,out]
448 {
449 out func, out <- Processor Allocate[func,name,size,type]
450 }
451
452 Resolve@X86 Function[func,op:out,out func]
453 {
454 If[[Type Of[op]] = ["String"]]
455 {
456 out <- [[func]Variables >>]Index[op]
457 }{
458 out <- op
459 }
460 }
461
462 Allocate Scratch@X86 Function[func,size:out func,scratch]
463 {
464 out func,scratch <- Processor Reg[func,"data"] {} {}
465 {
466 //FIXME: need to use a reg that's not involved in the current op
467 //FIXME: Also, might need two scratch regs and both might be in use
468 ,stack inc <- [func]Save Reg[0]
469 {
470 out func <- [~]Scratch << [ [[~]Scratch >>]Set[0, Yes] ]
471 }
472 }
473 }
474
475 Free Scratch@X86 Function[func,scratch:out func]
476 {
477 [[func]Scratch >>]Index[scratch]
478 {
479 [func]Restore Reg[scratch]
480 {
481 out func <- [~]Scratch << [ [[~]Scratch >>]Remove[scratch] ]
482 }
483 }{
484 out func <- Processor Free Reg[func, scratch]
485 }
486 If[[scratch]Index[1]]
487 {
488
489 }{
490
491 }
492 }
493
494 Classify Op@X86 Function[func,op:class]
495 {
496 If[[op]In Memory?]
497 {
498 If[[Type Of[op]] = ["Pointer"]]
499 {
500 If[[[[op]Base >>]In Memory?] Or [[[op]Offset >>]In Memory?]]
501 {
502 class <- "u"
503 }{
504 class <- "m"
505 }
506 }{
507 class <- "m"
508 }
509 }{
510 class <- "r"
511 }
512 }
513
514 RegMem2Op@X86 Function[func,dest,notdest,op,size:out]
515 {
516 out <- [func]Add Instruction[X86 Instruction[op, dest, notdest, size]]
517 }
518
519 MemPointer2Op@X86 Function[func,dest,notdest,op,size:out]
520 {
521 ,scratch <- [func]Allocate Scratch[size]
522 {
523 out <- [[[~]Fetch[notdest,scratch]
524 ]Add Instruction[X86 Instruction[op, dest, scratch, size]]
525 ]Free Scratch[scratch]
526 }
527 }
528
529 //Make sure to map this to both r, (m or r) -> m and r, (m or r) -> r
530 RegMemToNotPointer@X86 Function[func,source1,source2,dest,op,size:out]
531 {
532 out <- [[func]Move[source2,dest]
533 ]Add Instruction[X86 Instruction[op, dest, source1, size]]
534 }
535
536 RegMemToPointer@X86 Function[func,source1,source2,dest,op,size:out]
537 {
538 ,scratch <- [func]Allocate Scratch[size]
539 {
540 spointer <- Pointer[scratch, None[], size]
541 out <- [[[[~]Calculate Address[dest, scratch]
542 ]Move[source2, spointer]
543 ]Add Instruction[X86 Instruction[op, spointer, source1, size]]
544 ]Free Scratch[scratch]
545 }
546 }
547
548 RegPointerToMem@X86 Function[func,source1,source2,dest,op,size:out]
549 {
550 ,scratch <- [func]Allocate Scratch[size]
551 {
552 spointer <- Pointer[scratch, None[], size]
553 out <- [[[[~]Calculate Address[source2, scratch]
554 ]Move[spointer, dest]
555 ]Add Instruction[X86 Instruction[op, dest, source1, size]]
556 ]Free Scratch[scratch]
557 }
558 }
559
560 RegPointerReg2Op@X86 Function[func,dest,notdest,op,size:out]
561 {
562 ,scratch <- [func]Allocate Scratch[size]
563 {
564 spointer <- Pointer[scratch, None[], size]
565 out <- [[[~]Calculate Address[notdest, scratch]
566 ]Add Instruction[X86 Instruction[op, dest, spointer, size]]
567 ]Free Scratch[scratch]
568 }
569 }
570
571 RegPointerPointer2Op@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[dest, scratch]
577 ]Add Instruction[X86 Instruction[op, spointer, notdest, size]]
578 ]Free Scratch[scratch]
579 }
580 }
581
582 RegPointerToPointer@X86 Function[func,source1,source2,dest,op,size:out]
583 {
584 ,scratch <- [func]Allocate Scratch[size]
585 {
586 spointer <- Pointer[scratch, None[], size]
587 ,scratch2 <- [~]Allocate Scratch[size]
588 {
589 spointer2 <- Pointer[scratch2, None[], size]
590 out <- [[[[[[~]Calculate Address[source2, scratch]
591 ]Calculate Address[dest, scratch2]
592 ]Move[spointer2, spointer]
593 ]Add Instruction[X86 Instruction[op, spointer2, source1, size]]
594 ]Free Scratch[scratch2]
595 ]Free Scratch[scratch]
596 }
597 }
598 }
599
600 //If source1, source2 and dest are all pointers with register offsets, allocating a scratch register could
601 //become a problem unless I let ebp be used as a scratch register. Should be doable as long as thread local
602 //variables properly report ebp as a used register. Alternatively, one register could be reserved for scratch
603 //usage
604 MemPointerToMem@X86 Function[func,source1,source2,dest,op,size:out]
605 {
606 ,scratch <- [func]Allocate Scratch[size]
607 {
608 out <- [[[[~]Fetch[source2, scratch]
609 ]Add Instruction[X86 Instruction[op, scratch, source1, size]]
610 ]Move[scratch, dest]
611 ]Free Scratch[scratch]
612 }
613 }
614
615 MemPointerToPointer@X86 Function[func,source1,source2,dest,op,size:out]
616 {
617 ,scratch <- [func]Allocate Scratch[size]
618 {
619 ,scratch2 <- [~]Allocate Scratch[size]
620 {
621 spointer2 <- Pointer[scratch2, None[], size]
622 out <- [[[[[[~]Fetch[source2, scratch]
623 ]Add Instruction[X86 Instruction[op, scratch, source1, size]]
624 ]Calculate Address[dest, scratch2]
625 ]Move[scratch, spointer2]
626 ]Free Scratch[scratch2]
627 ]Free Scratch[scratch]
628 }
629 }
630 }
631
632 //This does almost the same thing as RegMemToNotPointer, depending on how I do the pattern matching I could maybe combine them
633 PointerMemToReg@X86 Function[func,source1,source2,dest,op,size:out]
634 {
635 out <- [[func]Fetch[source1,dest]
636 ]Add Instruction[X86 Instruction[op, dest, source2, size]]
637 }
638
639 PointerPointer2Op@X86 Function[func,dest,notdest,op,size:out]
640 {
641 ,scratch <- [func]Allocate Scratch[size]
642 {
643 spointer <- Pointer[scratch, None[], size]
644 ,scratch2 <- [~]Allocate Scratch[size]
645 {
646 out <- [[[[[[[~]Calculate Address[dest, scratch]
647 ]Fetch[notdest, scratch2]
648 ]Add Instruction[X86 Instruction[op, scratch, scratch2, size]]
649 ]Calculate Address[dest, scratch2]
650 ]Move[scratch, spointer2]
651 ]Free Scratch[scratch2]
652 ]Free Scratch[scratch]
653 }
654 }
655 }
656
657 PointerPointerToPointer@X86 Function[func,source1,source2,dest,op,size:out]
658 {
659 ,scratch <- [func]Allocate Scratch[size]
660 {
661 ,scratch2 <- [~]Allocate Scratch[size]
662 {
663 spointer2 <- Pointer[scratch2, None[], size]
664 out <- [[[[[[[~]Fetch[source1, scratch]
665 ]Calculate Address[source2, scratch2]
666 ]Add Instruction[X86 Instruction[op, scratch, spointer2, size]]
667 ]Calculate Address[dest, scratch2]
668 ]Move[scratch, spointer2]
669 ]Free Scratch[scratch2]
670 ]Free Scratch[scratch]
671 }
672 }
673 }
674
675 PointerPointerToMem@X86 Function[func,source1,souce2,dest,op,size:out]
676 {
677 ,scratch <- [func]Allocate Scratch[size]
678 {
679 spointer <- Pointer[scratch, None[], size]
680 out <- [[[[[~]Calculate Address[source1, scratch]
681 ]Move[dest, spointer]
682 ]Fetch[source2, scratch]
683 ]Add Instruction[X86 Instruction[op, dest, scratch, size]]
684 ]Free Scratch[scratch]
685 }
686 }
687
688 PointerPointerToReg@X86 Function[func,source1,souce2,dest,op,size:out]
689 {
690 ,scratch <- [func]Allocate Scratch[size]
691 {
692 spointer <- Pointer[scratch, None[], size]
693 out <- [[[[~]Fetch[source1, dest]
694 ]Calculate Address[source2, scratch]
695 ]Add Instruction[X86 Instruction[op, dest, scratch, size]]
696 ]Free Scratch[scratch]
697 }
698 }
699
700 2Op Associative@X86 Function[func,psource1,psource2,pdest,name:out func]
701 {
702 source1 <- [func]Resolve[psource1]
703 source2 <- [func]Resolve[psource2]
704 dest <- [func]Resolve[pdest]
705 dest class <- [func]Classify Op[dest]
706 width <- Min[Min[Min[[source1]Size,[source2]Size], [dest]Size], 4]
707 swapper <- (1,0)
708 sources <- [[()]Append[source1]Append[source2]
709 [sources]Find[dest]
710 {
711 source <- [swapper]Index[~]
712 source class <- [func]Classify Op[source]
713 If[[dest class] = ["u"]]
714 {
715 If[[source class] = ["r"]]
716 {
717 out func <- [func]RegPointerPointer2Op[dest,source,name,width]
718 }{
719 out func <- [func]PointerPointer2Op[dest,source,name,width]
720 }
721 }{
722 If[[dest class] = ["r"]]
723 {
724 If[[source class] = ["u"]]
725 {
726 out func <- [func]RegPointerReg2Op[dest,source,name,width]
727 }{
728 out func <- [func]RegMem2Op[dest,source,name,width]
729 }
730 }{
731 If[[source class] = ["r"]]
732 {
733 out func <- [func]RegMem2Op[dest,source,name,width]
734 }{
735 out func <- [func]MemPointer2Op[dest,source,name,width]
736 }
737 }
738 }
739 }{
740 sclasses <- Map[sources, ["Classify Op"]Set Input[0, func]]
741 first <- [sources]Index[found index]
742 other index <- [swapper]Index[found index]
743 other <- [sources]Index[other index]
744 other class <- [sclasses]Index[other index]
745 found index <- [sclasses]Find["r"]
746 {
747 If[[other class] = ["u"]]
748 {
749 If[[dest class] = ["m"]]
750 {
751 out func <- [func]RegPointerToMem[first,other,dest,name,width]
752 }{
753 If[[dest class] = ["u"]]
754 {
755 out func <- [func]RegPointerToPointer[first,other,dest,name,width]
756 }{
757 out func <- [func]PointerMemToReg[other,first,dest,name,width]
758 }
759 }
760 }{
761 If[[dest class] = ["u"]]
762 {
763 out func <- [func]RegMemToPointer[first,other,dest,name,width]
764 }{
765 out func <- [func]RegMemToNotPointer[first,other,dest,name,width]
766 }
767 }
768 }{
769 found index <- [sclasses]Find["m"]
770 {
771 If[[dest class] = ["r"]]
772 {
773 out func <- [func]PointerMemToReg[other,first,dest,name,width]
774 }{
775 If[[dest class] = ["m"]]
776 {
777 out func <- [func]MemPointerToMem[first,other,dest,name,width]
778 }{
779 out func <- [func]MemPointerToPointer[first,other,dest,name,width]
780 }
781 }
782 }{
783 If[[dest class] = ["r"]]
784 {
785 out func <- [func]PointerPointerToReg[first,other,dest,name,width]
786 }{
787 If[[dest class] = ["m"]]
788 {
789 out func <- [func]PointerPointerToMem[first,other,dest,name,width]
790 }{
791 out func <- [func]PointerPointerToPointer[first,other,dest,name,width]
792 }
793 }
794 }
795 }
796 }
797 }
798
799 2Op@X86 Function[func,psource1,psource2,pdest,name:out func]
800 {
801 source1 <- [func]Resolve[psource1]
802 source2 <- [func]Resolve[psource2]
803 dest <- [func]Resolve[pdest]
804 width <- Min[Min[Min[[source1]Size,[source2]Size], [dest]Size], 4]
805 If[[source1] = [dest]]
806 {
807 If[[[source1]In Memory?] And [[source2]In Memory?]]
808 {
809 ,scratch, stack inc <- [func]Allocate Scratch[width]
810 {
811 out func <- [[[~]Add Instruction[X86 Instruction["mov", [scratch]Index[0], source2, width, stack inc]]
812 ]Add Instruction[X86 Instruction[name, source1, [scratch]Index[0], width, stack inc]]
813 ]Free Scratch[scratch]
814 }
815 }{
816 out func <- [func]Add Instruction[X86 Instruction[name, dest, source2, width, 0]]
817 }
818 }{
819 If[[dest]In Memory?]
820 {
821 If[[source2]In Memory?]
822 {
823 ,scratch, stack inc <- [func]Allocate Scratch[width]
824 {
825 out func <- [[[[~]Add Instruction[X86 Instruction["mov", [scratch]Index[0], source1, width, stack inc]]
826 ]Add Instruction[X86 Instruction[name, [scratch]Index[0], source2, width, stack inc]]
827 ]Add Instruction[X86 Instruction["mov", dest, [scratch]Index[0], width, stack inc]]
828 ]Free Scratch[scratch]
829 }
830 }{
831 out func <- [[func]Move[source1,dest]
832 ]Add Instruction[X86 Instruction[name, dest, source2, width, 0]]
833 }
834 }{
835 out func <- [[func]Move[source1,dest]
836 ]Add Instruction[X86 Instruction[name, dest, source2, width, 0]]
837 }
838 }
839 }
840
841 Add@X86 Function[func,source1,source2,dest:out func]
842 {
843 out func <- [func]2Op Associative[source1,source2,dest,"add"]
844 }
845
846 Sub@X86 Function[func,source1,source2,dest:out func]
847 {
848 out func <- [func]2Op[source1,source2,dest,"sub"]
849 }
850
851 Move@X86 Function[func,psource,pdest:out func]
852 {
853 source <- [func]Resolve[psource]
854 dest <- [func]Resolve[pdest]
855 out func <- [func]Add Instruction[X86 Instruction["mov", dest, source, 4]]
856 }
857
858 Instruction ASM[current,instruction,func:out]
859 {
860 out <- [[[current]Append["\t"]]Append[ [instruction]Inst ASM[func] ]]Append["\n"]
861 }
862
863 Save Reg@X86 Function[func,reg:out]
864 {
865 out <- [[func]Add Instruction[X86 Instruction["push", Register[reg, 4], None[], 4]]
866 ]Temp Stack << [ [[func]Temp Stack >>]+[4] ]
867 }
868
869 Prolog Save@X86 Function[func,junk,reg:out]
870 {
871 out <- [[func]Add Instruction[X86 Instruction["push", Register[reg, 4], None[], 4]]
872 ]Stack Size << [ [[func]Stack Size >>]+[4] ]
873 }
874
875 Restore Reg@X86 Function[func,reg:out]
876 {
877 out <- [[func]Add Instruction[X86 Instruction["pop", Register[reg, 4], None[], 4]]
878 ]Temp Stack << [ [[func]Temp Stack >>]-[4] ]
879 }
880
881 Epilogue Restore@X86 Function[func,junk,reg:out]
882 {
883 out <- [func]Add Instruction[X86 Instruction["pop", Register[reg, 4], None[], 4]]
884 }
885
886 Finalize@X86 Function[func:out]
887 {
888 alloc stack <- [[func]Stack Size >>] - [[func]Param Size >>]
889
890 oldstream <- [func]Instructions >>
891
892 If[[alloc stack] > [0]]
893 {
894 start <- [()]Append[X86 Instruction["sub", Register[6, 4],Immediate[alloc stack], Register[6, 4], 4], func]
895 }{
896 start <- ()
897 }
898
899 If[[[func]Convention >>] = ["cdecl"]]
900 {
901 If[ [alloc stack] > [0] ]
902 {
903 retparam <- Immediate[alloc stack]
904 }{
905 retparam <- None[]
906 }
907 }{
908 retparam <- Immediate[[func]Stack Size >>]
909 }
910
911 [[func]Need Save >>]First
912 {
913 prolog <- Fold["Prolog Save", [func]Instructions << [start], [func]Need Save >>]
914 out <- [Reverse Fold["Epilogue Restore", body, [func]Need Save >>]]Add Instruction[X86 Instruction["ret", retparam, None[], 4]]
915 }{
916 prolog <- [func]Instructions <<[start]
917 out <- [body]Add Instruction[X86 Instruction["ret", retparam, None[], 4]]
918 }
919
920 body <- Fold["Add Instruction", prolog, oldstream]
921 }
922
923 Text@X86 Function[func:out]
924 {
925 name line <- [Escape Rhope Name[[func]Name >>]
926 ]Append[":\n"]
927
928 out <- Fold[["Instruction ASM"]Set Input[2, func], name line, [func]Instructions >>]
929 }