From 1b050736eea04323e09e5e8e7499c33cee1899d0 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Wed, 1 Jan 2020 17:11:05 -0800 Subject: 5855 --- html/apps/calls.subx.html | 6 +- html/apps/crenshaw2-1.subx.html | 4 +- html/apps/crenshaw2-1b.subx.html | 4 +- html/apps/mu.subx.html | 8833 ++++++++++++++++++++------------------ 4 files changed, 4566 insertions(+), 4281 deletions(-) (limited to 'html/apps') diff --git a/html/apps/calls.subx.html b/html/apps/calls.subx.html index f6e99787..9f78d04d 100644 --- a/html/apps/calls.subx.html +++ b/html/apps/calls.subx.html @@ -813,7 +813,7 @@ if ('onhashchange' in window) { 823 # . ecx = line->read 824 8b/-> *(esi+4) 1/r32/ecx 825 # . if (ecx >= line->write) return out = {0, 0} - 826 3b/compare *esi 1/r32/ecx + 826 3b/compare 1/r32/ecx *esi 827 0f 8d/jump-if-greater-or-equal $next-word-string-or-expression-without-metadata:return-eol/disp32 828 $next-word-string-or-expression-without-metadata:check-for-comment: 829 # out->start = &line->data[line->read] @@ -899,7 +899,7 @@ if ('onhashchange' in window) { 909 # . ecx = line->read 910 8b/-> *(esi+4) 1/r32/ecx 911 # . if (ecx >= line->write) return {0, 0} - 912 3b/compare *esi 1/r32/ecx + 912 3b/compare 1/r32/ecx *esi 913 0f 8d/jump-if-greater-or-equal $next-word-string-or-expression-without-metadata:return-eol/disp32 914 # if (line->data[line->read] == '/') goto error3 915 # . eax = line->data[line->read] @@ -918,7 +918,7 @@ if ('onhashchange' in window) { 928 # . ecx = line->read 929 8b/-> *(esi+4) 1/r32/ecx 930 # . if (ecx >= line->write) return {0, 0} - 931 3b/compare *esi 1/r32/ecx + 931 3b/compare 1/r32/ecx *esi 932 0f 8d/jump-if-greater-or-equal $next-word-string-or-expression-without-metadata:return-eol/disp32 933 # if (line->data[line->read] == '#') return out = {0, 0} 934 # . eax = line->data[line->read] diff --git a/html/apps/crenshaw2-1.subx.html b/html/apps/crenshaw2-1.subx.html index fb893b41..df65b454 100644 --- a/html/apps/crenshaw2-1.subx.html +++ b/html/apps/crenshaw2-1.subx.html @@ -285,7 +285,7 @@ if ('onhashchange' in window) { 224 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 225 # . if (eax == false) 226 3d/compare-eax-and 0/imm32/false -227 75/jump-if-not-equal $get-num:main/disp8 +227 75/jump-if-not-equal $get-num:main/disp8 228 # . expected(ed, err, "integer") 229 # . . push args 230 68/push "integer"/imm32 @@ -295,7 +295,7 @@ if ('onhashchange' in window) { 234 e8/call expected/disp32 # never returns 235 # . . discard args 236 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -237 $get-num:main: +237 $get-num:main: 238 # - otherwise read a digit 239 # . save registers 240 50/push-eax diff --git a/html/apps/crenshaw2-1b.subx.html b/html/apps/crenshaw2-1b.subx.html index d8a42a13..1c15f4f9 100644 --- a/html/apps/crenshaw2-1b.subx.html +++ b/html/apps/crenshaw2-1b.subx.html @@ -290,7 +290,7 @@ if ('onhashchange' in window) { 229 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 230 # . if (eax == false) 231 3d/compare-eax-and 0/imm32/false -232 75/jump-if-not-equal $get-num:main/disp8 +232 75/jump-if-not-equal $get-num:main/disp8 233 # . expected(ed, err, "integer") 234 # . . push args 235 68/push "integer"/imm32 @@ -300,7 +300,7 @@ if ('onhashchange' in window) { 239 e8/call expected/disp32 # never returns 240 # . . discard args 241 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp -242 $get-num:main: +242 $get-num:main: 243 # - otherwise read a digit 244 # . save registers 245 50/push-eax diff --git a/html/apps/mu.subx.html b/html/apps/mu.subx.html index 9c288619..8201c261 100644 --- a/html/apps/mu.subx.html +++ b/html/apps/mu.subx.html @@ -308,7 +308,7 @@ if ('onhashchange' in window) { 246 247 == data 248 - 249 Program: # (handle function) + 249 Program: # (address (handle function)) 250 0/imm32 251 252 Function-name: @@ -445,9 +445,9 @@ if ('onhashchange' in window) { 383 55/push-ebp 384 89/<- %ebp 4/r32/esp 385 # - 386 (parse-mu *(ebp+8)) - 387 (check-mu-types) - 388 (emit-subx *(ebp+0xc)) + 386 (parse-mu *(ebp+8)) + 387 (check-mu-types) + 388 (emit-subx *(ebp+0xc)) 389 $convert-mu:end: 390 # . epilogue 391 89/<- %esp 5/r32/ebp @@ -774,1383 +774,1368 @@ if ('onhashchange' in window) { 742 5d/pop-to-ebp 743 c3/return 744 - 745 ####################################################### - 746 # Parsing - 747 ####################################################### - 748 - 749 parse-mu: # in : (address buffered-file) - 750 # pseudocode - 751 # var curr-function : (handle function) = Program - 752 # var line : (ref stream byte 512) - 753 # var word-slice : (ref slice) - 754 # while true # line loop - 755 # clear-stream(line) - 756 # read-line-buffered(in, line) - 757 # if (line->write == 0) break # end of file - 758 # word-slice = next-word-or-string(line) - 759 # if slice-empty?(word-slice) # end of line - 760 # continue - 761 # else if slice-starts-with?(word-slice, "#") # comment - 762 # continue # end of line - 763 # else if slice-equal(word-slice, "fn") - 764 # var new-function : (handle function) = allocate(function) - 765 # var vars : (ref stack (address var) 256) - 766 # populate-mu-function-header(in, new-function, vars) - 767 # populate-mu-function-body(in, new-function, vars) - 768 # assert(vars->top == 0) - 769 # *curr-function = new-function - 770 # curr-function = &new-function->next - 771 # else - 772 # abort() - 773 # - 774 # . prologue - 775 55/push-ebp - 776 89/<- %ebp 4/r32/esp - 777 # . save registers - 778 50/push-eax - 779 51/push-ecx - 780 52/push-edx - 781 53/push-ebx - 782 57/push-edi - 783 # var line/ecx : (ref stream byte 512) - 784 81 5/subop/subtract %esp 0x200/imm32 - 785 68/push 0x200/imm32/length - 786 68/push 0/imm32/read - 787 68/push 0/imm32/write - 788 89/<- %ecx 4/r32/esp - 789 # var word-slice/edx : (ref slice) - 790 68/push 0/imm32/end - 791 68/push 0/imm32/start - 792 89/<- %edx 4/r32/esp - 793 # var curr-function/edi : (handle function) = Program - 794 bf/copy-to-edi Program/imm32 - 795 # var vars/ebx : (ref stack (address var) 256) - 796 81 5/subop/subtract %esp 0x400/imm32 - 797 68/push 0x400/imm32/length - 798 68/push 0/imm32/top - 799 89/<- %ebx 4/r32/esp - 800 { - 801 $parse-mu:line-loop: - 802 (clear-stream %ecx) - 803 (read-line-buffered *(ebp+8) %ecx) - 804 # if (line->write == 0) break - 805 81 7/subop/compare *ecx 0/imm32 - 806 0f 84/jump-if-equal break/disp32 - 807 +-- 6 lines: #? # dump line --------------------------------------------------------------------------------------------------------------------------- - 813 (next-word-or-string %ecx %edx) - 814 # if slice-empty?(word-slice) continue - 815 (slice-empty? %edx) - 816 3d/compare-eax-and 0/imm32 - 817 0f 85/jump-if-not-equal loop/disp32 - 818 # if (*word-slice->start == "#") continue - 819 # . eax = *word-slice->start - 820 8b/-> *edx 0/r32/eax - 821 8a/copy-byte *eax 0/r32/AL - 822 81 4/subop/and %eax 0xff/imm32 - 823 # . if (eax == '#') continue - 824 3d/compare-eax-and 0x23/imm32/hash - 825 0f 84/jump-if-equal loop/disp32 - 826 # if (slice-equal?(word-slice, "fn")) parse a function - 827 { - 828 $parse-mu:fn: - 829 (slice-equal? %edx "fn") - 830 3d/compare-eax-and 0/imm32 - 831 0f 84/jump-if-equal break/disp32 - 832 # var new-function/eax : (handle function) = populate-mu-function(in, new-function, vars) - 833 (allocate Heap *Function-size) # => eax - 834 (zero-out %eax *Function-size) - 835 (clear-stack %ebx) - 836 (populate-mu-function-header %ecx %eax %ebx) - 837 (populate-mu-function-body *(ebp+8) %eax %ebx) - 838 # *curr-function = new-function - 839 89/<- *edi 0/r32/eax - 840 # curr-function = &new-function->next - 841 8d/address-> *(eax+0x14) 7/r32/edi # Function-next - 842 e9/jump $parse-mu:line-loop/disp32 - 843 } - 844 # otherwise abort - 845 e9/jump $parse-mu:error1/disp32 - 846 } # end line loop - 847 $parse-mu:end: - 848 # . reclaim locals - 849 81 0/subop/add %esp 0x630/imm32 - 850 # . restore registers - 851 5f/pop-to-edi - 852 5b/pop-to-ebx - 853 5a/pop-to-edx - 854 59/pop-to-ecx - 855 58/pop-to-eax - 856 # . epilogue - 857 89/<- %esp 5/r32/ebp - 858 5d/pop-to-ebp - 859 c3/return - 860 - 861 $parse-mu:error1: - 862 # error("unexpected top-level command: " word-slice "\n") - 863 (write-buffered Stderr "unexpected top-level command: ") - 864 (write-slice-buffered Stderr %edx) - 865 (write-buffered Stderr "\n") - 866 (flush Stderr) - 867 # . syscall(exit, 1) - 868 bb/copy-to-ebx 1/imm32 - 869 b8/copy-to-eax 1/imm32/exit - 870 cd/syscall 0x80/imm8 - 871 # never gets here - 872 - 873 $parse-mu:error2: - 874 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") - 875 (print-int32-buffered Stderr *ebx) - 876 (write-buffered Stderr " vars not reclaimed after fn '") - 877 (write-slice-buffered Stderr *eax) # Function-name - 878 (write-buffered Stderr "'\n") - 879 (flush Stderr) - 880 # . syscall(exit, 1) - 881 bb/copy-to-ebx 1/imm32 - 882 b8/copy-to-eax 1/imm32/exit - 883 cd/syscall 0x80/imm8 - 884 # never gets here - 885 - 886 # scenarios considered: - 887 # ✗ fn foo # no block - 888 # ✓ fn foo { - 889 # ✗ fn foo { { - 890 # ✗ fn foo { } - 891 # ✗ fn foo { } { - 892 # ✗ fn foo x { - 893 # ✗ fn foo x : { - 894 # ✓ fn foo x : int { - 895 # ✓ fn foo x: int { - 896 # ✓ fn foo x: int -> y/eax: int { - 897 populate-mu-function-header: # first-line : (address stream byte), out : (handle function), vars : (address stack (handle var)) - 898 # pseudocode: - 899 # var name : (ref slice) - 900 # next-word(first-line, name) - 901 # assert(name not in '{' '}' '->') - 902 # out->name = slice-to-string(name) - 903 # var next-offset : int = 8 - 904 # ## inouts - 905 # while true - 906 # ## name - 907 # name = next-word(first-line) - 908 # if (name == '{') goto done - 909 # if (name == '->') break - 910 # assert(name != '}') - 911 # var v : (handle var) = parse-var-with-type(name, first-line) - 912 # assert(v->register == null) - 913 # v->stack-offset = next-offset - 914 # next-offset += size-of(v) - 915 # out->inouts = append(out->inouts, v) - 916 # push(vars, v) - 917 # ## outputs - 918 # while true - 919 # ## name - 920 # name = next-word(first-line) - 921 # assert(name not in '{' '}' '->') - 922 # var v : (handle var) = parse-var-with-type(name, first-line) - 923 # assert(v->register != null) - 924 # out->outputs = append(out->outputs, v) - 925 # done: - 926 # - 927 # . prologue - 928 55/push-ebp - 929 89/<- %ebp 4/r32/esp - 930 # . save registers - 931 50/push-eax - 932 51/push-ecx - 933 52/push-edx - 934 53/push-ebx - 935 57/push-edi - 936 # edi = out - 937 8b/-> *(ebp+0xc) 7/r32/edi - 938 # var word-slice/ecx : (ref slice) - 939 68/push 0/imm32/end - 940 68/push 0/imm32/start - 941 89/<- %ecx 4/r32/esp - 942 # var next-offset/edx = 8 - 943 ba/copy-to-edx 8/imm32 - 944 # read function name - 945 (next-word *(ebp+8) %ecx) - 946 # error checking - 947 # if (word-slice == '{') abort - 948 (slice-equal? %ecx "{") # => eax - 949 3d/compare-eax-and 0/imm32 - 950 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 - 951 # if (word-slice == '->') abort - 952 (slice-equal? %ecx "->") # => eax - 953 3d/compare-eax-and 0/imm32 - 954 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 - 955 # if (word-slice == '}') abort - 956 (slice-equal? %ecx "}") # => eax - 957 3d/compare-eax-and 0/imm32 - 958 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 - 959 # save function name - 960 (slice-to-string Heap %ecx) # => eax - 961 89/<- *edi 0/r32/eax # Function-name - 962 # save function inouts - 963 { - 964 $populate-mu-function-header:check-for-inout: - 965 (next-word *(ebp+8) %ecx) - 966 # if (word-slice == '{') goto done - 967 (slice-equal? %ecx "{") # => eax - 968 3d/compare-eax-and 0/imm32 - 969 0f 85/jump-if-not-equal $populate-mu-function-header:done/disp32 - 970 # if (word-slice == '->') break - 971 (slice-equal? %ecx "->") # => eax - 972 3d/compare-eax-and 0/imm32 - 973 0f 85/jump-if-not-equal break/disp32 - 974 # if (word-slice == '}') abort - 975 (slice-equal? %ecx "}") # => eax - 976 3d/compare-eax-and 0/imm32 - 977 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 - 978 # var v/ebx : (handle var) = parse-var-with-type(word-slice, first-line) - 979 (parse-var-with-type %ecx *(ebp+8)) # => eax - 980 89/<- %ebx 0/r32/eax - 981 # assert(v->register == null) - 982 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register - 983 0f 85/jump-if-not-equal $populate-mu-function-header:error2/disp32 - 984 # v->stack-offset = next-offset - 985 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset - 986 # next-offset += size-of(v) - 987 (size-of %ebx) # => eax - 988 01/add %edx 0/r32/eax - 989 # - 990 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax - 991 89/<- *(edi+8) 0/r32/eax # Function-inouts - 992 (push *(ebp+0x10) %ebx) - 993 # - 994 e9/jump loop/disp32 - 995 } - 996 # save function outputs - 997 { - 998 $parse-var-with-type:check-for-out: - 999 (next-word *(ebp+8) %ecx) -1000 # if (word-slice == '{') break -1001 (slice-equal? %ecx "{") # => eax -1002 3d/compare-eax-and 0/imm32 -1003 0f 85/jump-if-not-equal break/disp32 -1004 # if (word-slice == '->') abort -1005 (slice-equal? %ecx "->") # => eax -1006 3d/compare-eax-and 0/imm32 -1007 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 -1008 # if (word-slice == '}') abort -1009 (slice-equal? %ecx "}") # => eax -1010 3d/compare-eax-and 0/imm32 -1011 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 -1012 # -1013 (parse-var-with-type %ecx *(ebp+8)) # => eax -1014 89/<- %ebx 0/r32/eax -1015 # assert(var->register != null) -1016 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register -1017 0f 84/jump-if-equal $populate-mu-function-header:error3/disp32 -1018 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax -1019 89/<- *(edi+0xc) 0/r32/eax # Function-outputs -1020 e9/jump loop/disp32 -1021 } -1022 $populate-mu-function-header:done: -1023 (check-no-tokens-left *(ebp+8)) -1024 $populate-mu-function-header:end: -1025 # . reclaim locals -1026 81 0/subop/add %esp 8/imm32 -1027 # . restore registers -1028 5f/pop-to-edi -1029 5b/pop-to-ebx -1030 5a/pop-to-edx -1031 59/pop-to-ecx -1032 58/pop-to-eax -1033 # . epilogue -1034 89/<- %esp 5/r32/ebp -1035 5d/pop-to-ebp -1036 c3/return -1037 -1038 $populate-mu-function-header:error1: -1039 # error("function header not in form 'fn <name> {'") -1040 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") -1041 (flush Stderr) -1042 (rewind-stream *(ebp+8)) -1043 (write-stream 2 *(ebp+8)) -1044 (write-buffered Stderr "'\n") -1045 (flush Stderr) -1046 # . syscall(exit, 1) -1047 bb/copy-to-ebx 1/imm32 -1048 b8/copy-to-eax 1/imm32/exit -1049 cd/syscall 0x80/imm8 -1050 # never gets here -1051 -1052 $populate-mu-function-header:error2: -1053 # error("function input '" var "' cannot be in a register") -1054 (write-buffered Stderr "function input '") -1055 (write-buffered Stderr *ebx) # Var-name -1056 (write-buffered Stderr "' cannot be in a register") -1057 (flush Stderr) -1058 # . syscall(exit, 1) -1059 bb/copy-to-ebx 1/imm32 -1060 b8/copy-to-eax 1/imm32/exit -1061 cd/syscall 0x80/imm8 -1062 # never gets here -1063 -1064 $populate-mu-function-header:error3: -1065 # error("function input '" var "' must be in a register") -1066 (write-buffered Stderr "function input '") -1067 (write-buffered Stderr *eax) # Var-name -1068 (write-buffered Stderr " must be in a register'") -1069 (flush Stderr) -1070 (rewind-stream *(ebp+8)) -1071 (write-stream 2 *(ebp+8)) -1072 (write-buffered Stderr "'\n") -1073 (flush Stderr) -1074 # . syscall(exit, 1) -1075 bb/copy-to-ebx 1/imm32 -1076 b8/copy-to-eax 1/imm32/exit -1077 cd/syscall 0x80/imm8 -1078 # never gets here -1079 -1080 test-function-header-with-arg: -1081 # 'foo n : int {' -1082 # . prologue -1083 55/push-ebp -1084 89/<- %ebp 4/r32/esp -1085 # setup -1086 (clear-stream _test-input-stream) -1087 (write _test-input-stream "foo n : int {\n") -1088 # result/ecx : (ref function) -1089 2b/subtract-> *Function-size 4/r32/esp -1090 89/<- %ecx 4/r32/esp -1091 (zero-out %ecx *Function-size) -1092 # var vars/ebx : (ref stack (address var) 16) -1093 81 5/subop/subtract %esp 0x10/imm32 -1094 68/push 0x10/imm32/length -1095 68/push 0/imm32/top -1096 89/<- %ebx 4/r32/esp -1097 # convert -1098 (populate-mu-function-header _test-input-stream %ecx %ebx) -1099 # check result -1100 (check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name -1101 # edx : (handle list var) = result->inouts -1102 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1103 # ebx : (handle var) = result->inouts->value -1104 8b/-> *edx 3/r32/ebx # List-value -1105 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name -1106 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:0/type") # Var-type -1107 # . epilogue -1108 89/<- %esp 5/r32/ebp -1109 5d/pop-to-ebp -1110 c3/return -1111 -1112 test-function-header-with-multiple-args: -1113 # 'fn foo a: int, b: int, c: int {' -1114 # . prologue -1115 55/push-ebp -1116 89/<- %ebp 4/r32/esp -1117 # setup -1118 (clear-stream _test-input-stream) -1119 (write _test-input-stream "foo a: int, b: int c: int {\n") -1120 # result/ecx : (handle function) -1121 2b/subtract-> *Function-size 4/r32/esp -1122 89/<- %ecx 4/r32/esp -1123 (zero-out %ecx *Function-size) -1124 # var vars/ebx : (ref stack (address var) 16) -1125 81 5/subop/subtract %esp 0x10/imm32 -1126 68/push 0x10/imm32/length -1127 68/push 0/imm32/top -1128 89/<- %ebx 4/r32/esp -1129 # convert -1130 (populate-mu-function-header _test-input-stream %ecx %ebx) -1131 # check result -1132 (check-strings-equal *ecx "foo") # Function-name -1133 # edx : (handle list var) = result->inouts -1134 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1135 $test-function-header-with-multiple-args:inout0: -1136 # ebx : (handle var) = result->inouts->value -1137 8b/-> *edx 3/r32/ebx # List-value -1138 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name -1139 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:0/type") # Var-type -1140 # edx = result->inouts->next -1141 8b/-> *(edx+4) 2/r32/edx # List-next -1142 $test-function-header-with-multiple-args:inout1: -1143 # ebx = result->inouts->next->value -1144 8b/-> *edx 3/r32/ebx # List-value -1145 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name -1146 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:1/type") # Var-type -1147 # edx = result->inouts->next->next -1148 8b/-> *(edx+4) 2/r32/edx # List-next -1149 $test-function-header-with-multiple-args:inout2: -1150 # ebx = result->inouts->next->next->value -1151 8b/-> *edx 3/r32/ebx # List-value -1152 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name -1153 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:2/type") # Var-type -1154 # . epilogue -1155 89/<- %esp 5/r32/ebp -1156 5d/pop-to-ebp -1157 c3/return -1158 -1159 test-function-with-multiple-args-and-outputs: -1160 # fn foo a: int, b: int, c: int -> x: int, y: int { -1161 # . prologue -1162 55/push-ebp -1163 89/<- %ebp 4/r32/esp -1164 # setup -1165 (clear-stream _test-input-stream) -1166 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx : int {\n") -1167 # result/ecx : (handle function) -1168 2b/subtract-> *Function-size 4/r32/esp -1169 89/<- %ecx 4/r32/esp -1170 (zero-out %ecx *Function-size) -1171 # var vars/ebx : (ref stack (address var) 16) -1172 81 5/subop/subtract %esp 0x10/imm32 -1173 68/push 0x10/imm32/length -1174 68/push 0/imm32/top -1175 89/<- %ebx 4/r32/esp -1176 # convert -1177 (populate-mu-function-header _test-input-stream %ecx %ebx) -1178 # check result -1179 (check-strings-equal *ecx "foo") # Function-name -1180 # edx : (handle list var) = result->inouts -1181 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1182 # ebx : (handle var) = result->inouts->value -1183 8b/-> *edx 3/r32/ebx # List-value -1184 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name -1185 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:0/type") # Var-type -1186 # edx = result->inouts->next -1187 8b/-> *(edx+4) 2/r32/edx # List-next -1188 # ebx = result->inouts->next->value -1189 8b/-> *edx 3/r32/ebx # List-value -1190 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name -1191 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:1/type") # Var-type -1192 # edx = result->inouts->next->next -1193 8b/-> *(edx+4) 2/r32/edx # List-next -1194 # ebx = result->inouts->next->next->value -1195 8b/-> *edx 3/r32/ebx # List-value -1196 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name -1197 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:2/type") # Var-type -1198 # edx : (handle list var) = result->outputs -1199 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs -1200 # ebx : (handle var) = result->outputs->value -1201 8b/-> *edx 3/r32/ebx # List-value -1202 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args/output:0") # Var-name -1203 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/output:0/type") # Var-type -1204 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-arg/output:0/register") # Var-register -1205 # edx = result->outputs->next -1206 8b/-> *(edx+4) 2/r32/edx # List-next -1207 # ebx = result->outputs->next->value -1208 8b/-> *edx 3/r32/ebx # List-value -1209 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args/output:1") # Var-name -1210 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/output:1/type") # Var-type -1211 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-arg/output:0/register") # Var-register -1212 # . epilogue -1213 89/<- %esp 5/r32/ebp -1214 5d/pop-to-ebp -1215 c3/return -1216 -1217 # format for variables with types -1218 # x : int -1219 # x: int -1220 # x: int, -1221 # ignores at most one trailing colon or comma -1222 parse-var-with-type: # name: (address slice), first-line: (address stream byte) -> result/eax: (handle var) -1223 # pseudocode: -1224 # var v : (handle var) = allocate(Heap, Var-size) -1225 # var s : (ref slice) -1226 # next-token-from-slice(name->start, name->end, '/', s) -1227 # var end : (address byte) = s->end -1228 # if (slice-ends-with(s, ":")) -1229 # decrement s->end -1230 # if (slice-ends-with(s, ",")) -1231 # decrement s->end -1232 # v->name = slice-to-string(s) -1233 # ## register -1234 # next-token-from-slice(end, name->end, '/', s) -1235 # if (slice-ends-with(s, ":")) -1236 # decrement s->end -1237 # if (slice-ends-with(s, ",")) -1238 # decrement s->end -1239 # if (!slice-empty?(s)) -1240 # v->register = slice-to-string(s) -1241 # ## type -1242 # s = next-mu-token(first-line) -1243 # assert(s not in '{' '}' '->') -1244 # if (slice-empty?(s)) { -1245 # s = next-mu-token(first-line) -1246 # assert(type not in '{' '}' '->') -1247 # } -1248 # type = type-for(s) -1249 # v->type = type -1250 # return v -1251 # -1252 # . prologue -1253 55/push-ebp -1254 89/<- %ebp 4/r32/esp -1255 # . save registers -1256 51/push-ecx -1257 52/push-edx -1258 53/push-ebx -1259 56/push-esi -1260 57/push-edi -1261 # var result/edi : (handle var) = allocate(Heap, Var-size) -1262 (allocate Heap *Var-size) # => eax -1263 (zero-out %eax *Var-size) -1264 89/<- %edi 0/r32/eax -1265 # esi = name -1266 8b/-> *(ebp+8) 6/r32/esi -1267 # var s/ecx : (ref slice) -1268 68/push 0/imm32/end -1269 68/push 0/imm32/start -1270 89/<- %ecx 4/r32/esp -1271 $parse-var-with-type:save-name: -1272 # save v->name -1273 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' -1274 # . end/edx = s->end -1275 8b/-> *(ecx+4) 2/r32/edx -1276 # . if s ends with ':', decrement s->end -1277 { -1278 8b/-> *(ecx+4) 0/r32/eax -1279 48/decrement-eax -1280 8a/copy-byte *eax 3/r32/BL -1281 81 4/subop/and %ebx 0xff/imm32 -1282 81 7/subop/compare %ebx 0x3a/imm32/colon -1283 75/jump-if-not-equal break/disp8 -1284 89/<- *(ecx+4) 0/r32/eax -1285 } -1286 # . if s ends with ',', decrement s->end -1287 { -1288 8b/-> *(ecx+4) 0/r32/eax -1289 48/decrement-eax -1290 8a/copy-byte *eax 3/r32/BL -1291 81 4/subop/and %ebx 0xff/imm32 -1292 81 7/subop/compare %ebx 0x2c/imm32/comma -1293 75/jump-if-not-equal break/disp8 -1294 89/<- *(ecx+4) 0/r32/eax -1295 } -1296 $parse-var-with-type:write-name: -1297 (slice-to-string Heap %ecx) # => eax -1298 89/<- *edi 0/r32/eax # Var-name -1299 # save v->register -1300 $parse-var-with-type:save-register: -1301 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' -1302 # . if s ends with ':', decrement s->end -1303 { -1304 8b/-> *(ecx+4) 0/r32/eax -1305 48/decrement-eax -1306 8a/copy-byte *eax 3/r32/BL -1307 81 4/subop/and %ebx 0xff/imm32 -1308 81 7/subop/compare %ebx 0x3a/imm32/colon -1309 75/jump-if-not-equal break/disp8 -1310 89/<- *(ecx+4) 0/r32/eax -1311 } -1312 # . if s ends with ',', decrement s->end -1313 { -1314 8b/-> *(ecx+4) 0/r32/eax -1315 48/decrement-eax -1316 8a/copy-byte *eax 3/r32/BL -1317 81 4/subop/and %ebx 0xff/imm32 -1318 81 7/subop/compare %ebx 0x2c/imm32/comma -1319 75/jump-if-not-equal break/disp8 -1320 89/<- *(ecx+4) 0/r32/eax -1321 } -1322 # if (!slice-empty?(s)) v->register = slice-to-string(s) -1323 { -1324 $parse-var-with-type:write-register: -1325 # HACK: s->end can be less than s->start with all the decrements above -1326 # That's probably a sign we have the wrong algorithm for this function. -1327 8b/-> *ecx 0/r32/eax -1328 39/compare 0/r32/eax *(ecx+4) -1329 76/jump-if-lesser-or-equal break/disp8 -1330 (slice-to-string Heap %ecx) -1331 89/<- *(edi+0x10) 0/r32/eax # Var-register -1332 } -1333 # save v->type -1334 (next-mu-token *(ebp+0xc) %ecx) -1335 # if (word-slice == '{') abort -1336 (slice-equal? %ecx "{") # => eax -1337 3d/compare-eax-and 0/imm32 -1338 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1339 # if (word-slice == '->') abort -1340 (slice-equal? %ecx "->") # => eax -1341 3d/compare-eax-and 0/imm32 -1342 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1343 # if (word-slice == '}') abort -1344 (slice-equal? %ecx "}") # => eax -1345 3d/compare-eax-and 0/imm32 -1346 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1347 # if (slice-empty?(type)) skip -1348 (slice-empty? %ecx) -1349 { -1350 3d/compare-eax-and 0/imm32 -1351 0f 84/jump-if-equal break/disp32 -1352 (next-mu-token *(ebp+0xc) %ecx) -1353 # if (word-slice == '{') abort -1354 (slice-equal? %ecx "{") # => eax -1355 3d/compare-eax-and 0/imm32 -1356 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1357 # if (word-slice == '->') abort -1358 (slice-equal? %ecx "->") # => eax -1359 3d/compare-eax-and 0/imm32 -1360 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1361 # if (word-slice == '}') abort -1362 (slice-equal? %ecx "}") # => eax -1363 3d/compare-eax-and 0/imm32 -1364 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1365 } -1366 (type-for %ecx) -1367 89/<- *(edi+4) 0/r32/eax # Var-type -1368 $parse-var-with-type:end: -1369 # return result -1370 89/<- %eax 7/r32/edi -1371 # . reclaim locals -1372 81 0/subop/add %esp 8/imm32 -1373 # . restore registers -1374 5f/pop-to-edi -1375 5e/pop-to-esi -1376 5b/pop-to-ebx -1377 5a/pop-to-edx -1378 59/pop-to-ecx -1379 # . epilogue -1380 89/<- %esp 5/r32/ebp -1381 5d/pop-to-ebp -1382 c3/return -1383 -1384 $parse-var-with-type:abort: -1385 # error("function header not in form 'fn <name> {'") -1386 (write-buffered Stderr "var should have form 'name: type' in '") -1387 (flush Stderr) -1388 (rewind-stream *(ebp+0xc)) -1389 (write-stream 2 *(ebp+0xc)) -1390 (write-buffered Stderr "'\n") -1391 (flush Stderr) -1392 # . syscall(exit, 1) -1393 bb/copy-to-ebx 1/imm32 -1394 b8/copy-to-eax 1/imm32/exit -1395 cd/syscall 0x80/imm8 -1396 # never gets here -1397 -1398 next-mu-token: # in: (address stream byte), out: (address slice) -1399 # . prologue -1400 55/push-ebp -1401 89/<- %ebp 4/r32/esp -1402 # . save registers -1403 50/push-eax -1404 57/push-edi -1405 # edi = out -1406 8b/-> *(ebp+0xc) 7/r32/edi -1407 # -1408 (next-word *(ebp+8) %edi) # TODO: support s-expressions -1409 # if out ends with ':', decrement out->end -1410 { -1411 8b/-> *(edi+4) 0/r32/eax -1412 48/decrement-eax -1413 8a/copy-byte *eax 3/r32/BL -1414 81 4/subop/and %ebx 0xff/imm32 -1415 81 7/subop/compare %ebx 0x3a/imm32/colon -1416 75/jump-if-not-equal break/disp8 -1417 89/<- *(edi+4) 0/r32/eax -1418 } -1419 # if out ends with ',', decrement out->end -1420 { -1421 8b/-> *(edi+4) 0/r32/eax -1422 48/decrement-eax -1423 8a/copy-byte *eax 3/r32/BL -1424 81 4/subop/and %ebx 0xff/imm32 -1425 81 7/subop/compare %ebx 0x2c/imm32/comma -1426 75/jump-if-not-equal break/disp8 -1427 89/<- *(edi+4) 0/r32/eax -1428 } -1429 $next-mu-token:end: -1430 b8/copy-to-eax 1/imm32/int -1431 # . restore registers -1432 5f/pop-to-edi -1433 58/pop-to-eax -1434 # . epilogue -1435 89/<- %esp 5/r32/ebp -1436 5d/pop-to-ebp -1437 c3/return -1438 -1439 type-for: # name: (address slice) -> result/eax: (handle s-expression type-id) -1440 # . prologue -1441 55/push-ebp -1442 89/<- %ebp 4/r32/esp -1443 # . save registers -1444 #? (write-buffered Stderr "type: ") -1445 #? (write-slice-buffered Stderr *(ebp+8)) -1446 #? (write-buffered Stderr Newline) -1447 #? (flush Stderr) -1448 $type-for:end: -1449 b8/copy-to-eax 1/imm32/int -1450 # . restore registers -1451 # . epilogue -1452 89/<- %esp 5/r32/ebp -1453 5d/pop-to-ebp -1454 c3/return -1455 -1456 test-parse-var-with-type: -1457 # . prologue -1458 55/push-ebp -1459 89/<- %ebp 4/r32/esp -1460 # (eax..ecx) = "x:" -1461 b8/copy-to-eax "x:"/imm32 -1462 8b/-> *eax 1/r32/ecx -1463 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1464 05/add-to-eax 4/imm32 -1465 # var slice/ecx : (ref slice) = {eax, ecx} -1466 51/push-ecx -1467 50/push-eax -1468 89/<- %ecx 4/r32/esp -1469 # _test-input-stream contains "int" -1470 (clear-stream _test-input-stream) -1471 (write _test-input-stream "int") -1472 # -1473 (parse-var-with-type %ecx _test-input-stream) -1474 8b/-> *eax 2/r32/edx # Var-name -1475 (check-strings-equal %edx "x" "F - test-var-with-type/name") -1476 8b/-> *(eax+4) 2/r32/edx # Var-type -1477 (check-ints-equal %edx 1 "F - test-var-with-type/type") -1478 # . epilogue -1479 89/<- %esp 5/r32/ebp -1480 5d/pop-to-ebp -1481 c3/return -1482 -1483 test-parse-var-with-type-and-register: -1484 # . prologue -1485 55/push-ebp -1486 89/<- %ebp 4/r32/esp -1487 # (eax..ecx) = "x/eax" -1488 b8/copy-to-eax "x/eax"/imm32 -1489 8b/-> *eax 1/r32/ecx -1490 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1491 05/add-to-eax 4/imm32 -1492 # var slice/ecx : (ref slice) = {eax, ecx} -1493 51/push-ecx -1494 50/push-eax -1495 89/<- %ecx 4/r32/esp -1496 # _test-input-stream contains ": int" -1497 (clear-stream _test-input-stream) -1498 (write _test-input-stream ": int") -1499 # -1500 (parse-var-with-type %ecx _test-input-stream) -1501 8b/-> *eax 2/r32/edx # Var-name -1502 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") -1503 8b/-> *(eax+0x10) 2/r32/edx # Var-register -1504 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") -1505 8b/-> *(eax+4) 2/r32/edx # Var-type -1506 (check-ints-equal %edx 1 "F - test-var-with-type-and-register/type") -1507 # . epilogue -1508 89/<- %esp 5/r32/ebp -1509 5d/pop-to-ebp -1510 c3/return -1511 -1512 test-parse-var-with-trailing-characters: -1513 # . prologue -1514 55/push-ebp -1515 89/<- %ebp 4/r32/esp -1516 # (eax..ecx) = "x:" -1517 b8/copy-to-eax "x:"/imm32 -1518 8b/-> *eax 1/r32/ecx -1519 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1520 05/add-to-eax 4/imm32 -1521 # var slice/ecx : (ref slice) = {eax, ecx} -1522 51/push-ecx -1523 50/push-eax -1524 89/<- %ecx 4/r32/esp -1525 # _test-input-stream contains "int," -1526 (clear-stream _test-input-stream) -1527 (write _test-input-stream "int,") -1528 # -1529 (parse-var-with-type %ecx _test-input-stream) -1530 8b/-> *eax 2/r32/edx # Var-name -1531 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") -1532 8b/-> *(eax+0x10) 2/r32/edx # Var-register -1533 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") -1534 8b/-> *(eax+4) 2/r32/edx # Var-type -1535 (check-ints-equal %edx 1 "F - test-var-with-trailing-characters/type") -1536 # . epilogue -1537 89/<- %esp 5/r32/ebp -1538 5d/pop-to-ebp -1539 c3/return -1540 -1541 test-parse-var-with-register-and-trailing-characters: -1542 # . prologue -1543 55/push-ebp -1544 89/<- %ebp 4/r32/esp -1545 # (eax..ecx) = "x/eax:" -1546 b8/copy-to-eax "x/eax:"/imm32 -1547 8b/-> *eax 1/r32/ecx -1548 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1549 05/add-to-eax 4/imm32 -1550 # var slice/ecx : (ref slice) = {eax, ecx} -1551 51/push-ecx -1552 50/push-eax -1553 89/<- %ecx 4/r32/esp -1554 # _test-input-stream contains "int," -1555 (clear-stream _test-input-stream) -1556 (write _test-input-stream "int,") -1557 # -1558 (parse-var-with-type %ecx _test-input-stream) -1559 8b/-> *eax 2/r32/edx # Var-name -1560 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") -1561 8b/-> *(eax+0x10) 2/r32/edx # Var-register -1562 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") -1563 8b/-> *(eax+4) 2/r32/edx # Var-type -1564 (check-ints-equal %edx 1 "F - test-var-with-register-and-trailing-characters/type") -1565 # . epilogue -1566 89/<- %esp 5/r32/ebp -1567 5d/pop-to-ebp -1568 c3/return -1569 -1570 # identifier starts with a letter or '$' or '_' -1571 # no constraints at the moment on later letters -1572 # all we really want to do so far is exclude '{', '}' and '->' -1573 is-identifier?: # in : (address slice) -> result/eax : boolean -1574 # . prologue -1575 55/push-ebp -1576 89/<- %ebp 4/r32/esp -1577 # if (slice-empty?(in)) return false -1578 (slice-empty? *(ebp+8)) # => eax -1579 3d/compare-eax-and 0/imm32 -1580 75/jump-if-not-equal $is-identifier?:false/disp8 -1581 # var c/eax : byte = *in->start -1582 8b/-> *(ebp+8) 0/r32/eax -1583 8b/-> *eax 0/r32/eax -1584 8a/copy-byte *eax 0/r32/AL -1585 81 4/subop/and %eax 0xff/imm32 -1586 # if (c == '$') return true -1587 3d/compare-eax-and 0x24/imm32/$ -1588 74/jump-if-equal $is-identifier?:true/disp8 -1589 # if (c == '_') return true -1590 3d/compare-eax-and 0x5f/imm32/_ -1591 74/jump-if-equal $is-identifier?:true/disp8 -1592 # drop case -1593 25/and-eax-with 0x5f/imm32 -1594 # if (c < 'A') return false -1595 3d/compare-eax-and 0x41/imm32/A -1596 7c/jump-if-lesser $is-identifier?:false/disp8 -1597 # if (c > 'Z') return false -1598 3d/compare-eax-and 0x5a/imm32/Z -1599 7f/jump-if-greater $is-identifier?:false/disp8 -1600 # otherwise return true -1601 $is-identifier?:true: -1602 b8/copy-to-eax 1/imm32/true -1603 eb/jump $is-identifier?:end/disp8 -1604 $is-identifier?:false: -1605 b8/copy-to-eax 0/imm32/false -1606 $is-identifier?:end: -1607 # . epilogue -1608 89/<- %esp 5/r32/ebp -1609 5d/pop-to-ebp -1610 c3/return -1611 -1612 test-is-identifier-dollar: -1613 # . prologue -1614 55/push-ebp -1615 89/<- %ebp 4/r32/esp -1616 # (eax..ecx) = "$a" -1617 b8/copy-to-eax "$a"/imm32 -1618 8b/-> *eax 1/r32/ecx -1619 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1620 05/add-to-eax 4/imm32 -1621 # var slice/ecx : (ref slice) = {eax, ecx} -1622 51/push-ecx -1623 50/push-eax -1624 89/<- %ecx 4/r32/esp -1625 # -1626 (is-identifier? %ecx) -1627 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") -1628 # . epilogue -1629 89/<- %esp 5/r32/ebp -1630 5d/pop-to-ebp -1631 c3/return -1632 -1633 test-is-identifier-underscore: -1634 # . prologue -1635 55/push-ebp -1636 89/<- %ebp 4/r32/esp -1637 # (eax..ecx) = "_a" -1638 b8/copy-to-eax "_a"/imm32 -1639 8b/-> *eax 1/r32/ecx -1640 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1641 05/add-to-eax 4/imm32 -1642 # var slice/ecx : (ref slice) = {eax, ecx} -1643 51/push-ecx -1644 50/push-eax -1645 89/<- %ecx 4/r32/esp -1646 # -1647 (is-identifier? %ecx) -1648 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") -1649 # . epilogue -1650 89/<- %esp 5/r32/ebp -1651 5d/pop-to-ebp -1652 c3/return -1653 -1654 test-is-identifier-a: -1655 # . prologue -1656 55/push-ebp -1657 89/<- %ebp 4/r32/esp -1658 # (eax..ecx) = "a$" -1659 b8/copy-to-eax "a$"/imm32 -1660 8b/-> *eax 1/r32/ecx -1661 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1662 05/add-to-eax 4/imm32 -1663 # var slice/ecx : (ref slice) = {eax, ecx} -1664 51/push-ecx -1665 50/push-eax -1666 89/<- %ecx 4/r32/esp -1667 # -1668 (is-identifier? %ecx) -1669 (check-ints-equal %eax 1 "F - test-is-identifier-a") -1670 # . epilogue -1671 89/<- %esp 5/r32/ebp -1672 5d/pop-to-ebp -1673 c3/return -1674 -1675 test-is-identifier-z: -1676 # . prologue -1677 55/push-ebp -1678 89/<- %ebp 4/r32/esp -1679 # (eax..ecx) = "z$" -1680 b8/copy-to-eax "z$"/imm32 -1681 8b/-> *eax 1/r32/ecx -1682 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1683 05/add-to-eax 4/imm32 -1684 # var slice/ecx : (ref slice) = {eax, ecx} -1685 51/push-ecx -1686 50/push-eax -1687 89/<- %ecx 4/r32/esp -1688 # -1689 (is-identifier? %ecx) -1690 (check-ints-equal %eax 1 "F - test-is-identifier-z") -1691 # . epilogue -1692 89/<- %esp 5/r32/ebp -1693 5d/pop-to-ebp -1694 c3/return -1695 -1696 test-is-identifier-A: -1697 # . prologue -1698 55/push-ebp -1699 89/<- %ebp 4/r32/esp -1700 # (eax..ecx) = "A$" -1701 b8/copy-to-eax "A$"/imm32 -1702 8b/-> *eax 1/r32/ecx -1703 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1704 05/add-to-eax 4/imm32 -1705 # var slice/ecx : (ref slice) = {eax, ecx} -1706 51/push-ecx -1707 50/push-eax -1708 89/<- %ecx 4/r32/esp -1709 # -1710 (is-identifier? %ecx) -1711 (check-ints-equal %eax 1 "F - test-is-identifier-A") -1712 # . epilogue -1713 89/<- %esp 5/r32/ebp -1714 5d/pop-to-ebp -1715 c3/return -1716 -1717 test-is-identifier-Z: -1718 # . prologue -1719 55/push-ebp -1720 89/<- %ebp 4/r32/esp -1721 # (eax..ecx) = "Z$" -1722 b8/copy-to-eax "Z$"/imm32 -1723 8b/-> *eax 1/r32/ecx -1724 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1725 05/add-to-eax 4/imm32 -1726 # var slice/ecx : (ref slice) = {eax, ecx} -1727 51/push-ecx -1728 50/push-eax -1729 89/<- %ecx 4/r32/esp -1730 # -1731 (is-identifier? %ecx) -1732 (check-ints-equal %eax 1 "F - test-is-identifier-Z") -1733 # . epilogue -1734 89/<- %esp 5/r32/ebp -1735 5d/pop-to-ebp -1736 c3/return -1737 -1738 test-is-identifier-@: -1739 # character before 'A' is invalid -1740 # . prologue -1741 55/push-ebp -1742 89/<- %ebp 4/r32/esp -1743 # (eax..ecx) = "@a" -1744 b8/copy-to-eax "@a"/imm32 -1745 8b/-> *eax 1/r32/ecx -1746 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1747 05/add-to-eax 4/imm32 -1748 # var slice/ecx : (ref slice) = {eax, ecx} -1749 51/push-ecx -1750 50/push-eax -1751 89/<- %ecx 4/r32/esp -1752 # -1753 (is-identifier? %ecx) -1754 (check-ints-equal %eax 0 "F - test-is-identifier-@") -1755 # . epilogue -1756 89/<- %esp 5/r32/ebp -1757 5d/pop-to-ebp -1758 c3/return -1759 -1760 test-is-identifier-square-bracket: -1761 # character after 'Z' is invalid -1762 # . prologue -1763 55/push-ebp -1764 89/<- %ebp 4/r32/esp -1765 # (eax..ecx) = "[a" -1766 b8/copy-to-eax "[a"/imm32 -1767 8b/-> *eax 1/r32/ecx -1768 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1769 05/add-to-eax 4/imm32 -1770 # var slice/ecx : (ref slice) = {eax, ecx} -1771 51/push-ecx -1772 50/push-eax -1773 89/<- %ecx 4/r32/esp -1774 # -1775 (is-identifier? %ecx) -1776 (check-ints-equal %eax 0 "F - test-is-identifier-@") -1777 # . epilogue -1778 89/<- %esp 5/r32/ebp -1779 5d/pop-to-ebp -1780 c3/return -1781 -1782 test-is-identifier-backtick: -1783 # character before 'a' is invalid -1784 # . prologue -1785 55/push-ebp -1786 89/<- %ebp 4/r32/esp -1787 # (eax..ecx) = "`a" -1788 b8/copy-to-eax "`a"/imm32 -1789 8b/-> *eax 1/r32/ecx -1790 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1791 05/add-to-eax 4/imm32 -1792 # var slice/ecx : (ref slice) = {eax, ecx} -1793 51/push-ecx -1794 50/push-eax -1795 89/<- %ecx 4/r32/esp -1796 # -1797 (is-identifier? %ecx) -1798 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") -1799 # . epilogue -1800 89/<- %esp 5/r32/ebp -1801 5d/pop-to-ebp -1802 c3/return -1803 -1804 test-is-identifier-curly-brace-open: -1805 # character after 'z' is invalid; also used for blocks -1806 # . prologue -1807 55/push-ebp -1808 89/<- %ebp 4/r32/esp -1809 # (eax..ecx) = "{a" -1810 b8/copy-to-eax "{a"/imm32 -1811 8b/-> *eax 1/r32/ecx -1812 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1813 05/add-to-eax 4/imm32 -1814 # var slice/ecx : (ref slice) = {eax, ecx} -1815 51/push-ecx -1816 50/push-eax -1817 89/<- %ecx 4/r32/esp -1818 # -1819 (is-identifier? %ecx) -1820 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") -1821 # . epilogue -1822 89/<- %esp 5/r32/ebp -1823 5d/pop-to-ebp -1824 c3/return -1825 -1826 test-is-identifier-curly-brace-close: -1827 # . prologue -1828 55/push-ebp -1829 89/<- %ebp 4/r32/esp -1830 # (eax..ecx) = "}a" -1831 b8/copy-to-eax "}a"/imm32 -1832 8b/-> *eax 1/r32/ecx -1833 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1834 05/add-to-eax 4/imm32 -1835 # var slice/ecx : (ref slice) = {eax, ecx} -1836 51/push-ecx -1837 50/push-eax -1838 89/<- %ecx 4/r32/esp -1839 # -1840 (is-identifier? %ecx) -1841 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") -1842 # . epilogue -1843 89/<- %esp 5/r32/ebp -1844 5d/pop-to-ebp -1845 c3/return -1846 -1847 test-is-identifier-hyphen: -1848 # disallow leading '-' since '->' has special meaning -1849 # . prologue -1850 55/push-ebp -1851 89/<- %ebp 4/r32/esp -1852 # (eax..ecx) = "-a" -1853 b8/copy-to-eax "-a"/imm32 -1854 8b/-> *eax 1/r32/ecx -1855 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1856 05/add-to-eax 4/imm32 -1857 # var slice/ecx : (ref slice) = {eax, ecx} -1858 51/push-ecx -1859 50/push-eax -1860 89/<- %ecx 4/r32/esp -1861 # -1862 (is-identifier? %ecx) -1863 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") -1864 # . epilogue -1865 89/<- %esp 5/r32/ebp -1866 5d/pop-to-ebp -1867 c3/return -1868 -1869 populate-mu-function-body: # in : (address buffered-file), out : (handle function), vars : (address stack (handle var)) -1870 # . prologue -1871 55/push-ebp -1872 89/<- %ebp 4/r32/esp -1873 # . save registers -1874 50/push-eax -1875 56/push-esi -1876 57/push-edi -1877 # esi = in -1878 8b/-> *(ebp+8) 6/r32/esi -1879 # edi = out -1880 8b/-> *(ebp+0xc) 7/r32/edi -1881 # var eax : (handle block) = parse-mu-block(in, vars) -1882 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax -1883 # out->body = eax -1884 89/<- *(edi+0x10) 0/r32/eax # Function-body -1885 $populate-mu-function-body:end: -1886 # . restore registers -1887 5f/pop-to-edi -1888 5e/pop-to-esi -1889 58/pop-to-eax -1890 # . epilogue -1891 89/<- %esp 5/r32/ebp -1892 5d/pop-to-ebp -1893 c3/return -1894 -1895 # parses a block, assuming that the leading '{' has already been read by the caller -1896 parse-mu-block: # in : (address buffered-file), vars : (address stack (handle var)), fn : (handle function) -> result/eax : (handle block) -1897 # pseudocode: -1898 # var line : (ref stream byte 512) -1899 # var word-slice : (ref slice) -1900 # result/eax = allocate(Heap, Stmt-size) -1901 # result->tag = 0/Block -1902 # while true # line loop -1903 # clear-stream(line) -1904 # read-line-buffered(in, line) -1905 # if (line->write == 0) break # end of file -1906 # word-slice = next-word(line) -1907 # if slice-empty?(word-slice) # end of line -1908 # continue -1909 # else if slice-starts-with?(word-slice, "#") -1910 # continue -1911 # else if slice-equal?(word-slice, "{") -1912 # assert(no-tokens-in(line)) -1913 # block = parse-mu-block(in, vars, fn) -1914 # append-to-block(result, block) -1915 # else if slice-equal?(word-slice, "}") -1916 # break -1917 # else if slice-ends-with?(word-slice, ":") -1918 # named-block = parse-mu-named-block(word-slice, line, in, vars, fn) -1919 # append-to-block(result, named-block) -1920 # else if slice-equal?(word-slice, "var") -1921 # var-def = parse-mu-var-def(line, vars) -1922 # append-to-block(result, var-def) -1923 # else -1924 # stmt = parse-mu-stmt(line, vars, fn) -1925 # append-to-block(result, stmt) -1926 # return result -1927 # -1928 # . prologue -1929 55/push-ebp -1930 89/<- %ebp 4/r32/esp -1931 # . save registers -1932 51/push-ecx -1933 52/push-edx -1934 53/push-ebx -1935 57/push-edi -1936 # var line/ecx : (ref stream byte 512) -1937 81 5/subop/subtract %esp 0x200/imm32 -1938 68/push 0x200/imm32/length -1939 68/push 0/imm32/read -1940 68/push 0/imm32/write -1941 89/<- %ecx 4/r32/esp -1942 # var word-slice/edx : (ref slice) -1943 68/push 0/imm32/end -1944 68/push 0/imm32/start -1945 89/<- %edx 4/r32/esp -1946 # edi = result -1947 (allocate Heap *Stmt-size) # => eax -1948 (zero-out %eax *Stmt-size) -1949 89/<- %edi 0/r32/eax -1950 { # line loop -1951 $parse-mu-block:line-loop: -1952 # line = read-line-buffered(in) -1953 (clear-stream %ecx) -1954 (read-line-buffered *(ebp+8) %ecx) -1955 #? (write-buffered Stderr "line: ") -1956 #? (write-stream-data Stderr %ecx) -1957 #? (write-buffered Stderr Newline) -1958 #? (flush Stderr) -1959 # if (line->write == 0) break -1960 81 7/subop/compare *ecx 0/imm32 -1961 0f 84/jump-if-equal break/disp32 -1962 # word-slice = next-word(line) -1963 (next-word %ecx %edx) -1964 #? (write-buffered Stderr "word: ") -1965 #? (write-slice-buffered Stderr %edx) -1966 #? (write-buffered Stderr Newline) -1967 #? (flush Stderr) -1968 # if slice-empty?(word-slice) continue -1969 (slice-empty? %edx) -1970 3d/compare-eax-and 0/imm32 -1971 0f 85/jump-if-not-equal loop/disp32 -1972 # if (slice-starts-with?(word-slice, '#') continue -1973 # . eax = *word-slice->start -1974 8b/-> *edx 0/r32/eax -1975 8a/copy-byte *eax 0/r32/AL -1976 81 4/subop/and %eax 0xff/imm32 -1977 # . if (eax == '#') continue -1978 3d/compare-eax-and 0x23/imm32/hash -1979 0f 84/jump-if-equal loop/disp32 -1980 # if slice-equal?(word-slice, "{") -1981 { -1982 $parse-mu-block:check-for-block: -1983 (slice-equal? %edx "{") -1984 3d/compare-eax-and 0/imm32 -1985 74/jump-if-equal break/disp8 -1986 (check-no-tokens-left %ecx) -1987 # parse new block and append -1988 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -1989 (append-to-block %edi %eax) -1990 e9/jump $parse-mu-block:line-loop/disp32 -1991 } -1992 # if slice-equal?(word-slice, "}") break -1993 $parse-mu-block:check-for-end: -1994 (slice-equal? %edx "}") -1995 3d/compare-eax-and 0/imm32 -1996 0f 85/jump-if-not-equal break/disp32 -1997 # if slice-ends-with?(word-slice, ":") parse named block and append -1998 { -1999 $parse-mu-block:check-for-named-block: -2000 # . eax = *word-slice->end -2001 8b/-> *(edx+4) 0/r32/eax -2002 8a/copy-byte *eax 0/r32/AL -2003 81 4/subop/and %eax 0xff/imm32 -2004 # . if (eax != ':') break -2005 3d/compare-eax-and 0x23/imm32/hash -2006 0f 85/jump-if-not-equal break/disp32 -2007 # -2008 (parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -2009 (append-to-block %edi %eax) -2010 e9/jump $parse-mu-block:line-loop/disp32 -2011 } -2012 # if slice-equal?(word-slice, "var") -2013 { -2014 $parse-mu-block:check-for-var: -2015 (slice-equal? %edx "var") -2016 3d/compare-eax-and 0/imm32 -2017 74/jump-if-equal break/disp8 -2018 # -2019 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax -2020 (append-to-block %edi %eax) -2021 e9/jump $parse-mu-block:line-loop/disp32 -2022 } -2023 $parse-mu-block:regular-stmt: -2024 # otherwise -2025 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -2026 (append-to-block Heap %edi %eax) -2027 e9/jump loop/disp32 -2028 } # end line loop -2029 # return result -2030 89/<- %eax 7/r32/edi -2031 $parse-mu-block:end: -2032 # . reclaim locals -2033 81 0/subop/add %esp 0x214/imm32 -2034 # . restore registers -2035 5f/pop-to-edi -2036 5b/pop-to-ebx -2037 5a/pop-to-edx -2038 59/pop-to-ecx -2039 # . epilogue -2040 89/<- %esp 5/r32/ebp -2041 5d/pop-to-ebp -2042 c3/return -2043 -2044 $parse-mu-block:abort: -2045 # error("'{' or '}' should be on its own line, but got '") -2046 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2047 (rewind-stream %ecx) -2048 (write-stream 2 %ecx) -2049 (write-buffered Stderr "'\n") -2050 (flush Stderr) -2051 # . syscall(exit, 1) -2052 bb/copy-to-ebx 1/imm32 -2053 b8/copy-to-eax 1/imm32/exit -2054 cd/syscall 0x80/imm8 -2055 # never gets here -2056 -2057 check-no-tokens-left: # line : (address stream byte) -2058 # . prologue -2059 55/push-ebp -2060 89/<- %ebp 4/r32/esp -2061 # . save registers -2062 50/push-eax -2063 51/push-ecx -2064 # var s/ecx : (ref slice) -2065 68/push 0/imm32/end -2066 68/push 0/imm32/start -2067 89/<- %ecx 4/r32/esp -2068 # -2069 (next-word *(ebp+8) %ecx) -2070 # if slice-empty?(s) return -2071 (slice-empty? %ecx) -2072 3d/compare-eax-and 0/imm32 -2073 75/jump-if-not-equal $check-no-tokens-left:end/disp8 -2074 # if (slice-starts-with?(s, '#') return -2075 # . eax = *s->start -2076 8b/-> *edx 0/r32/eax -2077 8a/copy-byte *eax 0/r32/AL -2078 81 4/subop/and %eax 0xff/imm32 -2079 # . if (eax == '#') continue -2080 3d/compare-eax-and 0x23/imm32/hash -2081 74/jump-if-equal $check-no-tokens-left:end/disp8 -2082 # abort -2083 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2084 (rewind-stream %ecx) -2085 (write-stream 2 %ecx) -2086 (write-buffered Stderr "'\n") -2087 (flush Stderr) -2088 # . syscall(exit, 1) -2089 bb/copy-to-ebx 1/imm32 -2090 b8/copy-to-eax 1/imm32/exit -2091 cd/syscall 0x80/imm8 -2092 # never gets here -2093 $check-no-tokens-left:end: -2094 # . reclaim locals -2095 81 0/subop/add %esp 8/imm32 -2096 # . restore registers -2097 59/pop-to-ecx -2098 58/pop-to-eax -2099 # . epilogue -2100 89/<- %esp 5/r32/ebp -2101 5d/pop-to-ebp -2102 c3/return -2103 -2104 parse-mu-named-block: # name : (address slice), first-line : (address stream byte), in : (address buffered-file), vars : (address stack (handle var)) -> result/eax : (handle stmt) + 745 test-convert-function-literal-arg: + 746 # function writes to output + 747 # fn foo a: int, b: int -> result/eax: int { + 748 # result <- copy a + 749 # result <- add 1 + 750 # } + 751 # => + 752 # foo: + 753 # # . prologue + 754 # 55/push-ebp + 755 # 89/<- %ebp 4/r32/esp + 756 # { + 757 # 89/-> *(ebp+8) 0/r32/eax + 758 # 05/add-to-eax 1/imm32 + 759 # } + 760 # # . epilogue + 761 # 89/<- %esp 5/r32/ebp + 762 # 5d/pop-to-ebp + 763 # c3/return + 764 # . prologue + 765 55/push-ebp + 766 89/<- %ebp 4/r32/esp + 767 # setup + 768 (clear-stream _test-input-stream) + 769 (clear-stream $_test-input-buffered-file->buffer) + 770 (clear-stream _test-output-stream) + 771 (clear-stream $_test-output-buffered-file->buffer) + 772 # + 773 (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n") + 774 (write _test-input-stream " result <- copy a\n") + 775 (write _test-input-stream " result <- add 1\n") + 776 (write _test-input-stream "}\n") + 777 # convert + 778 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 779 (flush _test-output-buffered-file) + 780 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 786 # check output + 787 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-literal-arg/0") + 788 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-literal-arg/1") + 789 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-literal-arg/2") + 790 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-literal-arg/3") + 791 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-literal-arg/4") + 792 (check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-function-literal-arg/5") + 793 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 1/imm32" "F - test-convert-function-literal-arg/6") + 794 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-literal-arg/7") + 795 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-literal-arg/8") + 796 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-literal-arg/9") + 797 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-literal-arg/10") + 798 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-literal-arg/11") + 799 # . epilogue + 800 89/<- %esp 5/r32/ebp + 801 5d/pop-to-ebp + 802 c3/return + 803 + 804 test-convert-function-literal-arg-2: + 805 # function writes to output + 806 # fn foo a: int, b: int -> result/ebx: int { + 807 # result <- copy a + 808 # result <- add 1 + 809 # } + 810 # => + 811 # foo: + 812 # # . prologue + 813 # 55/push-ebp + 814 # 89/<- %ebp 4/r32/esp + 815 # { + 816 # 89/-> *(ebp+8) 3/r32/ebx + 817 # 81 0/subop/add %ebx 1/imm32 + 818 # } + 819 # # . epilogue + 820 # 89/<- %esp 5/r32/ebp + 821 # 5d/pop-to-ebp + 822 # c3/return + 823 # . prologue + 824 55/push-ebp + 825 89/<- %ebp 4/r32/esp + 826 # setup + 827 (clear-stream _test-input-stream) + 828 (clear-stream $_test-input-buffered-file->buffer) + 829 (clear-stream _test-output-stream) + 830 (clear-stream $_test-output-buffered-file->buffer) + 831 # + 832 (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n") + 833 (write _test-input-stream " result <- copy a\n") + 834 (write _test-input-stream " result <- add 1\n") + 835 (write _test-input-stream "}\n") + 836 # convert + 837 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 838 (flush _test-output-buffered-file) + 839 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 845 # check output + 846 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-literal-arg-2/0") + 847 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-literal-arg-2/1") + 848 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-literal-arg-2/2") + 849 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-literal-arg-2/3") + 850 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-literal-arg-2/4") + 851 (check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-literal-arg-2/5") + 852 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ebx 1/imm32" "F - test-convert-function-literal-arg-2/6") + 853 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-literal-arg-2/7") + 854 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-literal-arg-2/8") + 855 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-literal-arg-2/9") + 856 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-literal-arg-2/10") + 857 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-literal-arg-2/11") + 858 # . epilogue + 859 89/<- %esp 5/r32/ebp + 860 5d/pop-to-ebp + 861 c3/return + 862 + 863 test-convert-function-call-with-literal-arg: + 864 # function writes to output + 865 # fn main -> result/ebx: int { + 866 # result <- do-add 3 4 + 867 # } + 868 # + 869 # fn do-add a: int, b: int -> result/ebx: int { + 870 # result <- copy a + 871 # result <- add b + 872 # } + 873 # => + 874 # main: + 875 # # . prologue + 876 # 55/push-ebp + 877 # 89/<- %ebp 4/r32/esp + 878 # { + 879 # (do-add 3 4) + 880 # } + 881 # # . epilogue + 882 # 89/<- %esp 5/r32/ebp + 883 # 5d/pop-to-ebp + 884 # c3/return + 885 # do-add: + 886 # # . prologue + 887 # 55/push-ebp + 888 # 89/<- %ebp 4/r32/esp + 889 # { + 890 # 8b/-> *(ebp+8) 3/r32/ebx + 891 # 03/add-to 3/r32/ebx *(ebp+0xc) + 892 # } + 893 # # . epilogue + 894 # 89/<- %esp 5/r32/ebp + 895 # 5d/pop-to-ebp + 896 # c3/return + 897 # . prologue + 898 55/push-ebp + 899 89/<- %ebp 4/r32/esp + 900 # setup + 901 (clear-stream _test-input-stream) + 902 (clear-stream $_test-input-buffered-file->buffer) + 903 (clear-stream _test-output-stream) + 904 (clear-stream $_test-output-buffered-file->buffer) + 905 # + 906 (write _test-input-stream "fn main -> result/ebx: int {\n") + 907 (write _test-input-stream " result <- do-add 3 4\n") + 908 (write _test-input-stream "}\n") + 909 (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n") + 910 (write _test-input-stream " result <- copy a\n") + 911 (write _test-input-stream " result <- add b\n") + 912 (write _test-input-stream "}\n") + 913 # convert + 914 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 915 (flush _test-output-buffered-file) + 916 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- + 922 # check output + 923 (check-next-stream-line-equal _test-output-stream "main:" "F - test-convert-function-call-with-literal-arg/0") + 924 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-call-with-literal-arg/1") + 925 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-call-with-literal-arg/2") + 926 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/3") + 927 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-call-with-literal-arg/4") + 928 (check-next-stream-line-equal _test-output-stream "(do-add 3 4)" "F - test-convert-function-call-with-literal-arg/5") + 929 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-call-with-literal-arg/6") + 930 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-call-with-literal-arg/7") + 931 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/8") + 932 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/9") + 933 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-call-with-literal-arg/10") + 934 (check-next-stream-line-equal _test-output-stream "do-add:" "F - test-convert-function-call-with-literal-arg/11") + 935 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-call-with-literal-arg/12") + 936 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-call-with-literal-arg/13") + 937 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-call-with-literal-arg/14") + 938 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-call-with-literal-arg/15") + 939 (check-next-stream-line-equal _test-output-stream "8b/copy-from *(ebp+0x00000008) 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/16") + 940 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x0000000c) 0x00000003/r32" "F - test-convert-function-call-with-literal-arg/17") + 941 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-call-with-literal-arg/18") + 942 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-call-with-literal-arg/19") + 943 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-call-with-literal-arg/20") + 944 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-call-with-literal-arg/21") + 945 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-call-with-literal-arg/22") + 946 # . epilogue + 947 89/<- %esp 5/r32/ebp + 948 5d/pop-to-ebp + 949 c3/return + 950 + 951 ####################################################### + 952 # Parsing + 953 ####################################################### + 954 + 955 parse-mu: # in : (address buffered-file) + 956 # pseudocode + 957 # var curr-function : (address (handle function)) = Program + 958 # var line : (ref stream byte 512) + 959 # var word-slice : (ref slice) + 960 # while true # line loop + 961 # clear-stream(line) + 962 # read-line-buffered(in, line) + 963 # if (line->write == 0) break # end of file + 964 # word-slice = next-word-or-string(line) + 965 # if slice-empty?(word-slice) # end of line + 966 # continue + 967 # else if slice-starts-with?(word-slice, "#") # comment + 968 # continue # end of line + 969 # else if slice-equal(word-slice, "fn") + 970 # var new-function : (handle function) = allocate(function) + 971 # var vars : (ref stack (address var) 256) + 972 # populate-mu-function-header(in, new-function, vars) + 973 # populate-mu-function-body(in, new-function, vars) + 974 # assert(vars->top == 0) + 975 # *curr-function = new-function + 976 # curr-function = &new-function->next + 977 # else + 978 # abort() + 979 # + 980 # . prologue + 981 55/push-ebp + 982 89/<- %ebp 4/r32/esp + 983 # . save registers + 984 50/push-eax + 985 51/push-ecx + 986 52/push-edx + 987 53/push-ebx + 988 57/push-edi + 989 # var line/ecx : (ref stream byte 512) + 990 81 5/subop/subtract %esp 0x200/imm32 + 991 68/push 0x200/imm32/length + 992 68/push 0/imm32/read + 993 68/push 0/imm32/write + 994 89/<- %ecx 4/r32/esp + 995 # var word-slice/edx : (ref slice) + 996 68/push 0/imm32/end + 997 68/push 0/imm32/start + 998 89/<- %edx 4/r32/esp + 999 # var curr-function/edi : (address (handle function)) = Program +1000 bf/copy-to-edi Program/imm32 +1001 # var vars/ebx : (ref stack (address var) 256) +1002 81 5/subop/subtract %esp 0x400/imm32 +1003 68/push 0x400/imm32/length +1004 68/push 0/imm32/top +1005 89/<- %ebx 4/r32/esp +1006 { +1007 $parse-mu:line-loop: +1008 (clear-stream %ecx) +1009 (read-line-buffered *(ebp+8) %ecx) +1010 # if (line->write == 0) break +1011 81 7/subop/compare *ecx 0/imm32 +1012 0f 84/jump-if-equal break/disp32 +1013 +-- 6 lines: #? # dump line --------------------------------------------------------------------------------------------------------------------------- +1019 (next-word-or-string %ecx %edx) +1020 # if slice-empty?(word-slice) continue +1021 (slice-empty? %edx) +1022 3d/compare-eax-and 0/imm32 +1023 0f 85/jump-if-not-equal loop/disp32 +1024 # if (*word-slice->start == "#") continue +1025 # . eax = *word-slice->start +1026 8b/-> *edx 0/r32/eax +1027 8a/copy-byte *eax 0/r32/AL +1028 81 4/subop/and %eax 0xff/imm32 +1029 # . if (eax == '#') continue +1030 3d/compare-eax-and 0x23/imm32/hash +1031 0f 84/jump-if-equal loop/disp32 +1032 # if (slice-equal?(word-slice, "fn")) parse a function +1033 { +1034 $parse-mu:fn: +1035 (slice-equal? %edx "fn") +1036 3d/compare-eax-and 0/imm32 +1037 0f 84/jump-if-equal break/disp32 +1038 # var new-function/eax : (handle function) = populate-mu-function(in, new-function, vars) +1039 (allocate Heap *Function-size) # => eax +1040 (zero-out %eax *Function-size) +1041 (clear-stack %ebx) +1042 (populate-mu-function-header %ecx %eax %ebx) +1043 (populate-mu-function-body *(ebp+8) %eax %ebx) +1044 # *curr-function = new-function +1045 89/<- *edi 0/r32/eax +1046 # curr-function = &new-function->next +1047 8d/address-> *(eax+0x14) 7/r32/edi # Function-next +1048 e9/jump $parse-mu:line-loop/disp32 +1049 } +1050 # otherwise abort +1051 e9/jump $parse-mu:error1/disp32 +1052 } # end line loop +1053 $parse-mu:end: +1054 # . reclaim locals +1055 81 0/subop/add %esp 0x630/imm32 +1056 # . restore registers +1057 5f/pop-to-edi +1058 5b/pop-to-ebx +1059 5a/pop-to-edx +1060 59/pop-to-ecx +1061 58/pop-to-eax +1062 # . epilogue +1063 89/<- %esp 5/r32/ebp +1064 5d/pop-to-ebp +1065 c3/return +1066 +1067 $parse-mu:error1: +1068 # error("unexpected top-level command: " word-slice "\n") +1069 (write-buffered Stderr "unexpected top-level command: ") +1070 (write-slice-buffered Stderr %edx) +1071 (write-buffered Stderr "\n") +1072 (flush Stderr) +1073 # . syscall(exit, 1) +1074 bb/copy-to-ebx 1/imm32 +1075 b8/copy-to-eax 1/imm32/exit +1076 cd/syscall 0x80/imm8 +1077 # never gets here +1078 +1079 $parse-mu:error2: +1080 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") +1081 (print-int32-buffered Stderr *ebx) +1082 (write-buffered Stderr " vars not reclaimed after fn '") +1083 (write-slice-buffered Stderr *eax) # Function-name +1084 (write-buffered Stderr "'\n") +1085 (flush Stderr) +1086 # . syscall(exit, 1) +1087 bb/copy-to-ebx 1/imm32 +1088 b8/copy-to-eax 1/imm32/exit +1089 cd/syscall 0x80/imm8 +1090 # never gets here +1091 +1092 # scenarios considered: +1093 # ✗ fn foo # no block +1094 # ✓ fn foo { +1095 # ✗ fn foo { { +1096 # ✗ fn foo { } +1097 # ✗ fn foo { } { +1098 # ✗ fn foo x { +1099 # ✗ fn foo x : { +1100 # ✓ fn foo x : int { +1101 # ✓ fn foo x: int { +1102 # ✓ fn foo x: int -> y/eax: int { +1103 populate-mu-function-header: # first-line : (address stream byte), out : (handle function), vars : (address stack (handle var)) +1104 # pseudocode: +1105 # var name : (ref slice) +1106 # next-word(first-line, name) +1107 # assert(name not in '{' '}' '->') +1108 # out->name = slice-to-string(name) +1109 # var next-offset : int = 8 +1110 # ## inouts +1111 # while true +1112 # ## name +1113 # name = next-word(first-line) +1114 # if (name == '{') goto done +1115 # if (name == '->') break +1116 # assert(name != '}') +1117 # var v : (handle var) = parse-var-with-type(name, first-line) +1118 # assert(v->register == null) +1119 # v->stack-offset = next-offset +1120 # next-offset += size-of(v) +1121 # out->inouts = append(out->inouts, v) +1122 # push(vars, v) +1123 # ## outputs +1124 # while true +1125 # ## name +1126 # name = next-word(first-line) +1127 # assert(name not in '{' '}' '->') +1128 # var v : (handle var) = parse-var-with-type(name, first-line) +1129 # assert(v->register != null) +1130 # out->outputs = append(out->outputs, v) +1131 # done: +1132 # +1133 # . prologue +1134 55/push-ebp +1135 89/<- %ebp 4/r32/esp +1136 # . save registers +1137 50/push-eax +1138 51/push-ecx +1139 52/push-edx +1140 53/push-ebx +1141 57/push-edi +1142 # edi = out +1143 8b/-> *(ebp+0xc) 7/r32/edi +1144 # var word-slice/ecx : (ref slice) +1145 68/push 0/imm32/end +1146 68/push 0/imm32/start +1147 89/<- %ecx 4/r32/esp +1148 # var next-offset/edx = 8 +1149 ba/copy-to-edx 8/imm32 +1150 # read function name +1151 (next-word *(ebp+8) %ecx) +1152 # error checking +1153 # if (word-slice == '{') abort +1154 (slice-equal? %ecx "{") # => eax +1155 3d/compare-eax-and 0/imm32 +1156 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 +1157 # if (word-slice == '->') abort +1158 (slice-equal? %ecx "->") # => eax +1159 3d/compare-eax-and 0/imm32 +1160 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 +1161 # if (word-slice == '}') abort +1162 (slice-equal? %ecx "}") # => eax +1163 3d/compare-eax-and 0/imm32 +1164 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 +1165 # save function name +1166 (slice-to-string Heap %ecx) # => eax +1167 89/<- *edi 0/r32/eax # Function-name +1168 # initialize default subx-name as well +1169 89/<- *(edi+4) 0/r32/eax # Function-subx-name +1170 # save function inouts +1171 { +1172 $populate-mu-function-header:check-for-inout: +1173 (next-word *(ebp+8) %ecx) +1174 # if (word-slice == '{') goto done +1175 (slice-equal? %ecx "{") # => eax +1176 3d/compare-eax-and 0/imm32 +1177 0f 85/jump-if-not-equal $populate-mu-function-header:done/disp32 +1178 # if (word-slice == '->') break +1179 (slice-equal? %ecx "->") # => eax +1180 3d/compare-eax-and 0/imm32 +1181 0f 85/jump-if-not-equal break/disp32 +1182 # if (word-slice == '}') abort +1183 (slice-equal? %ecx "}") # => eax +1184 3d/compare-eax-and 0/imm32 +1185 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 +1186 # var v/ebx : (handle var) = parse-var-with-type(word-slice, first-line) +1187 (parse-var-with-type %ecx *(ebp+8)) # => eax +1188 89/<- %ebx 0/r32/eax +1189 # assert(v->register == null) +1190 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +1191 0f 85/jump-if-not-equal $populate-mu-function-header:error2/disp32 +1192 # v->stack-offset = next-offset +1193 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset +1194 # next-offset += size-of(v) +1195 (size-of %ebx) # => eax +1196 01/add %edx 0/r32/eax +1197 # +1198 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax +1199 89/<- *(edi+8) 0/r32/eax # Function-inouts +1200 (push *(ebp+0x10) %ebx) +1201 # +1202 e9/jump loop/disp32 +1203 } +1204 # save function outputs +1205 { +1206 $parse-var-with-type:check-for-out: +1207 (next-word *(ebp+8) %ecx) +1208 # if (word-slice == '{') break +1209 (slice-equal? %ecx "{") # => eax +1210 3d/compare-eax-and 0/imm32 +1211 0f 85/jump-if-not-equal break/disp32 +1212 # if (word-slice == '->') abort +1213 (slice-equal? %ecx "->") # => eax +1214 3d/compare-eax-and 0/imm32 +1215 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 +1216 # if (word-slice == '}') abort +1217 (slice-equal? %ecx "}") # => eax +1218 3d/compare-eax-and 0/imm32 +1219 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 +1220 # +1221 (parse-var-with-type %ecx *(ebp+8)) # => eax +1222 89/<- %ebx 0/r32/eax +1223 # assert(var->register != null) +1224 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +1225 0f 84/jump-if-equal $populate-mu-function-header:error3/disp32 +1226 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax +1227 89/<- *(edi+0xc) 0/r32/eax # Function-outputs +1228 e9/jump loop/disp32 +1229 } +1230 $populate-mu-function-header:done: +1231 (check-no-tokens-left *(ebp+8)) +1232 $populate-mu-function-header:end: +1233 # . reclaim locals +1234 81 0/subop/add %esp 8/imm32 +1235 # . restore registers +1236 5f/pop-to-edi +1237 5b/pop-to-ebx +1238 5a/pop-to-edx +1239 59/pop-to-ecx +1240 58/pop-to-eax +1241 # . epilogue +1242 89/<- %esp 5/r32/ebp +1243 5d/pop-to-ebp +1244 c3/return +1245 +1246 $populate-mu-function-header:error1: +1247 # error("function header not in form 'fn <name> {'") +1248 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") +1249 (flush Stderr) +1250 (rewind-stream *(ebp+8)) +1251 (write-stream 2 *(ebp+8)) +1252 (write-buffered Stderr "'\n") +1253 (flush Stderr) +1254 # . syscall(exit, 1) +1255 bb/copy-to-ebx 1/imm32 +1256 b8/copy-to-eax 1/imm32/exit +1257 cd/syscall 0x80/imm8 +1258 # never gets here +1259 +1260 $populate-mu-function-header:error2: +1261 # error("function input '" var "' cannot be in a register") +1262 (write-buffered Stderr "function input '") +1263 (write-buffered Stderr *ebx) # Var-name +1264 (write-buffered Stderr "' cannot be in a register") +1265 (flush Stderr) +1266 # . syscall(exit, 1) +1267 bb/copy-to-ebx 1/imm32 +1268 b8/copy-to-eax 1/imm32/exit +1269 cd/syscall 0x80/imm8 +1270 # never gets here +1271 +1272 $populate-mu-function-header:error3: +1273 # error("function input '" var "' must be in a register") +1274 (write-buffered Stderr "function input '") +1275 (write-buffered Stderr *eax) # Var-name +1276 (write-buffered Stderr " must be in a register'") +1277 (flush Stderr) +1278 (rewind-stream *(ebp+8)) +1279 (write-stream 2 *(ebp+8)) +1280 (write-buffered Stderr "'\n") +1281 (flush Stderr) +1282 # . syscall(exit, 1) +1283 bb/copy-to-ebx 1/imm32 +1284 b8/copy-to-eax 1/imm32/exit +1285 cd/syscall 0x80/imm8 +1286 # never gets here +1287 +1288 test-function-header-with-arg: +1289 # 'foo n : int {' +1290 # . prologue +1291 55/push-ebp +1292 89/<- %ebp 4/r32/esp +1293 # setup +1294 (clear-stream _test-input-stream) +1295 (write _test-input-stream "foo n : int {\n") +1296 # result/ecx : (ref function) +1297 2b/subtract-> *Function-size 4/r32/esp +1298 89/<- %ecx 4/r32/esp +1299 (zero-out %ecx *Function-size) +1300 # var vars/ebx : (ref stack (address var) 16) +1301 81 5/subop/subtract %esp 0x10/imm32 +1302 68/push 0x10/imm32/length +1303 68/push 0/imm32/top +1304 89/<- %ebx 4/r32/esp +1305 # convert +1306 (populate-mu-function-header _test-input-stream %ecx %ebx) +1307 # check result +1308 (check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name +1309 # edx : (handle list var) = result->inouts +1310 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1311 # ebx : (handle var) = result->inouts->value +1312 8b/-> *edx 3/r32/ebx # List-value +1313 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name +1314 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:0/type") # Var-type +1315 # . epilogue +1316 89/<- %esp 5/r32/ebp +1317 5d/pop-to-ebp +1318 c3/return +1319 +1320 test-function-header-with-multiple-args: +1321 # 'fn foo a: int, b: int, c: int {' +1322 # . prologue +1323 55/push-ebp +1324 89/<- %ebp 4/r32/esp +1325 # setup +1326 (clear-stream _test-input-stream) +1327 (write _test-input-stream "foo a: int, b: int c: int {\n") +1328 # result/ecx : (handle function) +1329 2b/subtract-> *Function-size 4/r32/esp +1330 89/<- %ecx 4/r32/esp +1331 (zero-out %ecx *Function-size) +1332 # var vars/ebx : (ref stack (address var) 16) +1333 81 5/subop/subtract %esp 0x10/imm32 +1334 68/push 0x10/imm32/length +1335 68/push 0/imm32/top +1336 89/<- %ebx 4/r32/esp +1337 # convert +1338 (populate-mu-function-header _test-input-stream %ecx %ebx) +1339 # check result +1340 (check-strings-equal *ecx "foo") # Function-name +1341 # edx : (handle list var) = result->inouts +1342 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1343 $test-function-header-with-multiple-args:inout0: +1344 # ebx : (handle var) = result->inouts->value +1345 8b/-> *edx 3/r32/ebx # List-value +1346 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name +1347 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:0/type") # Var-type +1348 # edx = result->inouts->next +1349 8b/-> *(edx+4) 2/r32/edx # List-next +1350 $test-function-header-with-multiple-args:inout1: +1351 # ebx = result->inouts->next->value +1352 8b/-> *edx 3/r32/ebx # List-value +1353 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name +1354 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:1/type") # Var-type +1355 # edx = result->inouts->next->next +1356 8b/-> *(edx+4) 2/r32/edx # List-next +1357 $test-function-header-with-multiple-args:inout2: +1358 # ebx = result->inouts->next->next->value +1359 8b/-> *edx 3/r32/ebx # List-value +1360 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name +1361 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:2/type") # Var-type +1362 # . epilogue +1363 89/<- %esp 5/r32/ebp +1364 5d/pop-to-ebp +1365 c3/return +1366 +1367 test-function-with-multiple-args-and-outputs: +1368 # fn foo a: int, b: int, c: int -> x: int, y: int { +1369 # . prologue +1370 55/push-ebp +1371 89/<- %ebp 4/r32/esp +1372 # setup +1373 (clear-stream _test-input-stream) +1374 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx : int {\n") +1375 # result/ecx : (handle function) +1376 2b/subtract-> *Function-size 4/r32/esp +1377 89/<- %ecx 4/r32/esp +1378 (zero-out %ecx *Function-size) +1379 # var vars/ebx : (ref stack (address var) 16) +1380 81 5/subop/subtract %esp 0x10/imm32 +1381 68/push 0x10/imm32/length +1382 68/push 0/imm32/top +1383 89/<- %ebx 4/r32/esp +1384 # convert +1385 (populate-mu-function-header _test-input-stream %ecx %ebx) +1386 # check result +1387 (check-strings-equal *ecx "foo") # Function-name +1388 # edx : (handle list var) = result->inouts +1389 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1390 # ebx : (handle var) = result->inouts->value +1391 8b/-> *edx 3/r32/ebx # List-value +1392 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name +1393 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:0/type") # Var-type +1394 # edx = result->inouts->next +1395 8b/-> *(edx+4) 2/r32/edx # List-next +1396 # ebx = result->inouts->next->value +1397 8b/-> *edx 3/r32/ebx # List-value +1398 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name +1399 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:1/type") # Var-type +1400 # edx = result->inouts->next->next +1401 8b/-> *(edx+4) 2/r32/edx # List-next +1402 # ebx = result->inouts->next->next->value +1403 8b/-> *edx 3/r32/ebx # List-value +1404 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name +1405 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:2/type") # Var-type +1406 # edx : (handle list var) = result->outputs +1407 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs +1408 # ebx : (handle var) = result->outputs->value +1409 8b/-> *edx 3/r32/ebx # List-value +1410 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args/output:0") # Var-name +1411 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/output:0/type") # Var-type +1412 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-arg/output:0/register") # Var-register +1413 # edx = result->outputs->next +1414 8b/-> *(edx+4) 2/r32/edx # List-next +1415 # ebx = result->outputs->next->value +1416 8b/-> *edx 3/r32/ebx # List-value +1417 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args/output:1") # Var-name +1418 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/output:1/type") # Var-type +1419 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-arg/output:0/register") # Var-register +1420 # . epilogue +1421 89/<- %esp 5/r32/ebp +1422 5d/pop-to-ebp +1423 c3/return +1424 +1425 # format for variables with types +1426 # x : int +1427 # x: int +1428 # x: int, +1429 # ignores at most one trailing colon or comma +1430 parse-var-with-type: # name: (address slice), first-line: (address stream byte) -> result/eax: (handle var) +1431 # pseudocode: +1432 # var v : (handle var) = allocate(Heap, Var-size) +1433 # var s : (ref slice) +1434 # next-token-from-slice(name->start, name->end, '/', s) +1435 # var end : (address byte) = s->end +1436 # if (slice-ends-with(s, ":")) +1437 # decrement s->end +1438 # if (slice-ends-with(s, ",")) +1439 # decrement s->end +1440 # v->name = slice-to-string(s) +1441 # ## register +1442 # next-token-from-slice(end, name->end, '/', s) +1443 # if (slice-ends-with(s, ":")) +1444 # decrement s->end +1445 # if (slice-ends-with(s, ",")) +1446 # decrement s->end +1447 # if (!slice-empty?(s)) +1448 # v->register = slice-to-string(s) +1449 # ## type +1450 # s = next-mu-token(first-line) +1451 # assert(s not in '{' '}' '->') +1452 # if (slice-empty?(s)) { +1453 # s = next-mu-token(first-line) +1454 # assert(type not in '{' '}' '->') +1455 # } +1456 # type = type-for(s) +1457 # v->type = type +1458 # return v +1459 # +1460 # . prologue +1461 55/push-ebp +1462 89/<- %ebp 4/r32/esp +1463 # . save registers +1464 51/push-ecx +1465 52/push-edx +1466 53/push-ebx +1467 56/push-esi +1468 57/push-edi +1469 # var result/edi : (handle var) = allocate(Heap, Var-size) +1470 (allocate Heap *Var-size) # => eax +1471 (zero-out %eax *Var-size) +1472 89/<- %edi 0/r32/eax +1473 # esi = name +1474 8b/-> *(ebp+8) 6/r32/esi +1475 # var s/ecx : (ref slice) +1476 68/push 0/imm32/end +1477 68/push 0/imm32/start +1478 89/<- %ecx 4/r32/esp +1479 $parse-var-with-type:save-name: +1480 # save v->name +1481 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' +1482 # . end/edx = s->end +1483 8b/-> *(ecx+4) 2/r32/edx +1484 # . if s ends with ':', decrement s->end +1485 { +1486 8b/-> *(ecx+4) 0/r32/eax +1487 48/decrement-eax +1488 8a/copy-byte *eax 3/r32/BL +1489 81 4/subop/and %ebx 0xff/imm32 +1490 81 7/subop/compare %ebx 0x3a/imm32/colon +1491 75/jump-if-not-equal break/disp8 +1492 89/<- *(ecx+4) 0/r32/eax +1493 } +1494 # . if s ends with ',', decrement s->end +1495 { +1496 8b/-> *(ecx+4) 0/r32/eax +1497 48/decrement-eax +1498 8a/copy-byte *eax 3/r32/BL +1499 81 4/subop/and %ebx 0xff/imm32 +1500 81 7/subop/compare %ebx 0x2c/imm32/comma +1501 75/jump-if-not-equal break/disp8 +1502 89/<- *(ecx+4) 0/r32/eax +1503 } +1504 $parse-var-with-type:write-name: +1505 (slice-to-string Heap %ecx) # => eax +1506 89/<- *edi 0/r32/eax # Var-name +1507 # save v->register +1508 $parse-var-with-type:save-register: +1509 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' +1510 # . if s ends with ':', decrement s->end +1511 { +1512 8b/-> *(ecx+4) 0/r32/eax +1513 48/decrement-eax +1514 8a/copy-byte *eax 3/r32/BL +1515 81 4/subop/and %ebx 0xff/imm32 +1516 81 7/subop/compare %ebx 0x3a/imm32/colon +1517 75/jump-if-not-equal break/disp8 +1518 89/<- *(ecx+4) 0/r32/eax +1519 } +1520 # . if s ends with ',', decrement s->end +1521 { +1522 8b/-> *(ecx+4) 0/r32/eax +1523 48/decrement-eax +1524 8a/copy-byte *eax 3/r32/BL +1525 81 4/subop/and %ebx 0xff/imm32 +1526 81 7/subop/compare %ebx 0x2c/imm32/comma +1527 75/jump-if-not-equal break/disp8 +1528 89/<- *(ecx+4) 0/r32/eax +1529 } +1530 # if (!slice-empty?(s)) v->register = slice-to-string(s) +1531 { +1532 $parse-var-with-type:write-register: +1533 # HACK: s->end can be less than s->start with all the decrements above +1534 # That's probably a sign we have the wrong algorithm for this function. +1535 8b/-> *ecx 0/r32/eax +1536 39/compare 0/r32/eax *(ecx+4) +1537 76/jump-if-lesser-or-equal break/disp8 +1538 (slice-to-string Heap %ecx) +1539 89/<- *(edi+0x10) 0/r32/eax # Var-register +1540 } +1541 # save v->type +1542 (next-mu-token *(ebp+0xc) %ecx) +1543 # if (word-slice == '{') abort +1544 (slice-equal? %ecx "{") # => eax +1545 3d/compare-eax-and 0/imm32 +1546 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1547 # if (word-slice == '->') abort +1548 (slice-equal? %ecx "->") # => eax +1549 3d/compare-eax-and 0/imm32 +1550 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1551 # if (word-slice == '}') abort +1552 (slice-equal? %ecx "}") # => eax +1553 3d/compare-eax-and 0/imm32 +1554 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1555 # if (slice-empty?(type)) skip +1556 (slice-empty? %ecx) +1557 { +1558 3d/compare-eax-and 0/imm32 +1559 0f 84/jump-if-equal break/disp32 +1560 (next-mu-token *(ebp+0xc) %ecx) +1561 # if (word-slice == '{') abort +1562 (slice-equal? %ecx "{") # => eax +1563 3d/compare-eax-and 0/imm32 +1564 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1565 # if (word-slice == '->') abort +1566 (slice-equal? %ecx "->") # => eax +1567 3d/compare-eax-and 0/imm32 +1568 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1569 # if (word-slice == '}') abort +1570 (slice-equal? %ecx "}") # => eax +1571 3d/compare-eax-and 0/imm32 +1572 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1573 } +1574 (type-for %ecx) +1575 89/<- *(edi+4) 0/r32/eax # Var-type +1576 $parse-var-with-type:end: +1577 # return result +1578 89/<- %eax 7/r32/edi +1579 # . reclaim locals +1580 81 0/subop/add %esp 8/imm32 +1581 # . restore registers +1582 5f/pop-to-edi +1583 5e/pop-to-esi +1584 5b/pop-to-ebx +1585 5a/pop-to-edx +1586 59/pop-to-ecx +1587 # . epilogue +1588 89/<- %esp 5/r32/ebp +1589 5d/pop-to-ebp +1590 c3/return +1591 +1592 $parse-var-with-type:abort: +1593 # error("function header not in form 'fn <name> {'") +1594 (write-buffered Stderr "var should have form 'name: type' in '") +1595 (flush Stderr) +1596 (rewind-stream *(ebp+0xc)) +1597 (write-stream 2 *(ebp+0xc)) +1598 (write-buffered Stderr "'\n") +1599 (flush Stderr) +1600 # . syscall(exit, 1) +1601 bb/copy-to-ebx 1/imm32 +1602 b8/copy-to-eax 1/imm32/exit +1603 cd/syscall 0x80/imm8 +1604 # never gets here +1605 +1606 next-mu-token: # in: (address stream byte), out: (address slice) +1607 # . prologue +1608 55/push-ebp +1609 89/<- %ebp 4/r32/esp +1610 # . save registers +1611 50/push-eax +1612 57/push-edi +1613 # edi = out +1614 8b/-> *(ebp+0xc) 7/r32/edi +1615 # +1616 (next-word *(ebp+8) %edi) # TODO: support s-expressions +1617 # if out ends with ':', decrement out->end +1618 { +1619 8b/-> *(edi+4) 0/r32/eax +1620 48/decrement-eax +1621 8a/copy-byte *eax 3/r32/BL +1622 81 4/subop/and %ebx 0xff/imm32 +1623 81 7/subop/compare %ebx 0x3a/imm32/colon +1624 75/jump-if-not-equal break/disp8 +1625 89/<- *(edi+4) 0/r32/eax +1626 } +1627 # if out ends with ',', decrement out->end +1628 { +1629 8b/-> *(edi+4) 0/r32/eax +1630 48/decrement-eax +1631 8a/copy-byte *eax 3/r32/BL +1632 81 4/subop/and %ebx 0xff/imm32 +1633 81 7/subop/compare %ebx 0x2c/imm32/comma +1634 75/jump-if-not-equal break/disp8 +1635 89/<- *(edi+4) 0/r32/eax +1636 } +1637 $next-mu-token:end: +1638 b8/copy-to-eax 1/imm32/int +1639 # . restore registers +1640 5f/pop-to-edi +1641 58/pop-to-eax +1642 # . epilogue +1643 89/<- %esp 5/r32/ebp +1644 5d/pop-to-ebp +1645 c3/return +1646 +1647 type-for: # name: (address slice) -> result/eax: (handle s-expression type-id) +1648 # . prologue +1649 55/push-ebp +1650 89/<- %ebp 4/r32/esp +1651 # . save registers +1652 #? (write-buffered Stderr "type: ") +1653 #? (write-slice-buffered Stderr *(ebp+8)) +1654 #? (write-buffered Stderr Newline) +1655 #? (flush Stderr) +1656 $type-for:end: +1657 b8/copy-to-eax 1/imm32/int +1658 # . restore registers +1659 # . epilogue +1660 89/<- %esp 5/r32/ebp +1661 5d/pop-to-ebp +1662 c3/return +1663 +1664 test-parse-var-with-type: +1665 # . prologue +1666 55/push-ebp +1667 89/<- %ebp 4/r32/esp +1668 # (eax..ecx) = "x:" +1669 b8/copy-to-eax "x:"/imm32 +1670 8b/-> *eax 1/r32/ecx +1671 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1672 05/add-to-eax 4/imm32 +1673 # var slice/ecx : (ref slice) = {eax, ecx} +1674 51/push-ecx +1675 50/push-eax +1676 89/<- %ecx 4/r32/esp +1677 # _test-input-stream contains "int" +1678 (clear-stream _test-input-stream) +1679 (write _test-input-stream "int") +1680 # +1681 (parse-var-with-type %ecx _test-input-stream) +1682 8b/-> *eax 2/r32/edx # Var-name +1683 (check-strings-equal %edx "x" "F - test-var-with-type/name") +1684 8b/-> *(eax+4) 2/r32/edx # Var-type +1685 (check-ints-equal %edx 1 "F - test-var-with-type/type") +1686 # . epilogue +1687 89/<- %esp 5/r32/ebp +1688 5d/pop-to-ebp +1689 c3/return +1690 +1691 test-parse-var-with-type-and-register: +1692 # . prologue +1693 55/push-ebp +1694 89/<- %ebp 4/r32/esp +1695 # (eax..ecx) = "x/eax" +1696 b8/copy-to-eax "x/eax"/imm32 +1697 8b/-> *eax 1/r32/ecx +1698 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1699 05/add-to-eax 4/imm32 +1700 # var slice/ecx : (ref slice) = {eax, ecx} +1701 51/push-ecx +1702 50/push-eax +1703 89/<- %ecx 4/r32/esp +1704 # _test-input-stream contains ": int" +1705 (clear-stream _test-input-stream) +1706 (write _test-input-stream ": int") +1707 # +1708 (parse-var-with-type %ecx _test-input-stream) +1709 8b/-> *eax 2/r32/edx # Var-name +1710 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") +1711 8b/-> *(eax+0x10) 2/r32/edx # Var-register +1712 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") +1713 8b/-> *(eax+4) 2/r32/edx # Var-type +1714 (check-ints-equal %edx 1 "F - test-var-with-type-and-register/type") +1715 # . epilogue +1716 89/<- %esp 5/r32/ebp +1717 5d/pop-to-ebp +1718 c3/return +1719 +1720 test-parse-var-with-trailing-characters: +1721 # . prologue +1722 55/push-ebp +1723 89/<- %ebp 4/r32/esp +1724 # (eax..ecx) = "x:" +1725 b8/copy-to-eax "x:"/imm32 +1726 8b/-> *eax 1/r32/ecx +1727 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1728 05/add-to-eax 4/imm32 +1729 # var slice/ecx : (ref slice) = {eax, ecx} +1730 51/push-ecx +1731 50/push-eax +1732 89/<- %ecx 4/r32/esp +1733 # _test-input-stream contains "int," +1734 (clear-stream _test-input-stream) +1735 (write _test-input-stream "int,") +1736 # +1737 (parse-var-with-type %ecx _test-input-stream) +1738 8b/-> *eax 2/r32/edx # Var-name +1739 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") +1740 8b/-> *(eax+0x10) 2/r32/edx # Var-register +1741 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") +1742 8b/-> *(eax+4) 2/r32/edx # Var-type +1743 (check-ints-equal %edx 1 "F - test-var-with-trailing-characters/type") +1744 # . epilogue +1745 89/<- %esp 5/r32/ebp +1746 5d/pop-to-ebp +1747 c3/return +1748 +1749 test-parse-var-with-register-and-trailing-characters: +1750 # . prologue +1751 55/push-ebp +1752 89/<- %ebp 4/r32/esp +1753 # (eax..ecx) = "x/eax:" +1754 b8/copy-to-eax "x/eax:"/imm32 +1755 8b/-> *eax 1/r32/ecx +1756 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1757 05/add-to-eax 4/imm32 +1758 # var slice/ecx : (ref slice) = {eax, ecx} +1759 51/push-ecx +1760 50/push-eax +1761 89/<- %ecx 4/r32/esp +1762 # _test-input-stream contains "int," +1763 (clear-stream _test-input-stream) +1764 (write _test-input-stream "int,") +1765 # +1766 (parse-var-with-type %ecx _test-input-stream) +1767 8b/-> *eax 2/r32/edx # Var-name +1768 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") +1769 8b/-> *(eax+0x10) 2/r32/edx # Var-register +1770 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") +1771 8b/-> *(eax+4) 2/r32/edx # Var-type +1772 (check-ints-equal %edx 1 "F - test-var-with-register-and-trailing-characters/type") +1773 # . epilogue +1774 89/<- %esp 5/r32/ebp +1775 5d/pop-to-ebp +1776 c3/return +1777 +1778 # identifier starts with a letter or '$' or '_' +1779 # no constraints at the moment on later letters +1780 # all we really want to do so far is exclude '{', '}' and '->' +1781 is-identifier?: # in : (address slice) -> result/eax : boolean +1782 # . prologue +1783 55/push-ebp +1784 89/<- %ebp 4/r32/esp +1785 # if (slice-empty?(in)) return false +1786 (slice-empty? *(ebp+8)) # => eax +1787 3d/compare-eax-and 0/imm32 +1788 75/jump-if-not-equal $is-identifier?:false/disp8 +1789 # var c/eax : byte = *in->start +1790 8b/-> *(ebp+8) 0/r32/eax +1791 8b/-> *eax 0/r32/eax +1792 8a/copy-byte *eax 0/r32/AL +1793 81 4/subop/and %eax 0xff/imm32 +1794 # if (c == '$') return true +1795 3d/compare-eax-and 0x24/imm32/$ +1796 74/jump-if-equal $is-identifier?:true/disp8 +1797 # if (c == '_') return true +1798 3d/compare-eax-and 0x5f/imm32/_ +1799 74/jump-if-equal $is-identifier?:true/disp8 +1800 # drop case +1801 25/and-eax-with 0x5f/imm32 +1802 # if (c < 'A') return false +1803 3d/compare-eax-and 0x41/imm32/A +1804 7c/jump-if-lesser $is-identifier?:false/disp8 +1805 # if (c > 'Z') return false +1806 3d/compare-eax-and 0x5a/imm32/Z +1807 7f/jump-if-greater $is-identifier?:false/disp8 +1808 # otherwise return true +1809 $is-identifier?:true: +1810 b8/copy-to-eax 1/imm32/true +1811 eb/jump $is-identifier?:end/disp8 +1812 $is-identifier?:false: +1813 b8/copy-to-eax 0/imm32/false +1814 $is-identifier?:end: +1815 # . epilogue +1816 89/<- %esp 5/r32/ebp +1817 5d/pop-to-ebp +1818 c3/return +1819 +1820 test-is-identifier-dollar: +1821 # . prologue +1822 55/push-ebp +1823 89/<- %ebp 4/r32/esp +1824 # (eax..ecx) = "$a" +1825 b8/copy-to-eax "$a"/imm32 +1826 8b/-> *eax 1/r32/ecx +1827 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1828 05/add-to-eax 4/imm32 +1829 # var slice/ecx : (ref slice) = {eax, ecx} +1830 51/push-ecx +1831 50/push-eax +1832 89/<- %ecx 4/r32/esp +1833 # +1834 (is-identifier? %ecx) +1835 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") +1836 # . epilogue +1837 89/<- %esp 5/r32/ebp +1838 5d/pop-to-ebp +1839 c3/return +1840 +1841 test-is-identifier-underscore: +1842 # . prologue +1843 55/push-ebp +1844 89/<- %ebp 4/r32/esp +1845 # (eax..ecx) = "_a" +1846 b8/copy-to-eax "_a"/imm32 +1847 8b/-> *eax 1/r32/ecx +1848 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1849 05/add-to-eax 4/imm32 +1850 # var slice/ecx : (ref slice) = {eax, ecx} +1851 51/push-ecx +1852 50/push-eax +1853 89/<- %ecx 4/r32/esp +1854 # +1855 (is-identifier? %ecx) +1856 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") +1857 # . epilogue +1858 89/<- %esp 5/r32/ebp +1859 5d/pop-to-ebp +1860 c3/return +1861 +1862 test-is-identifier-a: +1863 # . prologue +1864 55/push-ebp +1865 89/<- %ebp 4/r32/esp +1866 # (eax..ecx) = "a$" +1867 b8/copy-to-eax "a$"/imm32 +1868 8b/-> *eax 1/r32/ecx +1869 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1870 05/add-to-eax 4/imm32 +1871 # var slice/ecx : (ref slice) = {eax, ecx} +1872 51/push-ecx +1873 50/push-eax +1874 89/<- %ecx 4/r32/esp +1875 # +1876 (is-identifier? %ecx) +1877 (check-ints-equal %eax 1 "F - test-is-identifier-a") +1878 # . epilogue +1879 89/<- %esp 5/r32/ebp +1880 5d/pop-to-ebp +1881 c3/return +1882 +1883 test-is-identifier-z: +1884 # . prologue +1885 55/push-ebp +1886 89/<- %ebp 4/r32/esp +1887 # (eax..ecx) = "z$" +1888 b8/copy-to-eax "z$"/imm32 +1889 8b/-> *eax 1/r32/ecx +1890 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1891 05/add-to-eax 4/imm32 +1892 # var slice/ecx : (ref slice) = {eax, ecx} +1893 51/push-ecx +1894 50/push-eax +1895 89/<- %ecx 4/r32/esp +1896 # +1897 (is-identifier? %ecx) +1898 (check-ints-equal %eax 1 "F - test-is-identifier-z") +1899 # . epilogue +1900 89/<- %esp 5/r32/ebp +1901 5d/pop-to-ebp +1902 c3/return +1903 +1904 test-is-identifier-A: +1905 # . prologue +1906 55/push-ebp +1907 89/<- %ebp 4/r32/esp +1908 # (eax..ecx) = "A$" +1909 b8/copy-to-eax "A$"/imm32 +1910 8b/-> *eax 1/r32/ecx +1911 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1912 05/add-to-eax 4/imm32 +1913 # var slice/ecx : (ref slice) = {eax, ecx} +1914 51/push-ecx +1915 50/push-eax +1916 89/<- %ecx 4/r32/esp +1917 # +1918 (is-identifier? %ecx) +1919 (check-ints-equal %eax 1 "F - test-is-identifier-A") +1920 # . epilogue +1921 89/<- %esp 5/r32/ebp +1922 5d/pop-to-ebp +1923 c3/return +1924 +1925 test-is-identifier-Z: +1926 # . prologue +1927 55/push-ebp +1928 89/<- %ebp 4/r32/esp +1929 # (eax..ecx) = "Z$" +1930 b8/copy-to-eax "Z$"/imm32 +1931 8b/-> *eax 1/r32/ecx +1932 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1933 05/add-to-eax 4/imm32 +1934 # var slice/ecx : (ref slice) = {eax, ecx} +1935 51/push-ecx +1936 50/push-eax +1937 89/<- %ecx 4/r32/esp +1938 # +1939 (is-identifier? %ecx) +1940 (check-ints-equal %eax 1 "F - test-is-identifier-Z") +1941 # . epilogue +1942 89/<- %esp 5/r32/ebp +1943 5d/pop-to-ebp +1944 c3/return +1945 +1946 test-is-identifier-@: +1947 # character before 'A' is invalid +1948 # . prologue +1949 55/push-ebp +1950 89/<- %ebp 4/r32/esp +1951 # (eax..ecx) = "@a" +1952 b8/copy-to-eax "@a"/imm32 +1953 8b/-> *eax 1/r32/ecx +1954 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1955 05/add-to-eax 4/imm32 +1956 # var slice/ecx : (ref slice) = {eax, ecx} +1957 51/push-ecx +1958 50/push-eax +1959 89/<- %ecx 4/r32/esp +1960 # +1961 (is-identifier? %ecx) +1962 (check-ints-equal %eax 0 "F - test-is-identifier-@") +1963 # . epilogue +1964 89/<- %esp 5/r32/ebp +1965 5d/pop-to-ebp +1966 c3/return +1967 +1968 test-is-identifier-square-bracket: +1969 # character after 'Z' is invalid +1970 # . prologue +1971 55/push-ebp +1972 89/<- %ebp 4/r32/esp +1973 # (eax..ecx) = "[a" +1974 b8/copy-to-eax "[a"/imm32 +1975 8b/-> *eax 1/r32/ecx +1976 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1977 05/add-to-eax 4/imm32 +1978 # var slice/ecx : (ref slice) = {eax, ecx} +1979 51/push-ecx +1980 50/push-eax +1981 89/<- %ecx 4/r32/esp +1982 # +1983 (is-identifier? %ecx) +1984 (check-ints-equal %eax 0 "F - test-is-identifier-@") +1985 # . epilogue +1986 89/<- %esp 5/r32/ebp +1987 5d/pop-to-ebp +1988 c3/return +1989 +1990 test-is-identifier-backtick: +1991 # character before 'a' is invalid +1992 # . prologue +1993 55/push-ebp +1994 89/<- %ebp 4/r32/esp +1995 # (eax..ecx) = "`a" +1996 b8/copy-to-eax "`a"/imm32 +1997 8b/-> *eax 1/r32/ecx +1998 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1999 05/add-to-eax 4/imm32 +2000 # var slice/ecx : (ref slice) = {eax, ecx} +2001 51/push-ecx +2002 50/push-eax +2003 89/<- %ecx 4/r32/esp +2004 # +2005 (is-identifier? %ecx) +2006 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") +2007 # . epilogue +2008 89/<- %esp 5/r32/ebp +2009 5d/pop-to-ebp +2010 c3/return +2011 +2012 test-is-identifier-curly-brace-open: +2013 # character after 'z' is invalid; also used for blocks +2014 # . prologue +2015 55/push-ebp +2016 89/<- %ebp 4/r32/esp +2017 # (eax..ecx) = "{a" +2018 b8/copy-to-eax "{a"/imm32 +2019 8b/-> *eax 1/r32/ecx +2020 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2021 05/add-to-eax 4/imm32 +2022 # var slice/ecx : (ref slice) = {eax, ecx} +2023 51/push-ecx +2024 50/push-eax +2025 89/<- %ecx 4/r32/esp +2026 # +2027 (is-identifier? %ecx) +2028 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") +2029 # . epilogue +2030 89/<- %esp 5/r32/ebp +2031 5d/pop-to-ebp +2032 c3/return +2033 +2034 test-is-identifier-curly-brace-close: +2035 # . prologue +2036 55/push-ebp +2037 89/<- %ebp 4/r32/esp +2038 # (eax..ecx) = "}a" +2039 b8/copy-to-eax "}a"/imm32 +2040 8b/-> *eax 1/r32/ecx +2041 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2042 05/add-to-eax 4/imm32 +2043 # var slice/ecx : (ref slice) = {eax, ecx} +2044 51/push-ecx +2045 50/push-eax +2046 89/<- %ecx 4/r32/esp +2047 # +2048 (is-identifier? %ecx) +2049 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") +2050 # . epilogue +2051 89/<- %esp 5/r32/ebp +2052 5d/pop-to-ebp +2053 c3/return +2054 +2055 test-is-identifier-hyphen: +2056 # disallow leading '-' since '->' has special meaning +2057 # . prologue +2058 55/push-ebp +2059 89/<- %ebp 4/r32/esp +2060 # (eax..ecx) = "-a" +2061 b8/copy-to-eax "-a"/imm32 +2062 8b/-> *eax 1/r32/ecx +2063 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2064 05/add-to-eax 4/imm32 +2065 # var slice/ecx : (ref slice) = {eax, ecx} +2066 51/push-ecx +2067 50/push-eax +2068 89/<- %ecx 4/r32/esp +2069 # +2070 (is-identifier? %ecx) +2071 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") +2072 # . epilogue +2073 89/<- %esp 5/r32/ebp +2074 5d/pop-to-ebp +2075 c3/return +2076 +2077 populate-mu-function-body: # in : (address buffered-file), out : (handle function), vars : (address stack (handle var)) +2078 # . prologue +2079 55/push-ebp +2080 89/<- %ebp 4/r32/esp +2081 # . save registers +2082 50/push-eax +2083 56/push-esi +2084 57/push-edi +2085 # esi = in +2086 8b/-> *(ebp+8) 6/r32/esi +2087 # edi = out +2088 8b/-> *(ebp+0xc) 7/r32/edi +2089 # var eax : (handle block) = parse-mu-block(in, vars) +2090 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax +2091 # out->body = eax +2092 89/<- *(edi+0x10) 0/r32/eax # Function-body +2093 $populate-mu-function-body:end: +2094 # . restore registers +2095 5f/pop-to-edi +2096 5e/pop-to-esi +2097 58/pop-to-eax +2098 # . epilogue +2099 89/<- %esp 5/r32/ebp +2100 5d/pop-to-ebp +2101 c3/return +2102 +2103 # parses a block, assuming that the leading '{' has already been read by the caller +2104 parse-mu-block: # in : (address buffered-file), vars : (address stack (handle var)), fn : (handle function) -> result/eax : (handle block) 2105 # pseudocode: 2106 # var line : (ref stream byte 512) 2107 # var word-slice : (ref slice) 2108 # result/eax = allocate(Heap, Stmt-size) -2109 # result->tag = 4/Named-block -2110 # result->name = name -2111 # assert(next-word(first-line) == "{") -2112 # assert(no-tokens-in(first-line)) -2113 # while true # line loop -2114 # clear-stream(line) -2115 # read-line-buffered(in, line) -2116 # if (line->write == 0) break # end of file -2117 # word-slice = next-word(line) -2118 # if slice-empty?(word-slice) # end of line -2119 # break -2120 # else if slice-equal?(word-slice, "{") -2121 # block = parse-mu-block(in, vars) +2109 # result->tag = 0/Block +2110 # while true # line loop +2111 # clear-stream(line) +2112 # read-line-buffered(in, line) +2113 # if (line->write == 0) break # end of file +2114 # word-slice = next-word(line) +2115 # if slice-empty?(word-slice) # end of line +2116 # continue +2117 # else if slice-starts-with?(word-slice, "#") +2118 # continue +2119 # else if slice-equal?(word-slice, "{") +2120 # assert(no-tokens-in(line)) +2121 # block = parse-mu-block(in, vars, fn) 2122 # append-to-block(result, block) 2123 # else if slice-equal?(word-slice, "}") 2124 # break 2125 # else if slice-ends-with?(word-slice, ":") -2126 # named-block = parse-mu-named-block(word-slice, in, vars) +2126 # named-block = parse-mu-named-block(word-slice, line, in, vars, fn) 2127 # append-to-block(result, named-block) 2128 # else if slice-equal?(word-slice, "var") 2129 # var-def = parse-mu-var-def(line, vars) @@ -2164,2589 +2149,2614 @@ if ('onhashchange' in window) { 2137 55/push-ebp 2138 89/<- %ebp 4/r32/esp 2139 # . save registers -2140 $parse-mu-named-block:end: -2141 # . reclaim locals -2142 # . restore registers -2143 # . epilogue -2144 89/<- %esp 5/r32/ebp -2145 5d/pop-to-ebp -2146 c3/return -2147 -2148 parse-mu-var-def: # line : (address stream byte), vars : (address stack (handle var)) -> result/eax : (handle stmt) -2149 # pseudocode: -2150 # -2151 # . prologue -2152 55/push-ebp -2153 89/<- %ebp 4/r32/esp -2154 # . save registers -2155 $parse-mu-var-def:end: -2156 # . reclaim locals -2157 # . restore registers -2158 # . epilogue -2159 89/<- %esp 5/r32/ebp -2160 5d/pop-to-ebp -2161 c3/return -2162 -2163 parse-mu-stmt: # line : (address stream byte), vars : (address stack (handle var)), fn : (handle function) -> result/eax : (handle stmt) -2164 # pseudocode: -2165 # var name : (ref slice) -2166 # result = allocate(Heap, Stmt-size) -2167 # if stmt-has-outputs?(line) -2168 # while true -2169 # name = next-word(line) -2170 # if (name == '<-') break -2171 # assert(is-identifier?(name)) -2172 # var v : (handle var) = lookup-or-define-var(name, vars) -2173 # result->outputs = append(result->outputs, v) -2174 # result->name = slice-to-string(next-word(line)) -2175 # while true -2176 # name = next-word-or-string(line) -2177 # v = lookup-var-or-literal(name) -2178 # result->inouts = append(result->inouts, v) -2179 # -2180 # . prologue -2181 55/push-ebp -2182 89/<- %ebp 4/r32/esp -2183 # . save registers -2184 51/push-ecx -2185 57/push-edi -2186 # var name/ecx : (ref slice) -2187 68/push 0/imm32/end -2188 68/push 0/imm32/start -2189 89/<- %ecx 4/r32/esp -2190 # result/edi : (handle stmt) -2191 (allocate Heap *Stmt-size) # => eax -2192 (zero-out %eax *Stmt-size) -2193 89/<- %edi 0/r32/eax -2194 # result->tag = 1/stmt -2195 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag -2196 { -2197 (stmt-has-outputs? *(ebp+8)) -2198 3d/compare-eax-and 0/imm32 -2199 0f 84/jump-if-equal break/disp32 -2200 { -2201 $parse-mu-stmt:read-outputs: -2202 # name = next-word(line) -2203 (next-word *(ebp+8) %ecx) -2204 # if slice-empty?(word-slice) break -2205 (slice-empty? %ecx) -2206 3d/compare-eax-and 0/imm32 -2207 0f 85/jump-if-not-equal break/disp32 -2208 # if (name == "<-") break -2209 (slice-equal? %ecx "<-") -2210 3d/compare-eax-and 0/imm32 -2211 75/jump-if-not-equal break/disp8 -2212 # assert(is-identifier?(name)) -2213 (is-identifier? %ecx) -2214 3d/compare-eax-and 0/imm32 -2215 0f 84/jump-if-equal $parse-mu-stmt:abort/disp32 -2216 # -2217 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -2218 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax -2219 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs -2220 e9/jump loop/disp32 -2221 } -2222 } -2223 $parse-mu-stmt:read-operation: -2224 (next-word *(ebp+8) %ecx) -2225 (slice-to-string Heap %ecx) -2226 89/<- *(edi+4) 0/r32/eax # Stmt1-operation -2227 { -2228 $parse-mu-stmt:read-inouts: -2229 # name = next-word-or-string(line) -2230 (next-word-or-string *(ebp+8) %ecx) -2231 # if slice-empty?(word-slice) break -2232 (slice-empty? %ecx) -2233 3d/compare-eax-and 0/imm32 -2234 0f 85/jump-if-not-equal break/disp32 -2235 # if (name == "<-") abort -2236 (slice-equal? %ecx "<-") -2237 3d/compare-eax-and 0/imm32 -2238 0f 85/jump-if-not-equal $parse-mu-stmt:abort2/disp32 -2239 # -2240 (lookup-var %ecx *(ebp+0xc)) # => eax # TODO: lookup-var-or-literal -2241 (append-list Heap %eax *(edi+8)) # Stmt1-inouts => eax -2242 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts -2243 e9/jump loop/disp32 -2244 } -2245 $parse-mu-stmt:end: -2246 # return result -2247 89/<- %eax 7/r32/edi -2248 # . reclaim locals -2249 81 0/subop/add %esp 8/imm32 -2250 # . restore registers -2251 5f/pop-to-edi -2252 59/pop-to-ecx -2253 # . epilogue -2254 89/<- %esp 5/r32/ebp -2255 5d/pop-to-ebp -2256 c3/return -2257 -2258 $parse-mu-stmt:abort: -2259 # error("invalid identifier '" name "'\n") -2260 (write-buffered Stderr "invalid identifier '") -2261 (write-slice-buffered Stderr %ecx) -2262 (write-buffered Stderr "'\n") -2263 (flush Stderr) -2264 # . syscall(exit, 1) -2265 bb/copy-to-ebx 1/imm32 -2266 b8/copy-to-eax 1/imm32/exit -2267 cd/syscall 0x80/imm8 -2268 # never gets here -2269 -2270 $parse-mu-stmt:abort2: -2271 # error("invalid statement '" line "'\n") -2272 (rewind-stream *(ebp+8)) -2273 (write-buffered Stderr "invalid identifier '") -2274 (write-stream Stderr *(ebp+8)) -2275 (write-buffered Stderr "'\n") -2276 (flush Stderr) -2277 # . syscall(exit, 1) -2278 bb/copy-to-ebx 1/imm32 -2279 b8/copy-to-eax 1/imm32/exit -2280 cd/syscall 0x80/imm8 -2281 # never gets here -2282 -2283 stmt-has-outputs?: # line : (address stream byte) -> result/eax : boolean -2284 # . prologue -2285 55/push-ebp -2286 89/<- %ebp 4/r32/esp -2287 # . save registers -2288 51/push-ecx -2289 # var word-slice/ecx : (ref slice) -2290 68/push 0/imm32/end -2291 68/push 0/imm32/start -2292 89/<- %ecx 4/r32/esp -2293 # result = false -2294 b8/copy-to-eax 0/imm32/false -2295 (rewind-stream *(ebp+8)) -2296 { -2297 (next-word-or-string *(ebp+8) %ecx) -2298 # if slice-empty?(word-slice) break -2299 (slice-empty? %ecx) -2300 3d/compare-eax-and 0/imm32 -2301 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -2302 0f 85/jump-if-not-equal break/disp32 -2303 # if slice-starts-with?(word-slice, '#') break -2304 # . eax = *word-slice->start -2305 8b/-> *ecx 0/r32/eax -2306 8a/copy-byte *eax 0/r32/AL -2307 81 4/subop/and %eax 0xff/imm32 -2308 # . if (eax == '#') break -2309 3d/compare-eax-and 0x23/imm32/hash -2310 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -2311 0f 84/jump-if-equal break/disp32 -2312 # if slice-equal?(word-slice, '<-') return true -2313 (slice-equal? %ecx "<-") -2314 3d/compare-eax-and 0/imm32 -2315 74/jump-if-equal loop/disp8 -2316 b8/copy-to-eax 1/imm32/true -2317 } -2318 $stmt-has-outputs:end: -2319 (rewind-stream *(ebp+8)) -2320 # . reclaim locals -2321 81 0/subop/add %esp 8/imm32 -2322 # . restore registers -2323 59/pop-to-ecx -2324 # . epilogue -2325 89/<- %esp 5/r32/ebp -2326 5d/pop-to-ebp -2327 c3/return -2328 -2329 lookup-var: # name: (address slice), vars : (address stack (handle var)) -> result/eax: (handle var) -2330 # . prologue -2331 55/push-ebp -2332 89/<- %ebp 4/r32/esp -2333 # var target/eax : (handle array byte) = slice-to-string(name) -2334 (slice-to-string Heap *(ebp+8)) # => eax -2335 # -2336 (lookup-var-helper %eax *(ebp+0xc)) # => eax -2337 # if (result == 0) abort -2338 3d/compare-eax-and 0/imm32 -2339 74/jump-if-equal $lookup-var:abort/disp8 -2340 $lookup-var:end: -2341 # . epilogue -2342 89/<- %esp 5/r32/ebp -2343 5d/pop-to-ebp -2344 c3/return -2345 -2346 $lookup-var:abort: -2347 (write-buffered Stderr "unknown variable '") -2348 (write-slice-buffered Stderr *(ebp+8)) -2349 (write-buffered Stderr "'\n") -2350 (flush Stderr) -2351 # . syscall(exit, 1) -2352 bb/copy-to-ebx 1/imm32 -2353 b8/copy-to-eax 1/imm32/exit -2354 cd/syscall 0x80/imm8 -2355 # never gets here -2356 -2357 lookup-var-helper: # name: (address array byte), vars : (address stack (handle var)) -> result/eax: (handle var) -2358 # pseudocode: -2359 # var curr : (address handle var) = &vars->data[vars->top - 4] -2360 # var min = vars->data -2361 # while curr >= min -2362 # var v : (handle var) = *curr -2363 # if v->name == name -2364 # return v -2365 # return 0 -2366 # -2367 # . prologue -2368 55/push-ebp -2369 89/<- %ebp 4/r32/esp -2370 # . save registers -2371 52/push-edx -2372 53/push-ebx -2373 56/push-esi -2374 # esi = vars -2375 8b/-> *(ebp+0xc) 6/r32/esi -2376 # ebx = vars->top -2377 8b/-> *esi 3/r32/ebx -2378 # if (vars->top > vars->length) abort -2379 3b/compare 0/r32/eax *(esi+4) -2380 0f 8f/jump-if-greater $lookup-var-helper:error1/disp32 -2381 # var min/edx : (address handle var) = vars->data -2382 8d/copy-address *(esi+8) 2/r32/edx -2383 # var curr/ebx : (address handle var) = &vars->data[vars->top - 4] -2384 81 5/subop/subtract %ebx 4/imm32 -2385 8d/copy-address *(esi+ebx+8) 3/r32/ebx -2386 { -2387 # if (curr < min) return 0 -2388 39/compare %ebx 2/r32/edx -2389 b8/copy-to-eax 0/imm32 -2390 0f 82/jump-if-lesser-unsigned break/disp32 -2391 # var v/eax : (handle var) = *curr -2392 8b/-> *ebx 0/r32/eax -2393 # if (v->name == name) return v -2394 (string-equal? *eax *(ebp+8)) # Var-name -2395 3d/compare-eax-and 0/imm32 -2396 8b/-> *ebx 0/r32/eax -2397 75/jump-if-not-equal break/disp8 -2398 # curr -= 4 -2399 81 5/subop/subtract %ebx 4/imm32 -2400 e9/jump loop/disp32 -2401 } -2402 $lookup-var-helper:end: -2403 # . restore registers -2404 5e/pop-to-esi -2405 5b/pop-to-ebx -2406 5a/pop-to-edx -2407 # . epilogue -2408 89/<- %esp 5/r32/ebp -2409 5d/pop-to-ebp -2410 c3/return -2411 -2412 $lookup-var-helper:error1: -2413 (write-buffered Stderr "malformed stack when looking up '") -2414 (write-slice-buffered Stderr *(ebp+8)) -2415 (write-buffered Stderr "'\n") -2416 (flush Stderr) -2417 # . syscall(exit, 1) -2418 bb/copy-to-ebx 1/imm32 -2419 b8/copy-to-eax 1/imm32/exit -2420 cd/syscall 0x80/imm8 -2421 # never gets here -2422 -2423 lookup-or-define-var: # name: (address slice), vars : (address stack (handle var)), fn : (handle function) -> result/eax: (handle var) -2424 # . prologue -2425 55/push-ebp -2426 89/<- %ebp 4/r32/esp -2427 # . save registers -2428 51/push-ecx -2429 # var target/ecx : (handle array byte) = slice-to-string(name) -2430 (slice-to-string Heap *(ebp+8)) # => eax -2431 89/<- %ecx 0/r32/eax -2432 # -2433 (lookup-var-helper *(ebp+8) *(ebp+0xc)) # => eax -2434 { -2435 # if (result != 0) return -2436 3d/compare-eax-and 0/imm32 -2437 75/jump-if-not-equal break/disp8 -2438 # if name is one of fn's outputs, return it -2439 { -2440 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax -2441 3d/compare-eax-and 0/imm32 -2442 # otherwise abort -2443 0f 84/jump-if-not-equal $lookup-var:abort/disp32 -2444 } -2445 } -2446 $lookup-or-define-var:end: -2447 # . restore registers -2448 59/pop-to-ecx -2449 # . epilogue -2450 89/<- %esp 5/r32/ebp -2451 5d/pop-to-ebp -2452 c3/return -2453 -2454 find-in-function-outputs: # fn : (handle function), name : (handle array byte) => result/eax : (handle var) -2455 # . prologue -2456 55/push-ebp -2457 89/<- %ebp 4/r32/esp -2458 # . save registers -2459 51/push-ecx -2460 # var curr/ecx : (handle list var) = fn->outputs -2461 8b/-> *(ebp+8) 1/r32/ecx -2462 8b/-> *(ecx+0xc) 1/r32/ecx -2463 # while curr != null -2464 { -2465 81 7/subop/compare %ecx 0/imm32 -2466 74/jump-if-equal break/disp8 -2467 # var v : (handle var) = *curr -2468 8b/-> *ecx 0/r32/eax # List-value -2469 # if (curr->name == name) return curr -2470 50/push-eax -2471 (string-equal? *eax *(ebp+0xc)) -2472 3d/compare-eax-and 0/imm32 -2473 58/pop-to-eax -2474 75/jump-if-not-equal $find-in-function-outputs:end/disp8 -2475 # curr = curr->next -2476 8b/-> *(ecx+4) 1/r32/ecx # List-next -2477 eb/jump loop/disp8 -2478 } -2479 b8/copy-to-eax 0/imm32 -2480 $find-in-function-outputs:end: -2481 # . restore registers -2482 59/pop-to-ecx -2483 # . epilogue -2484 89/<- %esp 5/r32/ebp -2485 5d/pop-to-ebp -2486 c3/return -2487 -2488 test-parse-mu-stmt: -2489 # 'increment n' -2490 # . prologue -2491 55/push-ebp -2492 89/<- %ebp 4/r32/esp -2493 # setup -2494 (clear-stream _test-input-stream) -2495 (write _test-input-stream "increment n\n") -2496 # var vars/ecx : (ref stack (address var) 4) -2497 81 5/subop/subtract %esp 0x10/imm32 -2498 68/push 0x10/imm32/length -2499 68/push 0/imm32/top +2140 51/push-ecx +2141 52/push-edx +2142 53/push-ebx +2143 57/push-edi +2144 # var line/ecx : (ref stream byte 512) +2145 81 5/subop/subtract %esp 0x200/imm32 +2146 68/push 0x200/imm32/length +2147 68/push 0/imm32/read +2148 68/push 0/imm32/write +2149 89/<- %ecx 4/r32/esp +2150 # var word-slice/edx : (ref slice) +2151 68/push 0/imm32/end +2152 68/push 0/imm32/start +2153 89/<- %edx 4/r32/esp +2154 # edi = result +2155 (allocate Heap *Stmt-size) # => eax +2156 (zero-out %eax *Stmt-size) +2157 89/<- %edi 0/r32/eax +2158 { # line loop +2159 $parse-mu-block:line-loop: +2160 # line = read-line-buffered(in) +2161 (clear-stream %ecx) +2162 (read-line-buffered *(ebp+8) %ecx) +2163 #? (write-buffered Stderr "line: ") +2164 #? (write-stream-data Stderr %ecx) +2165 #? (write-buffered Stderr Newline) +2166 #? (flush Stderr) +2167 # if (line->write == 0) break +2168 81 7/subop/compare *ecx 0/imm32 +2169 0f 84/jump-if-equal break/disp32 +2170 # word-slice = next-word(line) +2171 (next-word %ecx %edx) +2172 #? (write-buffered Stderr "word: ") +2173 #? (write-slice-buffered Stderr %edx) +2174 #? (write-buffered Stderr Newline) +2175 #? (flush Stderr) +2176 # if slice-empty?(word-slice) continue +2177 (slice-empty? %edx) +2178 3d/compare-eax-and 0/imm32 +2179 0f 85/jump-if-not-equal loop/disp32 +2180 # if (slice-starts-with?(word-slice, '#') continue +2181 # . eax = *word-slice->start +2182 8b/-> *edx 0/r32/eax +2183 8a/copy-byte *eax 0/r32/AL +2184 81 4/subop/and %eax 0xff/imm32 +2185 # . if (eax == '#') continue +2186 3d/compare-eax-and 0x23/imm32/hash +2187 0f 84/jump-if-equal loop/disp32 +2188 # if slice-equal?(word-slice, "{") +2189 { +2190 $parse-mu-block:check-for-block: +2191 (slice-equal? %edx "{") +2192 3d/compare-eax-and 0/imm32 +2193 74/jump-if-equal break/disp8 +2194 (check-no-tokens-left %ecx) +2195 # parse new block and append +2196 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2197 (append-to-block %edi %eax) +2198 e9/jump $parse-mu-block:line-loop/disp32 +2199 } +2200 # if slice-equal?(word-slice, "}") break +2201 $parse-mu-block:check-for-end: +2202 (slice-equal? %edx "}") +2203 3d/compare-eax-and 0/imm32 +2204 0f 85/jump-if-not-equal break/disp32 +2205 # if slice-ends-with?(word-slice, ":") parse named block and append +2206 { +2207 $parse-mu-block:check-for-named-block: +2208 # . eax = *word-slice->end +2209 8b/-> *(edx+4) 0/r32/eax +2210 8a/copy-byte *eax 0/r32/AL +2211 81 4/subop/and %eax 0xff/imm32 +2212 # . if (eax != ':') break +2213 3d/compare-eax-and 0x23/imm32/hash +2214 0f 85/jump-if-not-equal break/disp32 +2215 # +2216 (parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2217 (append-to-block %edi %eax) +2218 e9/jump $parse-mu-block:line-loop/disp32 +2219 } +2220 # if slice-equal?(word-slice, "var") +2221 { +2222 $parse-mu-block:check-for-var: +2223 (slice-equal? %edx "var") +2224 3d/compare-eax-and 0/imm32 +2225 74/jump-if-equal break/disp8 +2226 # +2227 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax +2228 (append-to-block %edi %eax) +2229 e9/jump $parse-mu-block:line-loop/disp32 +2230 } +2231 $parse-mu-block:regular-stmt: +2232 # otherwise +2233 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +2234 (append-to-block Heap %edi %eax) +2235 e9/jump loop/disp32 +2236 } # end line loop +2237 # return result +2238 89/<- %eax 7/r32/edi +2239 $parse-mu-block:end: +2240 # . reclaim locals +2241 81 0/subop/add %esp 0x214/imm32 +2242 # . restore registers +2243 5f/pop-to-edi +2244 5b/pop-to-ebx +2245 5a/pop-to-edx +2246 59/pop-to-ecx +2247 # . epilogue +2248 89/<- %esp 5/r32/ebp +2249 5d/pop-to-ebp +2250 c3/return +2251 +2252 $parse-mu-block:abort: +2253 # error("'{' or '}' should be on its own line, but got '") +2254 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +2255 (rewind-stream %ecx) +2256 (write-stream 2 %ecx) +2257 (write-buffered Stderr "'\n") +2258 (flush Stderr) +2259 # . syscall(exit, 1) +2260 bb/copy-to-ebx 1/imm32 +2261 b8/copy-to-eax 1/imm32/exit +2262 cd/syscall 0x80/imm8 +2263 # never gets here +2264 +2265 check-no-tokens-left: # line : (address stream byte) +2266 # . prologue +2267 55/push-ebp +2268 89/<- %ebp 4/r32/esp +2269 # . save registers +2270 50/push-eax +2271 51/push-ecx +2272 # var s/ecx : (ref slice) +2273 68/push 0/imm32/end +2274 68/push 0/imm32/start +2275 89/<- %ecx 4/r32/esp +2276 # +2277 (next-word *(ebp+8) %ecx) +2278 # if slice-empty?(s) return +2279 (slice-empty? %ecx) +2280 3d/compare-eax-and 0/imm32 +2281 75/jump-if-not-equal $check-no-tokens-left:end/disp8 +2282 # if (slice-starts-with?(s, '#') return +2283 # . eax = *s->start +2284 8b/-> *edx 0/r32/eax +2285 8a/copy-byte *eax 0/r32/AL +2286 81 4/subop/and %eax 0xff/imm32 +2287 # . if (eax == '#') continue +2288 3d/compare-eax-and 0x23/imm32/hash +2289 74/jump-if-equal $check-no-tokens-left:end/disp8 +2290 # abort +2291 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +2292 (rewind-stream %ecx) +2293 (write-stream 2 %ecx) +2294 (write-buffered Stderr "'\n") +2295 (flush Stderr) +2296 # . syscall(exit, 1) +2297 bb/copy-to-ebx 1/imm32 +2298 b8/copy-to-eax 1/imm32/exit +2299 cd/syscall 0x80/imm8 +2300 # never gets here +2301 $check-no-tokens-left:end: +2302 # . reclaim locals +2303 81 0/subop/add %esp 8/imm32 +2304 # . restore registers +2305 59/pop-to-ecx +2306 58/pop-to-eax +2307 # . epilogue +2308 89/<- %esp 5/r32/ebp +2309 5d/pop-to-ebp +2310 c3/return +2311 +2312 parse-mu-named-block: # name : (address slice), first-line : (address stream byte), in : (address buffered-file), vars : (address stack (handle var)) -> result/eax : (handle stmt) +2313 # pseudocode: +2314 # var line : (ref stream byte 512) +2315 # var word-slice : (ref slice) +2316 # result/eax = allocate(Heap, Stmt-size) +2317 # result->tag = 4/Named-block +2318 # result->name = name +2319 # assert(next-word(first-line) == "{") +2320 # assert(no-tokens-in(first-line)) +2321 # while true # line loop +2322 # clear-stream(line) +2323 # read-line-buffered(in, line) +2324 # if (line->write == 0) break # end of file +2325 # word-slice = next-word(line) +2326 # if slice-empty?(word-slice) # end of line +2327 # break +2328 # else if slice-equal?(word-slice, "{") +2329 # block = parse-mu-block(in, vars) +2330 # append-to-block(result, block) +2331 # else if slice-equal?(word-slice, "}") +2332 # break +2333 # else if slice-ends-with?(word-slice, ":") +2334 # named-block = parse-mu-named-block(word-slice, in, vars) +2335 # append-to-block(result, named-block) +2336 # else if slice-equal?(word-slice, "var") +2337 # var-def = parse-mu-var-def(line, vars) +2338 # append-to-block(result, var-def) +2339 # else +2340 # stmt = parse-mu-stmt(line, vars, fn) +2341 # append-to-block(result, stmt) +2342 # return result +2343 # +2344 # . prologue +2345 55/push-ebp +2346 89/<- %ebp 4/r32/esp +2347 # . save registers +2348 $parse-mu-named-block:end: +2349 # . reclaim locals +2350 # . restore registers +2351 # . epilogue +2352 89/<- %esp 5/r32/ebp +2353 5d/pop-to-ebp +2354 c3/return +2355 +2356 parse-mu-var-def: # line : (address stream byte), vars : (address stack (handle var)) -> result/eax : (handle stmt) +2357 # pseudocode: +2358 # +2359 # . prologue +2360 55/push-ebp +2361 89/<- %ebp 4/r32/esp +2362 # . save registers +2363 $parse-mu-var-def:end: +2364 # . reclaim locals +2365 # . restore registers +2366 # . epilogue +2367 89/<- %esp 5/r32/ebp +2368 5d/pop-to-ebp +2369 c3/return +2370 +2371 parse-mu-stmt: # line : (address stream byte), vars : (address stack (handle var)), fn : (handle function) -> result/eax : (handle stmt) +2372 # pseudocode: +2373 # var name : (ref slice) +2374 # result = allocate(Heap, Stmt-size) +2375 # if stmt-has-outputs?(line) +2376 # while true +2377 # name = next-word(line) +2378 # if (name == '<-') break +2379 # assert(is-identifier?(name)) +2380 # var v : (handle var) = lookup-or-define-var(name, vars) +2381 # result->outputs = append(result->outputs, v) +2382 # result->name = slice-to-string(next-word(line)) +2383 # while true +2384 # name = next-word-or-string(line) +2385 # v = lookup-var-or-literal(name) +2386 # result->inouts = append(result->inouts, v) +2387 # +2388 # . prologue +2389 55/push-ebp +2390 89/<- %ebp 4/r32/esp +2391 # . save registers +2392 51/push-ecx +2393 57/push-edi +2394 # var name/ecx : (ref slice) +2395 68/push 0/imm32/end +2396 68/push 0/imm32/start +2397 89/<- %ecx 4/r32/esp +2398 # result/edi : (handle stmt) +2399 (allocate Heap *Stmt-size) # => eax +2400 (zero-out %eax *Stmt-size) +2401 89/<- %edi 0/r32/eax +2402 # result->tag = 1/stmt +2403 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag +2404 { +2405 (stmt-has-outputs? *(ebp+8)) +2406 3d/compare-eax-and 0/imm32 +2407 0f 84/jump-if-equal break/disp32 +2408 { +2409 $parse-mu-stmt:read-outputs: +2410 # name = next-word(line) +2411 (next-word *(ebp+8) %ecx) +2412 # if slice-empty?(word-slice) break +2413 (slice-empty? %ecx) +2414 3d/compare-eax-and 0/imm32 +2415 0f 85/jump-if-not-equal break/disp32 +2416 # if (name == "<-") break +2417 (slice-equal? %ecx "<-") +2418 3d/compare-eax-and 0/imm32 +2419 75/jump-if-not-equal break/disp8 +2420 # assert(is-identifier?(name)) +2421 (is-identifier? %ecx) +2422 3d/compare-eax-and 0/imm32 +2423 0f 84/jump-if-equal $parse-mu-stmt:abort/disp32 +2424 # +2425 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +2426 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax +2427 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs +2428 e9/jump loop/disp32 +2429 } +2430 } +2431 $parse-mu-stmt:read-operation: +2432 (next-word *(ebp+8) %ecx) +2433 (slice-to-string Heap %ecx) +2434 89/<- *(edi+4) 0/r32/eax # Stmt1-operation +2435 { +2436 $parse-mu-stmt:read-inouts: +2437 # name = next-word-or-string(line) +2438 (next-word-or-string *(ebp+8) %ecx) +2439 # if slice-empty?(word-slice) break +2440 (slice-empty? %ecx) +2441 3d/compare-eax-and 0/imm32 +2442 0f 85/jump-if-not-equal break/disp32 +2443 # if (name == "<-") abort +2444 (slice-equal? %ecx "<-") +2445 3d/compare-eax-and 0/imm32 +2446 0f 85/jump-if-not-equal $parse-mu-stmt:abort2/disp32 +2447 # +2448 (lookup-var-or-literal %ecx *(ebp+0xc)) # => eax +2449 (append-list Heap %eax *(edi+8)) # Stmt1-inouts => eax +2450 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts +2451 e9/jump loop/disp32 +2452 } +2453 $parse-mu-stmt:end: +2454 # return result +2455 89/<- %eax 7/r32/edi +2456 # . reclaim locals +2457 81 0/subop/add %esp 8/imm32 +2458 # . restore registers +2459 5f/pop-to-edi +2460 59/pop-to-ecx +2461 # . epilogue +2462 89/<- %esp 5/r32/ebp +2463 5d/pop-to-ebp +2464 c3/return +2465 +2466 $parse-mu-stmt:abort: +2467 # error("invalid identifier '" name "'\n") +2468 (write-buffered Stderr "invalid identifier '") +2469 (write-slice-buffered Stderr %ecx) +2470 (write-buffered Stderr "'\n") +2471 (flush Stderr) +2472 # . syscall(exit, 1) +2473 bb/copy-to-ebx 1/imm32 +2474 b8/copy-to-eax 1/imm32/exit +2475 cd/syscall 0x80/imm8 +2476 # never gets here +2477 +2478 $parse-mu-stmt:abort2: +2479 # error("invalid statement '" line "'\n") +2480 (rewind-stream *(ebp+8)) +2481 (write-buffered Stderr "invalid identifier '") +2482 (write-stream Stderr *(ebp+8)) +2483 (write-buffered Stderr "'\n") +2484 (flush Stderr) +2485 # . syscall(exit, 1) +2486 bb/copy-to-ebx 1/imm32 +2487 b8/copy-to-eax 1/imm32/exit +2488 cd/syscall 0x80/imm8 +2489 # never gets here +2490 +2491 stmt-has-outputs?: # line : (address stream byte) -> result/eax : boolean +2492 # . prologue +2493 55/push-ebp +2494 89/<- %ebp 4/r32/esp +2495 # . save registers +2496 51/push-ecx +2497 # var word-slice/ecx : (ref slice) +2498 68/push 0/imm32/end +2499 68/push 0/imm32/start 2500 89/<- %ecx 4/r32/esp -2501 (clear-stack %ecx) -2502 # var v/edx : (ref var) -2503 81 5/subop/subtract %esp 0x14/imm32 # Var-size -2504 89/<- %edx 4/r32/esp -2505 (zero-out %edx 0x14) -2506 # v->name = "n" -2507 c7 0/subop/copy *edx "n"/imm32 # Var-name -2508 # -2509 (push %ecx %edx) -2510 # convert -2511 (parse-mu-stmt _test-input-stream %ecx) -2512 # check result -2513 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation -2514 # edx : (handle list var) = result->inouts -2515 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts -2516 # ebx : (handle var) = result->inouts->value -2517 8b/-> *edx 3/r32/ebx # List-value -2518 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name -2519 # . epilogue -2520 89/<- %esp 5/r32/ebp -2521 5d/pop-to-ebp -2522 c3/return -2523 -2524 new-function: # ad: allocation-descriptor, name: string, subx-name: string, inouts: (handle list var), outputs: (handle list var), body: (handle block), next: (handle function) -> result/eax: (handle function) -2525 # . prologue -2526 55/push-ebp -2527 89/<- %ebp 4/r32/esp -2528 # . save registers -2529 51/push-ecx -2530 # -2531 (allocate *(ebp+8) *Function-size) # => eax -2532 8b/-> *(ebp+0xc) 1/r32/ecx -2533 89/<- *eax 1/r32/ecx # Function-name -2534 8b/-> *(ebp+0x10) 1/r32/ecx -2535 89/<- *(eax+4) 1/r32/ecx # Function-subx-name -2536 8b/-> *(ebp+0x14) 1/r32/ecx -2537 89/<- *(eax+8) 1/r32/ecx # Function-inouts -2538 8b/-> *(ebp+0x18) 1/r32/ecx -2539 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs -2540 8b/-> *(ebp+0x1c) 1/r32/ecx -2541 89/<- *(eax+0x10) 1/r32/ecx # Function-body -2542 8b/-> *(ebp+0x20) 1/r32/ecx -2543 89/<- *(eax+0x14) 1/r32/ecx # Function-next -2544 $new-function:end: -2545 # . restore registers -2546 59/pop-to-ecx -2547 # . epilogue -2548 89/<- %esp 5/r32/ebp -2549 5d/pop-to-ebp -2550 c3/return -2551 -2552 new-var: # ad: allocation-descriptor, name: string, type: int, block: int, stack-offset: int, register: string -> result/eax: (handle var) -2553 # . prologue -2554 55/push-ebp -2555 89/<- %ebp 4/r32/esp -2556 # . save registers -2557 51/push-ecx -2558 # -2559 (allocate *(ebp+8) *Var-size) # => eax -2560 8b/-> *(ebp+0xc) 1/r32/ecx -2561 89/<- *eax 1/r32/ecx # Var-name -2562 8b/-> *(ebp+0x10) 1/r32/ecx -2563 89/<- *(eax+4) 1/r32/ecx # Var-type -2564 8b/-> *(ebp+0x14) 1/r32/ecx -2565 89/<- *(eax+8) 1/r32/ecx # Var-block -2566 8b/-> *(ebp+0x18) 1/r32/ecx -2567 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset -2568 8b/-> *(ebp+0x1c) 1/r32/ecx -2569 89/<- *(eax+0x10) 1/r32/ecx # Var-register -2570 $new-var:end: -2571 # . restore registers -2572 59/pop-to-ecx -2573 # . epilogue -2574 89/<- %esp 5/r32/ebp -2575 5d/pop-to-ebp -2576 c3/return -2577 -2578 new-block: # ad: allocation-descriptor, data: (handle list statement) -> result/eax: (handle statement) -2579 # . prologue -2580 55/push-ebp -2581 89/<- %ebp 4/r32/esp -2582 # . save registers -2583 51/push-ecx -2584 # -2585 (allocate *(ebp+8) *Stmt-size) # => eax -2586 (zero-out %eax *Stmt-size) -2587 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag -2588 8b/-> *(ebp+0xc) 1/r32/ecx -2589 89/<- *(eax+4) 1/r32/ecx # Block-statements -2590 $new-block:end: -2591 # . restore registers -2592 59/pop-to-ecx -2593 # . epilogue -2594 89/<- %esp 5/r32/ebp -2595 5d/pop-to-ebp -2596 c3/return -2597 -2598 new-stmt: # ad: allocation-descriptor, operation: string, inouts: (handle list var), outputs: (handle list var) -> result/eax: (handle statement) -2599 # . prologue -2600 55/push-ebp -2601 89/<- %ebp 4/r32/esp -2602 # . save registers -2603 51/push-ecx -2604 # -2605 (allocate *(ebp+8) *Stmt-size) # => eax -2606 (zero-out %eax *Stmt-size) -2607 c7 0/subop/copy *eax 1/imm32/tag/regular-stmt # Stmt-tag -2608 8b/-> *(ebp+0xc) 1/r32/ecx -2609 89/<- *(eax+4) 1/r32/ecx # Stmt1-operation -2610 8b/-> *(ebp+0x10) 1/r32/ecx -2611 89/<- *(eax+8) 1/r32/ecx # Stmt1-inouts -2612 8b/-> *(ebp+0x14) 1/r32/ecx -2613 89/<- *(eax+0xc) 1/r32/ecx # Stmt1-outputs -2614 $new-stmt:end: -2615 # . restore registers -2616 59/pop-to-ecx -2617 # . epilogue -2618 89/<- %esp 5/r32/ebp -2619 5d/pop-to-ebp -2620 c3/return -2621 -2622 new-vardef: # ad: allocation-descriptor, name: string, type: int -> result/eax: (handle statement) -2623 # . prologue -2624 55/push-ebp -2625 89/<- %ebp 4/r32/esp -2626 # . save registers -2627 51/push-ecx -2628 # -2629 (allocate *(ebp+8) *Stmt-size) # => eax -2630 (zero-out %eax *Stmt-size) -2631 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag -2632 8b/-> *(ebp+0xc) 1/r32/ecx -2633 89/<- *(eax+4) 1/r32/ecx # Vardef-name -2634 8b/-> *(ebp+0x10) 1/r32/ecx -2635 89/<- *(eax+8) 1/r32/ecx # Vardef-type -2636 $new-vardef:end: -2637 # . restore registers -2638 59/pop-to-ecx -2639 # . epilogue -2640 89/<- %esp 5/r32/ebp -2641 5d/pop-to-ebp -2642 c3/return -2643 -2644 new-regvardef: # ad: allocation-descriptor, name: string, type: int, register: string -> result/eax: (handle statement) -2645 # . prologue -2646 55/push-ebp -2647 89/<- %ebp 4/r32/esp -2648 # . save registers -2649 51/push-ecx -2650 # -2651 (allocate *(ebp+8) *Stmt-size) # => eax -2652 (zero-out %eax *Stmt-size) -2653 c7 0/subop/copy *eax 3/imm32/tag/var-in-register -2654 8b/-> *(ebp+0xc) 1/r32/ecx -2655 89/<- *(eax+4) 1/r32/ecx # Regvardef-name -2656 8b/-> *(ebp+0x10) 1/r32/ecx -2657 89/<- *(eax+8) 1/r32/ecx # Regvardef-type -2658 8b/-> *(ebp+0x14) 1/r32/ecx -2659 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-register -2660 $new-regvardef:end: -2661 # . restore registers -2662 59/pop-to-ecx -2663 # . epilogue -2664 89/<- %esp 5/r32/ebp -2665 5d/pop-to-ebp -2666 c3/return -2667 -2668 new-named-block: # ad: allocation-descriptor, name: string, data: (handle list statement) -> result/eax: (handle statement) -2669 # . prologue -2670 55/push-ebp -2671 89/<- %ebp 4/r32/esp -2672 # . save registers -2673 51/push-ecx -2674 # -2675 (allocate *(ebp+8) *Stmt-size) # => eax -2676 (zero-out %eax *Stmt-size) -2677 c7 0/subop/copy *eax 4/imm32/tag/named-block -2678 8b/-> *(ebp+0xc) 1/r32/ecx -2679 89/<- *(eax+4) 1/r32/ecx # Named-block-name -2680 8b/-> *(ebp+0x10) 1/r32/ecx -2681 89/<- *(eax+8) 1/r32/ecx # Named-block-statements -2682 $new-named-block:end: -2683 # . restore registers -2684 59/pop-to-ecx -2685 # . epilogue -2686 89/<- %esp 5/r32/ebp -2687 5d/pop-to-ebp -2688 c3/return -2689 -2690 new-list: # ad: allocation-descriptor, value: _type, next: (handle list _type) -> result/eax : (handle list _type) -2691 # . prologue -2692 55/push-ebp -2693 89/<- %ebp 4/r32/esp -2694 # . save registers -2695 51/push-ecx -2696 # -2697 (allocate *(ebp+8) *List-size) # => eax -2698 8b/-> *(ebp+0xc) 1/r32/ecx -2699 89/<- *eax 1/r32/ecx # List-value -2700 8b/-> *(ebp+0x10) 1/r32/ecx -2701 89/<- *(eax+4) 1/r32/ecx # List-next -2702 $new-list:end: -2703 # . restore registers -2704 59/pop-to-ecx -2705 # . epilogue -2706 89/<- %esp 5/r32/ebp -2707 5d/pop-to-ebp -2708 c3/return -2709 -2710 append-list: # ad: allocation-descriptor, value: _type, list: (handle list _type) -> result/eax : (handle list _type) -2711 # . prologue -2712 55/push-ebp -2713 89/<- %ebp 4/r32/esp -2714 # . save registers -2715 51/push-ecx -2716 # -2717 (allocate *(ebp+8) *List-size) # => eax -2718 8b/-> *(ebp+0xc) 1/r32/ecx -2719 89/<- *eax 1/r32/ecx # List-value -2720 # if (list == null) return result -2721 81 7/subop/compare *(ebp+0x10) 0/imm32 -2722 74/jump-if-equal $new-list:end/disp8 -2723 # otherwise append -2724 # var curr/ecx = list -2725 8b/-> *(ebp+0x10) 1/r32/ecx -2726 # while (curr->next != null) curr = curr->next -2727 { -2728 81 7/subop/compare *(ecx+4) 0/imm32 # List-next -2729 74/jump-if-equal break/disp8 -2730 # curr = curr->next -2731 8b/-> *(ecx+4) 1/r32/ecx -2732 eb/jump loop/disp8 -2733 } -2734 # curr->next = result -2735 89/<- *(ecx+4) 0/r32/eax -2736 # return list -2737 8b/-> *(ebp+0x10) 0/r32/eax -2738 $append-list:end: -2739 # . restore registers -2740 59/pop-to-ecx -2741 # . epilogue -2742 89/<- %esp 5/r32/ebp -2743 5d/pop-to-ebp -2744 c3/return -2745 -2746 append-to-block: # ad: allocation-descriptor, block: (handle block), x: (handle stmt) -2747 # . prologue -2748 55/push-ebp -2749 89/<- %ebp 4/r32/esp -2750 # . save registers -2751 56/push-esi -2752 # esi = block -2753 8b/-> *(ebp+0xc) 6/r32/esi -2754 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements -2755 89/<- *(esi+4) 0/r32/eax # Block-statements -2756 $append-to-block:end: -2757 # . restore registers -2758 5e/pop-to-esi -2759 # . epilogue -2760 89/<- %esp 5/r32/ebp -2761 5d/pop-to-ebp -2762 c3/return -2763 -2764 ####################################################### -2765 # Type-checking -2766 ####################################################### -2767 -2768 check-mu-types: -2769 # . prologue -2770 55/push-ebp -2771 89/<- %ebp 4/r32/esp -2772 # -2773 $check-mu-types:end: -2774 # . epilogue -2775 89/<- %esp 5/r32/ebp -2776 5d/pop-to-ebp -2777 c3/return -2778 -2779 size-of: # n : (address var) -2780 # . prologue -2781 55/push-ebp -2782 89/<- %ebp 4/r32/esp -2783 # hard-coded since we only support 'int' types for now -2784 b8/copy-to-eax 4/imm32 -2785 $size-of:end: -2786 # . epilogue -2787 89/<- %esp 5/r32/ebp -2788 5d/pop-to-ebp -2789 c3/return -2790 -2791 ####################################################### -2792 # Code-generation -2793 ####################################################### -2794 -2795 emit-subx: # out : (address buffered-file) -2796 # . prologue -2797 55/push-ebp -2798 89/<- %ebp 4/r32/esp -2799 # . save registers -2800 50/push-eax -2801 51/push-ecx -2802 57/push-edi -2803 # edi = out -2804 8b/-> *(ebp+8) 7/r32/edi -2805 # var curr/ecx : (handle function) = Program -2806 8b/-> *Program 1/r32/ecx -2807 { -2808 # if (curr == null) break -2809 81 7/subop/compare %ecx 0/imm32 -2810 0f 84/jump-if-equal break/disp32 -2811 (emit-subx-function %edi %ecx) -2812 # curr = curr->next -2813 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -2814 e9/jump loop/disp32 -2815 } -2816 $emit-subx:end: -2817 # . restore registers -2818 5f/pop-to-edi -2819 59/pop-to-ecx -2820 58/pop-to-eax -2821 # . epilogue -2822 89/<- %esp 5/r32/ebp -2823 5d/pop-to-ebp -2824 c3/return -2825 -2826 emit-subx-function: # out : (address buffered-file), f : (handle function) -2827 # . prologue -2828 55/push-ebp -2829 89/<- %ebp 4/r32/esp -2830 # . save registers -2831 50/push-eax -2832 51/push-ecx -2833 57/push-edi -2834 # edi = out -2835 8b/-> *(ebp+8) 7/r32/edi -2836 # ecx = f -2837 8b/-> *(ebp+0xc) 1/r32/ecx -2838 # -2839 (write-buffered %edi *ecx) -2840 (write-buffered %edi ":\n") -2841 (emit-subx-prologue %edi) -2842 (emit-subx-block %edi *(ecx+0x10)) # Function-body -2843 (emit-subx-epilogue %edi) -2844 $emit-subx-function:end: -2845 # . restore registers -2846 5f/pop-to-edi -2847 59/pop-to-ecx -2848 58/pop-to-eax -2849 # . epilogue -2850 89/<- %esp 5/r32/ebp -2851 5d/pop-to-ebp -2852 c3/return -2853 -2854 emit-subx-block: # out : (address buffered-file), block : (handle block) -2855 # . prologue -2856 55/push-ebp -2857 89/<- %ebp 4/r32/esp -2858 # curr/esi : (handle list statement) = block->statements -2859 8b/-> *(ebp+0xc) 6/r32/esi -2860 8b/-> *(esi+4) 6/r32/esi # Block-statements -2861 # -2862 { -2863 $emit-subx-block:check-empty: -2864 81 7/subop/compare %esi 0/imm32 -2865 0f 84/jump-if-equal break/disp32 -2866 (write-buffered *(ebp+8) "{\n") -2867 { -2868 $emit-subx-block:stmt: -2869 81 7/subop/compare %esi 0/imm32 -2870 74/jump-if-equal break/disp8 -2871 (emit-subx-statement *(ebp+8) *esi Primitives 0) -2872 (write-buffered *(ebp+8) Newline) -2873 8b/-> *(esi+4) 6/r32/esi # List-next -2874 eb/jump loop/disp8 -2875 } -2876 (write-buffered *(ebp+8) "}\n") -2877 } -2878 $emit-subx-block:end: -2879 # . epilogue -2880 89/<- %esp 5/r32/ebp -2881 5d/pop-to-ebp -2882 c3/return -2883 -2884 emit-subx-statement: # out : (address buffered-file), stmt : (handle statement), primitives : (handle primitive), functions : (handle function) -2885 # . prologue -2886 55/push-ebp -2887 89/<- %ebp 4/r32/esp -2888 # . save registers -2889 50/push-eax -2890 51/push-ecx -2891 # if stmt matches a primitive, emit it -2892 { -2893 $emit-subx-statement:primitive: -2894 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax -2895 3d/compare-eax-and 0/imm32 -2896 74/jump-if-equal break/disp8 -2897 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -2898 e9/jump $emit-subx-statement:end/disp32 -2899 } -2900 # else if stmt matches a function, emit a call to it -2901 { -2902 $emit-subx-statement:call: -2903 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax -2904 3d/compare-eax-and 0/imm32 -2905 74/jump-if-equal break/disp8 -2906 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -2907 e9/jump $emit-subx-statement:end/disp32 -2908 } -2909 # else abort -2910 e9/jump $emit-subx-statement:abort/disp32 -2911 $emit-subx-statement:end: -2912 # . restore registers -2913 59/pop-to-ecx -2914 58/pop-to-eax -2915 # . epilogue -2916 89/<- %esp 5/r32/ebp -2917 5d/pop-to-ebp -2918 c3/return -2919 -2920 $emit-subx-statement:abort: -2921 # error("couldn't translate '" stmt "'\n") -2922 (write-buffered Stderr "couldn't translate '") -2923 #? (emit-string Stderr *(ebp+0xc)) # TODO -2924 (write-buffered Stderr "'\n") -2925 (flush Stderr) -2926 # . syscall(exit, 1) -2927 bb/copy-to-ebx 1/imm32 -2928 b8/copy-to-eax 1/imm32/exit -2929 cd/syscall 0x80/imm8 -2930 # never gets here -2931 -2932 # Primitives supported -2933 # For each operation, put variants with hard-coded registers before flexible ones. -2934 == data -2935 Primitives: -2936 # - increment/decrement -2937 _Primitive-inc-eax: -2938 # var/eax <- increment => 40/increment-eax -2939 "increment"/imm32/name -2940 0/imm32/no-inouts -2941 Single-int-var-in-eax/imm32/outputs -2942 "40/increment-eax"/imm32/subx-name -2943 0/imm32/no-rm32 -2944 0/imm32/no-r32 -2945 0/imm32/no-imm32 -2946 0/imm32/output-is-write-only -2947 _Primitive-inc-ecx/imm32/next -2948 _Primitive-inc-ecx: -2949 # var/ecx <- increment => 41/increment-ecx -2950 "increment"/imm32/name -2951 0/imm32/no-inouts -2952 Single-int-var-in-ecx/imm32/outputs -2953 "41/increment-ecx"/imm32/subx-name -2954 0/imm32/no-rm32 -2955 0/imm32/no-r32 -2956 0/imm32/no-imm32 -2957 0/imm32/output-is-write-only -2958 _Primitive-inc-edx/imm32/next -2959 _Primitive-inc-edx: -2960 # var/edx <- increment => 42/increment-edx -2961 "increment"/imm32/name -2962 0/imm32/no-inouts -2963 Single-int-var-in-edx/imm32/outputs -2964 "42/increment-edx"/imm32/subx-name -2965 0/imm32/no-rm32 -2966 0/imm32/no-r32 -2967 0/imm32/no-imm32 -2968 0/imm32/output-is-write-only -2969 _Primitive-inc-ebx/imm32/next -2970 _Primitive-inc-ebx: -2971 # var/ebx <- increment => 43/increment-ebx -2972 "increment"/imm32/name -2973 0/imm32/no-inouts -2974 Single-int-var-in-ebx/imm32/outputs -2975 "43/increment-ebx"/imm32/subx-name -2976 0/imm32/no-rm32 -2977 0/imm32/no-r32 -2978 0/imm32/no-imm32 -2979 0/imm32/output-is-write-only -2980 _Primitive-inc-esi/imm32/next -2981 _Primitive-inc-esi: -2982 # var/esi <- increment => 46/increment-esi -2983 "increment"/imm32/name -2984 0/imm32/no-inouts -2985 Single-int-var-in-esi/imm32/outputs -2986 "46/increment-esi"/imm32/subx-name -2987 0/imm32/no-rm32 -2988 0/imm32/no-r32 -2989 0/imm32/no-imm32 -2990 0/imm32/output-is-write-only -2991 _Primitive-inc-edi/imm32/next -2992 _Primitive-inc-edi: -2993 # var/edi <- increment => 47/increment-edi -2994 "increment"/imm32/name -2995 0/imm32/no-inouts -2996 Single-int-var-in-edi/imm32/outputs -2997 "47/increment-edi"/imm32/subx-name -2998 0/imm32/no-rm32 -2999 0/imm32/no-r32 -3000 0/imm32/no-imm32 -3001 0/imm32/output-is-write-only -3002 _Primitive-dec-eax/imm32/next -3003 _Primitive-dec-eax: -3004 # var/eax <- decrement => 48/decrement-eax -3005 "decrement"/imm32/name -3006 0/imm32/no-inouts -3007 Single-int-var-in-eax/imm32/outputs -3008 "48/decrement-eax"/imm32/subx-name -3009 0/imm32/no-rm32 -3010 0/imm32/no-r32 -3011 0/imm32/no-imm32 -3012 0/imm32/output-is-write-only -3013 _Primitive-dec-ecx/imm32/next -3014 _Primitive-dec-ecx: -3015 # var/ecx <- decrement => 49/decrement-ecx -3016 "decrement"/imm32/name -3017 0/imm32/no-inouts -3018 Single-int-var-in-ecx/imm32/outputs -3019 "49/decrement-ecx"/imm32/subx-name -3020 0/imm32/no-rm32 -3021 0/imm32/no-r32 -3022 0/imm32/no-imm32 -3023 0/imm32/output-is-write-only -3024 _Primitive-dec-edx/imm32/next -3025 _Primitive-dec-edx: -3026 # var/edx <- decrement => 4a/decrement-edx -3027 "decrement"/imm32/name -3028 0/imm32/no-inouts -3029 Single-int-var-in-edx/imm32/outputs -3030 "4a/decrement-edx"/imm32/subx-name -3031 0/imm32/no-rm32 -3032 0/imm32/no-r32 -3033 0/imm32/no-imm32 -3034 0/imm32/output-is-write-only -3035 _Primitive-dec-ebx/imm32/next -3036 _Primitive-dec-ebx: -3037 # var/ebx <- decrement => 4b/decrement-ebx -3038 "decrement"/imm32/name -3039 0/imm32/no-inouts -3040 Single-int-var-in-ebx/imm32/outputs -3041 "4b/decrement-ebx"/imm32/subx-name -3042 0/imm32/no-rm32 -3043 0/imm32/no-r32 -3044 0/imm32/no-imm32 -3045 0/imm32/output-is-write-only -3046 _Primitive-dec-esi/imm32/next -3047 _Primitive-dec-esi: -3048 # var/esi <- decrement => 4e/decrement-esi -3049 "decrement"/imm32/name -3050 0/imm32/no-inouts -3051 Single-int-var-in-esi/imm32/outputs -3052 "4e/decrement-esi"/imm32/subx-name -3053 0/imm32/no-rm32 -3054 0/imm32/no-r32 -3055 0/imm32/no-imm32 -3056 0/imm32/output-is-write-only -3057 _Primitive-dec-edi/imm32/next -3058 _Primitive-dec-edi: -3059 # var/edi <- decrement => 4f/decrement-edi -3060 "decrement"/imm32/name -3061 0/imm32/no-inouts -3062 Single-int-var-in-edi/imm32/outputs -3063 "4f/decrement-edi"/imm32/subx-name -3064 0/imm32/no-rm32 -3065 0/imm32/no-r32 -3066 0/imm32/no-imm32 -3067 0/imm32/output-is-write-only -3068 _Primitive-inc-mem/imm32/next -3069 _Primitive-inc-mem: -3070 # increment var => ff 0/subop/increment *(ebp+__) -3071 "increment"/imm32/name -3072 Single-int-var-on-stack/imm32/inouts -3073 0/imm32/no-outputs -3074 "ff 0/subop/increment"/imm32/subx-name -3075 1/imm32/rm32-is-first-inout -3076 0/imm32/no-r32 -3077 0/imm32/no-imm32 -3078 0/imm32/output-is-write-only -3079 _Primitive-inc-reg/imm32/next -3080 _Primitive-inc-reg: -3081 # var/reg <- increment => ff 0/subop/increment %__ -3082 "increment"/imm32/name -3083 0/imm32/no-inouts -3084 Single-int-var-in-some-register/imm32/outputs -3085 "ff 0/subop/increment"/imm32/subx-name -3086 3/imm32/rm32-is-first-output -3087 0/imm32/no-r32 -3088 0/imm32/no-imm32 -3089 0/imm32/output-is-write-only -3090 _Primitive-dec-mem/imm32/next -3091 _Primitive-dec-mem: -3092 # decrement var => ff 1/subop/decrement *(ebp+__) -3093 "decrement"/imm32/name -3094 Single-int-var-on-stack/imm32/inouts -3095 0/imm32/no-outputs -3096 "ff 1/subop/decrement"/imm32/subx-name -3097 1/imm32/rm32-is-first-inout -3098 0/imm32/no-r32 -3099 0/imm32/no-imm32 -3100 0/imm32/output-is-write-only -3101 _Primitive-dec-reg/imm32/next -3102 _Primitive-dec-reg: -3103 # var/reg <- decrement => ff 1/subop/decrement %__ -3104 "decrement"/imm32/name -3105 0/imm32/no-inouts -3106 Single-int-var-in-some-register/imm32/outputs -3107 "ff 1/subop/decrement"/imm32/subx-name -3108 3/imm32/rm32-is-first-output -3109 0/imm32/no-r32 -3110 0/imm32/no-imm32 -3111 0/imm32/output-is-write-only -3112 _Primitive-add-to-eax/imm32/next -3113 # - add -3114 _Primitive-add-to-eax: -3115 # var/eax <- add lit => 05/add-to-eax lit/imm32 -3116 "add"/imm32/name -3117 Single-lit-var/imm32/inouts -3118 Single-int-var-in-eax/imm32/outputs -3119 "05/add-to-eax"/imm32/subx-name -3120 0/imm32/no-rm32 -3121 0/imm32/no-r32 -3122 1/imm32/imm32-is-first-inout -3123 0/imm32/output-is-write-only -3124 _Primitive-add-reg-to-reg/imm32/next -3125 _Primitive-add-reg-to-reg: -3126 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 -3127 "add"/imm32/name -3128 Single-int-var-in-some-register/imm32/inouts -3129 Single-int-var-in-some-register/imm32/outputs -3130 "01/add-to"/imm32/subx-name -3131 3/imm32/rm32-is-first-output -3132 1/imm32/r32-is-first-inout -3133 0/imm32/no-imm32 -3134 0/imm32/output-is-write-only -3135 _Primitive-add-reg-to-mem/imm32/next -3136 _Primitive-add-reg-to-mem: -3137 # add-to var1 var2/reg => 01/add-to var1 var2/r32 -3138 "add-to"/imm32/name -3139 Int-var-and-second-int-var-in-some-register/imm32/inouts -3140 0/imm32/outputs -3141 "01/add-to"/imm32/subx-name -3142 1/imm32/rm32-is-first-inout -3143 2/imm32/r32-is-second-inout -3144 0/imm32/no-imm32 -3145 0/imm32/output-is-write-only -3146 _Primitive-add-mem-to-reg/imm32/next -3147 _Primitive-add-mem-to-reg: -3148 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 -3149 "add"/imm32/name -3150 Single-int-var-on-stack/imm32/inouts -3151 Single-int-var-in-some-register/imm32/outputs -3152 "03/add"/imm32/subx-name -3153 1/imm32/rm32-is-first-inout -3154 3/imm32/r32-is-first-output -3155 0/imm32/no-imm32 -3156 0/imm32/output-is-write-only -3157 _Primitive-add-lit-to-reg/imm32/next -3158 _Primitive-add-lit-to-reg: -3159 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 -3160 "add"/imm32/name -3161 Single-lit-var/imm32/inouts -3162 Single-int-var-in-some-register/imm32/outputs -3163 "81 0/subop/add"/imm32/subx-name -3164 3/imm32/rm32-is-first-output -3165 0/imm32/no-r32 -3166 1/imm32/imm32-is-first-inout -3167 0/imm32/output-is-write-only -3168 _Primitive-add-lit-to-mem/imm32/next -3169 _Primitive-add-lit-to-mem: -3170 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 -3171 "add-to"/imm32/name -3172 Int-var-and-literal/imm32/inouts -3173 0/imm32/outputs -3174 "81 0/subop/add"/imm32/subx-name -3175 1/imm32/rm32-is-first-inout -3176 0/imm32/no-r32 -3177 2/imm32/imm32-is-first-inout -3178 0/imm32/output-is-write-only -3179 _Primitive-subtract-from-eax/imm32/next -3180 # - subtract -3181 _Primitive-subtract-from-eax: -3182 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 -3183 "subtract"/imm32/name -3184 Single-lit-var/imm32/inouts -3185 Single-int-var-in-eax/imm32/outputs -3186 "2d/subtract-from-eax"/imm32/subx-name -3187 0/imm32/no-rm32 -3188 0/imm32/no-r32 -3189 1/imm32/imm32-is-first-inout -3190 0/imm32/output-is-write-only -3191 _Primitive-subtract-reg-from-reg/imm32/next -3192 _Primitive-subtract-reg-from-reg: -3193 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 -3194 "subtract"/imm32/name -3195 Single-int-var-in-some-register/imm32/inouts -3196 Single-int-var-in-some-register/imm32/outputs -3197 "29/subtract-from"/imm32/subx-name -3198 3/imm32/rm32-is-first-output -3199 1/imm32/r32-is-first-inout -3200 0/imm32/no-imm32 -3201 0/imm32/output-is-write-only -3202 _Primitive-subtract-reg-from-mem/imm32/next -3203 _Primitive-subtract-reg-from-mem: -3204 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 -3205 "subtract-from"/imm32/name -3206 Int-var-and-second-int-var-in-some-register/imm32/inouts -3207 0/imm32/outputs -3208 "29/subtract-from"/imm32/subx-name -3209 1/imm32/rm32-is-first-inout -3210 2/imm32/r32-is-second-inout -3211 0/imm32/no-imm32 -3212 0/imm32/output-is-write-only -3213 _Primitive-subtract-mem-from-reg/imm32/next -3214 _Primitive-subtract-mem-from-reg: -3215 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 -3216 "subtract"/imm32/name -3217 Single-int-var-on-stack/imm32/inouts -3218 Single-int-var-in-some-register/imm32/outputs -3219 "2b/subtract"/imm32/subx-name -3220 1/imm32/rm32-is-first-inout -3221 3/imm32/r32-is-first-output -3222 0/imm32/no-imm32 -3223 0/imm32/output-is-write-only -3224 _Primitive-subtract-lit-from-reg/imm32/next -3225 _Primitive-subtract-lit-from-reg: -3226 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 -3227 "subtract"/imm32/name -3228 Single-lit-var/imm32/inouts -3229 Single-int-var-in-some-register/imm32/outputs -3230 "81 5/subop/subtract"/imm32/subx-name -3231 3/imm32/rm32-is-first-output -3232 0/imm32/no-r32 -3233 1/imm32/imm32-is-first-inout -3234 0/imm32/output-is-write-only -3235 _Primitive-subtract-lit-from-mem/imm32/next -3236 _Primitive-subtract-lit-from-mem: -3237 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 -3238 "subtract-from"/imm32/name -3239 Int-var-and-literal/imm32/inouts -3240 0/imm32/outputs -3241 "81 5/subop/subtract"/imm32/subx-name -3242 1/imm32/rm32-is-first-inout +2501 # result = false +2502 b8/copy-to-eax 0/imm32/false +2503 (rewind-stream *(ebp+8)) +2504 { +2505 (next-word-or-string *(ebp+8) %ecx) +2506 # if slice-empty?(word-slice) break +2507 (slice-empty? %ecx) +2508 3d/compare-eax-and 0/imm32 +2509 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +2510 0f 85/jump-if-not-equal break/disp32 +2511 # if slice-starts-with?(word-slice, '#') break +2512 # . eax = *word-slice->start +2513 8b/-> *ecx 0/r32/eax +2514 8a/copy-byte *eax 0/r32/AL +2515 81 4/subop/and %eax 0xff/imm32 +2516 # . if (eax == '#') break +2517 3d/compare-eax-and 0x23/imm32/hash +2518 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +2519 0f 84/jump-if-equal break/disp32 +2520 # if slice-equal?(word-slice, '<-') return true +2521 (slice-equal? %ecx "<-") +2522 3d/compare-eax-and 0/imm32 +2523 74/jump-if-equal loop/disp8 +2524 b8/copy-to-eax 1/imm32/true +2525 } +2526 $stmt-has-outputs:end: +2527 (rewind-stream *(ebp+8)) +2528 # . reclaim locals +2529 81 0/subop/add %esp 8/imm32 +2530 # . restore registers +2531 59/pop-to-ecx +2532 # . epilogue +2533 89/<- %esp 5/r32/ebp +2534 5d/pop-to-ebp +2535 c3/return +2536 +2537 # if 'name' starts with a digit, create a new literal var for it +2538 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found +2539 lookup-var-or-literal: # name: (address slice), vars : (address stack (handle var)) -> result/eax: (handle var) +2540 # . prologue +2541 55/push-ebp +2542 89/<- %ebp 4/r32/esp +2543 # . save registers +2544 51/push-ecx +2545 56/push-esi +2546 # esi = name +2547 8b/-> *(ebp+8) 6/r32/esi +2548 # if slice-empty?(name) abort +2549 (slice-empty? %esi) # => eax +2550 3d/compare-eax-and 0/imm32 +2551 0f 85/jump-if-not-equal $lookup-var-or-literal:abort/disp32 +2552 # var ecx : byte = *name->start +2553 8b/-> *esi 1/r32/ecx +2554 8a/copy-byte *ecx 1/r32/CL +2555 81 4/subop/and %ecx 0xff/imm32 +2556 # if is-decimal-digit?(*name->start) return new var(name) +2557 (is-decimal-digit? %ecx) # => eax +2558 81 7/subop/compare %eax 0/imm32 +2559 { +2560 74/jump-if-equal break/disp8 +2561 (new-literal-integer Heap %esi) # => eax +2562 } +2563 # otherwise return lookup-var(name, vars) +2564 { +2565 75/jump-if-not-equal break/disp8 +2566 (lookup-var %esi *(ebp+0xc)) # => eax +2567 } +2568 $lookup-var-or-literal:end: +2569 # . restore registers +2570 5e/pop-to-esi +2571 59/pop-to-ecx +2572 # . epilogue +2573 89/<- %esp 5/r32/ebp +2574 5d/pop-to-ebp +2575 c3/return +2576 +2577 $lookup-var-or-literal:abort: +2578 (write-buffered Stderr "empty variable!") +2579 (flush Stderr) +2580 # . syscall(exit, 1) +2581 bb/copy-to-ebx 1/imm32 +2582 b8/copy-to-eax 1/imm32/exit +2583 cd/syscall 0x80/imm8 +2584 # never gets here +2585 +2586 # return first 'name' from the top (back) of 'vars' and abort if not found +2587 lookup-var: # name: (address slice), vars : (address stack (handle var)) -> result/eax: (handle var) +2588 # . prologue +2589 55/push-ebp +2590 89/<- %ebp 4/r32/esp +2591 # var target/eax : (handle array byte) = slice-to-string(name) +2592 (slice-to-string Heap *(ebp+8)) # => eax +2593 # +2594 (lookup-var-helper %eax *(ebp+0xc)) # => eax +2595 # if (result == 0) abort +2596 3d/compare-eax-and 0/imm32 +2597 74/jump-if-equal $lookup-var:abort/disp8 +2598 $lookup-var:end: +2599 # . epilogue +2600 89/<- %esp 5/r32/ebp +2601 5d/pop-to-ebp +2602 c3/return +2603 +2604 $lookup-var:abort: +2605 (write-buffered Stderr "unknown variable '") +2606 (write-slice-buffered Stderr *(ebp+8)) +2607 (write-buffered Stderr "'\n") +2608 (flush Stderr) +2609 # . syscall(exit, 1) +2610 bb/copy-to-ebx 1/imm32 +2611 b8/copy-to-eax 1/imm32/exit +2612 cd/syscall 0x80/imm8 +2613 # never gets here +2614 +2615 # return first 'name' from the top (back) of 'vars', and 0/null if not found +2616 lookup-var-helper: # name: (address array byte), vars : (address stack (handle var)) -> result/eax: (handle var) +2617 # pseudocode: +2618 # var curr : (address handle var) = &vars->data[vars->top - 4] +2619 # var min = vars->data +2620 # while curr >= min +2621 # var v : (handle var) = *curr +2622 # if v->name == name +2623 # return v +2624 # return 0 +2625 # +2626 # . prologue +2627 55/push-ebp +2628 89/<- %ebp 4/r32/esp +2629 # . save registers +2630 52/push-edx +2631 53/push-ebx +2632 56/push-esi +2633 # esi = vars +2634 8b/-> *(ebp+0xc) 6/r32/esi +2635 # ebx = vars->top +2636 8b/-> *esi 3/r32/ebx +2637 # if (vars->top > vars->length) abort +2638 3b/compare 0/r32/eax *(esi+4) +2639 0f 8f/jump-if-greater $lookup-var-helper:error1/disp32 +2640 # var min/edx : (address handle var) = vars->data +2641 8d/copy-address *(esi+8) 2/r32/edx +2642 # var curr/ebx : (address handle var) = &vars->data[vars->top - 4] +2643 81 5/subop/subtract %ebx 4/imm32 +2644 8d/copy-address *(esi+ebx+8) 3/r32/ebx +2645 { +2646 # if (curr < min) return 0 +2647 39/compare %ebx 2/r32/edx +2648 b8/copy-to-eax 0/imm32 +2649 0f 82/jump-if-lesser-unsigned break/disp32 +2650 # var v/eax : (handle var) = *curr +2651 8b/-> *ebx 0/r32/eax +2652 # if (v->name == name) return v +2653 (string-equal? *eax *(ebp+8)) # Var-name +2654 3d/compare-eax-and 0/imm32 +2655 8b/-> *ebx 0/r32/eax +2656 75/jump-if-not-equal break/disp8 +2657 # curr -= 4 +2658 81 5/subop/subtract %ebx 4/imm32 +2659 e9/jump loop/disp32 +2660 } +2661 $lookup-var-helper:end: +2662 # . restore registers +2663 5e/pop-to-esi +2664 5b/pop-to-ebx +2665 5a/pop-to-edx +2666 # . epilogue +2667 89/<- %esp 5/r32/ebp +2668 5d/pop-to-ebp +2669 c3/return +2670 +2671 $lookup-var-helper:error1: +2672 (write-buffered Stderr "malformed stack when looking up '") +2673 (write-slice-buffered Stderr *(ebp+8)) +2674 (write-buffered Stderr "'\n") +2675 (flush Stderr) +2676 # . syscall(exit, 1) +2677 bb/copy-to-ebx 1/imm32 +2678 b8/copy-to-eax 1/imm32/exit +2679 cd/syscall 0x80/imm8 +2680 # never gets here +2681 +2682 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found +2683 lookup-or-define-var: # name: (address slice), vars : (address stack (handle var)), fn : (handle function) -> result/eax: (handle var) +2684 # . prologue +2685 55/push-ebp +2686 89/<- %ebp 4/r32/esp +2687 # . save registers +2688 51/push-ecx +2689 # var target/ecx : (handle array byte) = slice-to-string(name) +2690 (slice-to-string Heap *(ebp+8)) # => eax +2691 89/<- %ecx 0/r32/eax +2692 # +2693 (lookup-var-helper *(ebp+8) *(ebp+0xc)) # => eax +2694 { +2695 # if (result != 0) return +2696 3d/compare-eax-and 0/imm32 +2697 75/jump-if-not-equal break/disp8 +2698 # if name is one of fn's outputs, return it +2699 { +2700 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax +2701 3d/compare-eax-and 0/imm32 +2702 # otherwise abort +2703 0f 84/jump-if-not-equal $lookup-var:abort/disp32 +2704 } +2705 } +2706 $lookup-or-define-var:end: +2707 # . restore registers +2708 59/pop-to-ecx +2709 # . epilogue +2710 89/<- %esp 5/r32/ebp +2711 5d/pop-to-ebp +2712 c3/return +2713 +2714 find-in-function-outputs: # fn : (handle function), name : (handle array byte) => result/eax : (handle var) +2715 # . prologue +2716 55/push-ebp +2717 89/<- %ebp 4/r32/esp +2718 # . save registers +2719 51/push-ecx +2720 # var curr/ecx : (handle list var) = fn->outputs +2721 8b/-> *(ebp+8) 1/r32/ecx +2722 8b/-> *(ecx+0xc) 1/r32/ecx +2723 # while curr != null +2724 { +2725 81 7/subop/compare %ecx 0/imm32 +2726 74/jump-if-equal break/disp8 +2727 # var v : (handle var) = *curr +2728 8b/-> *ecx 0/r32/eax # List-value +2729 # if (curr->name == name) return curr +2730 50/push-eax +2731 (string-equal? *eax *(ebp+0xc)) +2732 3d/compare-eax-and 0/imm32 +2733 58/pop-to-eax +2734 75/jump-if-not-equal $find-in-function-outputs:end/disp8 +2735 # curr = curr->next +2736 8b/-> *(ecx+4) 1/r32/ecx # List-next +2737 eb/jump loop/disp8 +2738 } +2739 b8/copy-to-eax 0/imm32 +2740 $find-in-function-outputs:end: +2741 # . restore registers +2742 59/pop-to-ecx +2743 # . epilogue +2744 89/<- %esp 5/r32/ebp +2745 5d/pop-to-ebp +2746 c3/return +2747 +2748 test-parse-mu-stmt: +2749 # 'increment n' +2750 # . prologue +2751 55/push-ebp +2752 89/<- %ebp 4/r32/esp +2753 # setup +2754 (clear-stream _test-input-stream) +2755 (write _test-input-stream "increment n\n") +2756 # var vars/ecx : (ref stack (address var) 4) +2757 81 5/subop/subtract %esp 0x10/imm32 +2758 68/push 0x10/imm32/length +2759 68/push 0/imm32/top +2760 89/<- %ecx 4/r32/esp +2761 (clear-stack %ecx) +2762 # var v/edx : (ref var) +2763 81 5/subop/subtract %esp 0x14/imm32 # Var-size +2764 89/<- %edx 4/r32/esp +2765 (zero-out %edx 0x14) +2766 # v->name = "n" +2767 c7 0/subop/copy *edx "n"/imm32 # Var-name +2768 # +2769 (push %ecx %edx) +2770 # convert +2771 (parse-mu-stmt _test-input-stream %ecx) +2772 # check result +2773 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation +2774 # edx : (handle list var) = result->inouts +2775 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts +2776 # ebx : (handle var) = result->inouts->value +2777 8b/-> *edx 3/r32/ebx # List-value +2778 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name +2779 # . epilogue +2780 89/<- %esp 5/r32/ebp +2781 5d/pop-to-ebp +2782 c3/return +2783 +2784 new-function: # ad: (address allocation-descriptor), name: (address array byte), subx-name: (address array byte), inouts: (handle list var), outputs: (handle list var), body: (handle block), next: (handle function) -> result/eax: (handle function) +2785 # . prologue +2786 55/push-ebp +2787 89/<- %ebp 4/r32/esp +2788 # . save registers +2789 51/push-ecx +2790 # +2791 (allocate *(ebp+8) *Function-size) # => eax +2792 8b/-> *(ebp+0xc) 1/r32/ecx +2793 89/<- *eax 1/r32/ecx # Function-name +2794 8b/-> *(ebp+0x10) 1/r32/ecx +2795 89/<- *(eax+4) 1/r32/ecx # Function-subx-name +2796 8b/-> *(ebp+0x14) 1/r32/ecx +2797 89/<- *(eax+8) 1/r32/ecx # Function-inouts +2798 8b/-> *(ebp+0x18) 1/r32/ecx +2799 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs +2800 8b/-> *(ebp+0x1c) 1/r32/ecx +2801 89/<- *(eax+0x10) 1/r32/ecx # Function-body +2802 8b/-> *(ebp+0x20) 1/r32/ecx +2803 89/<- *(eax+0x14) 1/r32/ecx # Function-next +2804 $new-function:end: +2805 # . restore registers +2806 59/pop-to-ecx +2807 # . epilogue +2808 89/<- %esp 5/r32/ebp +2809 5d/pop-to-ebp +2810 c3/return +2811 +2812 new-var: # ad: (address allocation-descriptor), name: (address array byte), type: int, block: int, stack-offset: int, register: (address array byte) -> result/eax: (handle var) +2813 # . prologue +2814 55/push-ebp +2815 89/<- %ebp 4/r32/esp +2816 # . save registers +2817 51/push-ecx +2818 # +2819 (allocate *(ebp+8) *Var-size) # => eax +2820 8b/-> *(ebp+0xc) 1/r32/ecx +2821 89/<- *eax 1/r32/ecx # Var-name +2822 8b/-> *(ebp+0x10) 1/r32/ecx +2823 89/<- *(eax+4) 1/r32/ecx # Var-type +2824 8b/-> *(ebp+0x14) 1/r32/ecx +2825 89/<- *(eax+8) 1/r32/ecx # Var-block +2826 8b/-> *(ebp+0x18) 1/r32/ecx +2827 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset +2828 8b/-> *(ebp+0x1c) 1/r32/ecx +2829 89/<- *(eax+0x10) 1/r32/ecx # Var-register +2830 $new-var:end: +2831 # . restore registers +2832 59/pop-to-ecx +2833 # . epilogue +2834 89/<- %esp 5/r32/ebp +2835 5d/pop-to-ebp +2836 c3/return +2837 +2838 new-literal-integer: # ad: (address allocation-descriptor), name: (address slice) -> result/eax: (handle var) +2839 # . prologue +2840 55/push-ebp +2841 89/<- %ebp 4/r32/esp +2842 # . save registers +2843 51/push-ecx +2844 # if (!is-hex-int?(name)) abort +2845 (is-hex-int? *(ebp+0xc)) # => eax +2846 3d/compare-eax-and 0/imm32 +2847 0f 84/jump-if-equal $new-literal-integer:abort/disp32 +2848 # var s/ecx : (address array byte) +2849 (slice-to-string Heap *(ebp+0xc)) # => eax +2850 89/<- %ecx 0/r32/eax +2851 # +2852 (allocate *(ebp+8) *Var-size) # => eax +2853 89/<- *eax 1/r32/ecx # Var-name +2854 c7 0/subop/copy *(eax+4) 0/imm32/tag/literal # Var-type +2855 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block +2856 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset +2857 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register +2858 $new-literal-integer:end: +2859 # . restore registers +2860 59/pop-to-ecx +2861 # . epilogue +2862 89/<- %esp 5/r32/ebp +2863 5d/pop-to-ebp +2864 c3/return +2865 +2866 $new-literal-integer:abort: +2867 (write-buffered Stderr "variable cannot begin with a digit '") +2868 (write-slice-buffered Stderr *(ebp+0xc)) +2869 (write-buffered Stderr "'\n") +2870 (flush Stderr) +2871 # . syscall(exit, 1) +2872 bb/copy-to-ebx 1/imm32 +2873 b8/copy-to-eax 1/imm32/exit +2874 cd/syscall 0x80/imm8 +2875 # never gets here +2876 +2877 new-block: # ad: (address allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) +2878 # . prologue +2879 55/push-ebp +2880 89/<- %ebp 4/r32/esp +2881 # . save registers +2882 51/push-ecx +2883 # +2884 (allocate *(ebp+8) *Stmt-size) # => eax +2885 (zero-out %eax *Stmt-size) +2886 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag +2887 8b/-> *(ebp+0xc) 1/r32/ecx +2888 89/<- *(eax+4) 1/r32/ecx # Block-statements +2889 $new-block:end: +2890 # . restore registers +2891 59/pop-to-ecx +2892 # . epilogue +2893 89/<- %esp 5/r32/ebp +2894 5d/pop-to-ebp +2895 c3/return +2896 +2897 new-stmt: # ad: (address allocation-descriptor), operation: (address array byte), inouts: (handle list var), outputs: (handle list var) -> result/eax: (handle statement) +2898 # . prologue +2899 55/push-ebp +2900 89/<- %ebp 4/r32/esp +2901 # . save registers +2902 51/push-ecx +2903 # +2904 (allocate *(ebp+8) *Stmt-size) # => eax +2905 (zero-out %eax *Stmt-size) +2906 c7 0/subop/copy *eax 1/imm32/tag/regular-stmt # Stmt-tag +2907 8b/-> *(ebp+0xc) 1/r32/ecx +2908 89/<- *(eax+4) 1/r32/ecx # Stmt1-operation +2909 8b/-> *(ebp+0x10) 1/r32/ecx +2910 89/<- *(eax+8) 1/r32/ecx # Stmt1-inouts +2911 8b/-> *(ebp+0x14) 1/r32/ecx +2912 89/<- *(eax+0xc) 1/r32/ecx # Stmt1-outputs +2913 $new-stmt:end: +2914 # . restore registers +2915 59/pop-to-ecx +2916 # . epilogue +2917 89/<- %esp 5/r32/ebp +2918 5d/pop-to-ebp +2919 c3/return +2920 +2921 new-vardef: # ad: (address allocation-descriptor), name: (address array byte), type: int -> result/eax: (handle statement) +2922 # . prologue +2923 55/push-ebp +2924 89/<- %ebp 4/r32/esp +2925 # . save registers +2926 51/push-ecx +2927 # +2928 (allocate *(ebp+8) *Stmt-size) # => eax +2929 (zero-out %eax *Stmt-size) +2930 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag +2931 8b/-> *(ebp+0xc) 1/r32/ecx +2932 89/<- *(eax+4) 1/r32/ecx # Vardef-name +2933 8b/-> *(ebp+0x10) 1/r32/ecx +2934 89/<- *(eax+8) 1/r32/ecx # Vardef-type +2935 $new-vardef:end: +2936 # . restore registers +2937 59/pop-to-ecx +2938 # . epilogue +2939 89/<- %esp 5/r32/ebp +2940 5d/pop-to-ebp +2941 c3/return +2942 +2943 new-regvardef: # ad: (address allocation-descriptor), name: (address array byte), type: int, register: (address array byte) -> result/eax: (handle statement) +2944 # . prologue +2945 55/push-ebp +2946 89/<- %ebp 4/r32/esp +2947 # . save registers +2948 51/push-ecx +2949 # +2950 (allocate *(ebp+8) *Stmt-size) # => eax +2951 (zero-out %eax *Stmt-size) +2952 c7 0/subop/copy *eax 3/imm32/tag/var-in-register +2953 8b/-> *(ebp+0xc) 1/r32/ecx +2954 89/<- *(eax+4) 1/r32/ecx # Regvardef-name +2955 8b/-> *(ebp+0x10) 1/r32/ecx +2956 89/<- *(eax+8) 1/r32/ecx # Regvardef-type +2957 8b/-> *(ebp+0x14) 1/r32/ecx +2958 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-register +2959 $new-regvardef:end: +2960 # . restore registers +2961 59/pop-to-ecx +2962 # . epilogue +2963 89/<- %esp 5/r32/ebp +2964 5d/pop-to-ebp +2965 c3/return +2966 +2967 new-named-block: # ad: (address allocation-descriptor), name: (address array byte), data: (handle list statement) -> result/eax: (handle statement) +2968 # . prologue +2969 55/push-ebp +2970 89/<- %ebp 4/r32/esp +2971 # . save registers +2972 51/push-ecx +2973 # +2974 (allocate *(ebp+8) *Stmt-size) # => eax +2975 (zero-out %eax *Stmt-size) +2976 c7 0/subop/copy *eax 4/imm32/tag/named-block +2977 8b/-> *(ebp+0xc) 1/r32/ecx +2978 89/<- *(eax+4) 1/r32/ecx # Named-block-name +2979 8b/-> *(ebp+0x10) 1/r32/ecx +2980 89/<- *(eax+8) 1/r32/ecx # Named-block-statements +2981 $new-named-block:end: +2982 # . restore registers +2983 59/pop-to-ecx +2984 # . epilogue +2985 89/<- %esp 5/r32/ebp +2986 5d/pop-to-ebp +2987 c3/return +2988 +2989 new-list: # ad: (address allocation-descriptor), value: _type, next: (handle list _type) -> result/eax : (handle list _type) +2990 # . prologue +2991 55/push-ebp +2992 89/<- %ebp 4/r32/esp +2993 # . save registers +2994 51/push-ecx +2995 # +2996 (allocate *(ebp+8) *List-size) # => eax +2997 8b/-> *(ebp+0xc) 1/r32/ecx +2998 89/<- *eax 1/r32/ecx # List-value +2999 8b/-> *(ebp+0x10) 1/r32/ecx +3000 89/<- *(eax+4) 1/r32/ecx # List-next +3001 $new-list:end: +3002 # . restore registers +3003 59/pop-to-ecx +3004 # . epilogue +3005 89/<- %esp 5/r32/ebp +3006 5d/pop-to-ebp +3007 c3/return +3008 +3009 append-list: # ad: (address allocation-descriptor), value: _type, list: (handle list _type) -> result/eax : (handle list _type) +3010 # . prologue +3011 55/push-ebp +3012 89/<- %ebp 4/r32/esp +3013 # . save registers +3014 51/push-ecx +3015 # +3016 (allocate *(ebp+8) *List-size) # => eax +3017 8b/-> *(ebp+0xc) 1/r32/ecx +3018 89/<- *eax 1/r32/ecx # List-value +3019 # if (list == null) return result +3020 81 7/subop/compare *(ebp+0x10) 0/imm32 +3021 74/jump-if-equal $new-list:end/disp8 +3022 # otherwise append +3023 # var curr/ecx = list +3024 8b/-> *(ebp+0x10) 1/r32/ecx +3025 # while (curr->next != null) curr = curr->next +3026 { +3027 81 7/subop/compare *(ecx+4) 0/imm32 # List-next +3028 74/jump-if-equal break/disp8 +3029 # curr = curr->next +3030 8b/-> *(ecx+4) 1/r32/ecx +3031 eb/jump loop/disp8 +3032 } +3033 # curr->next = result +3034 89/<- *(ecx+4) 0/r32/eax +3035 # return list +3036 8b/-> *(ebp+0x10) 0/r32/eax +3037 $append-list:end: +3038 # . restore registers +3039 59/pop-to-ecx +3040 # . epilogue +3041 89/<- %esp 5/r32/ebp +3042 5d/pop-to-ebp +3043 c3/return +3044 +3045 append-to-block: # ad: (address allocation-descriptor), block: (handle block), x: (handle stmt) +3046 # . prologue +3047 55/push-ebp +3048 89/<- %ebp 4/r32/esp +3049 # . save registers +3050 56/push-esi +3051 # esi = block +3052 8b/-> *(ebp+0xc) 6/r32/esi +3053 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements +3054 89/<- *(esi+4) 0/r32/eax # Block-statements +3055 $append-to-block:end: +3056 # . restore registers +3057 5e/pop-to-esi +3058 # . epilogue +3059 89/<- %esp 5/r32/ebp +3060 5d/pop-to-ebp +3061 c3/return +3062 +3063 ####################################################### +3064 # Type-checking +3065 ####################################################### +3066 +3067 check-mu-types: +3068 # . prologue +3069 55/push-ebp +3070 89/<- %ebp 4/r32/esp +3071 # +3072 $check-mu-types:end: +3073 # . epilogue +3074 89/<- %esp 5/r32/ebp +3075 5d/pop-to-ebp +3076 c3/return +3077 +3078 size-of: # n : (address var) +3079 # . prologue +3080 55/push-ebp +3081 89/<- %ebp 4/r32/esp +3082 # hard-coded since we only support 'int' types for now +3083 b8/copy-to-eax 4/imm32 +3084 $size-of:end: +3085 # . epilogue +3086 89/<- %esp 5/r32/ebp +3087 5d/pop-to-ebp +3088 c3/return +3089 +3090 ####################################################### +3091 # Code-generation +3092 ####################################################### +3093 +3094 emit-subx: # out : (address buffered-file) +3095 # . prologue +3096 55/push-ebp +3097 89/<- %ebp 4/r32/esp +3098 # . save registers +3099 50/push-eax +3100 51/push-ecx +3101 57/push-edi +3102 # edi = out +3103 8b/-> *(ebp+8) 7/r32/edi +3104 # var curr/ecx : (handle function) = Program +3105 8b/-> *Program 1/r32/ecx +3106 { +3107 # if (curr == null) break +3108 81 7/subop/compare %ecx 0/imm32 +3109 0f 84/jump-if-equal break/disp32 +3110 (emit-subx-function %edi %ecx) +3111 # curr = curr->next +3112 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +3113 e9/jump loop/disp32 +3114 } +3115 $emit-subx:end: +3116 # . restore registers +3117 5f/pop-to-edi +3118 59/pop-to-ecx +3119 58/pop-to-eax +3120 # . epilogue +3121 89/<- %esp 5/r32/ebp +3122 5d/pop-to-ebp +3123 c3/return +3124 +3125 emit-subx-function: # out : (address buffered-file), f : (handle function) +3126 # . prologue +3127 55/push-ebp +3128 89/<- %ebp 4/r32/esp +3129 # . save registers +3130 50/push-eax +3131 51/push-ecx +3132 57/push-edi +3133 # edi = out +3134 8b/-> *(ebp+8) 7/r32/edi +3135 # ecx = f +3136 8b/-> *(ebp+0xc) 1/r32/ecx +3137 # +3138 (write-buffered %edi *ecx) +3139 (write-buffered %edi ":\n") +3140 (emit-subx-prologue %edi) +3141 (emit-subx-block %edi *(ecx+0x10)) # Function-body +3142 (emit-subx-epilogue %edi) +3143 $emit-subx-function:end: +3144 # . restore registers +3145 5f/pop-to-edi +3146 59/pop-to-ecx +3147 58/pop-to-eax +3148 # . epilogue +3149 89/<- %esp 5/r32/ebp +3150 5d/pop-to-ebp +3151 c3/return +3152 +3153 emit-subx-block: # out : (address buffered-file), block : (handle block) +3154 # . prologue +3155 55/push-ebp +3156 89/<- %ebp 4/r32/esp +3157 # curr/esi : (handle list statement) = block->statements +3158 8b/-> *(ebp+0xc) 6/r32/esi +3159 8b/-> *(esi+4) 6/r32/esi # Block-statements +3160 # +3161 { +3162 $emit-subx-block:check-empty: +3163 81 7/subop/compare %esi 0/imm32 +3164 0f 84/jump-if-equal break/disp32 +3165 (write-buffered *(ebp+8) "{\n") +3166 { +3167 $emit-subx-block:stmt: +3168 81 7/subop/compare %esi 0/imm32 +3169 74/jump-if-equal break/disp8 +3170 (emit-subx-statement *(ebp+8) *esi Primitives *Program) +3171 (write-buffered *(ebp+8) Newline) +3172 8b/-> *(esi+4) 6/r32/esi # List-next +3173 eb/jump loop/disp8 +3174 } +3175 (write-buffered *(ebp+8) "}\n") +3176 } +3177 $emit-subx-block:end: +3178 # . epilogue +3179 89/<- %esp 5/r32/ebp +3180 5d/pop-to-ebp +3181 c3/return +3182 +3183 emit-subx-statement: # out : (address buffered-file), stmt : (handle statement), primitives : (handle primitive), functions : (handle function) +3184 # . prologue +3185 55/push-ebp +3186 89/<- %ebp 4/r32/esp +3187 # . save registers +3188 50/push-eax +3189 51/push-ecx +3190 # if stmt matches a primitive, emit it +3191 { +3192 $emit-subx-statement:primitive: +3193 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax +3194 3d/compare-eax-and 0/imm32 +3195 74/jump-if-equal break/disp8 +3196 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +3197 e9/jump $emit-subx-statement:end/disp32 +3198 } +3199 # else if stmt matches a function, emit a call to it +3200 { +3201 $emit-subx-statement:call: +3202 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax +3203 3d/compare-eax-and 0/imm32 +3204 74/jump-if-equal break/disp8 +3205 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +3206 e9/jump $emit-subx-statement:end/disp32 +3207 } +3208 # else abort +3209 e9/jump $emit-subx-statement:abort/disp32 +3210 $emit-subx-statement:end: +3211 # . restore registers +3212 59/pop-to-ecx +3213 58/pop-to-eax +3214 # . epilogue +3215 89/<- %esp 5/r32/ebp +3216 5d/pop-to-ebp +3217 c3/return +3218 +3219 $emit-subx-statement:abort: +3220 # error("couldn't translate '" stmt "'\n") +3221 (write-buffered Stderr "couldn't translate '") +3222 #? (emit-string Stderr *(ebp+0xc)) # TODO +3223 (write-buffered Stderr "'\n") +3224 (flush Stderr) +3225 # . syscall(exit, 1) +3226 bb/copy-to-ebx 1/imm32 +3227 b8/copy-to-eax 1/imm32/exit +3228 cd/syscall 0x80/imm8 +3229 # never gets here +3230 +3231 # Primitives supported +3232 # For each operation, put variants with hard-coded registers before flexible ones. +3233 == data +3234 Primitives: +3235 # - increment/decrement +3236 _Primitive-inc-eax: +3237 # var/eax <- increment => 40/increment-eax +3238 "increment"/imm32/name +3239 0/imm32/no-inouts +3240 Single-int-var-in-eax/imm32/outputs +3241 "40/increment-eax"/imm32/subx-name +3242 0/imm32/no-rm32 3243 0/imm32/no-r32 -3244 2/imm32/imm32-is-first-inout +3244 0/imm32/no-imm32 3245 0/imm32/output-is-write-only -3246 _Primitive-and-with-eax/imm32/next -3247 # - and -3248 _Primitive-and-with-eax: -3249 # var/eax <- and lit => 25/and-with-eax lit/imm32 -3250 "and"/imm32/name -3251 Single-lit-var/imm32/inouts -3252 Single-int-var-in-eax/imm32/outputs -3253 "25/and-with-eax"/imm32/subx-name -3254 0/imm32/no-rm32 -3255 0/imm32/no-r32 -3256 1/imm32/imm32-is-first-inout -3257 0/imm32/output-is-write-only -3258 _Primitive-and-reg-with-reg/imm32/next -3259 _Primitive-and-reg-with-reg: -3260 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 -3261 "and"/imm32/name -3262 Single-int-var-in-some-register/imm32/inouts -3263 Single-int-var-in-some-register/imm32/outputs -3264 "21/and-with"/imm32/subx-name -3265 3/imm32/rm32-is-first-output -3266 1/imm32/r32-is-first-inout -3267 0/imm32/no-imm32 -3268 0/imm32/output-is-write-only -3269 _Primitive-and-reg-with-mem/imm32/next -3270 _Primitive-and-reg-with-mem: -3271 # and-with var1 var2/reg => 21/and-with var1 var2/r32 -3272 "and-with"/imm32/name -3273 Int-var-and-second-int-var-in-some-register/imm32/inouts -3274 0/imm32/outputs -3275 "21/and-with"/imm32/subx-name -3276 1/imm32/rm32-is-first-inout -3277 2/imm32/r32-is-second-inout -3278 0/imm32/no-imm32 -3279 0/imm32/output-is-write-only -3280 _Primitive-and-mem-with-reg/imm32/next -3281 _Primitive-and-mem-with-reg: -3282 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 -3283 "and"/imm32/name -3284 Single-int-var-on-stack/imm32/inouts -3285 Single-int-var-in-some-register/imm32/outputs -3286 "23/and"/imm32/subx-name -3287 1/imm32/rm32-is-first-inout -3288 3/imm32/r32-is-first-output -3289 0/imm32/no-imm32 -3290 0/imm32/output-is-write-only -3291 _Primitive-and-lit-with-reg/imm32/next -3292 _Primitive-and-lit-with-reg: -3293 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 -3294 "and"/imm32/name -3295 Single-lit-var/imm32/inouts -3296 Single-int-var-in-some-register/imm32/outputs -3297 "81 4/subop/and"/imm32/subx-name -3298 3/imm32/rm32-is-first-output -3299 0/imm32/no-r32 -3300 1/imm32/imm32-is-first-inout -3301 0/imm32/output-is-write-only -3302 _Primitive-and-lit-with-mem/imm32/next -3303 _Primitive-and-lit-with-mem: -3304 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 -3305 "and-with"/imm32/name -3306 Int-var-and-literal/imm32/inouts -3307 0/imm32/outputs -3308 "81 4/subop/and"/imm32/subx-name -3309 1/imm32/rm32-is-first-inout -3310 0/imm32/no-r32 -3311 2/imm32/imm32-is-first-inout -3312 0/imm32/output-is-write-only -3313 _Primitive-or-with-eax/imm32/next -3314 # - or -3315 _Primitive-or-with-eax: -3316 # var/eax <- or lit => 0d/or-with-eax lit/imm32 -3317 "or"/imm32/name -3318 Single-lit-var/imm32/inouts -3319 Single-int-var-in-eax/imm32/outputs -3320 "0d/or-with-eax"/imm32/subx-name -3321 0/imm32/no-rm32 -3322 0/imm32/no-r32 -3323 1/imm32/imm32-is-first-inout -3324 0/imm32/output-is-write-only -3325 _Primitive-or-reg-with-reg/imm32/next -3326 _Primitive-or-reg-with-reg: -3327 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 -3328 "or"/imm32/name -3329 Single-int-var-in-some-register/imm32/inouts -3330 Single-int-var-in-some-register/imm32/outputs -3331 "09/or-with"/imm32/subx-name -3332 3/imm32/rm32-is-first-output -3333 1/imm32/r32-is-first-inout -3334 0/imm32/no-imm32 -3335 0/imm32/output-is-write-only -3336 _Primitive-or-reg-with-mem/imm32/next -3337 _Primitive-or-reg-with-mem: -3338 # or-with var1 var2/reg => 09/or-with var1 var2/r32 -3339 "or-with"/imm32/name -3340 Int-var-and-second-int-var-in-some-register/imm32/inouts -3341 0/imm32/outputs -3342 "09/or-with"/imm32/subx-name -3343 1/imm32/rm32-is-first-inout -3344 2/imm32/r32-is-second-inout -3345 0/imm32/no-imm32 -3346 0/imm32/output-is-write-only -3347 _Primitive-or-mem-with-reg/imm32/next -3348 _Primitive-or-mem-with-reg: -3349 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 -3350 "or"/imm32/name -3351 Single-int-var-on-stack/imm32/inouts -3352 Single-int-var-in-some-register/imm32/outputs -3353 "0b/or"/imm32/subx-name -3354 1/imm32/rm32-is-first-inout -3355 3/imm32/r32-is-first-output -3356 0/imm32/no-imm32 -3357 0/imm32/output-is-write-only -3358 _Primitive-or-lit-with-reg/imm32/next -3359 _Primitive-or-lit-with-reg: -3360 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 -3361 "or"/imm32/name -3362 Single-lit-var/imm32/inouts -3363 Single-int-var-in-some-register/imm32/outputs -3364 "81 4/subop/or"/imm32/subx-name -3365 3/imm32/rm32-is-first-output -3366 0/imm32/no-r32 -3367 1/imm32/imm32-is-first-inout -3368 0/imm32/output-is-write-only -3369 _Primitive-or-lit-with-mem/imm32/next -3370 _Primitive-or-lit-with-mem: -3371 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 -3372 "or-with"/imm32/name -3373 Int-var-and-literal/imm32/inouts -3374 0/imm32/outputs -3375 "81 4/subop/or"/imm32/subx-name -3376 1/imm32/rm32-is-first-inout -3377 0/imm32/no-r32 -3378 2/imm32/imm32-is-first-inout -3379 0/imm32/output-is-write-only -3380 _Primitive-xor-with-eax/imm32/next -3381 # - xor -3382 _Primitive-xor-with-eax: -3383 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 -3384 "xor"/imm32/name -3385 Single-lit-var/imm32/inouts -3386 Single-int-var-in-eax/imm32/outputs -3387 "35/xor-with-eax"/imm32/subx-name -3388 0/imm32/no-rm32 -3389 0/imm32/no-r32 -3390 1/imm32/imm32-is-first-inout -3391 0/imm32/output-is-write-only -3392 _Primitive-xor-reg-with-reg/imm32/next -3393 _Primitive-xor-reg-with-reg: -3394 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 -3395 "xor"/imm32/name -3396 Single-int-var-in-some-register/imm32/inouts -3397 Single-int-var-in-some-register/imm32/outputs -3398 "31/xor-with"/imm32/subx-name -3399 3/imm32/rm32-is-first-output -3400 1/imm32/r32-is-first-inout -3401 0/imm32/no-imm32 -3402 0/imm32/output-is-write-only -3403 _Primitive-xor-reg-with-mem/imm32/next -3404 _Primitive-xor-reg-with-mem: -3405 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 -3406 "xor-with"/imm32/name -3407 Int-var-and-second-int-var-in-some-register/imm32/inouts -3408 0/imm32/outputs -3409 "31/xor-with"/imm32/subx-name -3410 1/imm32/rm32-is-first-inout -3411 2/imm32/r32-is-second-inout -3412 0/imm32/no-imm32 -3413 0/imm32/output-is-write-only -3414 _Primitive-xor-mem-with-reg/imm32/next -3415 _Primitive-xor-mem-with-reg: -3416 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 -3417 "xor"/imm32/name -3418 Single-int-var-on-stack/imm32/inouts -3419 Single-int-var-in-some-register/imm32/outputs -3420 "33/xor"/imm32/subx-name -3421 1/imm32/rm32-is-first-inout -3422 3/imm32/r32-is-first-output -3423 0/imm32/no-imm32 -3424 0/imm32/output-is-write-only -3425 _Primitive-xor-lit-with-reg/imm32/next -3426 _Primitive-xor-lit-with-reg: -3427 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 -3428 "xor"/imm32/name -3429 Single-lit-var/imm32/inouts -3430 Single-int-var-in-some-register/imm32/outputs -3431 "81 4/subop/xor"/imm32/subx-name -3432 3/imm32/rm32-is-first-output -3433 0/imm32/no-r32 -3434 1/imm32/imm32-is-first-inout -3435 0/imm32/output-is-write-only -3436 _Primitive-xor-lit-with-mem/imm32/next -3437 _Primitive-xor-lit-with-mem: -3438 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 -3439 "xor-with"/imm32/name -3440 Int-var-and-literal/imm32/inouts -3441 0/imm32/outputs -3442 "81 4/subop/xor"/imm32/subx-name -3443 1/imm32/rm32-is-first-inout -3444 0/imm32/no-r32 -3445 2/imm32/imm32-is-first-inout -3446 0/imm32/output-is-write-only -3447 _Primitive-copy-to-eax/imm32/next -3448 # - copy -3449 _Primitive-copy-to-eax: -3450 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 -3451 "copy"/imm32/name -3452 Single-lit-var/imm32/inouts -3453 Single-int-var-in-eax/imm32/outputs -3454 "b8/copy-to-eax"/imm32/subx-name -3455 0/imm32/no-rm32 -3456 0/imm32/no-r32 -3457 1/imm32/imm32-is-first-inout -3458 1/imm32/output-is-write-only -3459 _Primitive-copy-to-ecx/imm32/next -3460 _Primitive-copy-to-ecx: -3461 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 -3462 "copy"/imm32/name -3463 Single-lit-var/imm32/inouts -3464 Single-int-var-in-ecx/imm32/outputs -3465 "b9/copy-to-ecx"/imm32/subx-name -3466 0/imm32/no-rm32 -3467 0/imm32/no-r32 -3468 1/imm32/imm32-is-first-inout -3469 1/imm32/output-is-write-only -3470 _Primitive-copy-to-edx/imm32/next -3471 _Primitive-copy-to-edx: -3472 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 -3473 "copy"/imm32/name -3474 Single-lit-var/imm32/inouts -3475 Single-int-var-in-edx/imm32/outputs -3476 "ba/copy-to-edx"/imm32/subx-name -3477 0/imm32/no-rm32 -3478 0/imm32/no-r32 -3479 1/imm32/imm32-is-first-inout -3480 1/imm32/output-is-write-only -3481 _Primitive-copy-to-ebx/imm32/next -3482 _Primitive-copy-to-ebx: -3483 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 -3484 "copy"/imm32/name -3485 Single-lit-var/imm32/inouts -3486 Single-int-var-in-ebx/imm32/outputs -3487 "bb/copy-to-ebx"/imm32/subx-name -3488 0/imm32/no-rm32 -3489 0/imm32/no-r32 -3490 1/imm32/imm32-is-first-inout -3491 1/imm32/output-is-write-only -3492 _Primitive-copy-to-esi/imm32/next -3493 _Primitive-copy-to-esi: -3494 # var/esi <- copy lit => be/copy-to-esi lit/imm32 -3495 "copy"/imm32/name -3496 Single-lit-var/imm32/inouts -3497 Single-int-var-in-esi/imm32/outputs -3498 "be/copy-to-esi"/imm32/subx-name -3499 0/imm32/no-rm32 -3500 0/imm32/no-r32 -3501 1/imm32/imm32-is-first-inout -3502 1/imm32/output-is-write-only -3503 _Primitive-copy-to-edi/imm32/next -3504 _Primitive-copy-to-edi: -3505 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 -3506 "copy"/imm32/name -3507 Single-lit-var/imm32/inouts -3508 Single-int-var-in-edi/imm32/outputs -3509 "bf/copy-to-edi"/imm32/subx-name -3510 0/imm32/no-rm32 -3511 0/imm32/no-r32 -3512 1/imm32/imm32-is-first-inout -3513 1/imm32/output-is-write-only -3514 _Primitive-copy-reg-to-reg/imm32/next -3515 _Primitive-copy-reg-to-reg: -3516 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 -3517 "copy"/imm32/name -3518 Single-int-var-in-some-register/imm32/inouts -3519 Single-int-var-in-some-register/imm32/outputs -3520 "89/copy-to"/imm32/subx-name -3521 3/imm32/rm32-is-first-output -3522 1/imm32/r32-is-first-inout -3523 0/imm32/no-imm32 -3524 1/imm32/output-is-write-only -3525 _Primitive-copy-reg-to-mem/imm32/next -3526 _Primitive-copy-reg-to-mem: -3527 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 -3528 "copy-to"/imm32/name -3529 Int-var-and-second-int-var-in-some-register/imm32/inouts -3530 0/imm32/outputs -3531 "89/copy-to"/imm32/subx-name -3532 1/imm32/rm32-is-first-inout -3533 2/imm32/r32-is-second-inout -3534 0/imm32/no-imm32 -3535 1/imm32/output-is-write-only -3536 _Primitive-copy-mem-to-reg/imm32/next -3537 _Primitive-copy-mem-to-reg: -3538 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 -3539 "copy"/imm32/name -3540 Single-int-var-on-stack/imm32/inouts -3541 Single-int-var-in-some-register/imm32/outputs -3542 "8b/copy-from"/imm32/subx-name -3543 1/imm32/rm32-is-first-inout -3544 3/imm32/r32-is-first-output -3545 0/imm32/no-imm32 -3546 1/imm32/output-is-write-only -3547 _Primitive-copy-lit-to-reg/imm32/next -3548 _Primitive-copy-lit-to-reg: -3549 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 -3550 "copy"/imm32/name -3551 Single-lit-var/imm32/inouts -3552 Single-int-var-in-some-register/imm32/outputs -3553 "c7 0/subop/copy"/imm32/subx-name -3554 3/imm32/rm32-is-first-output -3555 0/imm32/no-r32 -3556 1/imm32/imm32-is-first-inout -3557 1/imm32/output-is-write-only -3558 _Primitive-copy-lit-to-mem/imm32/next -3559 _Primitive-copy-lit-to-mem: -3560 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 -3561 "copy-to"/imm32/name -3562 Int-var-and-literal/imm32/inouts -3563 0/imm32/outputs -3564 "c7 0/subop/copy"/imm32/subx-name -3565 1/imm32/rm32-is-first-inout -3566 0/imm32/no-r32 -3567 2/imm32/imm32-is-first-inout -3568 1/imm32/output-is-write-only -3569 0/imm32/next -3570 -3571 Single-int-var-on-stack: -3572 Int-var-on-stack/imm32 -3573 0/imm32/next -3574 -3575 Int-var-on-stack: -3576 "arg1"/imm32/name -3577 1/imm32/type-int -3578 1/imm32/some-block-depth -3579 1/imm32/some-stack-offset -3580 0/imm32/no-register -3581 -3582 Int-var-and-second-int-var-in-some-register: -3583 Int-var-on-stack/imm32 -3584 Single-int-var-in-some-register/imm32/next -3585 -3586 Int-var-and-literal: -3587 Int-var-on-stack/imm32 -3588 Single-lit-var/imm32/next -3589 -3590 Single-int-var-in-some-register: -3591 Int-var-in-some-register/imm32 -3592 0/imm32/next -3593 -3594 Int-var-in-some-register: -3595 "arg1"/imm32/name -3596 1/imm32/type-int -3597 1/imm32/some-block-depth -3598 0/imm32/no-stack-offset -3599 "*"/imm32/register -3600 -3601 Single-int-var-in-eax: -3602 Int-var-in-eax/imm32 -3603 0/imm32/next -3604 -3605 Int-var-in-eax: -3606 "arg1"/imm32/name -3607 1/imm32/type-int -3608 1/imm32/some-block-depth -3609 0/imm32/no-stack-offset -3610 "eax"/imm32/register -3611 -3612 Single-int-var-in-ecx: -3613 Int-var-in-ecx/imm32 -3614 0/imm32/next -3615 -3616 Int-var-in-ecx: -3617 "arg1"/imm32/name -3618 1/imm32/type-int -3619 1/imm32/some-block-depth -3620 0/imm32/no-stack-offset -3621 "ecx"/imm32/register -3622 -3623 Single-int-var-in-edx: -3624 Int-var-in-edx/imm32 -3625 0/imm32/next -3626 -3627 Int-var-in-edx: -3628 "arg1"/imm32/name -3629 1/imm32/type-int -3630 1/imm32/some-block-depth -3631 0/imm32/no-stack-offset -3632 "edx"/imm32/register -3633 -3634 Single-int-var-in-ebx: -3635 Int-var-in-ebx/imm32 -3636 0/imm32/next -3637 -3638 Int-var-in-ebx: -3639 "arg1"/imm32/name -3640 1/imm32/type-int -3641 1/imm32/some-block-depth -3642 0/imm32/no-stack-offset -3643 "ebx"/imm32/register -3644 -3645 Single-int-var-in-esi: -3646 Int-var-in-esi/imm32 -3647 0/imm32/next -3648 -3649 Int-var-in-esi: -3650 "arg1"/imm32/name -3651 1/imm32/type-int -3652 1/imm32/some-block-depth -3653 0/imm32/no-stack-offset -3654 "esi"/imm32/register -3655 -3656 Single-int-var-in-edi: -3657 Int-var-in-edi/imm32 -3658 0/imm32/next -3659 -3660 Int-var-in-edi: -3661 "arg1"/imm32/name -3662 1/imm32/type-int -3663 1/imm32/some-block-depth -3664 0/imm32/no-stack-offset -3665 "edi"/imm32/register -3666 -3667 Single-lit-var: -3668 Lit-var/imm32 -3669 0/imm32/next -3670 -3671 Lit-var: -3672 "literal"/imm32/name -3673 0/imm32/type-literal -3674 1/imm32/some-block-depth -3675 0/imm32/no-stack-offset -3676 0/imm32/no-register -3677 -3678 == code -3679 emit-subx-primitive: # out : (address buffered-file), stmt : (handle statement), primitive : (handle function) -3680 # . prologue -3681 55/push-ebp -3682 89/<- %ebp 4/r32/esp -3683 # . save registers -3684 50/push-eax -3685 51/push-ecx -3686 # ecx = primitive -3687 8b/-> *(ebp+0x10) 1/r32/ecx -3688 # emit primitive name -3689 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name -3690 # emit rm32 if necessary -3691 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt -3692 # emit r32 if necessary -3693 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt -3694 # emit imm32 if necessary -3695 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt -3696 $emit-subx-primitive:end: -3697 # . restore registers -3698 59/pop-to-ecx -3699 58/pop-to-eax -3700 # . epilogue -3701 89/<- %esp 5/r32/ebp -3702 5d/pop-to-ebp -3703 c3/return -3704 -3705 emit-subx-rm32: # out : (address buffered-file), l : arg-location, stmt : (handle statement) -3706 # . prologue -3707 55/push-ebp -3708 89/<- %ebp 4/r32/esp -3709 # . save registers -3710 50/push-eax -3711 # if (l == 0) return -3712 81 7/subop/compare *(ebp+0xc) 0/imm32 -3713 74/jump-if-equal $emit-subx-rm32:end/disp8 -3714 # -3715 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -3716 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var -3717 $emit-subx-rm32:end: -3718 # . restore registers -3719 58/pop-to-eax -3720 # . epilogue -3721 89/<- %esp 5/r32/ebp -3722 5d/pop-to-ebp -3723 c3/return -3724 -3725 get-stmt-operand-from-arg-location: # stmt : (handle statement), l : arg-location -> var/eax : (handle variable) -3726 # . prologue -3727 55/push-ebp -3728 89/<- %ebp 4/r32/esp -3729 # . save registers -3730 51/push-ecx -3731 # eax = l -3732 8b/-> *(ebp+0xc) 0/r32/eax -3733 # ecx = stmt -3734 8b/-> *(ebp+8) 1/r32/ecx -3735 # if (l == 1) return stmt->inouts->var -3736 { -3737 3d/compare-eax-and 1/imm32 -3738 75/jump-if-not-equal break/disp8 -3739 $get-stmt-operand-from-arg-location:1: -3740 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -3741 8b/-> *eax 0/r32/eax # Operand-var -3742 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -3743 } -3744 # if (l == 2) return stmt->inouts->next->var -3745 { -3746 3d/compare-eax-and 2/imm32 -3747 75/jump-if-not-equal break/disp8 -3748 $get-stmt-operand-from-arg-location:2: -3749 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -3750 8b/-> *(eax+4) 0/r32/eax # Operand-next -3751 8b/-> *eax 0/r32/eax # Operand-var -3752 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -3753 } -3754 # if (l == 3) return stmt->outputs -3755 { -3756 3d/compare-eax-and 3/imm32 -3757 75/jump-if-not-equal break/disp8 -3758 $get-stmt-operand-from-arg-location:3: -3759 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs -3760 8b/-> *eax 0/r32/eax # Operand-var -3761 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -3762 } -3763 # abort -3764 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 -3765 $get-stmt-operand-from-arg-location:end: -3766 # . restore registers -3767 59/pop-to-ecx -3768 # . epilogue -3769 89/<- %esp 5/r32/ebp -3770 5d/pop-to-ebp -3771 c3/return -3772 -3773 $get-stmt-operand-from-arg-location:abort: -3774 # error("invalid arg-location " eax) -3775 (write-buffered Stderr "invalid arg-location ") -3776 (print-int32-buffered Stderr %eax) -3777 (write-buffered Stderr "\n") -3778 (flush Stderr) -3779 # . syscall(exit, 1) -3780 bb/copy-to-ebx 1/imm32 -3781 b8/copy-to-eax 1/imm32/exit -3782 cd/syscall 0x80/imm8 -3783 # never gets here -3784 -3785 emit-subx-r32: # out : (address buffered-file), l : arg-location, stmt : (handle statement) -3786 # . prologue -3787 55/push-ebp -3788 89/<- %ebp 4/r32/esp -3789 # . save registers -3790 50/push-eax -3791 51/push-ecx -3792 # if (location == 0) return -3793 81 7/subop/compare *(ebp+0xc) 0/imm32 -3794 0f 84/jump-if-equal $emit-subx-r32:end/disp32 -3795 # -3796 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -3797 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (address register-index) -3798 (write-buffered *(ebp+8) Space) -3799 (print-int32-buffered *(ebp+8) *eax) -3800 (write-buffered *(ebp+8) "/r32") -3801 $emit-subx-r32:end: -3802 # . restore registers -3803 59/pop-to-ecx -3804 58/pop-to-eax -3805 # . epilogue -3806 89/<- %esp 5/r32/ebp -3807 5d/pop-to-ebp -3808 c3/return -3809 -3810 emit-subx-imm32: # out : (address buffered-file), l : arg-location, stmt : (handle statement) -3811 # . prologue -3812 55/push-ebp -3813 89/<- %ebp 4/r32/esp -3814 # . save registers -3815 50/push-eax -3816 51/push-ecx -3817 # if (location == 0) return -3818 81 7/subop/compare *(ebp+0xc) 0/imm32 -3819 74/jump-if-equal $emit-subx-imm32:end/disp8 -3820 # -3821 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -3822 (write-buffered *(ebp+8) Space) -3823 (write-buffered *(ebp+8) *eax) # Var-name -3824 (write-buffered *(ebp+8) "/imm32") -3825 $emit-subx-imm32:end: -3826 # . restore registers -3827 59/pop-to-ecx -3828 58/pop-to-eax -3829 # . epilogue -3830 89/<- %esp 5/r32/ebp -3831 5d/pop-to-ebp -3832 c3/return -3833 -3834 emit-subx-call: # out : (address buffered-file), stmt : (handle statement), callee : (handle function) -3835 # . prologue -3836 55/push-ebp -3837 89/<- %ebp 4/r32/esp -3838 # . save registers -3839 50/push-eax -3840 51/push-ecx -3841 # -3842 (write-buffered *(ebp+8) "(") -3843 # - emit function name -3844 8b/-> *(ebp+0x10) 1/r32/ecx -3845 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name -3846 # - emit arguments -3847 # var curr/ecx : (handle list var) = stmt->inouts -3848 8b/-> *(ebp+0xc) 1/r32/ecx -3849 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts -3850 { -3851 # if (curr == null) break -3852 81 7/subop/compare %ecx 0/imm32 -3853 74/jump-if-equal break/disp8 -3854 # -3855 (emit-subx-call-operand *(ebp+8) *ecx) -3856 # curr = curr->next -3857 8b/-> *(ecx+4) 1/r32/ecx -3858 } -3859 # -3860 (write-buffered *(ebp+8) ")") -3861 $emit-subx-call:end: -3862 # . restore registers -3863 59/pop-to-ecx -3864 58/pop-to-eax -3865 # . epilogue -3866 89/<- %esp 5/r32/ebp -3867 5d/pop-to-ebp -3868 c3/return +3246 _Primitive-inc-ecx/imm32/next +3247 _Primitive-inc-ecx: +3248 # var/ecx <- increment => 41/increment-ecx +3249 "increment"/imm32/name +3250 0/imm32/no-inouts +3251 Single-int-var-in-ecx/imm32/outputs +3252 "41/increment-ecx"/imm32/subx-name +3253 0/imm32/no-rm32 +3254 0/imm32/no-r32 +3255 0/imm32/no-imm32 +3256 0/imm32/output-is-write-only +3257 _Primitive-inc-edx/imm32/next +3258 _Primitive-inc-edx: +3259 # var/edx <- increment => 42/increment-edx +3260 "increment"/imm32/name +3261 0/imm32/no-inouts +3262 Single-int-var-in-edx/imm32/outputs +3263 "42/increment-edx"/imm32/subx-name +3264 0/imm32/no-rm32 +3265 0/imm32/no-r32 +3266 0/imm32/no-imm32 +3267 0/imm32/output-is-write-only +3268 _Primitive-inc-ebx/imm32/next +3269 _Primitive-inc-ebx: +3270 # var/ebx <- increment => 43/increment-ebx +3271 "increment"/imm32/name +3272 0/imm32/no-inouts +3273 Single-int-var-in-ebx/imm32/outputs +3274 "43/increment-ebx"/imm32/subx-name +3275 0/imm32/no-rm32 +3276 0/imm32/no-r32 +3277 0/imm32/no-imm32 +3278 0/imm32/output-is-write-only +3279 _Primitive-inc-esi/imm32/next +3280 _Primitive-inc-esi: +3281 # var/esi <- increment => 46/increment-esi +3282 "increment"/imm32/name +3283 0/imm32/no-inouts +3284 Single-int-var-in-esi/imm32/outputs +3285 "46/increment-esi"/imm32/subx-name +3286 0/imm32/no-rm32 +3287 0/imm32/no-r32 +3288 0/imm32/no-imm32 +3289 0/imm32/output-is-write-only +3290 _Primitive-inc-edi/imm32/next +3291 _Primitive-inc-edi: +3292 # var/edi <- increment => 47/increment-edi +3293 "increment"/imm32/name +3294 0/imm32/no-inouts +3295 Single-int-var-in-edi/imm32/outputs +3296 "47/increment-edi"/imm32/subx-name +3297 0/imm32/no-rm32 +3298 0/imm32/no-r32 +3299 0/imm32/no-imm32 +3300 0/imm32/output-is-write-only +3301 _Primitive-dec-eax/imm32/next +3302 _Primitive-dec-eax: +3303 # var/eax <- decrement => 48/decrement-eax +3304 "decrement"/imm32/name +3305 0/imm32/no-inouts +3306 Single-int-var-in-eax/imm32/outputs +3307 "48/decrement-eax"/imm32/subx-name +3308 0/imm32/no-rm32 +3309 0/imm32/no-r32 +3310 0/imm32/no-imm32 +3311 0/imm32/output-is-write-only +3312 _Primitive-dec-ecx/imm32/next +3313 _Primitive-dec-ecx: +3314 # var/ecx <- decrement => 49/decrement-ecx +3315 "decrement"/imm32/name +3316 0/imm32/no-inouts +3317 Single-int-var-in-ecx/imm32/outputs +3318 "49/decrement-ecx"/imm32/subx-name +3319 0/imm32/no-rm32 +3320 0/imm32/no-r32 +3321 0/imm32/no-imm32 +3322 0/imm32/output-is-write-only +3323 _Primitive-dec-edx/imm32/next +3324 _Primitive-dec-edx: +3325 # var/edx <- decrement => 4a/decrement-edx +3326 "decrement"/imm32/name +3327 0/imm32/no-inouts +3328 Single-int-var-in-edx/imm32/outputs +3329 "4a/decrement-edx"/imm32/subx-name +3330 0/imm32/no-rm32 +3331 0/imm32/no-r32 +3332 0/imm32/no-imm32 +3333 0/imm32/output-is-write-only +3334 _Primitive-dec-ebx/imm32/next +3335 _Primitive-dec-ebx: +3336 # var/ebx <- decrement => 4b/decrement-ebx +3337 "decrement"/imm32/name +3338 0/imm32/no-inouts +3339 Single-int-var-in-ebx/imm32/outputs +3340 "4b/decrement-ebx"/imm32/subx-name +3341 0/imm32/no-rm32 +3342 0/imm32/no-r32 +3343 0/imm32/no-imm32 +3344 0/imm32/output-is-write-only +3345 _Primitive-dec-esi/imm32/next +3346 _Primitive-dec-esi: +3347 # var/esi <- decrement => 4e/decrement-esi +3348 "decrement"/imm32/name +3349 0/imm32/no-inouts +3350 Single-int-var-in-esi/imm32/outputs +3351 "4e/decrement-esi"/imm32/subx-name +3352 0/imm32/no-rm32 +3353 0/imm32/no-r32 +3354 0/imm32/no-imm32 +3355 0/imm32/output-is-write-only +3356 _Primitive-dec-edi/imm32/next +3357 _Primitive-dec-edi: +3358 # var/edi <- decrement => 4f/decrement-edi +3359 "decrement"/imm32/name +3360 0/imm32/no-inouts +3361 Single-int-var-in-edi/imm32/outputs +3362 "4f/decrement-edi"/imm32/subx-name +3363 0/imm32/no-rm32 +3364 0/imm32/no-r32 +3365 0/imm32/no-imm32 +3366 0/imm32/output-is-write-only +3367 _Primitive-inc-mem/imm32/next +3368 _Primitive-inc-mem: +3369 # increment var => ff 0/subop/increment *(ebp+__) +3370 "increment"/imm32/name +3371 Single-int-var-on-stack/imm32/inouts +3372 0/imm32/no-outputs +3373 "ff 0/subop/increment"/imm32/subx-name +3374 1/imm32/rm32-is-first-inout +3375 0/imm32/no-r32 +3376 0/imm32/no-imm32 +3377 0/imm32/output-is-write-only +3378 _Primitive-inc-reg/imm32/next +3379 _Primitive-inc-reg: +3380 # var/reg <- increment => ff 0/subop/increment %__ +3381 "increment"/imm32/name +3382 0/imm32/no-inouts +3383 Single-int-var-in-some-register/imm32/outputs +3384 "ff 0/subop/increment"/imm32/subx-name +3385 3/imm32/rm32-is-first-output +3386 0/imm32/no-r32 +3387 0/imm32/no-imm32 +3388 0/imm32/output-is-write-only +3389 _Primitive-dec-mem/imm32/next +3390 _Primitive-dec-mem: +3391 # decrement var => ff 1/subop/decrement *(ebp+__) +3392 "decrement"/imm32/name +3393 Single-int-var-on-stack/imm32/inouts +3394 0/imm32/no-outputs +3395 "ff 1/subop/decrement"/imm32/subx-name +3396 1/imm32/rm32-is-first-inout +3397 0/imm32/no-r32 +3398 0/imm32/no-imm32 +3399 0/imm32/output-is-write-only +3400 _Primitive-dec-reg/imm32/next +3401 _Primitive-dec-reg: +3402 # var/reg <- decrement => ff 1/subop/decrement %__ +3403 "decrement"/imm32/name +3404 0/imm32/no-inouts +3405 Single-int-var-in-some-register/imm32/outputs +3406 "ff 1/subop/decrement"/imm32/subx-name +3407 3/imm32/rm32-is-first-output +3408 0/imm32/no-r32 +3409 0/imm32/no-imm32 +3410 0/imm32/output-is-write-only +3411 _Primitive-add-to-eax/imm32/next +3412 # - add +3413 _Primitive-add-to-eax: +3414 # var/eax <- add lit => 05/add-to-eax lit/imm32 +3415 "add"/imm32/name +3416 Single-lit-var/imm32/inouts +3417 Single-int-var-in-eax/imm32/outputs +3418 "05/add-to-eax"/imm32/subx-name +3419 0/imm32/no-rm32 +3420 0/imm32/no-r32 +3421 1/imm32/imm32-is-first-inout +3422 0/imm32/output-is-write-only +3423 _Primitive-add-reg-to-reg/imm32/next +3424 _Primitive-add-reg-to-reg: +3425 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 +3426 "add"/imm32/name +3427 Single-int-var-in-some-register/imm32/inouts +3428 Single-int-var-in-some-register/imm32/outputs +3429 "01/add-to"/imm32/subx-name +3430 3/imm32/rm32-is-first-output +3431 1/imm32/r32-is-first-inout +3432 0/imm32/no-imm32 +3433 0/imm32/output-is-write-only +3434 _Primitive-add-reg-to-mem/imm32/next +3435 _Primitive-add-reg-to-mem: +3436 # add-to var1 var2/reg => 01/add-to var1 var2/r32 +3437 "add-to"/imm32/name +3438 Int-var-and-second-int-var-in-some-register/imm32/inouts +3439 0/imm32/outputs +3440 "01/add-to"/imm32/subx-name +3441 1/imm32/rm32-is-first-inout +3442 2/imm32/r32-is-second-inout +3443 0/imm32/no-imm32 +3444 0/imm32/output-is-write-only +3445 _Primitive-add-mem-to-reg/imm32/next +3446 _Primitive-add-mem-to-reg: +3447 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 +3448 "add"/imm32/name +3449 Single-int-var-on-stack/imm32/inouts +3450 Single-int-var-in-some-register/imm32/outputs +3451 "03/add"/imm32/subx-name +3452 1/imm32/rm32-is-first-inout +3453 3/imm32/r32-is-first-output +3454 0/imm32/no-imm32 +3455 0/imm32/output-is-write-only +3456 _Primitive-add-lit-to-reg/imm32/next +3457 _Primitive-add-lit-to-reg: +3458 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 +3459 "add"/imm32/name +3460 Single-lit-var/imm32/inouts +3461 Single-int-var-in-some-register/imm32/outputs +3462 "81 0/subop/add"/imm32/subx-name +3463 3/imm32/rm32-is-first-output +3464 0/imm32/no-r32 +3465 1/imm32/imm32-is-first-inout +3466 0/imm32/output-is-write-only +3467 _Primitive-add-lit-to-mem/imm32/next +3468 _Primitive-add-lit-to-mem: +3469 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 +3470 "add-to"/imm32/name +3471 Int-var-and-literal/imm32/inouts +3472 0/imm32/outputs +3473 "81 0/subop/add"/imm32/subx-name +3474 1/imm32/rm32-is-first-inout +3475 0/imm32/no-r32 +3476 2/imm32/imm32-is-first-inout +3477 0/imm32/output-is-write-only +3478 _Primitive-subtract-from-eax/imm32/next +3479 # - subtract +3480 _Primitive-subtract-from-eax: +3481 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 +3482 "subtract"/imm32/name +3483 Single-lit-var/imm32/inouts +3484 Single-int-var-in-eax/imm32/outputs +3485 "2d/subtract-from-eax"/imm32/subx-name +3486 0/imm32/no-rm32 +3487 0/imm32/no-r32 +3488 1/imm32/imm32-is-first-inout +3489 0/imm32/output-is-write-only +3490 _Primitive-subtract-reg-from-reg/imm32/next +3491 _Primitive-subtract-reg-from-reg: +3492 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 +3493 "subtract"/imm32/name +3494 Single-int-var-in-some-register/imm32/inouts +3495 Single-int-var-in-some-register/imm32/outputs +3496 "29/subtract-from"/imm32/subx-name +3497 3/imm32/rm32-is-first-output +3498 1/imm32/r32-is-first-inout +3499 0/imm32/no-imm32 +3500 0/imm32/output-is-write-only +3501 _Primitive-subtract-reg-from-mem/imm32/next +3502 _Primitive-subtract-reg-from-mem: +3503 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 +3504 "subtract-from"/imm32/name +3505 Int-var-and-second-int-var-in-some-register/imm32/inouts +3506 0/imm32/outputs +3507 "29/subtract-from"/imm32/subx-name +3508 1/imm32/rm32-is-first-inout +3509 2/imm32/r32-is-second-inout +3510 0/imm32/no-imm32 +3511 0/imm32/output-is-write-only +3512 _Primitive-subtract-mem-from-reg/imm32/next +3513 _Primitive-subtract-mem-from-reg: +3514 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 +3515 "subtract"/imm32/name +3516 Single-int-var-on-stack/imm32/inouts +3517 Single-int-var-in-some-register/imm32/outputs +3518 "2b/subtract"/imm32/subx-name +3519 1/imm32/rm32-is-first-inout +3520 3/imm32/r32-is-first-output +3521 0/imm32/no-imm32 +3522 0/imm32/output-is-write-only +3523 _Primitive-subtract-lit-from-reg/imm32/next +3524 _Primitive-subtract-lit-from-reg: +3525 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 +3526 "subtract"/imm32/name +3527 Single-lit-var/imm32/inouts +3528 Single-int-var-in-some-register/imm32/outputs +3529 "81 5/subop/subtract"/imm32/subx-name +3530 3/imm32/rm32-is-first-output +3531 0/imm32/no-r32 +3532 1/imm32/imm32-is-first-inout +3533 0/imm32/output-is-write-only +3534 _Primitive-subtract-lit-from-mem/imm32/next +3535 _Primitive-subtract-lit-from-mem: +3536 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 +3537 "subtract-from"/imm32/name +3538 Int-var-and-literal/imm32/inouts +3539 0/imm32/outputs +3540 "81 5/subop/subtract"/imm32/subx-name +3541 1/imm32/rm32-is-first-inout +3542 0/imm32/no-r32 +3543 2/imm32/imm32-is-first-inout +3544 0/imm32/output-is-write-only +3545 _Primitive-and-with-eax/imm32/next +3546 # - and +3547 _Primitive-and-with-eax: +3548 # var/eax <- and lit => 25/and-with-eax lit/imm32 +3549 "and"/imm32/name +3550 Single-lit-var/imm32/inouts +3551 Single-int-var-in-eax/imm32/outputs +3552 "25/and-with-eax"/imm32/subx-name +3553 0/imm32/no-rm32 +3554 0/imm32/no-r32 +3555 1/imm32/imm32-is-first-inout +3556 0/imm32/output-is-write-only +3557 _Primitive-and-reg-with-reg/imm32/next +3558 _Primitive-and-reg-with-reg: +3559 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 +3560 "and"/imm32/name +3561 Single-int-var-in-some-register/imm32/inouts +3562 Single-int-var-in-some-register/imm32/outputs +3563 "21/and-with"/imm32/subx-name +3564 3/imm32/rm32-is-first-output +3565 1/imm32/r32-is-first-inout +3566 0/imm32/no-imm32 +3567 0/imm32/output-is-write-only +3568 _Primitive-and-reg-with-mem/imm32/next +3569 _Primitive-and-reg-with-mem: +3570 # and-with var1 var2/reg => 21/and-with var1 var2/r32 +3571 "and-with"/imm32/name +3572 Int-var-and-second-int-var-in-some-register/imm32/inouts +3573 0/imm32/outputs +3574 "21/and-with"/imm32/subx-name +3575 1/imm32/rm32-is-first-inout +3576 2/imm32/r32-is-second-inout +3577 0/imm32/no-imm32 +3578 0/imm32/output-is-write-only +3579 _Primitive-and-mem-with-reg/imm32/next +3580 _Primitive-and-mem-with-reg: +3581 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 +3582 "and"/imm32/name +3583 Single-int-var-on-stack/imm32/inouts +3584 Single-int-var-in-some-register/imm32/outputs +3585 "23/and"/imm32/subx-name +3586 1/imm32/rm32-is-first-inout +3587 3/imm32/r32-is-first-output +3588 0/imm32/no-imm32 +3589 0/imm32/output-is-write-only +3590 _Primitive-and-lit-with-reg/imm32/next +3591 _Primitive-and-lit-with-reg: +3592 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 +3593 "and"/imm32/name +3594 Single-lit-var/imm32/inouts +3595 Single-int-var-in-some-register/imm32/outputs +3596 "81 4/subop/and"/imm32/subx-name +3597 3/imm32/rm32-is-first-output +3598 0/imm32/no-r32 +3599 1/imm32/imm32-is-first-inout +3600 0/imm32/output-is-write-only +3601 _Primitive-and-lit-with-mem/imm32/next +3602 _Primitive-and-lit-with-mem: +3603 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 +3604 "and-with"/imm32/name +3605 Int-var-and-literal/imm32/inouts +3606 0/imm32/outputs +3607 "81 4/subop/and"/imm32/subx-name +3608 1/imm32/rm32-is-first-inout +3609 0/imm32/no-r32 +3610 2/imm32/imm32-is-first-inout +3611 0/imm32/output-is-write-only +3612 _Primitive-or-with-eax/imm32/next +3613 # - or +3614 _Primitive-or-with-eax: +3615 # var/eax <- or lit => 0d/or-with-eax lit/imm32 +3616 "or"/imm32/name +3617 Single-lit-var/imm32/inouts +3618 Single-int-var-in-eax/imm32/outputs +3619 "0d/or-with-eax"/imm32/subx-name +3620 0/imm32/no-rm32 +3621 0/imm32/no-r32 +3622 1/imm32/imm32-is-first-inout +3623 0/imm32/output-is-write-only +3624 _Primitive-or-reg-with-reg/imm32/next +3625 _Primitive-or-reg-with-reg: +3626 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 +3627 "or"/imm32/name +3628 Single-int-var-in-some-register/imm32/inouts +3629 Single-int-var-in-some-register/imm32/outputs +3630 "09/or-with"/imm32/subx-name +3631 3/imm32/rm32-is-first-output +3632 1/imm32/r32-is-first-inout +3633 0/imm32/no-imm32 +3634 0/imm32/output-is-write-only +3635 _Primitive-or-reg-with-mem/imm32/next +3636 _Primitive-or-reg-with-mem: +3637 # or-with var1 var2/reg => 09/or-with var1 var2/r32 +3638 "or-with"/imm32/name +3639 Int-var-and-second-int-var-in-some-register/imm32/inouts +3640 0/imm32/outputs +3641 "09/or-with"/imm32/subx-name +3642 1/imm32/rm32-is-first-inout +3643 2/imm32/r32-is-second-inout +3644 0/imm32/no-imm32 +3645 0/imm32/output-is-write-only +3646 _Primitive-or-mem-with-reg/imm32/next +3647 _Primitive-or-mem-with-reg: +3648 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 +3649 "or"/imm32/name +3650 Single-int-var-on-stack/imm32/inouts +3651 Single-int-var-in-some-register/imm32/outputs +3652 "0b/or"/imm32/subx-name +3653 1/imm32/rm32-is-first-inout +3654 3/imm32/r32-is-first-output +3655 0/imm32/no-imm32 +3656 0/imm32/output-is-write-only +3657 _Primitive-or-lit-with-reg/imm32/next +3658 _Primitive-or-lit-with-reg: +3659 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 +3660 "or"/imm32/name +3661 Single-lit-var/imm32/inouts +3662 Single-int-var-in-some-register/imm32/outputs +3663 "81 4/subop/or"/imm32/subx-name +3664 3/imm32/rm32-is-first-output +3665 0/imm32/no-r32 +3666 1/imm32/imm32-is-first-inout +3667 0/imm32/output-is-write-only +3668 _Primitive-or-lit-with-mem/imm32/next +3669 _Primitive-or-lit-with-mem: +3670 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 +3671 "or-with"/imm32/name +3672 Int-var-and-literal/imm32/inouts +3673 0/imm32/outputs +3674 "81 4/subop/or"/imm32/subx-name +3675 1/imm32/rm32-is-first-inout +3676 0/imm32/no-r32 +3677 2/imm32/imm32-is-first-inout +3678 0/imm32/output-is-write-only +3679 _Primitive-xor-with-eax/imm32/next +3680 # - xor +3681 _Primitive-xor-with-eax: +3682 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 +3683 "xor"/imm32/name +3684 Single-lit-var/imm32/inouts +3685 Single-int-var-in-eax/imm32/outputs +3686 "35/xor-with-eax"/imm32/subx-name +3687 0/imm32/no-rm32 +3688 0/imm32/no-r32 +3689 1/imm32/imm32-is-first-inout +3690 0/imm32/output-is-write-only +3691 _Primitive-xor-reg-with-reg/imm32/next +3692 _Primitive-xor-reg-with-reg: +3693 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 +3694 "xor"/imm32/name +3695 Single-int-var-in-some-register/imm32/inouts +3696 Single-int-var-in-some-register/imm32/outputs +3697 "31/xor-with"/imm32/subx-name +3698 3/imm32/rm32-is-first-output +3699 1/imm32/r32-is-first-inout +3700 0/imm32/no-imm32 +3701 0/imm32/output-is-write-only +3702 _Primitive-xor-reg-with-mem/imm32/next +3703 _Primitive-xor-reg-with-mem: +3704 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 +3705 "xor-with"/imm32/name +3706 Int-var-and-second-int-var-in-some-register/imm32/inouts +3707 0/imm32/outputs +3708 "31/xor-with"/imm32/subx-name +3709 1/imm32/rm32-is-first-inout +3710 2/imm32/r32-is-second-inout +3711 0/imm32/no-imm32 +3712 0/imm32/output-is-write-only +3713 _Primitive-xor-mem-with-reg/imm32/next +3714 _Primitive-xor-mem-with-reg: +3715 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 +3716 "xor"/imm32/name +3717 Single-int-var-on-stack/imm32/inouts +3718 Single-int-var-in-some-register/imm32/outputs +3719 "33/xor"/imm32/subx-name +3720 1/imm32/rm32-is-first-inout +3721 3/imm32/r32-is-first-output +3722 0/imm32/no-imm32 +3723 0/imm32/output-is-write-only +3724 _Primitive-xor-lit-with-reg/imm32/next +3725 _Primitive-xor-lit-with-reg: +3726 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 +3727 "xor"/imm32/name +3728 Single-lit-var/imm32/inouts +3729 Single-int-var-in-some-register/imm32/outputs +3730 "81 4/subop/xor"/imm32/subx-name +3731 3/imm32/rm32-is-first-output +3732 0/imm32/no-r32 +3733 1/imm32/imm32-is-first-inout +3734 0/imm32/output-is-write-only +3735 _Primitive-xor-lit-with-mem/imm32/next +3736 _Primitive-xor-lit-with-mem: +3737 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 +3738 "xor-with"/imm32/name +3739 Int-var-and-literal/imm32/inouts +3740 0/imm32/outputs +3741 "81 4/subop/xor"/imm32/subx-name +3742 1/imm32/rm32-is-first-inout +3743 0/imm32/no-r32 +3744 2/imm32/imm32-is-first-inout +3745 0/imm32/output-is-write-only +3746 _Primitive-copy-to-eax/imm32/next +3747 # - copy +3748 _Primitive-copy-to-eax: +3749 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 +3750 "copy"/imm32/name +3751 Single-lit-var/imm32/inouts +3752 Single-int-var-in-eax/imm32/outputs +3753 "b8/copy-to-eax"/imm32/subx-name +3754 0/imm32/no-rm32 +3755 0/imm32/no-r32 +3756 1/imm32/imm32-is-first-inout +3757 1/imm32/output-is-write-only +3758 _Primitive-copy-to-ecx/imm32/next +3759 _Primitive-copy-to-ecx: +3760 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 +3761 "copy"/imm32/name +3762 Single-lit-var/imm32/inouts +3763 Single-int-var-in-ecx/imm32/outputs +3764 "b9/copy-to-ecx"/imm32/subx-name +3765 0/imm32/no-rm32 +3766 0/imm32/no-r32 +3767 1/imm32/imm32-is-first-inout +3768 1/imm32/output-is-write-only +3769 _Primitive-copy-to-edx/imm32/next +3770 _Primitive-copy-to-edx: +3771 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 +3772 "copy"/imm32/name +3773 Single-lit-var/imm32/inouts +3774 Single-int-var-in-edx/imm32/outputs +3775 "ba/copy-to-edx"/imm32/subx-name +3776 0/imm32/no-rm32 +3777 0/imm32/no-r32 +3778 1/imm32/imm32-is-first-inout +3779 1/imm32/output-is-write-only +3780 _Primitive-copy-to-ebx/imm32/next +3781 _Primitive-copy-to-ebx: +3782 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 +3783 "copy"/imm32/name +3784 Single-lit-var/imm32/inouts +3785 Single-int-var-in-ebx/imm32/outputs +3786 "bb/copy-to-ebx"/imm32/subx-name +3787 0/imm32/no-rm32 +3788 0/imm32/no-r32 +3789 1/imm32/imm32-is-first-inout +3790 1/imm32/output-is-write-only +3791 _Primitive-copy-to-esi/imm32/next +3792 _Primitive-copy-to-esi: +3793 # var/esi <- copy lit => be/copy-to-esi lit/imm32 +3794 "copy"/imm32/name +3795 Single-lit-var/imm32/inouts +3796 Single-int-var-in-esi/imm32/outputs +3797 "be/copy-to-esi"/imm32/subx-name +3798 0/imm32/no-rm32 +3799 0/imm32/no-r32 +3800 1/imm32/imm32-is-first-inout +3801 1/imm32/output-is-write-only +3802 _Primitive-copy-to-edi/imm32/next +3803 _Primitive-copy-to-edi: +3804 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 +3805 "copy"/imm32/name +3806 Single-lit-var/imm32/inouts +3807 Single-int-var-in-edi/imm32/outputs +3808 "bf/copy-to-edi"/imm32/subx-name +3809 0/imm32/no-rm32 +3810 0/imm32/no-r32 +3811 1/imm32/imm32-is-first-inout +3812 1/imm32/output-is-write-only +3813 _Primitive-copy-reg-to-reg/imm32/next +3814 _Primitive-copy-reg-to-reg: +3815 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 +3816 "copy"/imm32/name +3817 Single-int-var-in-some-register/imm32/inouts +3818 Single-int-var-in-some-register/imm32/outputs +3819 "89/copy-to"/imm32/subx-name +3820 3/imm32/rm32-is-first-output +3821 1/imm32/r32-is-first-inout +3822 0/imm32/no-imm32 +3823 1/imm32/output-is-write-only +3824 _Primitive-copy-reg-to-mem/imm32/next +3825 _Primitive-copy-reg-to-mem: +3826 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 +3827 "copy-to"/imm32/name +3828 Int-var-and-second-int-var-in-some-register/imm32/inouts +3829 0/imm32/outputs +3830 "89/copy-to"/imm32/subx-name +3831 1/imm32/rm32-is-first-inout +3832 2/imm32/r32-is-second-inout +3833 0/imm32/no-imm32 +3834 1/imm32/output-is-write-only +3835 _Primitive-copy-mem-to-reg/imm32/next +3836 _Primitive-copy-mem-to-reg: +3837 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 +3838 "copy"/imm32/name +3839 Single-int-var-on-stack/imm32/inouts +3840 Single-int-var-in-some-register/imm32/outputs +3841 "8b/copy-from"/imm32/subx-name +3842 1/imm32/rm32-is-first-inout +3843 3/imm32/r32-is-first-output +3844 0/imm32/no-imm32 +3845 1/imm32/output-is-write-only +3846 _Primitive-copy-lit-to-reg/imm32/next +3847 _Primitive-copy-lit-to-reg: +3848 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 +3849 "copy"/imm32/name +3850 Single-lit-var/imm32/inouts +3851 Single-int-var-in-some-register/imm32/outputs +3852 "c7 0/subop/copy"/imm32/subx-name +3853 3/imm32/rm32-is-first-output +3854 0/imm32/no-r32 +3855 1/imm32/imm32-is-first-inout +3856 1/imm32/output-is-write-only +3857 _Primitive-copy-lit-to-mem/imm32/next +3858 _Primitive-copy-lit-to-mem: +3859 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 +3860 "copy-to"/imm32/name +3861 Int-var-and-literal/imm32/inouts +3862 0/imm32/outputs +3863 "c7 0/subop/copy"/imm32/subx-name +3864 1/imm32/rm32-is-first-inout +3865 0/imm32/no-r32 +3866 2/imm32/imm32-is-first-inout +3867 1/imm32/output-is-write-only +3868 0/imm32/next 3869 -3870 emit-subx-call-operand: # out : (address buffered-file), operand : (handle variable) -3871 # . prologue -3872 55/push-ebp -3873 89/<- %ebp 4/r32/esp -3874 # . save registers -3875 50/push-eax -3876 # eax = operand -3877 8b/-> *(ebp+0xc) 0/r32/eax -3878 # if non-literal, emit appropriately -3879 (emit-subx-var-as-rm32 *(ebp+8) %eax) -3880 # else if (operand->type == literal) emit "__" -3881 { -3882 81 7/subop/compare *(eax+4) 0/imm32 # Var-type -3883 75/jump-if-not-equal break/disp8 -3884 $emit-subx-call-operand:literal: -3885 (write-buffered *(ebp+8) Space) -3886 (write-buffered *(ebp+8) *eax) -3887 } -3888 $emit-subx-call-operand:end: -3889 # . restore registers -3890 58/pop-to-eax -3891 # . epilogue -3892 89/<- %esp 5/r32/ebp -3893 5d/pop-to-ebp -3894 c3/return -3895 -3896 emit-subx-var-as-rm32: # out : (address buffered-file), operand : (handle variable) -3897 # . prologue -3898 55/push-ebp -3899 89/<- %ebp 4/r32/esp -3900 # . save registers -3901 50/push-eax -3902 # eax = operand -3903 8b/-> *(ebp+0xc) 0/r32/eax -3904 # if (operand->register) emit "%__" -3905 { -3906 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -3907 74/jump-if-equal break/disp8 -3908 $emit-subx-var-as-rm32:register: -3909 (write-buffered *(ebp+8) " %") -3910 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -3911 } -3912 # else if (operand->stack-offset) emit "*(ebp+__)" -3913 { -3914 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -3915 74/jump-if-equal break/disp8 -3916 $emit-subx-var-as-rm32:stack: -3917 (write-buffered *(ebp+8) Space) -3918 (write-buffered *(ebp+8) "*(ebp+") -3919 8b/-> *(ebp+0xc) 0/r32/eax -3920 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -3921 (write-buffered *(ebp+8) ")") -3922 } -3923 $emit-subx-var-as-rm32:end: -3924 # . restore registers -3925 58/pop-to-eax -3926 # . epilogue -3927 89/<- %esp 5/r32/ebp -3928 5d/pop-to-ebp -3929 c3/return -3930 -3931 find-matching-function: # functions : (address function), stmt : (handle statement) -> result/eax : (handle function) -3932 # . prologue -3933 55/push-ebp -3934 89/<- %ebp 4/r32/esp -3935 # . save registers -3936 51/push-ecx -3937 # var curr/ecx : (handle function) = functions -3938 8b/-> *(ebp+8) 1/r32/ecx -3939 { -3940 # if (curr == null) break -3941 81 7/subop/compare %ecx 0/imm32 -3942 74/jump-if-equal break/disp8 -3943 # if match(stmt, curr) return curr -3944 { -3945 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax -3946 3d/compare-eax-and 0/imm32 -3947 74/jump-if-equal break/disp8 -3948 89/<- %eax 1/r32/ecx -3949 eb/jump $find-matching-function:end/disp8 -3950 } -3951 # curr = curr->next -3952 8b/-> *(ecx+0x10) 1/r32/ecx # Function-next -3953 eb/jump loop/disp8 -3954 } -3955 # return null -3956 b8/copy-to-eax 0/imm32 -3957 $find-matching-function:end: -3958 # . restore registers -3959 59/pop-to-ecx -3960 # . epilogue -3961 89/<- %esp 5/r32/ebp -3962 5d/pop-to-ebp -3963 c3/return -3964 -3965 find-matching-primitive: # primitives : (handle primitive), stmt : (handle statement) -> result/eax : (handle primitive) -3966 # . prologue -3967 55/push-ebp -3968 89/<- %ebp 4/r32/esp -3969 # . save registers -3970 51/push-ecx -3971 # var curr/ecx : (handle primitive) = primitives -3972 8b/-> *(ebp+8) 1/r32/ecx -3973 { -3974 $find-matching-primitive:loop: -3975 # if (curr == null) break -3976 81 7/subop/compare %ecx 0/imm32 -3977 0f 84/jump-if-equal break/disp32 -3978 #? (write-buffered Stderr "prim: ") -3979 #? (write-buffered Stderr *ecx) # Primitive-name -3980 #? (write-buffered Stderr " => ") -3981 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name -3982 #? (write-buffered Stderr "\n") -3983 #? (flush Stderr) -3984 # if match(curr, stmt) return curr -3985 { -3986 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax -3987 3d/compare-eax-and 0/imm32 -3988 74/jump-if-equal break/disp8 -3989 89/<- %eax 1/r32/ecx -3990 eb/jump $find-matching-primitive:end/disp8 -3991 } -3992 $find-matching-primitive:next-primitive: -3993 # curr = curr->next -3994 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next -3995 e9/jump loop/disp32 -3996 } -3997 # return null -3998 b8/copy-to-eax 0/imm32 -3999 $find-matching-primitive:end: -4000 # . restore registers -4001 59/pop-to-ecx -4002 # . epilogue -4003 89/<- %esp 5/r32/ebp -4004 5d/pop-to-ebp -4005 c3/return -4006 -4007 mu-stmt-matches-function?: # stmt : (handle statement), function : (handle function) => result/eax : boolean -4008 # . prologue -4009 55/push-ebp -4010 89/<- %ebp 4/r32/esp -4011 # . save registers -4012 51/push-ecx -4013 # return primitive->name == stmt->operation -4014 8b/-> *(ebp+8) 1/r32/ecx -4015 8b/-> *(ebp+0xc) 0/r32/eax -4016 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Primitive-name => eax -4017 $mu-stmt-matches-function?:end: -4018 # . restore registers -4019 59/pop-to-ecx -4020 # . epilogue -4021 89/<- %esp 5/r32/ebp -4022 5d/pop-to-ebp -4023 c3/return -4024 -4025 mu-stmt-matches-primitive?: # stmt : (handle statement), primitive : (handle primitive) => result/eax : boolean -4026 # A mu stmt matches a primitive if the name matches, all the inout vars -4027 # match, and all the output vars match. -4028 # Vars match if types match and registers match. -4029 # In addition, a stmt output matches a primitive's output if types match -4030 # and the primitive has a wildcard register. -4031 # . prologue -4032 55/push-ebp -4033 89/<- %ebp 4/r32/esp -4034 # . save registers -4035 51/push-ecx -4036 52/push-edx -4037 53/push-ebx -4038 56/push-esi -4039 57/push-edi -4040 # ecx = stmt -4041 8b/-> *(ebp+8) 1/r32/ecx -4042 # edx = primitive -4043 8b/-> *(ebp+0xc) 2/r32/edx +3870 Single-int-var-on-stack: +3871 Int-var-on-stack/imm32 +3872 0/imm32/next +3873 +3874 Int-var-on-stack: +3875 "arg1"/imm32/name +3876 1/imm32/type-int +3877 1/imm32/some-block-depth +3878 1/imm32/some-stack-offset +3879 0/imm32/no-register +3880 +3881 Int-var-and-second-int-var-in-some-register: +3882 Int-var-on-stack/imm32 +3883 Single-int-var-in-some-register/imm32/next +3884 +3885 Int-var-and-literal: +3886 Int-var-on-stack/imm32 +3887 Single-lit-var/imm32/next +3888 +3889 Single-int-var-in-some-register: +3890 Int-var-in-some-register/imm32 +3891 0/imm32/next +3892 +3893 Int-var-in-some-register: +3894 "arg1"/imm32/name +3895 1/imm32/type-int +3896 1/imm32/some-block-depth +3897 0/imm32/no-stack-offset +3898 "*"/imm32/register +3899 +3900 Single-int-var-in-eax: +3901 Int-var-in-eax/imm32 +3902 0/imm32/next +3903 +3904 Int-var-in-eax: +3905 "arg1"/imm32/name +3906 1/imm32/type-int +3907 1/imm32/some-block-depth +3908 0/imm32/no-stack-offset +3909 "eax"/imm32/register +3910 +3911 Single-int-var-in-ecx: +3912 Int-var-in-ecx/imm32 +3913 0/imm32/next +3914 +3915 Int-var-in-ecx: +3916 "arg1"/imm32/name +3917 1/imm32/type-int +3918 1/imm32/some-block-depth +3919 0/imm32/no-stack-offset +3920 "ecx"/imm32/register +3921 +3922 Single-int-var-in-edx: +3923 Int-var-in-edx/imm32 +3924 0/imm32/next +3925 +3926 Int-var-in-edx: +3927 "arg1"/imm32/name +3928 1/imm32/type-int +3929 1/imm32/some-block-depth +3930 0/imm32/no-stack-offset +3931 "edx"/imm32/register +3932 +3933 Single-int-var-in-ebx: +3934 Int-var-in-ebx/imm32 +3935 0/imm32/next +3936 +3937 Int-var-in-ebx: +3938 "arg1"/imm32/name +3939 1/imm32/type-int +3940 1/imm32/some-block-depth +3941 0/imm32/no-stack-offset +3942 "ebx"/imm32/register +3943 +3944 Single-int-var-in-esi: +3945 Int-var-in-esi/imm32 +3946 0/imm32/next +3947 +3948 Int-var-in-esi: +3949 "arg1"/imm32/name +3950 1/imm32/type-int +3951 1/imm32/some-block-depth +3952 0/imm32/no-stack-offset +3953 "esi"/imm32/register +3954 +3955 Single-int-var-in-edi: +3956 Int-var-in-edi/imm32 +3957 0/imm32/next +3958 +3959 Int-var-in-edi: +3960 "arg1"/imm32/name +3961 1/imm32/type-int +3962 1/imm32/some-block-depth +3963 0/imm32/no-stack-offset +3964 "edi"/imm32/register +3965 +3966 Single-lit-var: +3967 Lit-var/imm32 +3968 0/imm32/next +3969 +3970 Lit-var: +3971 "literal"/imm32/name +3972 0/imm32/type-literal +3973 1/imm32/some-block-depth +3974 0/imm32/no-stack-offset +3975 0/imm32/no-register +3976 +3977 == code +3978 emit-subx-primitive: # out : (address buffered-file), stmt : (handle statement), primitive : (handle function) +3979 # . prologue +3980 55/push-ebp +3981 89/<- %ebp 4/r32/esp +3982 # . save registers +3983 50/push-eax +3984 51/push-ecx +3985 # ecx = primitive +3986 8b/-> *(ebp+0x10) 1/r32/ecx +3987 # emit primitive name +3988 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name +3989 # emit rm32 if necessary +3990 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt +3991 # emit r32 if necessary +3992 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt +3993 # emit imm32 if necessary +3994 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt +3995 $emit-subx-primitive:end: +3996 # . restore registers +3997 59/pop-to-ecx +3998 58/pop-to-eax +3999 # . epilogue +4000 89/<- %esp 5/r32/ebp +4001 5d/pop-to-ebp +4002 c3/return +4003 +4004 emit-subx-rm32: # out : (address buffered-file), l : arg-location, stmt : (handle statement) +4005 # . prologue +4006 55/push-ebp +4007 89/<- %ebp 4/r32/esp +4008 # . save registers +4009 50/push-eax +4010 # if (l == 0) return +4011 81 7/subop/compare *(ebp+0xc) 0/imm32 +4012 74/jump-if-equal $emit-subx-rm32:end/disp8 +4013 # +4014 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4015 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var +4016 $emit-subx-rm32:end: +4017 # . restore registers +4018 58/pop-to-eax +4019 # . epilogue +4020 89/<- %esp 5/r32/ebp +4021 5d/pop-to-ebp +4022 c3/return +4023 +4024 get-stmt-operand-from-arg-location: # stmt : (handle statement), l : arg-location -> var/eax : (handle variable) +4025 # . prologue +4026 55/push-ebp +4027 89/<- %ebp 4/r32/esp +4028 # . save registers +4029 51/push-ecx +4030 # eax = l +4031 8b/-> *(ebp+0xc) 0/r32/eax +4032 # ecx = stmt +4033 8b/-> *(ebp+8) 1/r32/ecx +4034 # if (l == 1) return stmt->inouts->var +4035 { +4036 3d/compare-eax-and 1/imm32 +4037 75/jump-if-not-equal break/disp8 +4038 $get-stmt-operand-from-arg-location:1: +4039 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +4040 8b/-> *eax 0/r32/eax # Operand-var +4041 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4042 } +4043 # if (l == 2) return stmt->inouts->next->var 4044 { -4045 $mu-stmt-matches-primitive?:check-name: -4046 # if (primitive->name != stmt->operation) return false -4047 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax -4048 3d/compare-eax-and 0/imm32 -4049 75/jump-if-not-equal break/disp8 -4050 b8/copy-to-eax 0/imm32 -4051 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4045 3d/compare-eax-and 2/imm32 +4046 75/jump-if-not-equal break/disp8 +4047 $get-stmt-operand-from-arg-location:2: +4048 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +4049 8b/-> *(eax+4) 0/r32/eax # Operand-next +4050 8b/-> *eax 0/r32/eax # Operand-var +4051 eb/jump $get-stmt-operand-from-arg-location:end/disp8 4052 } -4053 $mu-stmt-matches-primitive?:check-inouts: -4054 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) -4055 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts -4056 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts -4057 { -4058 # if (curr == 0 && curr2 == 0) move on to check outputs -4059 { -4060 81 7/subop/compare %esi 0/imm32 -4061 75/jump-if-not-equal break/disp8 -4062 $mu-stmt-matches-primitive?:stmt-inout-is-null: -4063 { -4064 81 7/subop/compare %edi 0/imm32 -4065 75/jump-if-not-equal break/disp8 -4066 # -4067 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 -4068 } -4069 # return false -4070 b8/copy-to-eax 0/imm32/false -4071 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4072 } -4073 # if (curr2 == 0) return false -4074 { -4075 81 7/subop/compare %edi 0/imm32 -4076 75/jump-if-not-equal break/disp8 -4077 $mu-stmt-matches-primitive?:prim-inout-is-null: -4078 b8/copy-to-eax 0/imm32/false -4079 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4080 } -4081 # if (curr != curr2) return false -4082 { -4083 (operand-matches-primitive? *esi *edi) # => eax -4084 3d/compare-eax-and 0/imm32 -4085 75/jump-if-not-equal break/disp8 -4086 b8/copy-to-eax 0/imm32/false -4087 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4088 } -4089 # curr=curr->next -4090 8b/-> *(esi+4) 6/r32/esi # Operand-next -4091 # curr2=curr2->next -4092 8b/-> *(edi+4) 7/r32/edi # Operand-next -4093 eb/jump loop/disp8 -4094 } -4095 $mu-stmt-matches-primitive?:check-outputs: -4096 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) -4097 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs -4098 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs -4099 { -4100 # if (curr == 0) return (curr2 == 0) -4101 { -4102 $mu-stmt-matches-primitive?:check-output: -4103 81 7/subop/compare %esi 0/imm32 -4104 75/jump-if-not-equal break/disp8 -4105 { -4106 81 7/subop/compare %edi 0/imm32 -4107 75/jump-if-not-equal break/disp8 -4108 # return true -4109 b8/copy-to-eax 1/imm32 -4110 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4111 } -4112 # return false -4113 b8/copy-to-eax 0/imm32 -4114 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4115 } -4116 # if (curr2 == 0) return false -4117 { -4118 81 7/subop/compare %edi 0/imm32 -4119 75/jump-if-not-equal break/disp8 -4120 b8/copy-to-eax 0/imm32 -4121 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4122 } -4123 # if (curr != curr2) return false -4124 { -4125 (operand-matches-primitive? *esi *edi) # => eax -4126 3d/compare-eax-and 0/imm32 -4127 75/jump-if-not-equal break/disp8 -4128 b8/copy-to-eax 0/imm32 -4129 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4130 } -4131 # curr=curr->next -4132 8b/-> *(esi+4) 6/r32/esi # Operand-next -4133 # curr2=curr2->next -4134 8b/-> *(edi+4) 7/r32/edi # Operand-next -4135 eb/jump loop/disp8 -4136 } -4137 $mu-stmt-matches-primitive?:return-true: -4138 b8/copy-to-eax 1/imm32 -4139 $mu-stmt-matches-primitive?:end: -4140 # . restore registers -4141 5f/pop-to-edi -4142 5e/pop-to-esi -4143 5b/pop-to-ebx -4144 5a/pop-to-edx -4145 59/pop-to-ecx -4146 # . epilogue -4147 89/<- %esp 5/r32/ebp -4148 5d/pop-to-ebp -4149 c3/return -4150 -4151 operand-matches-primitive?: # var : (handle var), primout-var : (handle var) => result/eax : boolean -4152 # . prologue -4153 55/push-ebp -4154 89/<- %ebp 4/r32/esp -4155 # . save registers -4156 56/push-esi -4157 57/push-edi -4158 # esi = var -4159 8b/-> *(ebp+8) 6/r32/esi -4160 # edi = primout-var -4161 8b/-> *(ebp+0xc) 7/r32/edi -4162 # if (var->type != primout-var->type) return false -4163 8b/-> *(esi+4) 0/r32/eax # Var-type -4164 39/compare *(edi+4) 0/r32/eax # Var-type -4165 b8/copy-to-eax 0/imm32/false -4166 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 -4167 # return false if var->register doesn't match primout-var->register -4168 { -4169 # if addresses are equal, don't return here -4170 8b/-> *(esi+0x10) 0/r32/eax -4171 39/compare *(edi+0x10) 0/r32/eax -4172 74/jump-if-equal break/disp8 -4173 # if either address is 0, return false -4174 3d/compare-eax-and 0/imm32 -4175 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -4176 81 7/subop/compare *(edi+0x10) 0/imm32 -4177 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -4178 # if primout-var->register is "*", return true -4179 (string-equal? *(edi+0x10) "*") # Var-register -4180 3d/compare-eax-and 0/imm32 -4181 b8/copy-to-eax 1/imm32/true -4182 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 -4183 # if string contents don't match, return false -4184 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register -4185 3d/compare-eax-and 0/imm32 -4186 b8/copy-to-eax 0/imm32/false -4187 74/jump-if-equal $operand-matches-primitive?:end/disp8 -4188 } -4189 # return true -4190 b8/copy-to-eax 1/imm32/true -4191 $operand-matches-primitive?:end: -4192 # . restore registers -4193 5f/pop-to-edi -4194 5e/pop-to-esi -4195 # . epilogue -4196 89/<- %esp 5/r32/ebp -4197 5d/pop-to-ebp -4198 c3/return -4199 -4200 test-emit-subx-statement-primitive: -4201 # Primitive operation on a variable on the stack. -4202 # increment foo -4203 # => -4204 # ff 0/subop/increment *(ebp-8) -4205 # -4206 # There's a variable on the var stack as follows: -4207 # name: 'foo' -4208 # type: int -4209 # stack-offset: -8 -4210 # -4211 # There's a primitive with this info: -4212 # name: 'increment' -4213 # inouts: int/mem -4214 # value: 'ff 0/subop/increment' -4215 # -4216 # There's nothing in functions. -4217 # -4218 # . prologue -4219 55/push-ebp -4220 89/<- %ebp 4/r32/esp -4221 # setup -4222 (clear-stream _test-output-stream) -4223 (clear-stream $_test-output-buffered-file->buffer) -4224 # var var-foo/ecx : (ref var) -4225 68/push 0/imm32/no-register -4226 68/push -8/imm32/stack-offset -4227 68/push 1/imm32/block-depth -4228 68/push 1/imm32/type-int -4229 68/push "foo"/imm32 -4230 89/<- %ecx 4/r32/esp -4231 # var operand/ebx : (ref list var) -4232 68/push 0/imm32/next -4233 51/push-ecx/var-foo -4234 89/<- %ebx 4/r32/esp -4235 # var stmt/esi : (ref statement) -4236 68/push 0/imm32/next -4237 68/push 0/imm32/outputs -4238 53/push-ebx/operands -4239 68/push "increment"/imm32/operation -4240 68/push 1/imm32 -4241 89/<- %esi 4/r32/esp -4242 # var primitives/ebx : (ref primitive) -4243 68/push 0/imm32/next -4244 68/push 0/imm32/output-is-write-only -4245 68/push 0/imm32/no-imm32 -4246 68/push 0/imm32/no-r32 -4247 68/push 1/imm32/rm32-is-first-inout -4248 68/push "ff 0/subop/increment"/imm32/subx-name -4249 68/push 0/imm32/outputs -4250 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call -4251 68/push "increment"/imm32/name -4252 89/<- %ebx 4/r32/esp -4253 # convert -4254 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -4255 (flush _test-output-buffered-file) -4256 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4262 # check output -4263 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") -4264 # . epilogue -4265 89/<- %esp 5/r32/ebp -4266 5d/pop-to-ebp -4267 c3/return -4268 -4269 test-emit-subx-statement-primitive-register: -4270 # Primitive operation on a variable in a register. -4271 # foo <- increment -4272 # => -4273 # ff 0/subop/increment %eax # sub-optimal, but should suffice -4274 # -4275 # There's a variable on the var stack as follows: -4276 # name: 'foo' -4277 # type: int -4278 # register: 'eax' -4279 # -4280 # There's a primitive with this info: -4281 # name: 'increment' -4282 # out: int/reg -4283 # value: 'ff 0/subop/increment' -4284 # -4285 # There's nothing in functions. -4286 # -4287 # . prologue -4288 55/push-ebp -4289 89/<- %ebp 4/r32/esp -4290 # setup -4291 (clear-stream _test-output-stream) -4292 (clear-stream $_test-output-buffered-file->buffer) -4293 # var var-foo/ecx : (ref var) in eax -4294 68/push "eax"/imm32/register -4295 68/push 0/imm32/no-stack-offset -4296 68/push 1/imm32/block-depth -4297 68/push 1/imm32/type-int -4298 68/push "foo"/imm32 -4299 89/<- %ecx 4/r32/esp -4300 # var operand/ebx : (ref list var) -4301 68/push 0/imm32/next -4302 51/push-ecx/var-foo -4303 89/<- %ebx 4/r32/esp -4304 # var stmt/esi : (ref statement) -4305 68/push 0/imm32/next -4306 53/push-ebx/outputs -4307 68/push 0/imm32/inouts -4308 68/push "increment"/imm32/operation -4309 68/push 1/imm32 -4310 89/<- %esi 4/r32/esp -4311 # var formal-var/ebx : (ref var) in any register -4312 68/push Any-register/imm32 -4313 68/push 0/imm32/no-stack-offset -4314 68/push 1/imm32/block-depth -4315 68/push 1/imm32/type-int -4316 68/push "dummy"/imm32 -4317 89/<- %ebx 4/r32/esp -4318 # var operand/ebx : (ref list var) -4319 68/push 0/imm32/next -4320 53/push-ebx/formal-var -4321 89/<- %ebx 4/r32/esp -4322 # var primitives/ebx : (ref primitive) -4323 68/push 0/imm32/next -4324 68/push 0/imm32/output-is-write-only -4325 68/push 0/imm32/no-imm32 -4326 68/push 0/imm32/no-r32 -4327 68/push 3/imm32/rm32-in-first-output -4328 68/push "ff 0/subop/increment"/imm32/subx-name -4329 53/push-ebx/outputs -4330 68/push 0/imm32/inouts -4331 68/push "increment"/imm32/name -4332 89/<- %ebx 4/r32/esp -4333 # convert -4334 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -4335 (flush _test-output-buffered-file) -4336 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4342 # check output -4343 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") -4344 # . epilogue -4345 89/<- %esp 5/r32/ebp -4346 5d/pop-to-ebp -4347 c3/return -4348 -4349 test-emit-subx-statement-select-primitive: -4350 # Select the right primitive between overloads. -4351 # foo <- increment -4352 # => -4353 # ff 0/subop/increment %eax # sub-optimal, but should suffice -4354 # -4355 # There's a variable on the var stack as follows: -4356 # name: 'foo' -4357 # type: int -4358 # register: 'eax' -4359 # -4360 # There's two primitives, as follows: -4361 # - name: 'increment' -4362 # out: int/reg -4363 # value: 'ff 0/subop/increment' -4364 # - name: 'increment' -4365 # inout: int/mem -4366 # value: 'ff 0/subop/increment' -4367 # -4368 # There's nothing in functions. -4369 # -4370 # . prologue -4371 55/push-ebp -4372 89/<- %ebp 4/r32/esp -4373 # setup -4374 (clear-stream _test-output-stream) -4375 (clear-stream $_test-output-buffered-file->buffer) -4376 # var var-foo/ecx : (ref var) in eax -4377 68/push "eax"/imm32/register -4378 68/push 0/imm32/no-stack-offset -4379 68/push 1/imm32/block-depth -4380 68/push 1/imm32/type-int -4381 68/push "foo"/imm32 -4382 89/<- %ecx 4/r32/esp -4383 # var real-outputs/edi : (ref list var) -4384 68/push 0/imm32/next -4385 51/push-ecx/var-foo -4386 89/<- %edi 4/r32/esp -4387 # var stmt/esi : (ref statement) -4388 68/push 0/imm32/next -4389 57/push-edi/outputs -4390 68/push 0/imm32/inouts -4391 68/push "increment"/imm32/operation -4392 68/push 1/imm32 -4393 89/<- %esi 4/r32/esp -4394 # var formal-var/ebx : (ref var) in any register -4395 68/push Any-register/imm32 -4396 68/push 0/imm32/no-stack-offset -4397 68/push 1/imm32/block-depth -4398 68/push 1/imm32/type-int -4399 68/push "dummy"/imm32 -4400 89/<- %ebx 4/r32/esp -4401 # var formal-outputs/ebx : (ref list var) = {formal-var, 0} -4402 68/push 0/imm32/next -4403 53/push-ebx/formal-var -4404 89/<- %ebx 4/r32/esp -4405 # var primitive1/ebx : (ref primitive) -4406 68/push 0/imm32/next -4407 68/push 0/imm32/output-is-write-only -4408 68/push 0/imm32/no-imm32 -4409 68/push 0/imm32/no-r32 -4410 68/push 3/imm32/rm32-in-first-output -4411 68/push "ff 0/subop/increment"/imm32/subx-name -4412 53/push-ebx/outputs/formal-outputs -4413 68/push 0/imm32/inouts -4414 68/push "increment"/imm32/name -4415 89/<- %ebx 4/r32/esp -4416 # var primitives/ebx : (ref primitive) -4417 53/push-ebx/next -4418 68/push 0/imm32/output-is-write-only -4419 68/push 0/imm32/no-imm32 -4420 68/push 0/imm32/no-r32 -4421 68/push 1/imm32/rm32-is-first-inout -4422 68/push "ff 0/subop/increment"/imm32/subx-name -4423 68/push 0/imm32/outputs -4424 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -4425 68/push "increment"/imm32/name -4426 89/<- %ebx 4/r32/esp -4427 # convert -4428 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -4429 (flush _test-output-buffered-file) -4430 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4436 # check output -4437 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") -4438 # . epilogue -4439 89/<- %esp 5/r32/ebp -4440 5d/pop-to-ebp -4441 c3/return -4442 -4443 test-emit-subx-statement-select-primitive-2: -4444 # Select the right primitive between overloads. -4445 # foo <- increment -4446 # => -4447 # ff 0/subop/increment %eax # sub-optimal, but should suffice -4448 # -4449 # There's a variable on the var stack as follows: -4450 # name: 'foo' -4451 # type: int -4452 # register: 'eax' -4453 # -4454 # There's two primitives, as follows: -4455 # - name: 'increment' -4456 # out: int/reg -4457 # value: 'ff 0/subop/increment' -4458 # - name: 'increment' -4459 # inout: int/mem -4460 # value: 'ff 0/subop/increment' -4461 # -4462 # There's nothing in functions. -4463 # -4464 # . prologue -4465 55/push-ebp -4466 89/<- %ebp 4/r32/esp -4467 # setup -4468 (clear-stream _test-output-stream) -4469 (clear-stream $_test-output-buffered-file->buffer) -4470 # var var-foo/ecx : (ref var) in eax -4471 68/push "eax"/imm32/register -4472 68/push 0/imm32/no-stack-offset -4473 68/push 1/imm32/block-depth -4474 68/push 1/imm32/type-int -4475 68/push "foo"/imm32 -4476 89/<- %ecx 4/r32/esp -4477 # var inouts/edi : (ref list var) -4478 68/push 0/imm32/next -4479 51/push-ecx/var-foo -4480 89/<- %edi 4/r32/esp -4481 # var stmt/esi : (ref statement) -4482 68/push 0/imm32/next -4483 68/push 0/imm32/outputs -4484 57/push-edi/inouts -4485 68/push "increment"/imm32/operation -4486 68/push 1/imm32 -4487 89/<- %esi 4/r32/esp -4488 # var formal-var/ebx : (ref var) in any register -4489 68/push Any-register/imm32 -4490 68/push 0/imm32/no-stack-offset -4491 68/push 1/imm32/block-depth -4492 68/push 1/imm32/type-int -4493 68/push "dummy"/imm32 -4494 89/<- %ebx 4/r32/esp -4495 # var operand/ebx : (ref list var) -4496 68/push 0/imm32/next -4497 53/push-ebx/formal-var -4498 89/<- %ebx 4/r32/esp -4499 # var primitive1/ebx : primitive -4500 68/push 0/imm32/next -4501 68/push 0/imm32/output-is-write-only -4502 68/push 0/imm32/no-imm32 -4503 68/push 0/imm32/no-r32 -4504 68/push 3/imm32/rm32-in-first-output -4505 68/push "ff 0/subop/increment"/imm32/subx-name -4506 53/push-ebx/outputs/formal-outputs -4507 68/push 0/imm32/inouts -4508 68/push "increment"/imm32/name -4509 89/<- %ebx 4/r32/esp -4510 # var primitives/ebx : (ref primitive) -4511 53/push-ebx/next -4512 68/push 0/imm32/output-is-write-only -4513 68/push 0/imm32/no-imm32 -4514 68/push 0/imm32/no-r32 -4515 68/push 1/imm32/rm32-is-first-inout -4516 68/push "ff 0/subop/increment"/imm32/subx-name -4517 68/push 0/imm32/outputs -4518 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -4519 68/push "increment"/imm32/name -4520 89/<- %ebx 4/r32/esp -4521 # convert -4522 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -4523 (flush _test-output-buffered-file) -4524 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4530 # check output -4531 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") -4532 # . epilogue -4533 89/<- %esp 5/r32/ebp -4534 5d/pop-to-ebp -4535 c3/return -4536 -4537 test-increment-register: -4538 # Select the right primitive between overloads. -4539 # foo <- increment -4540 # => -4541 # 50/increment-eax -4542 # -4543 # There's a variable on the var stack as follows: -4544 # name: 'foo' -4545 # type: int -4546 # register: 'eax' -4547 # -4548 # Primitives are the global definitions. -4549 # -4550 # There are no functions defined. -4551 # -4552 # . prologue -4553 55/push-ebp -4554 89/<- %ebp 4/r32/esp -4555 # setup -4556 (clear-stream _test-output-stream) -4557 (clear-stream $_test-output-buffered-file->buffer) -4558 # var var-foo/ecx : (ref var) in eax -4559 68/push "eax"/imm32/register -4560 68/push 0/imm32/no-stack-offset -4561 68/push 1/imm32/block-depth -4562 68/push 1/imm32/type-int -4563 68/push "foo"/imm32 -4564 89/<- %ecx 4/r32/esp -4565 # var real-outputs/edi : (ref list var) -4566 68/push 0/imm32/next -4567 51/push-ecx/var-foo -4568 89/<- %edi 4/r32/esp -4569 # var stmt/esi : (ref statement) -4570 68/push 0/imm32/next -4571 57/push-edi/outputs -4572 68/push 0/imm32/inouts -4573 68/push "increment"/imm32/operation -4574 68/push 1/imm32 -4575 89/<- %esi 4/r32/esp -4576 # convert -4577 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -4578 (flush _test-output-buffered-file) -4579 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4585 # check output -4586 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") -4587 # . epilogue -4588 89/<- %esp 5/r32/ebp -4589 5d/pop-to-ebp -4590 c3/return -4591 -4592 test-increment-var: -4593 # Select the right primitive between overloads. -4594 # foo <- increment -4595 # => -4596 # ff 0/subop/increment %eax # sub-optimal, but should suffice -4597 # -4598 # There's a variable on the var stack as follows: -4599 # name: 'foo' -4600 # type: int -4601 # register: 'eax' -4602 # -4603 # Primitives are the global definitions. -4604 # -4605 # There are no functions defined. -4606 # -4607 # . prologue -4608 55/push-ebp -4609 89/<- %ebp 4/r32/esp -4610 # setup -4611 (clear-stream _test-output-stream) -4612 (clear-stream $_test-output-buffered-file->buffer) -4613 # var var-foo/ecx : (ref var) in eax -4614 68/push "eax"/imm32/register -4615 68/push 0/imm32/no-stack-offset -4616 68/push 1/imm32/block-depth -4617 68/push 1/imm32/type-int -4618 68/push "foo"/imm32 -4619 89/<- %ecx 4/r32/esp -4620 # var inouts/edi : (ref list var) -4621 68/push 0/imm32/next -4622 51/push-ecx/var-foo -4623 89/<- %edi 4/r32/esp -4624 # var stmt/esi : (ref statement) -4625 68/push 0/imm32/next -4626 68/push 0/imm32/outputs -4627 57/push-edi/inouts -4628 68/push "increment"/imm32/operation -4629 68/push 1/imm32 -4630 89/<- %esi 4/r32/esp -4631 # convert -4632 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -4633 (flush _test-output-buffered-file) -4634 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4640 # check output -4641 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") -4642 # . epilogue -4643 89/<- %esp 5/r32/ebp -4644 5d/pop-to-ebp -4645 c3/return -4646 -4647 test-add-reg-to-reg: -4648 # var1/reg <- add var2/reg -4649 # => -4650 # 01/add %var1 var2 -4651 # -4652 # . prologue -4653 55/push-ebp -4654 89/<- %ebp 4/r32/esp -4655 # setup -4656 (clear-stream _test-output-stream) -4657 (clear-stream $_test-output-buffered-file->buffer) -4658 # var var-var1/ecx : (ref var) in eax -4659 68/push "eax"/imm32/register -4660 68/push 0/imm32/no-stack-offset -4661 68/push 1/imm32/block-depth -4662 68/push 1/imm32/type-int -4663 68/push "var1"/imm32 -4664 89/<- %ecx 4/r32/esp -4665 # var var-var2/edx : (ref var) in ecx -4666 68/push "ecx"/imm32/register -4667 68/push 0/imm32/no-stack-offset -4668 68/push 1/imm32/block-depth -4669 68/push 1/imm32/type-int -4670 68/push "var2"/imm32 -4671 89/<- %edx 4/r32/esp -4672 # var inouts/esi : (ref list var2) -4673 68/push 0/imm32/next -4674 52/push-edx/var-var2 -4675 89/<- %esi 4/r32/esp -4676 # var outputs/edi : (ref list var1) -4677 68/push 0/imm32/next -4678 51/push-ecx/var-var1 -4679 89/<- %edi 4/r32/esp -4680 # var stmt/esi : (ref statement) -4681 68/push 0/imm32/next -4682 57/push-edi/outputs -4683 56/push-esi/inouts -4684 68/push "add"/imm32/operation -4685 68/push 1/imm32 -4686 89/<- %esi 4/r32/esp -4687 # convert -4688 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -4689 (flush _test-output-buffered-file) -4690 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4696 # check output -4697 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") -4698 # . epilogue -4699 89/<- %esp 5/r32/ebp -4700 5d/pop-to-ebp -4701 c3/return -4702 -4703 test-add-reg-to-mem: -4704 # add-to var1 var2/reg -4705 # => -4706 # 01/add *(ebp+__) var2 -4707 # -4708 # . prologue -4709 55/push-ebp -4710 89/<- %ebp 4/r32/esp -4711 # setup -4712 (clear-stream _test-output-stream) -4713 (clear-stream $_test-output-buffered-file->buffer) -4714 # var var-var1/ecx : (ref var) -4715 68/push 0/imm32/no-register -4716 68/push 8/imm32/stack-offset -4717 68/push 1/imm32/block-depth -4718 68/push 1/imm32/type-int -4719 68/push "var1"/imm32 -4720 89/<- %ecx 4/r32/esp -4721 # var var-var2/edx : (ref var) in ecx -4722 68/push "ecx"/imm32/register -4723 68/push 0/imm32/no-stack-offset -4724 68/push 1/imm32/block-depth -4725 68/push 1/imm32/type-int -4726 68/push "var2"/imm32 -4727 89/<- %edx 4/r32/esp -4728 # var inouts/esi : (ref list var2) -4729 68/push 0/imm32/next -4730 52/push-edx/var-var2 -4731 89/<- %esi 4/r32/esp -4732 # var inouts = (ref list var1 var2) -4733 56/push-esi/next -4734 51/push-ecx/var-var1 -4735 89/<- %esi 4/r32/esp -4736 # var stmt/esi : (ref statement) -4737 68/push 0/imm32/next -4738 68/push 0/imm32/outputs -4739 56/push-esi/inouts -4740 68/push "add-to"/imm32/operation -4741 68/push 1/imm32 -4742 89/<- %esi 4/r32/esp -4743 # convert -4744 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -4745 (flush _test-output-buffered-file) -4746 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4752 # check output -4753 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") -4754 # . epilogue -4755 89/<- %esp 5/r32/ebp -4756 5d/pop-to-ebp -4757 c3/return -4758 -4759 test-add-mem-to-reg: -4760 # var1/reg <- add var2 -4761 # => -4762 # 03/add *(ebp+__) var1 +4053 # if (l == 3) return stmt->outputs +4054 { +4055 3d/compare-eax-and 3/imm32 +4056 75/jump-if-not-equal break/disp8 +4057 $get-stmt-operand-from-arg-location:3: +4058 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs +4059 8b/-> *eax 0/r32/eax # Operand-var +4060 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4061 } +4062 # abort +4063 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 +4064 $get-stmt-operand-from-arg-location:end: +4065 # . restore registers +4066 59/pop-to-ecx +4067 # . epilogue +4068 89/<- %esp 5/r32/ebp +4069 5d/pop-to-ebp +4070 c3/return +4071 +4072 $get-stmt-operand-from-arg-location:abort: +4073 # error("invalid arg-location " eax) +4074 (write-buffered Stderr "invalid arg-location ") +4075 (print-int32-buffered Stderr %eax) +4076 (write-buffered Stderr "\n") +4077 (flush Stderr) +4078 # . syscall(exit, 1) +4079 bb/copy-to-ebx 1/imm32 +4080 b8/copy-to-eax 1/imm32/exit +4081 cd/syscall 0x80/imm8 +4082 # never gets here +4083 +4084 emit-subx-r32: # out : (address buffered-file), l : arg-location, stmt : (handle statement) +4085 # . prologue +4086 55/push-ebp +4087 89/<- %ebp 4/r32/esp +4088 # . save registers +4089 50/push-eax +4090 51/push-ecx +4091 # if (location == 0) return +4092 81 7/subop/compare *(ebp+0xc) 0/imm32 +4093 0f 84/jump-if-equal $emit-subx-r32:end/disp32 +4094 # +4095 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4096 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (address register-index) +4097 (write-buffered *(ebp+8) Space) +4098 (print-int32-buffered *(ebp+8) *eax) +4099 (write-buffered *(ebp+8) "/r32") +4100 $emit-subx-r32:end: +4101 # . restore registers +4102 59/pop-to-ecx +4103 58/pop-to-eax +4104 # . epilogue +4105 89/<- %esp 5/r32/ebp +4106 5d/pop-to-ebp +4107 c3/return +4108 +4109 emit-subx-imm32: # out : (address buffered-file), l : arg-location, stmt : (handle statement) +4110 # . prologue +4111 55/push-ebp +4112 89/<- %ebp 4/r32/esp +4113 # . save registers +4114 50/push-eax +4115 51/push-ecx +4116 # if (location == 0) return +4117 81 7/subop/compare *(ebp+0xc) 0/imm32 +4118 74/jump-if-equal $emit-subx-imm32:end/disp8 +4119 # +4120 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4121 (write-buffered *(ebp+8) Space) +4122 (write-buffered *(ebp+8) *eax) # Var-name +4123 (write-buffered *(ebp+8) "/imm32") +4124 $emit-subx-imm32:end: +4125 # . restore registers +4126 59/pop-to-ecx +4127 58/pop-to-eax +4128 # . epilogue +4129 89/<- %esp 5/r32/ebp +4130 5d/pop-to-ebp +4131 c3/return +4132 +4133 emit-subx-call: # out : (address buffered-file), stmt : (handle statement), callee : (handle function) +4134 # . prologue +4135 55/push-ebp +4136 89/<- %ebp 4/r32/esp +4137 # . save registers +4138 50/push-eax +4139 51/push-ecx +4140 # +4141 (write-buffered *(ebp+8) "(") +4142 # - emit function name +4143 8b/-> *(ebp+0x10) 1/r32/ecx +4144 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name +4145 # - emit arguments +4146 # var curr/ecx : (handle list var) = stmt->inouts +4147 8b/-> *(ebp+0xc) 1/r32/ecx +4148 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts +4149 { +4150 # if (curr == null) break +4151 81 7/subop/compare %ecx 0/imm32 +4152 74/jump-if-equal break/disp8 +4153 # +4154 (emit-subx-call-operand *(ebp+8) *ecx) +4155 # curr = curr->next +4156 8b/-> *(ecx+4) 1/r32/ecx +4157 eb/jump loop/disp8 +4158 } +4159 # +4160 (write-buffered *(ebp+8) ")") +4161 $emit-subx-call:end: +4162 # . restore registers +4163 59/pop-to-ecx +4164 58/pop-to-eax +4165 # . epilogue +4166 89/<- %esp 5/r32/ebp +4167 5d/pop-to-ebp +4168 c3/return +4169 +4170 emit-subx-call-operand: # out : (address buffered-file), operand : (handle variable) +4171 # . prologue +4172 55/push-ebp +4173 89/<- %ebp 4/r32/esp +4174 # . save registers +4175 50/push-eax +4176 # eax = operand +4177 8b/-> *(ebp+0xc) 0/r32/eax +4178 # if non-literal, emit appropriately +4179 (emit-subx-var-as-rm32 *(ebp+8) %eax) +4180 # else if (operand->type == literal) emit "__" +4181 { +4182 81 7/subop/compare *(eax+4) 0/imm32 # Var-type +4183 75/jump-if-not-equal break/disp8 +4184 $emit-subx-call-operand:literal: +4185 (write-buffered *(ebp+8) Space) +4186 (write-buffered *(ebp+8) *eax) +4187 } +4188 $emit-subx-call-operand:end: +4189 # . restore registers +4190 58/pop-to-eax +4191 # . epilogue +4192 89/<- %esp 5/r32/ebp +4193 5d/pop-to-ebp +4194 c3/return +4195 +4196 emit-subx-var-as-rm32: # out : (address buffered-file), operand : (handle variable) +4197 # . prologue +4198 55/push-ebp +4199 89/<- %ebp 4/r32/esp +4200 # . save registers +4201 50/push-eax +4202 # eax = operand +4203 8b/-> *(ebp+0xc) 0/r32/eax +4204 # if (operand->register) emit "%__" +4205 { +4206 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +4207 74/jump-if-equal break/disp8 +4208 $emit-subx-var-as-rm32:register: +4209 (write-buffered *(ebp+8) " %") +4210 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +4211 } +4212 # else if (operand->stack-offset) emit "*(ebp+__)" +4213 { +4214 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +4215 74/jump-if-equal break/disp8 +4216 $emit-subx-var-as-rm32:stack: +4217 (write-buffered *(ebp+8) Space) +4218 (write-buffered *(ebp+8) "*(ebp+") +4219 8b/-> *(ebp+0xc) 0/r32/eax +4220 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +4221 (write-buffered *(ebp+8) ")") +4222 } +4223 $emit-subx-var-as-rm32:end: +4224 # . restore registers +4225 58/pop-to-eax +4226 # . epilogue +4227 89/<- %esp 5/r32/ebp +4228 5d/pop-to-ebp +4229 c3/return +4230 +4231 find-matching-function: # functions : (address function), stmt : (handle statement) -> result/eax : (handle function) +4232 # . prologue +4233 55/push-ebp +4234 89/<- %ebp 4/r32/esp +4235 # . save registers +4236 51/push-ecx +4237 # var curr/ecx : (handle function) = functions +4238 8b/-> *(ebp+8) 1/r32/ecx +4239 { +4240 # if (curr == null) break +4241 81 7/subop/compare %ecx 0/imm32 +4242 74/jump-if-equal break/disp8 +4243 # if match(stmt, curr) return curr +4244 { +4245 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax +4246 3d/compare-eax-and 0/imm32 +4247 74/jump-if-equal break/disp8 +4248 89/<- %eax 1/r32/ecx +4249 eb/jump $find-matching-function:end/disp8 +4250 } +4251 # curr = curr->next +4252 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +4253 eb/jump loop/disp8 +4254 } +4255 # return null +4256 b8/copy-to-eax 0/imm32 +4257 $find-matching-function:end: +4258 # . restore registers +4259 59/pop-to-ecx +4260 # . epilogue +4261 89/<- %esp 5/r32/ebp +4262 5d/pop-to-ebp +4263 c3/return +4264 +4265 find-matching-primitive: # primitives : (handle primitive), stmt : (handle statement) -> result/eax : (handle primitive) +4266 # . prologue +4267 55/push-ebp +4268 89/<- %ebp 4/r32/esp +4269 # . save registers +4270 51/push-ecx +4271 # var curr/ecx : (handle primitive) = primitives +4272 8b/-> *(ebp+8) 1/r32/ecx +4273 { +4274 $find-matching-primitive:loop: +4275 # if (curr == null) break +4276 81 7/subop/compare %ecx 0/imm32 +4277 0f 84/jump-if-equal break/disp32 +4278 #? (write-buffered Stderr "prim: ") +4279 #? (write-buffered Stderr *ecx) # Primitive-name +4280 #? (write-buffered Stderr " => ") +4281 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name +4282 #? (write-buffered Stderr "\n") +4283 #? (flush Stderr) +4284 # if match(curr, stmt) return curr +4285 { +4286 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax +4287 3d/compare-eax-and 0/imm32 +4288 74/jump-if-equal break/disp8 +4289 89/<- %eax 1/r32/ecx +4290 eb/jump $find-matching-primitive:end/disp8 +4291 } +4292 $find-matching-primitive:next-primitive: +4293 # curr = curr->next +4294 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next +4295 e9/jump loop/disp32 +4296 } +4297 # return null +4298 b8/copy-to-eax 0/imm32 +4299 $find-matching-primitive:end: +4300 # . restore registers +4301 59/pop-to-ecx +4302 # . epilogue +4303 89/<- %esp 5/r32/ebp +4304 5d/pop-to-ebp +4305 c3/return +4306 +4307 mu-stmt-matches-function?: # stmt : (handle statement), function : (handle function) => result/eax : boolean +4308 # . prologue +4309 55/push-ebp +4310 89/<- %ebp 4/r32/esp +4311 # . save registers +4312 51/push-ecx +4313 # return function->name == stmt->operation +4314 8b/-> *(ebp+8) 1/r32/ecx +4315 8b/-> *(ebp+0xc) 0/r32/eax +4316 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax +4317 $mu-stmt-matches-function?:end: +4318 # . restore registers +4319 59/pop-to-ecx +4320 # . epilogue +4321 89/<- %esp 5/r32/ebp +4322 5d/pop-to-ebp +4323 c3/return +4324 +4325 mu-stmt-matches-primitive?: # stmt : (handle statement), primitive : (handle primitive) => result/eax : boolean +4326 # A mu stmt matches a primitive if the name matches, all the inout vars +4327 # match, and all the output vars match. +4328 # Vars match if types match and registers match. +4329 # In addition, a stmt output matches a primitive's output if types match +4330 # and the primitive has a wildcard register. +4331 # . prologue +4332 55/push-ebp +4333 89/<- %ebp 4/r32/esp +4334 # . save registers +4335 51/push-ecx +4336 52/push-edx +4337 53/push-ebx +4338 56/push-esi +4339 57/push-edi +4340 # ecx = stmt +4341 8b/-> *(ebp+8) 1/r32/ecx +4342 # edx = primitive +4343 8b/-> *(ebp+0xc) 2/r32/edx +4344 { +4345 $mu-stmt-matches-primitive?:check-name: +4346 # if (primitive->name != stmt->operation) return false +4347 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax +4348 3d/compare-eax-and 0/imm32 +4349 75/jump-if-not-equal break/disp8 +4350 b8/copy-to-eax 0/imm32 +4351 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4352 } +4353 $mu-stmt-matches-primitive?:check-inouts: +4354 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) +4355 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts +4356 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts +4357 { +4358 # if (curr == 0 && curr2 == 0) move on to check outputs +4359 { +4360 81 7/subop/compare %esi 0/imm32 +4361 75/jump-if-not-equal break/disp8 +4362 $mu-stmt-matches-primitive?:stmt-inout-is-null: +4363 { +4364 81 7/subop/compare %edi 0/imm32 +4365 75/jump-if-not-equal break/disp8 +4366 # +4367 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 +4368 } +4369 # return false +4370 b8/copy-to-eax 0/imm32/false +4371 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4372 } +4373 # if (curr2 == 0) return false +4374 { +4375 81 7/subop/compare %edi 0/imm32 +4376 75/jump-if-not-equal break/disp8 +4377 $mu-stmt-matches-primitive?:prim-inout-is-null: +4378 b8/copy-to-eax 0/imm32/false +4379 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4380 } +4381 # if (curr != curr2) return false +4382 { +4383 (operand-matches-primitive? *esi *edi) # => eax +4384 3d/compare-eax-and 0/imm32 +4385 75/jump-if-not-equal break/disp8 +4386 b8/copy-to-eax 0/imm32/false +4387 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4388 } +4389 # curr=curr->next +4390 8b/-> *(esi+4) 6/r32/esi # Operand-next +4391 # curr2=curr2->next +4392 8b/-> *(edi+4) 7/r32/edi # Operand-next +4393 eb/jump loop/disp8 +4394 } +4395 $mu-stmt-matches-primitive?:check-outputs: +4396 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) +4397 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs +4398 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs +4399 { +4400 # if (curr == 0) return (curr2 == 0) +4401 { +4402 $mu-stmt-matches-primitive?:check-output: +4403 81 7/subop/compare %esi 0/imm32 +4404 75/jump-if-not-equal break/disp8 +4405 { +4406 81 7/subop/compare %edi 0/imm32 +4407 75/jump-if-not-equal break/disp8 +4408 # return true +4409 b8/copy-to-eax 1/imm32 +4410 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4411 } +4412 # return false +4413 b8/copy-to-eax 0/imm32 +4414 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4415 } +4416 # if (curr2 == 0) return false +4417 { +4418 81 7/subop/compare %edi 0/imm32 +4419 75/jump-if-not-equal break/disp8 +4420 b8/copy-to-eax 0/imm32 +4421 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4422 } +4423 # if (curr != curr2) return false +4424 { +4425 (operand-matches-primitive? *esi *edi) # => eax +4426 3d/compare-eax-and 0/imm32 +4427 75/jump-if-not-equal break/disp8 +4428 b8/copy-to-eax 0/imm32 +4429 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4430 } +4431 # curr=curr->next +4432 8b/-> *(esi+4) 6/r32/esi # Operand-next +4433 # curr2=curr2->next +4434 8b/-> *(edi+4) 7/r32/edi # Operand-next +4435 eb/jump loop/disp8 +4436 } +4437 $mu-stmt-matches-primitive?:return-true: +4438 b8/copy-to-eax 1/imm32 +4439 $mu-stmt-matches-primitive?:end: +4440 # . restore registers +4441 5f/pop-to-edi +4442 5e/pop-to-esi +4443 5b/pop-to-ebx +4444 5a/pop-to-edx +4445 59/pop-to-ecx +4446 # . epilogue +4447 89/<- %esp 5/r32/ebp +4448 5d/pop-to-ebp +4449 c3/return +4450 +4451 operand-matches-primitive?: # var : (handle var), prim-var : (handle var) => result/eax : boolean +4452 # . prologue +4453 55/push-ebp +4454 89/<- %ebp 4/r32/esp +4455 # . save registers +4456 56/push-esi +4457 57/push-edi +4458 # esi = var +4459 8b/-> *(ebp+8) 6/r32/esi +4460 # edi = prim-var +4461 8b/-> *(ebp+0xc) 7/r32/edi +4462 # if (var->type != prim-var->type) return false +4463 8b/-> *(esi+4) 0/r32/eax # Var-type +4464 39/compare *(edi+4) 0/r32/eax # Var-type +4465 b8/copy-to-eax 0/imm32/false +4466 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 +4467 # return false if var->register doesn't match prim-var->register +4468 { +4469 # if addresses are equal, don't return here +4470 8b/-> *(esi+0x10) 0/r32/eax +4471 39/compare *(edi+0x10) 0/r32/eax +4472 74/jump-if-equal break/disp8 +4473 # if either address is 0, return false +4474 3d/compare-eax-and 0/imm32 +4475 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +4476 81 7/subop/compare *(edi+0x10) 0/imm32 +4477 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +4478 # if prim-var->register is "*", return true +4479 (string-equal? *(edi+0x10) "*") # Var-register +4480 3d/compare-eax-and 0/imm32 +4481 b8/copy-to-eax 1/imm32/true +4482 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 +4483 # if string contents don't match, return false +4484 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register +4485 3d/compare-eax-and 0/imm32 +4486 b8/copy-to-eax 0/imm32/false +4487 74/jump-if-equal $operand-matches-primitive?:end/disp8 +4488 } +4489 # return true +4490 b8/copy-to-eax 1/imm32/true +4491 $operand-matches-primitive?:end: +4492 # . restore registers +4493 5f/pop-to-edi +4494 5e/pop-to-esi +4495 # . epilogue +4496 89/<- %esp 5/r32/ebp +4497 5d/pop-to-ebp +4498 c3/return +4499 +4500 test-emit-subx-statement-primitive: +4501 # Primitive operation on a variable on the stack. +4502 # increment foo +4503 # => +4504 # ff 0/subop/increment *(ebp-8) +4505 # +4506 # There's a variable on the var stack as follows: +4507 # name: 'foo' +4508 # type: int +4509 # stack-offset: -8 +4510 # +4511 # There's a primitive with this info: +4512 # name: 'increment' +4513 # inouts: int/mem +4514 # value: 'ff 0/subop/increment' +4515 # +4516 # There's nothing in functions. +4517 # +4518 # . prologue +4519 55/push-ebp +4520 89/<- %ebp 4/r32/esp +4521 # setup +4522 (clear-stream _test-output-stream) +4523 (clear-stream $_test-output-buffered-file->buffer) +4524 # var var-foo/ecx : (ref var) +4525 68/push 0/imm32/no-register +4526 68/push -8/imm32/stack-offset +4527 68/push 1/imm32/block-depth +4528 68/push 1/imm32/type-int +4529 68/push "foo"/imm32 +4530 89/<- %ecx 4/r32/esp +4531 # var operand/ebx : (ref list var) +4532 68/push 0/imm32/next +4533 51/push-ecx/var-foo +4534 89/<- %ebx 4/r32/esp +4535 # var stmt/esi : (ref statement) +4536 68/push 0/imm32/next +4537 68/push 0/imm32/outputs +4538 53/push-ebx/operands +4539 68/push "increment"/imm32/operation +4540 68/push 1/imm32 +4541 89/<- %esi 4/r32/esp +4542 # var primitives/ebx : (ref primitive) +4543 68/push 0/imm32/next +4544 68/push 0/imm32/output-is-write-only +4545 68/push 0/imm32/no-imm32 +4546 68/push 0/imm32/no-r32 +4547 68/push 1/imm32/rm32-is-first-inout +4548 68/push "ff 0/subop/increment"/imm32/subx-name +4549 68/push 0/imm32/outputs +4550 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call +4551 68/push "increment"/imm32/name +4552 89/<- %ebx 4/r32/esp +4553 # convert +4554 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +4555 (flush _test-output-buffered-file) +4556 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +4562 # check output +4563 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") +4564 # . epilogue +4565 89/<- %esp 5/r32/ebp +4566 5d/pop-to-ebp +4567 c3/return +4568 +4569 test-emit-subx-statement-primitive-register: +4570 # Primitive operation on a variable in a register. +4571 # foo <- increment +4572 # => +4573 # ff 0/subop/increment %eax # sub-optimal, but should suffice +4574 # +4575 # There's a variable on the var stack as follows: +4576 # name: 'foo' +4577 # type: int +4578 # register: 'eax' +4579 # +4580 # There's a primitive with this info: +4581 # name: 'increment' +4582 # out: int/reg +4583 # value: 'ff 0/subop/increment' +4584 # +4585 # There's nothing in functions. +4586 # +4587 # . prologue +4588 55/push-ebp +4589 89/<- %ebp 4/r32/esp +4590 # setup +4591 (clear-stream _test-output-stream) +4592 (clear-stream $_test-output-buffered-file->buffer) +4593 # var var-foo/ecx : (ref var) in eax +4594 68/push "eax"/imm32/register +4595 68/push 0/imm32/no-stack-offset +4596 68/push 1/imm32/block-depth +4597 68/push 1/imm32/type-int +4598 68/push "foo"/imm32 +4599 89/<- %ecx 4/r32/esp +4600 # var operand/ebx : (ref list var) +4601 68/push 0/imm32/next +4602 51/push-ecx/var-foo +4603 89/<- %ebx 4/r32/esp +4604 # var stmt/esi : (ref statement) +4605 68/push 0/imm32/next +4606 53/push-ebx/outputs +4607 68/push 0/imm32/inouts +4608 68/push "increment"/imm32/operation +4609 68/push 1/imm32 +4610 89/<- %esi 4/r32/esp +4611 # var formal-var/ebx : (ref var) in any register +4612 68/push Any-register/imm32 +4613 68/push 0/imm32/no-stack-offset +4614 68/push 1/imm32/block-depth +4615 68/push 1/imm32/type-int +4616 68/push "dummy"/imm32 +4617 89/<- %ebx 4/r32/esp +4618 # var operand/ebx : (ref list var) +4619 68/push 0/imm32/next +4620 53/push-ebx/formal-var +4621 89/<- %ebx 4/r32/esp +4622 # var primitives/ebx : (ref primitive) +4623 68/push 0/imm32/next +4624 68/push 0/imm32/output-is-write-only +4625 68/push 0/imm32/no-imm32 +4626 68/push 0/imm32/no-r32 +4627 68/push 3/imm32/rm32-in-first-output +4628 68/push "ff 0/subop/increment"/imm32/subx-name +4629 53/push-ebx/outputs +4630 68/push 0/imm32/inouts +4631 68/push "increment"/imm32/name +4632 89/<- %ebx 4/r32/esp +4633 # convert +4634 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +4635 (flush _test-output-buffered-file) +4636 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +4642 # check output +4643 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") +4644 # . epilogue +4645 89/<- %esp 5/r32/ebp +4646 5d/pop-to-ebp +4647 c3/return +4648 +4649 test-emit-subx-statement-select-primitive: +4650 # Select the right primitive between overloads. +4651 # foo <- increment +4652 # => +4653 # ff 0/subop/increment %eax # sub-optimal, but should suffice +4654 # +4655 # There's a variable on the var stack as follows: +4656 # name: 'foo' +4657 # type: int +4658 # register: 'eax' +4659 # +4660 # There's two primitives, as follows: +4661 # - name: 'increment' +4662 # out: int/reg +4663 # value: 'ff 0/subop/increment' +4664 # - name: 'increment' +4665 # inout: int/mem +4666 # value: 'ff 0/subop/increment' +4667 # +4668 # There's nothing in functions. +4669 # +4670 # . prologue +4671 55/push-ebp +4672 89/<- %ebp 4/r32/esp +4673 # setup +4674 (clear-stream _test-output-stream) +4675 (clear-stream $_test-output-buffered-file->buffer) +4676 # var var-foo/ecx : (ref var) in eax +4677 68/push "eax"/imm32/register +4678 68/push 0/imm32/no-stack-offset +4679 68/push 1/imm32/block-depth +4680 68/push 1/imm32/type-int +4681 68/push "foo"/imm32 +4682 89/<- %ecx 4/r32/esp +4683 # var real-outputs/edi : (ref list var) +4684 68/push 0/imm32/next +4685 51/push-ecx/var-foo +4686 89/<- %edi 4/r32/esp +4687 # var stmt/esi : (ref statement) +4688 68/push 0/imm32/next +4689 57/push-edi/outputs +4690 68/push 0/imm32/inouts +4691 68/push "increment"/imm32/operation +4692 68/push 1/imm32 +4693 89/<- %esi 4/r32/esp +4694 # var formal-var/ebx : (ref var) in any register +4695 68/push Any-register/imm32 +4696 68/push 0/imm32/no-stack-offset +4697 68/push 1/imm32/block-depth +4698 68/push 1/imm32/type-int +4699 68/push "dummy"/imm32 +4700 89/<- %ebx 4/r32/esp +4701 # var formal-outputs/ebx : (ref list var) = {formal-var, 0} +4702 68/push 0/imm32/next +4703 53/push-ebx/formal-var +4704 89/<- %ebx 4/r32/esp +4705 # var primitive1/ebx : (ref primitive) +4706 68/push 0/imm32/next +4707 68/push 0/imm32/output-is-write-only +4708 68/push 0/imm32/no-imm32 +4709 68/push 0/imm32/no-r32 +4710 68/push 3/imm32/rm32-in-first-output +4711 68/push "ff 0/subop/increment"/imm32/subx-name +4712 53/push-ebx/outputs/formal-outputs +4713 68/push 0/imm32/inouts +4714 68/push "increment"/imm32/name +4715 89/<- %ebx 4/r32/esp +4716 # var primitives/ebx : (ref primitive) +4717 53/push-ebx/next +4718 68/push 0/imm32/output-is-write-only +4719 68/push 0/imm32/no-imm32 +4720 68/push 0/imm32/no-r32 +4721 68/push 1/imm32/rm32-is-first-inout +4722 68/push "ff 0/subop/increment"/imm32/subx-name +4723 68/push 0/imm32/outputs +4724 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +4725 68/push "increment"/imm32/name +4726 89/<- %ebx 4/r32/esp +4727 # convert +4728 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +4729 (flush _test-output-buffered-file) +4730 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +4736 # check output +4737 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") +4738 # . epilogue +4739 89/<- %esp 5/r32/ebp +4740 5d/pop-to-ebp +4741 c3/return +4742 +4743 test-emit-subx-statement-select-primitive-2: +4744 # Select the right primitive between overloads. +4745 # foo <- increment +4746 # => +4747 # ff 0/subop/increment %eax # sub-optimal, but should suffice +4748 # +4749 # There's a variable on the var stack as follows: +4750 # name: 'foo' +4751 # type: int +4752 # register: 'eax' +4753 # +4754 # There's two primitives, as follows: +4755 # - name: 'increment' +4756 # out: int/reg +4757 # value: 'ff 0/subop/increment' +4758 # - name: 'increment' +4759 # inout: int/mem +4760 # value: 'ff 0/subop/increment' +4761 # +4762 # There's nothing in functions. 4763 # 4764 # . prologue 4765 55/push-ebp @@ -4754,339 +4764,614 @@ if ('onhashchange' in window) { 4767 # setup 4768 (clear-stream _test-output-stream) 4769 (clear-stream $_test-output-buffered-file->buffer) -4770 # var var-var1/ecx : (ref var) in eax +4770 # var var-foo/ecx : (ref var) in eax 4771 68/push "eax"/imm32/register 4772 68/push 0/imm32/no-stack-offset 4773 68/push 1/imm32/block-depth 4774 68/push 1/imm32/type-int -4775 68/push "var1"/imm32 +4775 68/push "foo"/imm32 4776 89/<- %ecx 4/r32/esp -4777 # var var-var2/edx : (ref var) -4778 68/push 0/imm32/no-register -4779 68/push 8/imm32/stack-offset -4780 68/push 1/imm32/block-depth -4781 68/push 1/imm32/type-int -4782 68/push "var2"/imm32 -4783 89/<- %edx 4/r32/esp -4784 # var inouts/esi : (ref list var2) -4785 68/push 0/imm32/next -4786 52/push-edx/var-var2 +4777 # var inouts/edi : (ref list var) +4778 68/push 0/imm32/next +4779 51/push-ecx/var-foo +4780 89/<- %edi 4/r32/esp +4781 # var stmt/esi : (ref statement) +4782 68/push 0/imm32/next +4783 68/push 0/imm32/outputs +4784 57/push-edi/inouts +4785 68/push "increment"/imm32/operation +4786 68/push 1/imm32 4787 89/<- %esi 4/r32/esp -4788 # var outputs/edi : (ref list var1) -4789 68/push 0/imm32/next -4790 51/push-ecx/var-var1 -4791 89/<- %edi 4/r32/esp -4792 # var stmt/esi : (ref statement) -4793 68/push 0/imm32/next -4794 57/push-edi/outputs -4795 56/push-esi/inouts -4796 68/push "add"/imm32/operation -4797 68/push 1/imm32 -4798 89/<- %esi 4/r32/esp -4799 # convert -4800 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -4801 (flush _test-output-buffered-file) -4802 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4808 # check output -4809 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") -4810 # . epilogue -4811 89/<- %esp 5/r32/ebp -4812 5d/pop-to-ebp -4813 c3/return -4814 -4815 test-add-literal-to-eax: -4816 # var1/eax <- add 0x34 -4817 # => -4818 # 05/add-to-eax 0x34/imm32 -4819 # -4820 # . prologue -4821 55/push-ebp -4822 89/<- %ebp 4/r32/esp -4823 # setup -4824 (clear-stream _test-output-stream) -4825 (clear-stream $_test-output-buffered-file->buffer) -4826 # var var-var1/ecx : (ref var) in eax -4827 68/push "eax"/imm32/register -4828 68/push 0/imm32/no-stack-offset -4829 68/push 1/imm32/block-depth -4830 68/push 1/imm32/type-int -4831 68/push "var1"/imm32 -4832 89/<- %ecx 4/r32/esp -4833 # var var-var2/edx : (ref var) literal -4834 68/push 0/imm32/no-register -4835 68/push 0/imm32/no-stack-offset -4836 68/push 1/imm32/block-depth -4837 68/push 0/imm32/type-literal -4838 68/push "0x34"/imm32 -4839 89/<- %edx 4/r32/esp -4840 # var inouts/esi : (ref list var2) -4841 68/push 0/imm32/next -4842 52/push-edx/var-var2 -4843 89/<- %esi 4/r32/esp -4844 # var outputs/edi : (ref list var1) -4845 68/push 0/imm32/next -4846 51/push-ecx/var-var1 -4847 89/<- %edi 4/r32/esp -4848 # var stmt/esi : (ref statement) -4849 68/push 0/imm32/next -4850 57/push-edi/outputs -4851 56/push-esi/inouts -4852 68/push "add"/imm32/operation -4853 68/push 1/imm32 -4854 89/<- %esi 4/r32/esp -4855 # convert -4856 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -4857 (flush _test-output-buffered-file) -4858 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4864 # check output -4865 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") -4866 # . epilogue -4867 89/<- %esp 5/r32/ebp -4868 5d/pop-to-ebp -4869 c3/return -4870 -4871 test-add-literal-to-reg: -4872 # var1/ecx <- add 0x34 -4873 # => -4874 # 81 0/subop/add %ecx 0x34/imm32 -4875 # -4876 # . prologue -4877 55/push-ebp -4878 89/<- %ebp 4/r32/esp -4879 # setup -4880 (clear-stream _test-output-stream) -4881 (clear-stream $_test-output-buffered-file->buffer) -4882 # var var-var1/ecx : (ref var) in ecx -4883 68/push "ecx"/imm32/register -4884 68/push 0/imm32/no-stack-offset -4885 68/push 1/imm32/block-depth -4886 68/push 1/imm32/type-int -4887 68/push "var1"/imm32 -4888 89/<- %ecx 4/r32/esp -4889 # var var-var2/edx : (ref var) literal -4890 68/push 0/imm32/no-register -4891 68/push 0/imm32/no-stack-offset -4892 68/push 1/imm32/block-depth -4893 68/push 0/imm32/type-literal -4894 68/push "0x34"/imm32 -4895 89/<- %edx 4/r32/esp -4896 # var inouts/esi : (ref list var2) -4897 68/push 0/imm32/next -4898 52/push-edx/var-var2 -4899 89/<- %esi 4/r32/esp -4900 # var outputs/edi : (ref list var1) -4901 68/push 0/imm32/next -4902 51/push-ecx/var-var1 -4903 89/<- %edi 4/r32/esp -4904 # var stmt/esi : (ref statement) -4905 68/push 0/imm32/next -4906 57/push-edi/outputs -4907 56/push-esi/inouts -4908 68/push "add"/imm32/operation -4909 68/push 1/imm32 -4910 89/<- %esi 4/r32/esp -4911 # convert -4912 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -4913 (flush _test-output-buffered-file) -4914 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4920 # check output -4921 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") -4922 # . epilogue -4923 89/<- %esp 5/r32/ebp -4924 5d/pop-to-ebp -4925 c3/return -4926 -4927 test-add-literal-to-mem: -4928 # add-to var1, 0x34 -4929 # => -4930 # 81 0/subop/add %eax 0x34/imm32 -4931 # -4932 # . prologue -4933 55/push-ebp -4934 89/<- %ebp 4/r32/esp -4935 # setup -4936 (clear-stream _test-output-stream) -4937 (clear-stream $_test-output-buffered-file->buffer) -4938 # var var-var1/ecx : (ref var) -4939 68/push 0/imm32/no-register -4940 68/push 8/imm32/stack-offset -4941 68/push 1/imm32/block-depth -4942 68/push 1/imm32/type-int -4943 68/push "var1"/imm32 -4944 89/<- %ecx 4/r32/esp -4945 # var var-var2/edx : (ref var) literal -4946 68/push 0/imm32/no-register -4947 68/push 0/imm32/no-stack-offset -4948 68/push 1/imm32/block-depth -4949 68/push 0/imm32/type-literal -4950 68/push "0x34"/imm32 -4951 89/<- %edx 4/r32/esp -4952 # var inouts/esi : (ref list var2) -4953 68/push 0/imm32/next -4954 52/push-edx/var-var2 -4955 89/<- %esi 4/r32/esp -4956 # var inouts = (ref list var1 inouts) -4957 56/push-esi/next -4958 51/push-ecx/var-var1 -4959 89/<- %esi 4/r32/esp -4960 # var stmt/esi : (ref statement) -4961 68/push 0/imm32/next -4962 68/push 0/imm32/outputs -4963 56/push-esi/inouts -4964 68/push "add-to"/imm32/operation -4965 68/push 1/imm32 -4966 89/<- %esi 4/r32/esp -4967 # convert -4968 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -4969 (flush _test-output-buffered-file) -4970 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4976 # check output -4977 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") -4978 # . epilogue -4979 89/<- %esp 5/r32/ebp -4980 5d/pop-to-ebp -4981 c3/return -4982 -4983 test-emit-subx-statement-function-call: -4984 # Call a function on a variable on the stack. -4985 # f foo -4986 # => -4987 # (f2 *(ebp-8)) -4988 # (Changing the function name supports overloading in general, but here it -4989 # just serves to help disambiguate things.) -4990 # -4991 # There's a variable on the var stack as follows: -4992 # name: 'foo' -4993 # type: int -4994 # stack-offset: -8 -4995 # -4996 # There's nothing in primitives. -4997 # -4998 # There's a function with this info: -4999 # name: 'f' -5000 # inout: int/mem -5001 # value: 'f2' -5002 # -5003 # . prologue -5004 55/push-ebp -5005 89/<- %ebp 4/r32/esp -5006 # setup -5007 (clear-stream _test-output-stream) -5008 (clear-stream $_test-output-buffered-file->buffer) -5009 # var var-foo/ecx : (ref var) -5010 68/push 0/imm32/no-register -5011 68/push -8/imm32/stack-offset -5012 68/push 0/imm32/block-depth -5013 68/push 1/imm32/type-int -5014 68/push "foo"/imm32 -5015 89/<- %ecx 4/r32/esp -5016 # var operands/esi : (ref list var) -5017 68/push 0/imm32/next -5018 51/push-ecx/var-foo -5019 89/<- %esi 4/r32/esp -5020 # var stmt/esi : (ref statement) -5021 68/push 0/imm32/next -5022 68/push 0/imm32/outputs -5023 56/push-esi/inouts -5024 68/push "f"/imm32/operation -5025 68/push 1/imm32 -5026 89/<- %esi 4/r32/esp -5027 # var functions/ebx : (ref function) -5028 68/push 0/imm32/next -5029 68/push 0/imm32/body -5030 68/push 0/imm32/outputs -5031 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -5032 68/push "f2"/imm32/subx-name -5033 68/push "f"/imm32/name -5034 89/<- %ebx 4/r32/esp -5035 # convert -5036 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -5037 (flush _test-output-buffered-file) -5038 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5044 # check output -5045 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") -5046 # . epilogue -5047 89/<- %esp 5/r32/ebp -5048 5d/pop-to-ebp -5049 c3/return -5050 -5051 test-emit-subx-statement-function-call-with-literal-arg: -5052 # Call a function on a literal. -5053 # f 34 -5054 # => -5055 # (f2 34) -5056 # -5057 # . prologue -5058 55/push-ebp -5059 89/<- %ebp 4/r32/esp -5060 # setup -5061 (clear-stream _test-output-stream) -5062 (clear-stream $_test-output-buffered-file->buffer) -5063 # var var-foo/ecx : (ref var) literal -5064 68/push 0/imm32/no-register -5065 68/push 0/imm32/no-stack-offset -5066 68/push 0/imm32/block-depth -5067 68/push 0/imm32/type-literal -5068 68/push "34"/imm32 -5069 89/<- %ecx 4/r32/esp -5070 # var operands/esi : (ref list var) -5071 68/push 0/imm32/next -5072 51/push-ecx/var-foo -5073 89/<- %esi 4/r32/esp -5074 # var stmt/esi : (ref statement) -5075 68/push 0/imm32/next -5076 68/push 0/imm32/outputs -5077 56/push-esi/inouts -5078 68/push "f"/imm32/operation -5079 68/push 1/imm32 -5080 89/<- %esi 4/r32/esp -5081 # var functions/ebx : (ref function) -5082 68/push 0/imm32/next -5083 68/push 0/imm32/body -5084 68/push 0/imm32/outputs -5085 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -5086 68/push "f2"/imm32/subx-name -5087 68/push "f"/imm32/name -5088 89/<- %ebx 4/r32/esp -5089 # convert -5090 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -5091 (flush _test-output-buffered-file) -5092 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5098 # check output -5099 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") -5100 # . epilogue -5101 89/<- %esp 5/r32/ebp -5102 5d/pop-to-ebp -5103 c3/return -5104 -5105 emit-subx-prologue: # out : (address buffered-file) -5106 # . prologue -5107 55/push-ebp -5108 89/<- %ebp 4/r32/esp -5109 # -5110 (write-buffered *(ebp+8) "# . prologue\n") -5111 (write-buffered *(ebp+8) "55/push-ebp\n") -5112 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") -5113 $emit-subx-prologue:end: -5114 # . epilogue -5115 89/<- %esp 5/r32/ebp -5116 5d/pop-to-ebp -5117 c3/return -5118 -5119 emit-subx-epilogue: # out : (address buffered-file) +4788 # var formal-var/ebx : (ref var) in any register +4789 68/push Any-register/imm32 +4790 68/push 0/imm32/no-stack-offset +4791 68/push 1/imm32/block-depth +4792 68/push 1/imm32/type-int +4793 68/push "dummy"/imm32 +4794 89/<- %ebx 4/r32/esp +4795 # var operand/ebx : (ref list var) +4796 68/push 0/imm32/next +4797 53/push-ebx/formal-var +4798 89/<- %ebx 4/r32/esp +4799 # var primitive1/ebx : primitive +4800 68/push 0/imm32/next +4801 68/push 0/imm32/output-is-write-only +4802 68/push 0/imm32/no-imm32 +4803 68/push 0/imm32/no-r32 +4804 68/push 3/imm32/rm32-in-first-output +4805 68/push "ff 0/subop/increment"/imm32/subx-name +4806 53/push-ebx/outputs/formal-outputs +4807 68/push 0/imm32/inouts +4808 68/push "increment"/imm32/name +4809 89/<- %ebx 4/r32/esp +4810 # var primitives/ebx : (ref primitive) +4811 53/push-ebx/next +4812 68/push 0/imm32/output-is-write-only +4813 68/push 0/imm32/no-imm32 +4814 68/push 0/imm32/no-r32 +4815 68/push 1/imm32/rm32-is-first-inout +4816 68/push "ff 0/subop/increment"/imm32/subx-name +4817 68/push 0/imm32/outputs +4818 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +4819 68/push "increment"/imm32/name +4820 89/<- %ebx 4/r32/esp +4821 # convert +4822 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +4823 (flush _test-output-buffered-file) +4824 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +4830 # check output +4831 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") +4832 # . epilogue +4833 89/<- %esp 5/r32/ebp +4834 5d/pop-to-ebp +4835 c3/return +4836 +4837 test-increment-register: +4838 # Select the right primitive between overloads. +4839 # foo <- increment +4840 # => +4841 # 50/increment-eax +4842 # +4843 # There's a variable on the var stack as follows: +4844 # name: 'foo' +4845 # type: int +4846 # register: 'eax' +4847 # +4848 # Primitives are the global definitions. +4849 # +4850 # There are no functions defined. +4851 # +4852 # . prologue +4853 55/push-ebp +4854 89/<- %ebp 4/r32/esp +4855 # setup +4856 (clear-stream _test-output-stream) +4857 (clear-stream $_test-output-buffered-file->buffer) +4858 # var var-foo/ecx : (ref var) in eax +4859 68/push "eax"/imm32/register +4860 68/push 0/imm32/no-stack-offset +4861 68/push 1/imm32/block-depth +4862 68/push 1/imm32/type-int +4863 68/push "foo"/imm32 +4864 89/<- %ecx 4/r32/esp +4865 # var real-outputs/edi : (ref list var) +4866 68/push 0/imm32/next +4867 51/push-ecx/var-foo +4868 89/<- %edi 4/r32/esp +4869 # var stmt/esi : (ref statement) +4870 68/push 0/imm32/next +4871 57/push-edi/outputs +4872 68/push 0/imm32/inouts +4873 68/push "increment"/imm32/operation +4874 68/push 1/imm32 +4875 89/<- %esi 4/r32/esp +4876 # convert +4877 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +4878 (flush _test-output-buffered-file) +4879 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +4885 # check output +4886 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") +4887 # . epilogue +4888 89/<- %esp 5/r32/ebp +4889 5d/pop-to-ebp +4890 c3/return +4891 +4892 test-increment-var: +4893 # Select the right primitive between overloads. +4894 # foo <- increment +4895 # => +4896 # ff 0/subop/increment %eax # sub-optimal, but should suffice +4897 # +4898 # There's a variable on the var stack as follows: +4899 # name: 'foo' +4900 # type: int +4901 # register: 'eax' +4902 # +4903 # Primitives are the global definitions. +4904 # +4905 # There are no functions defined. +4906 # +4907 # . prologue +4908 55/push-ebp +4909 89/<- %ebp 4/r32/esp +4910 # setup +4911 (clear-stream _test-output-stream) +4912 (clear-stream $_test-output-buffered-file->buffer) +4913 # var var-foo/ecx : (ref var) in eax +4914 68/push "eax"/imm32/register +4915 68/push 0/imm32/no-stack-offset +4916 68/push 1/imm32/block-depth +4917 68/push 1/imm32/type-int +4918 68/push "foo"/imm32 +4919 89/<- %ecx 4/r32/esp +4920 # var inouts/edi : (ref list var) +4921 68/push 0/imm32/next +4922 51/push-ecx/var-foo +4923 89/<- %edi 4/r32/esp +4924 # var stmt/esi : (ref statement) +4925 68/push 0/imm32/next +4926 68/push 0/imm32/outputs +4927 57/push-edi/inouts +4928 68/push "increment"/imm32/operation +4929 68/push 1/imm32 +4930 89/<- %esi 4/r32/esp +4931 # convert +4932 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +4933 (flush _test-output-buffered-file) +4934 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +4940 # check output +4941 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") +4942 # . epilogue +4943 89/<- %esp 5/r32/ebp +4944 5d/pop-to-ebp +4945 c3/return +4946 +4947 test-add-reg-to-reg: +4948 # var1/reg <- add var2/reg +4949 # => +4950 # 01/add %var1 var2 +4951 # +4952 # . prologue +4953 55/push-ebp +4954 89/<- %ebp 4/r32/esp +4955 # setup +4956 (clear-stream _test-output-stream) +4957 (clear-stream $_test-output-buffered-file->buffer) +4958 # var var-var1/ecx : (ref var) in eax +4959 68/push "eax"/imm32/register +4960 68/push 0/imm32/no-stack-offset +4961 68/push 1/imm32/block-depth +4962 68/push 1/imm32/type-int +4963 68/push "var1"/imm32 +4964 89/<- %ecx 4/r32/esp +4965 # var var-var2/edx : (ref var) in ecx +4966 68/push "ecx"/imm32/register +4967 68/push 0/imm32/no-stack-offset +4968 68/push 1/imm32/block-depth +4969 68/push 1/imm32/type-int +4970 68/push "var2"/imm32 +4971 89/<- %edx 4/r32/esp +4972 # var inouts/esi : (ref list var2) +4973 68/push 0/imm32/next +4974 52/push-edx/var-var2 +4975 89/<- %esi 4/r32/esp +4976 # var outputs/edi : (ref list var1) +4977 68/push 0/imm32/next +4978 51/push-ecx/var-var1 +4979 89/<- %edi 4/r32/esp +4980 # var stmt/esi : (ref statement) +4981 68/push 0/imm32/next +4982 57/push-edi/outputs +4983 56/push-esi/inouts +4984 68/push "add"/imm32/operation +4985 68/push 1/imm32 +4986 89/<- %esi 4/r32/esp +4987 # convert +4988 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +4989 (flush _test-output-buffered-file) +4990 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +4996 # check output +4997 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") +4998 # . epilogue +4999 89/<- %esp 5/r32/ebp +5000 5d/pop-to-ebp +5001 c3/return +5002 +5003 test-add-reg-to-mem: +5004 # add-to var1 var2/reg +5005 # => +5006 # 01/add *(ebp+__) var2 +5007 # +5008 # . prologue +5009 55/push-ebp +5010 89/<- %ebp 4/r32/esp +5011 # setup +5012 (clear-stream _test-output-stream) +5013 (clear-stream $_test-output-buffered-file->buffer) +5014 # var var-var1/ecx : (ref var) +5015 68/push 0/imm32/no-register +5016 68/push 8/imm32/stack-offset +5017 68/push 1/imm32/block-depth +5018 68/push 1/imm32/type-int +5019 68/push "var1"/imm32 +5020 89/<- %ecx 4/r32/esp +5021 # var var-var2/edx : (ref var) in ecx +5022 68/push "ecx"/imm32/register +5023 68/push 0/imm32/no-stack-offset +5024 68/push 1/imm32/block-depth +5025 68/push 1/imm32/type-int +5026 68/push "var2"/imm32 +5027 89/<- %edx 4/r32/esp +5028 # var inouts/esi : (ref list var2) +5029 68/push 0/imm32/next +5030 52/push-edx/var-var2 +5031 89/<- %esi 4/r32/esp +5032 # var inouts = (ref list var1 var2) +5033 56/push-esi/next +5034 51/push-ecx/var-var1 +5035 89/<- %esi 4/r32/esp +5036 # var stmt/esi : (ref statement) +5037 68/push 0/imm32/next +5038 68/push 0/imm32/outputs +5039 56/push-esi/inouts +5040 68/push "add-to"/imm32/operation +5041 68/push 1/imm32 +5042 89/<- %esi 4/r32/esp +5043 # convert +5044 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5045 (flush _test-output-buffered-file) +5046 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5052 # check output +5053 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") +5054 # . epilogue +5055 89/<- %esp 5/r32/ebp +5056 5d/pop-to-ebp +5057 c3/return +5058 +5059 test-add-mem-to-reg: +5060 # var1/reg <- add var2 +5061 # => +5062 # 03/add *(ebp+__) var1 +5063 # +5064 # . prologue +5065 55/push-ebp +5066 89/<- %ebp 4/r32/esp +5067 # setup +5068 (clear-stream _test-output-stream) +5069 (clear-stream $_test-output-buffered-file->buffer) +5070 # var var-var1/ecx : (ref var) in eax +5071 68/push "eax"/imm32/register +5072 68/push 0/imm32/no-stack-offset +5073 68/push 1/imm32/block-depth +5074 68/push 1/imm32/type-int +5075 68/push "var1"/imm32 +5076 89/<- %ecx 4/r32/esp +5077 # var var-var2/edx : (ref var) +5078 68/push 0/imm32/no-register +5079 68/push 8/imm32/stack-offset +5080 68/push 1/imm32/block-depth +5081 68/push 1/imm32/type-int +5082 68/push "var2"/imm32 +5083 89/<- %edx 4/r32/esp +5084 # var inouts/esi : (ref list var2) +5085 68/push 0/imm32/next +5086 52/push-edx/var-var2 +5087 89/<- %esi 4/r32/esp +5088 # var outputs/edi : (ref list var1) +5089 68/push 0/imm32/next +5090 51/push-ecx/var-var1 +5091 89/<- %edi 4/r32/esp +5092 # var stmt/esi : (ref statement) +5093 68/push 0/imm32/next +5094 57/push-edi/outputs +5095 56/push-esi/inouts +5096 68/push "add"/imm32/operation +5097 68/push 1/imm32 +5098 89/<- %esi 4/r32/esp +5099 # convert +5100 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5101 (flush _test-output-buffered-file) +5102 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5108 # check output +5109 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") +5110 # . epilogue +5111 89/<- %esp 5/r32/ebp +5112 5d/pop-to-ebp +5113 c3/return +5114 +5115 test-add-literal-to-eax: +5116 # var1/eax <- add 0x34 +5117 # => +5118 # 05/add-to-eax 0x34/imm32 +5119 # 5120 # . prologue 5121 55/push-ebp 5122 89/<- %ebp 4/r32/esp -5123 # -5124 (write-buffered *(ebp+8) "# . epilogue\n") -5125 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") -5126 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") -5127 (write-buffered *(ebp+8) "c3/return\n") -5128 $emit-subx-epilogue:end: -5129 # . epilogue -5130 89/<- %esp 5/r32/ebp -5131 5d/pop-to-ebp -5132 c3/return +5123 # setup +5124 (clear-stream _test-output-stream) +5125 (clear-stream $_test-output-buffered-file->buffer) +5126 # var var-var1/ecx : (ref var) in eax +5127 68/push "eax"/imm32/register +5128 68/push 0/imm32/no-stack-offset +5129 68/push 1/imm32/block-depth +5130 68/push 1/imm32/type-int +5131 68/push "var1"/imm32 +5132 89/<- %ecx 4/r32/esp +5133 # var var-var2/edx : (ref var) literal +5134 68/push 0/imm32/no-register +5135 68/push 0/imm32/no-stack-offset +5136 68/push 1/imm32/block-depth +5137 68/push 0/imm32/type-literal +5138 68/push "0x34"/imm32 +5139 89/<- %edx 4/r32/esp +5140 # var inouts/esi : (ref list var2) +5141 68/push 0/imm32/next +5142 52/push-edx/var-var2 +5143 89/<- %esi 4/r32/esp +5144 # var outputs/edi : (ref list var1) +5145 68/push 0/imm32/next +5146 51/push-ecx/var-var1 +5147 89/<- %edi 4/r32/esp +5148 # var stmt/esi : (ref statement) +5149 68/push 0/imm32/next +5150 57/push-edi/outputs +5151 56/push-esi/inouts +5152 68/push "add"/imm32/operation +5153 68/push 1/imm32 +5154 89/<- %esi 4/r32/esp +5155 # convert +5156 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5157 (flush _test-output-buffered-file) +5158 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5164 # check output +5165 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") +5166 # . epilogue +5167 89/<- %esp 5/r32/ebp +5168 5d/pop-to-ebp +5169 c3/return +5170 +5171 test-add-literal-to-reg: +5172 # var1/ecx <- add 0x34 +5173 # => +5174 # 81 0/subop/add %ecx 0x34/imm32 +5175 # +5176 # . prologue +5177 55/push-ebp +5178 89/<- %ebp 4/r32/esp +5179 # setup +5180 (clear-stream _test-output-stream) +5181 (clear-stream $_test-output-buffered-file->buffer) +5182 # var var-var1/ecx : (ref var) in ecx +5183 68/push "ecx"/imm32/register +5184 68/push 0/imm32/no-stack-offset +5185 68/push 1/imm32/block-depth +5186 68/push 1/imm32/type-int +5187 68/push "var1"/imm32 +5188 89/<- %ecx 4/r32/esp +5189 # var var-var2/edx : (ref var) literal +5190 68/push 0/imm32/no-register +5191 68/push 0/imm32/no-stack-offset +5192 68/push 1/imm32/block-depth +5193 68/push 0/imm32/type-literal +5194 68/push "0x34"/imm32 +5195 89/<- %edx 4/r32/esp +5196 # var inouts/esi : (ref list var2) +5197 68/push 0/imm32/next +5198 52/push-edx/var-var2 +5199 89/<- %esi 4/r32/esp +5200 # var outputs/edi : (ref list var1) +5201 68/push 0/imm32/next +5202 51/push-ecx/var-var1 +5203 89/<- %edi 4/r32/esp +5204 # var stmt/esi : (ref statement) +5205 68/push 0/imm32/next +5206 57/push-edi/outputs +5207 56/push-esi/inouts +5208 68/push "add"/imm32/operation +5209 68/push 1/imm32 +5210 89/<- %esi 4/r32/esp +5211 # convert +5212 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5213 (flush _test-output-buffered-file) +5214 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5220 # check output +5221 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") +5222 # . epilogue +5223 89/<- %esp 5/r32/ebp +5224 5d/pop-to-ebp +5225 c3/return +5226 +5227 test-add-literal-to-mem: +5228 # add-to var1, 0x34 +5229 # => +5230 # 81 0/subop/add %eax 0x34/imm32 +5231 # +5232 # . prologue +5233 55/push-ebp +5234 89/<- %ebp 4/r32/esp +5235 # setup +5236 (clear-stream _test-output-stream) +5237 (clear-stream $_test-output-buffered-file->buffer) +5238 # var var-var1/ecx : (ref var) +5239 68/push 0/imm32/no-register +5240 68/push 8/imm32/stack-offset +5241 68/push 1/imm32/block-depth +5242 68/push 1/imm32/type-int +5243 68/push "var1"/imm32 +5244 89/<- %ecx 4/r32/esp +5245 # var var-var2/edx : (ref var) literal +5246 68/push 0/imm32/no-register +5247 68/push 0/imm32/no-stack-offset +5248 68/push 1/imm32/block-depth +5249 68/push 0/imm32/type-literal +5250 68/push "0x34"/imm32 +5251 89/<- %edx 4/r32/esp +5252 # var inouts/esi : (ref list var2) +5253 68/push 0/imm32/next +5254 52/push-edx/var-var2 +5255 89/<- %esi 4/r32/esp +5256 # var inouts = (ref list var1 inouts) +5257 56/push-esi/next +5258 51/push-ecx/var-var1 +5259 89/<- %esi 4/r32/esp +5260 # var stmt/esi : (ref statement) +5261 68/push 0/imm32/next +5262 68/push 0/imm32/outputs +5263 56/push-esi/inouts +5264 68/push "add-to"/imm32/operation +5265 68/push 1/imm32 +5266 89/<- %esi 4/r32/esp +5267 # convert +5268 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5269 (flush _test-output-buffered-file) +5270 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5276 # check output +5277 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") +5278 # . epilogue +5279 89/<- %esp 5/r32/ebp +5280 5d/pop-to-ebp +5281 c3/return +5282 +5283 test-emit-subx-statement-function-call: +5284 # Call a function on a variable on the stack. +5285 # f foo +5286 # => +5287 # (f2 *(ebp-8)) +5288 # (Changing the function name supports overloading in general, but here it +5289 # just serves to help disambiguate things.) +5290 # +5291 # There's a variable on the var stack as follows: +5292 # name: 'foo' +5293 # type: int +5294 # stack-offset: -8 +5295 # +5296 # There's nothing in primitives. +5297 # +5298 # There's a function with this info: +5299 # name: 'f' +5300 # inout: int/mem +5301 # value: 'f2' +5302 # +5303 # . prologue +5304 55/push-ebp +5305 89/<- %ebp 4/r32/esp +5306 # setup +5307 (clear-stream _test-output-stream) +5308 (clear-stream $_test-output-buffered-file->buffer) +5309 # var var-foo/ecx : (ref var) +5310 68/push 0/imm32/no-register +5311 68/push -8/imm32/stack-offset +5312 68/push 0/imm32/block-depth +5313 68/push 1/imm32/type-int +5314 68/push "foo"/imm32 +5315 89/<- %ecx 4/r32/esp +5316 # var operands/esi : (ref list var) +5317 68/push 0/imm32/next +5318 51/push-ecx/var-foo +5319 89/<- %esi 4/r32/esp +5320 # var stmt/esi : (ref statement) +5321 68/push 0/imm32/next +5322 68/push 0/imm32/outputs +5323 56/push-esi/inouts +5324 68/push "f"/imm32/operation +5325 68/push 1/imm32 +5326 89/<- %esi 4/r32/esp +5327 # var functions/ebx : (ref function) +5328 68/push 0/imm32/next +5329 68/push 0/imm32/body +5330 68/push 0/imm32/outputs +5331 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +5332 68/push "f2"/imm32/subx-name +5333 68/push "f"/imm32/name +5334 89/<- %ebx 4/r32/esp +5335 # convert +5336 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +5337 (flush _test-output-buffered-file) +5338 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5344 # check output +5345 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") +5346 # . epilogue +5347 89/<- %esp 5/r32/ebp +5348 5d/pop-to-ebp +5349 c3/return +5350 +5351 test-emit-subx-statement-function-call-with-literal-arg: +5352 # Call a function on a literal. +5353 # f 34 +5354 # => +5355 # (f2 34) +5356 # +5357 # . prologue +5358 55/push-ebp +5359 89/<- %ebp 4/r32/esp +5360 # setup +5361 (clear-stream _test-output-stream) +5362 (clear-stream $_test-output-buffered-file->buffer) +5363 # var var-foo/ecx : (ref var) literal +5364 68/push 0/imm32/no-register +5365 68/push 0/imm32/no-stack-offset +5366 68/push 0/imm32/block-depth +5367 68/push 0/imm32/type-literal +5368 68/push "34"/imm32 +5369 89/<- %ecx 4/r32/esp +5370 # var operands/esi : (ref list var) +5371 68/push 0/imm32/next +5372 51/push-ecx/var-foo +5373 89/<- %esi 4/r32/esp +5374 # var stmt/esi : (ref statement) +5375 68/push 0/imm32/next +5376 68/push 0/imm32/outputs +5377 56/push-esi/inouts +5378 68/push "f"/imm32/operation +5379 68/push 1/imm32 +5380 89/<- %esi 4/r32/esp +5381 # var functions/ebx : (ref function) +5382 68/push 0/imm32/next +5383 68/push 0/imm32/body +5384 68/push 0/imm32/outputs +5385 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +5386 68/push "f2"/imm32/subx-name +5387 68/push "f"/imm32/name +5388 89/<- %ebx 4/r32/esp +5389 # convert +5390 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +5391 (flush _test-output-buffered-file) +5392 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5398 # check output +5399 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") +5400 # . epilogue +5401 89/<- %esp 5/r32/ebp +5402 5d/pop-to-ebp +5403 c3/return +5404 +5405 emit-subx-prologue: # out : (address buffered-file) +5406 # . prologue +5407 55/push-ebp +5408 89/<- %ebp 4/r32/esp +5409 # +5410 (write-buffered *(ebp+8) "# . prologue\n") +5411 (write-buffered *(ebp+8) "55/push-ebp\n") +5412 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") +5413 $emit-subx-prologue:end: +5414 # . epilogue +5415 89/<- %esp 5/r32/ebp +5416 5d/pop-to-ebp +5417 c3/return +5418 +5419 emit-subx-epilogue: # out : (address buffered-file) +5420 # . prologue +5421 55/push-ebp +5422 89/<- %ebp 4/r32/esp +5423 # +5424 (write-buffered *(ebp+8) "# . epilogue\n") +5425 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") +5426 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") +5427 (write-buffered *(ebp+8) "c3/return\n") +5428 $emit-subx-epilogue:end: +5429 # . epilogue +5430 89/<- %esp 5/r32/ebp +5431 5d/pop-to-ebp +5432 c3/return -- cgit 1.4.1-2-gfad0