From e9db8e1f25d22feeb4c9ade38cb9130bbd2a22ac Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 18 Nov 2019 16:30:30 -0800 Subject: 5754 Support binary instructions with an immediate operand. --- html/apps/mu.subx.html | 2263 +++++++++++++++++++++++++----------------------- 1 file changed, 1168 insertions(+), 1095 deletions(-) (limited to 'html/apps') diff --git a/html/apps/mu.subx.html b/html/apps/mu.subx.html index 57a7c032..a68c3c7c 100644 --- a/html/apps/mu.subx.html +++ b/html/apps/mu.subx.html @@ -912,9 +912,9 @@ if ('onhashchange' in window) { 870 # 871 (write-buffered %edi *ecx) 872 (write-buffered %edi ":\n") - 873 (emit-subx-prologue %edi) + 873 (emit-subx-prologue %edi) 874 (emit-subx-block %edi *(ecx+0x10)) # Function-body - 875 (emit-subx-epilogue %edi) + 875 (emit-subx-epilogue %edi) 876 $emit-subx-function:end: 877 # . restore registers 878 5f/pop-to-edi @@ -946,19 +946,19 @@ if ('onhashchange' in window) { 904 # if stmt matches a primitive, emit it 905 { 906 $emit-subx-statement:primitive: - 907 (find-matching-primitive *(ebp+0x14) *(ebp+0xc)) # primitives, stmt => curr/eax + 907 (find-matching-primitive *(ebp+0x14) *(ebp+0xc)) # primitives, stmt => curr/eax 908 3d/compare-eax-and 0/imm32 909 74/jump-if-equal break/disp8 - 910 (emit-subx-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax) # out, stmt, vars, curr + 910 (emit-subx-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax) # out, stmt, vars, curr 911 e9/jump $emit-subx-statement:end/disp32 912 } 913 # else if stmt matches a function, emit a call to it 914 { 915 $emit-subx-statement:call: - 916 (find-matching-function *(ebp+0x18) *(ebp+0xc)) # functions, stmt => curr/eax + 916 (find-matching-function *(ebp+0x18) *(ebp+0xc)) # functions, stmt => curr/eax 917 3d/compare-eax-and 0/imm32 918 74/jump-if-equal break/disp8 - 919 (emit-subx-call *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax) # out, stmt, vars, curr + 919 (emit-subx-call *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax) # out, stmt, vars, curr 920 e9/jump $emit-subx-statement:end/disp32 921 } 922 # else abort @@ -989,7 +989,7 @@ if ('onhashchange' in window) { 947 Primitives: 948 # increment var => ff 0/subop/increment *(ebp+__) 949 "increment"/imm32/name - 950 Single-int-var-on-stack/imm32/inouts + 950 Single-int-var-on-stack/imm32/inouts 951 0/imm32/no-outputs 952 "ff 0/subop/increment"/imm32/subx-name 953 1/imm32/rm32-is-first-inout @@ -1000,7 +1000,7 @@ if ('onhashchange' in window) { 958 # var/reg <- increment => ff 0/subop/increment %__ 959 "increment"/imm32/name 960 0/imm32/no-inouts - 961 Single-int-var-in-some-register/imm32/outputs + 961 Single-int-var-in-some-register/imm32/outputs 962 "ff 0/subop/increment"/imm32/subx-name 963 3/imm32/rm32-is-first-output 964 0/imm32/no-r32 @@ -1009,1108 +1009,1181 @@ if ('onhashchange' in window) { 967 _Primitive-add-reg-to-reg: 968 # var1/reg <- add var2/reg => 01 var1/rm32 var2/r32 969 "add"/imm32/name - 970 Single-int-var-in-some-register/imm32/inouts - 971 Single-int-var-in-some-register/imm32/outputs + 970 Single-int-var-in-some-register/imm32/inouts + 971 Single-int-var-in-some-register/imm32/outputs 972 "01"/imm32/subx-name 973 3/imm32/rm32-is-first-output 974 1/imm32/r32-is-first-inout 975 0/imm32/no-imm32 - 976 0/imm32/next - 977 - 978 Single-int-var-on-stack: - 979 Int-var-on-stack/imm32 - 980 0/imm32/next - 981 - 982 Int-var-on-stack: - 983 "arg1"/imm32/name - 984 1/imm32/type-int - 985 1/imm32/some-block-depth - 986 1/imm32/some-stack-offset - 987 0/imm32/no-register - 988 - 989 Single-int-var-in-some-register: - 990 Int-var-in-some-register/imm32 - 991 0/imm32/next - 992 - 993 Int-var-in-some-register: - 994 "arg1"/imm32/name - 995 1/imm32/type-int - 996 1/imm32/some-block-depth - 997 0/imm32/some-stack-offset - 998 "*"/imm32/register - 999 -1000 == code -1001 emit-subx-primitive: # out : (address buffered-file), stmt : (address statement), vars : (address variable), primitive : (address function) -1002 # . prologue -1003 55/push-ebp -1004 89/<- %ebp 4/r32/esp -1005 # . save registers -1006 50/push-eax -1007 51/push-ecx -1008 # ecx = primitive -1009 8b/-> *(ebp+0x14) 1/r32/ecx -1010 # emit primitive name -1011 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name -1012 # emit rm32 if necessary -1013 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt -1014 # emit r32 if necessary -1015 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt -1016 #? # emit imm32 if necessary -1017 #? (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt -1018 $emit-subx-primitive:end: -1019 # . restore registers -1020 59/pop-to-ecx -1021 58/pop-to-eax -1022 # . epilogue -1023 89/<- %esp 5/r32/ebp -1024 5d/pop-to-ebp -1025 c3/return -1026 -1027 emit-subx-rm32: # out : (address buffered-file), l : arg-location, stmt : (address statement) -1028 # . prologue -1029 55/push-ebp -1030 89/<- %ebp 4/r32/esp -1031 # . save registers -1032 50/push-eax -1033 # if (l == 0) return -1034 81 7/subop/compare *(ebp+0xc) 0/imm32 -1035 74/jump-if-equal $emit-subx-rm32:end/disp8 -1036 # -1037 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -1038 (emit-subx-call-operand *(ebp+8) %eax) # out, var -1039 $emit-subx-rm32:end: + 976 _Primitive-add-lit-to-reg/imm32/next + 977 _Primitive-add-lit-to-reg: + 978 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 + 979 "add"/imm32/name + 980 Single-lit-var/imm32/inouts + 981 Single-int-var-in-some-register/imm32/outputs + 982 "81 0/subop/add"/imm32/subx-name + 983 3/imm32/rm32-is-first-output + 984 0/imm32/no-r32 + 985 1/imm32/imm32-is-first-inout + 986 0/imm32/next + 987 + 988 Single-int-var-on-stack: + 989 Int-var-on-stack/imm32 + 990 0/imm32/next + 991 + 992 Int-var-on-stack: + 993 "arg1"/imm32/name + 994 1/imm32/type-int + 995 1/imm32/some-block-depth + 996 1/imm32/some-stack-offset + 997 0/imm32/no-register + 998 + 999 Single-int-var-in-some-register: +1000 Int-var-in-some-register/imm32 +1001 0/imm32/next +1002 +1003 Int-var-in-some-register: +1004 "arg1"/imm32/name +1005 1/imm32/type-int +1006 1/imm32/some-block-depth +1007 0/imm32/some-stack-offset +1008 "*"/imm32/register +1009 +1010 Single-lit-var: +1011 Lit-var/imm32 +1012 0/imm32/next +1013 +1014 Lit-var: +1015 "literal"/imm32/name +1016 0/imm32/type-literal +1017 1/imm32/some-block-depth +1018 0/imm32/no-stack-offset +1019 0/imm32/no-register +1020 +1021 == code +1022 emit-subx-primitive: # out : (address buffered-file), stmt : (address statement), vars : (address variable), primitive : (address function) +1023 # . prologue +1024 55/push-ebp +1025 89/<- %ebp 4/r32/esp +1026 # . save registers +1027 50/push-eax +1028 51/push-ecx +1029 # ecx = primitive +1030 8b/-> *(ebp+0x14) 1/r32/ecx +1031 # emit primitive name +1032 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name +1033 # emit rm32 if necessary +1034 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt +1035 # emit r32 if necessary +1036 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt +1037 # emit imm32 if necessary +1038 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt +1039 $emit-subx-primitive:end: 1040 # . restore registers -1041 58/pop-to-eax -1042 # . epilogue -1043 89/<- %esp 5/r32/ebp -1044 5d/pop-to-ebp -1045 c3/return -1046 -1047 get-stmt-operand-from-arg-location: # stmt : (address statement), l : arg-location -> var/eax : (address variable) -1048 # . prologue -1049 55/push-ebp -1050 89/<- %ebp 4/r32/esp -1051 # . save registers -1052 51/push-ecx -1053 # eax = l -1054 8b/-> *(ebp+0xc) 0/r32/eax -1055 # ecx = stmt -1056 8b/-> *(ebp+8) 1/r32/ecx -1057 # if (l == 1) return stmt->inouts->var -1058 { -1059 3d/compare-eax-and 1/imm32 -1060 75/jump-if-not-equal break/disp8 -1061 $get-stmt-operand-from-arg-location:1: -1062 8b/-> *(ecx+4) 0/r32/eax # Stmt-inouts -1063 8b/-> *eax 0/r32/eax # Operand-var -1064 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -1065 } -1066 # if (l == 2) return stmt->inouts->next->var -1067 { -1068 3d/compare-eax-and 2/imm32 -1069 75/jump-if-not-equal break/disp8 -1070 $get-stmt-operand-from-arg-location:2: -1071 8b/-> *(ecx+4) 0/r32/eax # Stmt-inouts -1072 8b/-> *(eax+4) 0/r32/eax # Operand-next -1073 8b/-> *eax 0/r32/eax # Operand-var -1074 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -1075 } -1076 # if (l == 3) return stmt->outputs -1077 { -1078 3d/compare-eax-and 3/imm32 -1079 75/jump-if-not-equal break/disp8 -1080 $get-stmt-operand-from-arg-location:3: -1081 8b/-> *(ecx+8) 0/r32/eax # Stmt-outputs -1082 8b/-> *eax 0/r32/eax # Operand-var -1083 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -1084 } -1085 # abort -1086 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 -1087 $get-stmt-operand-from-arg-location:end: -1088 # . restore registers -1089 59/pop-to-ecx -1090 # . epilogue -1091 89/<- %esp 5/r32/ebp -1092 5d/pop-to-ebp -1093 c3/return -1094 -1095 $get-stmt-operand-from-arg-location:abort: -1096 # error("invalid arg-location " eax) -1097 (write-buffered Stderr "invalid arg-location ") -1098 (print-int32-buffered Stderr %eax) -1099 (write-buffered Stderr "\n") -1100 (flush Stderr) -1101 # . syscall(exit, 1) -1102 bb/copy-to-ebx 1/imm32 -1103 b8/copy-to-eax 1/imm32/exit -1104 cd/syscall 0x80/imm8 -1105 # never gets here -1106 -1107 emit-subx-r32: # out : (address buffered-file), l : arg-location, stmt : (address statement) -1108 # . prologue -1109 55/push-ebp -1110 89/<- %ebp 4/r32/esp -1111 # . save registers -1112 50/push-eax -1113 51/push-ecx -1114 # if (location == 0) return -1115 81 7/subop/compare *(ebp+0xc) 0/imm32 -1116 0f 84/jump-if-equal $emit-subx-r32:end/disp32 -1117 # -1118 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -1119 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (address register-index) -1120 (write-buffered *(ebp+8) Space) -1121 (print-int32-buffered *(ebp+8) *eax) -1122 (write-buffered *(ebp+8) "/r32") -1123 $emit-subx-r32:end: -1124 # . restore registers -1125 59/pop-to-ecx -1126 58/pop-to-eax -1127 # . epilogue -1128 89/<- %esp 5/r32/ebp -1129 5d/pop-to-ebp -1130 c3/return -1131 -1132 emit-subx-imm32: # out : (address buffered-file), l : arg-location, stmt : (address statement) -1133 # . prologue -1134 55/push-ebp -1135 89/<- %ebp 4/r32/esp -1136 # . save registers -1137 50/push-eax -1138 51/push-ecx -1139 # if (location == 0) return -1140 81 7/subop/compare *(ebp+0xc) 0/imm32 -1141 74/jump-if-equal $emit-subx-imm32:end/disp8 -1142 # -1143 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -1144 (emit-subx-call-operand *(ebp+8) %eax) # out, var -1145 $emit-subx-imm32:end: -1146 # . restore registers -1147 59/pop-to-ecx -1148 58/pop-to-eax -1149 # . epilogue -1150 89/<- %esp 5/r32/ebp -1151 5d/pop-to-ebp -1152 c3/return -1153 -1154 emit-subx-call: # out : (address buffered-file), stmt : (address statement), vars : (address variable), callee : (address function) -1155 # . prologue -1156 55/push-ebp -1157 89/<- %ebp 4/r32/esp -1158 # . save registers -1159 50/push-eax -1160 51/push-ecx -1161 # -1162 (write-buffered *(ebp+8) "(") -1163 # - emit function name -1164 8b/-> *(ebp+0x14) 1/r32/ecx -1165 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name -1166 # - emit arguments -1167 # var curr/ecx : (list var) = stmt->inouts -1168 8b/-> *(ebp+0xc) 1/r32/ecx -1169 8b/-> *(ecx+4) 1/r32/ecx # Stmt-inouts -1170 { -1171 # if (curr == null) break -1172 81 7/subop/compare %ecx 0/imm32 -1173 74/jump-if-equal break/disp8 -1174 # -1175 (emit-subx-call-operand *(ebp+8) *ecx) -1176 # curr = curr->next -1177 8b/-> *(ecx+4) 1/r32/ecx -1178 } -1179 # -1180 (write-buffered *(ebp+8) ")") -1181 $emit-subx-call:end: -1182 # . restore registers -1183 59/pop-to-ecx -1184 58/pop-to-eax -1185 # . epilogue -1186 89/<- %esp 5/r32/ebp -1187 5d/pop-to-ebp -1188 c3/return -1189 -1190 emit-subx-call-operand: # out : (address buffered-file), operand : (address variable) -1191 # . prologue -1192 55/push-ebp -1193 89/<- %ebp 4/r32/esp -1194 # . save registers -1195 50/push-eax -1196 # eax = operand -1197 8b/-> *(ebp+0xc) 0/r32/eax -1198 # if (operand->register) emit "%__" -1199 { -1200 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -1201 74/jump-if-equal break/disp8 -1202 $emit-subx-call-operand:register: -1203 (write-buffered *(ebp+8) " %") -1204 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -1205 } -1206 # else if (operand->stack-offset) emit "*(ebp+__)" -1207 { -1208 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -1209 74/jump-if-equal break/disp8 -1210 $emit-subx-call-operand:stack: -1211 (write-buffered *(ebp+8) Space) -1212 (write-buffered *(ebp+8) "*(ebp+") -1213 8b/-> *(ebp+0xc) 0/r32/eax -1214 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -1215 (write-buffered *(ebp+8) ")") -1216 } -1217 $emit-subx-call-operand:end: -1218 # . restore registers -1219 58/pop-to-eax -1220 # . epilogue -1221 89/<- %esp 5/r32/ebp -1222 5d/pop-to-ebp -1223 c3/return -1224 -1225 find-matching-function: # functions : (address function), stmt : (address statement) -> result/eax : (address function) -1226 # . prologue -1227 55/push-ebp -1228 89/<- %ebp 4/r32/esp -1229 # . save registers -1230 51/push-ecx -1231 # var curr/ecx : (address function) = functions -1232 8b/-> *(ebp+8) 1/r32/ecx -1233 { -1234 # if (curr == null) break -1235 81 7/subop/compare %ecx 0/imm32 -1236 74/jump-if-equal break/disp8 -1237 # if match(curr, stmt) return curr -1238 { -1239 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax -1240 3d/compare-eax-and 0/imm32 -1241 74/jump-if-equal break/disp8 -1242 89/<- %eax 1/r32/ecx -1243 eb/jump $find-matching-function:end/disp8 -1244 } -1245 # curr = curr->next -1246 8b/-> *(ecx+0x10) 1/r32/ecx # Function-next -1247 eb/jump loop/disp8 -1248 } -1249 # return null -1250 b8/copy-to-eax 0/imm32 -1251 $find-matching-function:end: -1252 # . restore registers -1253 59/pop-to-ecx -1254 # . epilogue -1255 89/<- %esp 5/r32/ebp -1256 5d/pop-to-ebp -1257 c3/return -1258 -1259 find-matching-primitive: # primitives : (address primitive), stmt : (address statement) -> result/eax : (address primitive) -1260 # . prologue -1261 55/push-ebp -1262 89/<- %ebp 4/r32/esp -1263 # . save registers -1264 51/push-ecx -1265 # var curr/ecx : (address primitive) = primitives -1266 8b/-> *(ebp+8) 1/r32/ecx -1267 { -1268 $find-matching-primitive:loop: -1269 # if (curr == null) break -1270 81 7/subop/compare %ecx 0/imm32 -1271 74/jump-if-equal break/disp8 -1272 # if match(curr, stmt) return curr -1273 { -1274 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax -1275 3d/compare-eax-and 0/imm32 -1276 74/jump-if-equal break/disp8 -1277 89/<- %eax 1/r32/ecx -1278 eb/jump $find-matching-function:end/disp8 -1279 } -1280 $find-matching-primitive:next-primitive: -1281 # curr = curr->next -1282 8b/-> *(ecx+0x1c) 1/r32/ecx # Primitive-next -1283 eb/jump loop/disp8 -1284 } -1285 # return null -1286 b8/copy-to-eax 0/imm32 -1287 $find-matching-primitive:end: -1288 # . restore registers -1289 59/pop-to-ecx -1290 # . epilogue -1291 89/<- %esp 5/r32/ebp -1292 5d/pop-to-ebp -1293 c3/return -1294 -1295 mu-stmt-matches-function?: # stmt : (address statement), function : (address opcode-info) => result/eax : boolean -1296 # . prologue -1297 55/push-ebp -1298 89/<- %ebp 4/r32/esp -1299 # . save registers -1300 51/push-ecx -1301 # return primitive->name == stmt->operation -1302 8b/-> *(ebp+8) 1/r32/ecx -1303 8b/-> *(ebp+0xc) 0/r32/eax -1304 (string-equal? *ecx *eax) # => eax -1305 $mu-stmt-matches-function?:end: -1306 # . restore registers -1307 59/pop-to-ecx -1308 # . epilogue -1309 89/<- %esp 5/r32/ebp -1310 5d/pop-to-ebp -1311 c3/return -1312 -1313 mu-stmt-matches-primitive?: # stmt : (address statement), primitive : (address primitive) => result/eax : boolean -1314 # A mu stmt matches a primitive if the name matches, all the inout vars -1315 # match, and all the output vars match. -1316 # Vars match if types match and registers match. -1317 # In addition, a stmt output matches a primitive's output if types match -1318 # and the primitive has a wildcard register. +1041 59/pop-to-ecx +1042 58/pop-to-eax +1043 # . epilogue +1044 89/<- %esp 5/r32/ebp +1045 5d/pop-to-ebp +1046 c3/return +1047 +1048 emit-subx-rm32: # out : (address buffered-file), l : arg-location, stmt : (address statement) +1049 # . prologue +1050 55/push-ebp +1051 89/<- %ebp 4/r32/esp +1052 # . save registers +1053 50/push-eax +1054 # if (l == 0) return +1055 81 7/subop/compare *(ebp+0xc) 0/imm32 +1056 74/jump-if-equal $emit-subx-rm32:end/disp8 +1057 # +1058 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +1059 (emit-subx-call-operand *(ebp+8) %eax) # out, var +1060 $emit-subx-rm32:end: +1061 # . restore registers +1062 58/pop-to-eax +1063 # . epilogue +1064 89/<- %esp 5/r32/ebp +1065 5d/pop-to-ebp +1066 c3/return +1067 +1068 get-stmt-operand-from-arg-location: # stmt : (address statement), l : arg-location -> var/eax : (address variable) +1069 # . prologue +1070 55/push-ebp +1071 89/<- %ebp 4/r32/esp +1072 # . save registers +1073 51/push-ecx +1074 # eax = l +1075 8b/-> *(ebp+0xc) 0/r32/eax +1076 # ecx = stmt +1077 8b/-> *(ebp+8) 1/r32/ecx +1078 # if (l == 1) return stmt->inouts->var +1079 { +1080 3d/compare-eax-and 1/imm32 +1081 75/jump-if-not-equal break/disp8 +1082 $get-stmt-operand-from-arg-location:1: +1083 8b/-> *(ecx+4) 0/r32/eax # Stmt-inouts +1084 8b/-> *eax 0/r32/eax # Operand-var +1085 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +1086 } +1087 # if (l == 2) return stmt->inouts->next->var +1088 { +1089 3d/compare-eax-and 2/imm32 +1090 75/jump-if-not-equal break/disp8 +1091 $get-stmt-operand-from-arg-location:2: +1092 8b/-> *(ecx+4) 0/r32/eax # Stmt-inouts +1093 8b/-> *(eax+4) 0/r32/eax # Operand-next +1094 8b/-> *eax 0/r32/eax # Operand-var +1095 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +1096 } +1097 # if (l == 3) return stmt->outputs +1098 { +1099 3d/compare-eax-and 3/imm32 +1100 75/jump-if-not-equal break/disp8 +1101 $get-stmt-operand-from-arg-location:3: +1102 8b/-> *(ecx+8) 0/r32/eax # Stmt-outputs +1103 8b/-> *eax 0/r32/eax # Operand-var +1104 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +1105 } +1106 # abort +1107 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 +1108 $get-stmt-operand-from-arg-location:end: +1109 # . restore registers +1110 59/pop-to-ecx +1111 # . epilogue +1112 89/<- %esp 5/r32/ebp +1113 5d/pop-to-ebp +1114 c3/return +1115 +1116 $get-stmt-operand-from-arg-location:abort: +1117 # error("invalid arg-location " eax) +1118 (write-buffered Stderr "invalid arg-location ") +1119 (print-int32-buffered Stderr %eax) +1120 (write-buffered Stderr "\n") +1121 (flush Stderr) +1122 # . syscall(exit, 1) +1123 bb/copy-to-ebx 1/imm32 +1124 b8/copy-to-eax 1/imm32/exit +1125 cd/syscall 0x80/imm8 +1126 # never gets here +1127 +1128 emit-subx-r32: # out : (address buffered-file), l : arg-location, stmt : (address statement) +1129 # . prologue +1130 55/push-ebp +1131 89/<- %ebp 4/r32/esp +1132 # . save registers +1133 50/push-eax +1134 51/push-ecx +1135 # if (location == 0) return +1136 81 7/subop/compare *(ebp+0xc) 0/imm32 +1137 0f 84/jump-if-equal $emit-subx-r32:end/disp32 +1138 # +1139 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +1140 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (address register-index) +1141 (write-buffered *(ebp+8) Space) +1142 (print-int32-buffered *(ebp+8) *eax) +1143 (write-buffered *(ebp+8) "/r32") +1144 $emit-subx-r32:end: +1145 # . restore registers +1146 59/pop-to-ecx +1147 58/pop-to-eax +1148 # . epilogue +1149 89/<- %esp 5/r32/ebp +1150 5d/pop-to-ebp +1151 c3/return +1152 +1153 emit-subx-imm32: # out : (address buffered-file), l : arg-location, stmt : (address statement) +1154 # . prologue +1155 55/push-ebp +1156 89/<- %ebp 4/r32/esp +1157 # . save registers +1158 50/push-eax +1159 51/push-ecx +1160 # if (location == 0) return +1161 81 7/subop/compare *(ebp+0xc) 0/imm32 +1162 74/jump-if-equal $emit-subx-imm32:end/disp8 +1163 # +1164 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +1165 (write-buffered *(ebp+8) Space) +1166 (write-buffered *(ebp+8) *eax) # Var-name +1167 (write-buffered *(ebp+8) "/imm32") +1168 $emit-subx-imm32:end: +1169 # . restore registers +1170 59/pop-to-ecx +1171 58/pop-to-eax +1172 # . epilogue +1173 89/<- %esp 5/r32/ebp +1174 5d/pop-to-ebp +1175 c3/return +1176 +1177 emit-subx-call: # out : (address buffered-file), stmt : (address statement), vars : (address variable), callee : (address function) +1178 # . prologue +1179 55/push-ebp +1180 89/<- %ebp 4/r32/esp +1181 # . save registers +1182 50/push-eax +1183 51/push-ecx +1184 # +1185 (write-buffered *(ebp+8) "(") +1186 # - emit function name +1187 8b/-> *(ebp+0x14) 1/r32/ecx +1188 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name +1189 # - emit arguments +1190 # var curr/ecx : (list var) = stmt->inouts +1191 8b/-> *(ebp+0xc) 1/r32/ecx +1192 8b/-> *(ecx+4) 1/r32/ecx # Stmt-inouts +1193 { +1194 # if (curr == null) break +1195 81 7/subop/compare %ecx 0/imm32 +1196 74/jump-if-equal break/disp8 +1197 # +1198 (emit-subx-call-operand *(ebp+8) *ecx) +1199 # curr = curr->next +1200 8b/-> *(ecx+4) 1/r32/ecx +1201 } +1202 # +1203 (write-buffered *(ebp+8) ")") +1204 $emit-subx-call:end: +1205 # . restore registers +1206 59/pop-to-ecx +1207 58/pop-to-eax +1208 # . epilogue +1209 89/<- %esp 5/r32/ebp +1210 5d/pop-to-ebp +1211 c3/return +1212 +1213 emit-subx-call-operand: # out : (address buffered-file), operand : (address variable) +1214 # . prologue +1215 55/push-ebp +1216 89/<- %ebp 4/r32/esp +1217 # . save registers +1218 50/push-eax +1219 # eax = operand +1220 8b/-> *(ebp+0xc) 0/r32/eax +1221 # if (operand->register) emit "%__" +1222 { +1223 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +1224 74/jump-if-equal break/disp8 +1225 $emit-subx-call-operand:register: +1226 (write-buffered *(ebp+8) " %") +1227 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +1228 } +1229 # else if (operand->stack-offset) emit "*(ebp+__)" +1230 { +1231 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +1232 74/jump-if-equal break/disp8 +1233 $emit-subx-call-operand:stack: +1234 (write-buffered *(ebp+8) Space) +1235 (write-buffered *(ebp+8) "*(ebp+") +1236 8b/-> *(ebp+0xc) 0/r32/eax +1237 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +1238 (write-buffered *(ebp+8) ")") +1239 } +1240 $emit-subx-call-operand:end: +1241 # . restore registers +1242 58/pop-to-eax +1243 # . epilogue +1244 89/<- %esp 5/r32/ebp +1245 5d/pop-to-ebp +1246 c3/return +1247 +1248 find-matching-function: # functions : (address function), stmt : (address statement) -> result/eax : (address function) +1249 # . prologue +1250 55/push-ebp +1251 89/<- %ebp 4/r32/esp +1252 # . save registers +1253 51/push-ecx +1254 # var curr/ecx : (address function) = functions +1255 8b/-> *(ebp+8) 1/r32/ecx +1256 { +1257 # if (curr == null) break +1258 81 7/subop/compare %ecx 0/imm32 +1259 74/jump-if-equal break/disp8 +1260 # if match(curr, stmt) return curr +1261 { +1262 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax +1263 3d/compare-eax-and 0/imm32 +1264 74/jump-if-equal break/disp8 +1265 89/<- %eax 1/r32/ecx +1266 eb/jump $find-matching-function:end/disp8 +1267 } +1268 # curr = curr->next +1269 8b/-> *(ecx+0x10) 1/r32/ecx # Function-next +1270 eb/jump loop/disp8 +1271 } +1272 # return null +1273 b8/copy-to-eax 0/imm32 +1274 $find-matching-function:end: +1275 # . restore registers +1276 59/pop-to-ecx +1277 # . epilogue +1278 89/<- %esp 5/r32/ebp +1279 5d/pop-to-ebp +1280 c3/return +1281 +1282 find-matching-primitive: # primitives : (address primitive), stmt : (address statement) -> result/eax : (address primitive) +1283 # . prologue +1284 55/push-ebp +1285 89/<- %ebp 4/r32/esp +1286 # . save registers +1287 51/push-ecx +1288 # var curr/ecx : (address primitive) = primitives +1289 8b/-> *(ebp+8) 1/r32/ecx +1290 { +1291 $find-matching-primitive:loop: +1292 # if (curr == null) break +1293 81 7/subop/compare %ecx 0/imm32 +1294 74/jump-if-equal break/disp8 +1295 # if match(curr, stmt) return curr +1296 { +1297 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax +1298 3d/compare-eax-and 0/imm32 +1299 74/jump-if-equal break/disp8 +1300 89/<- %eax 1/r32/ecx +1301 eb/jump $find-matching-function:end/disp8 +1302 } +1303 $find-matching-primitive:next-primitive: +1304 # curr = curr->next +1305 8b/-> *(ecx+0x1c) 1/r32/ecx # Primitive-next +1306 eb/jump loop/disp8 +1307 } +1308 # return null +1309 b8/copy-to-eax 0/imm32 +1310 $find-matching-primitive:end: +1311 # . restore registers +1312 59/pop-to-ecx +1313 # . epilogue +1314 89/<- %esp 5/r32/ebp +1315 5d/pop-to-ebp +1316 c3/return +1317 +1318 mu-stmt-matches-function?: # stmt : (address statement), function : (address opcode-info) => result/eax : boolean 1319 # . prologue 1320 55/push-ebp 1321 89/<- %ebp 4/r32/esp 1322 # . save registers 1323 51/push-ecx -1324 52/push-edx -1325 53/push-ebx -1326 56/push-esi -1327 57/push-edi -1328 # ecx = stmt -1329 8b/-> *(ebp+8) 1/r32/ecx -1330 # edx = primitive -1331 8b/-> *(ebp+0xc) 2/r32/edx -1332 { -1333 $mu-stmt-matches-primitive?:check-name: -1334 # if (primitive->name != stmt->operation) return false -1335 (string-equal? *ecx *edx) # => eax -1336 3d/compare-eax-and 0/imm32 -1337 75/jump-if-not-equal break/disp8 -1338 b8/copy-to-eax 0/imm32 -1339 e9/jump $mu-stmt-matches-primitive?:end/disp32 -1340 } -1341 $mu-stmt-matches-primitive?:check-inouts: -1342 # curr = stmt->inouts -1343 8b/-> *(ecx+4) 6/r32/esi # Stmt-inouts -1344 # curr2 = primitive->inouts -1345 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts -1346 { -1347 # if (curr == 0) return (curr2 == 0) -1348 { -1349 81 7/subop/compare %esi 0/imm32 -1350 75/jump-if-not-equal break/disp8 -1351 { -1352 81 7/subop/compare %edi 0/imm32 -1353 75/jump-if-not-equal break/disp8 -1354 # return true -1355 b8/copy-to-eax 1/imm32 -1356 e9/jump $mu-stmt-matches-primitive?:end/disp32 -1357 } -1358 # return false -1359 b8/copy-to-eax 0/imm32 -1360 e9/jump $mu-stmt-matches-primitive?:end/disp32 -1361 } -1362 # if (curr2 == 0) return false -1363 { -1364 81 7/subop/compare %edi 0/imm32 -1365 75/jump-if-not-equal break/disp8 -1366 b8/copy-to-eax 0/imm32 -1367 e9/jump $mu-stmt-matches-primitive?:end/disp32 -1368 } -1369 # if (curr != curr2) return false -1370 { -1371 (operand-matches-primitive? *esi *edi) # => eax -1372 3d/compare-eax-and 0/imm32 +1324 # return primitive->name == stmt->operation +1325 8b/-> *(ebp+8) 1/r32/ecx +1326 8b/-> *(ebp+0xc) 0/r32/eax +1327 (string-equal? *ecx *eax) # => eax +1328 $mu-stmt-matches-function?:end: +1329 # . restore registers +1330 59/pop-to-ecx +1331 # . epilogue +1332 89/<- %esp 5/r32/ebp +1333 5d/pop-to-ebp +1334 c3/return +1335 +1336 mu-stmt-matches-primitive?: # stmt : (address statement), primitive : (address primitive) => result/eax : boolean +1337 # A mu stmt matches a primitive if the name matches, all the inout vars +1338 # match, and all the output vars match. +1339 # Vars match if types match and registers match. +1340 # In addition, a stmt output matches a primitive's output if types match +1341 # and the primitive has a wildcard register. +1342 # . prologue +1343 55/push-ebp +1344 89/<- %ebp 4/r32/esp +1345 # . save registers +1346 51/push-ecx +1347 52/push-edx +1348 53/push-ebx +1349 56/push-esi +1350 57/push-edi +1351 # ecx = stmt +1352 8b/-> *(ebp+8) 1/r32/ecx +1353 # edx = primitive +1354 8b/-> *(ebp+0xc) 2/r32/edx +1355 { +1356 $mu-stmt-matches-primitive?:check-name: +1357 # if (primitive->name != stmt->operation) return false +1358 (string-equal? *ecx *edx) # => eax +1359 3d/compare-eax-and 0/imm32 +1360 75/jump-if-not-equal break/disp8 +1361 b8/copy-to-eax 0/imm32 +1362 e9/jump $mu-stmt-matches-primitive?:end/disp32 +1363 } +1364 $mu-stmt-matches-primitive?:check-inouts: +1365 # curr = stmt->inouts +1366 8b/-> *(ecx+4) 6/r32/esi # Stmt-inouts +1367 # curr2 = primitive->inouts +1368 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts +1369 { +1370 # if (curr == 0) return (curr2 == 0) +1371 { +1372 81 7/subop/compare %esi 0/imm32 1373 75/jump-if-not-equal break/disp8 -1374 b8/copy-to-eax 0/imm32 -1375 e9/jump $mu-stmt-matches-primitive?:end/disp32 -1376 } -1377 # curr=curr->next -1378 8b/-> *(ecx+4) 1/r32/ecx # Operand-next -1379 # curr2=curr2->next -1380 8b/-> *(edx+4) 2/r32/edx # Operand-next -1381 } -1382 $mu-stmt-matches-primitive?:check-outputs: -1383 # ecx = stmt -1384 8b/-> *(ebp+8) 1/r32/ecx -1385 # edx = primitive -1386 8b/-> *(ebp+0xc) 2/r32/edx -1387 # curr = stmt->outputs -1388 8b/-> *(ecx+8) 6/r32/esi # Stmt-outputs -1389 # curr2 = primitive->outputs -1390 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs -1391 { -1392 # if (curr == 0) return (curr2 == 0) +1374 { +1375 81 7/subop/compare %edi 0/imm32 +1376 75/jump-if-not-equal break/disp8 +1377 # return true +1378 b8/copy-to-eax 1/imm32 +1379 e9/jump $mu-stmt-matches-primitive?:end/disp32 +1380 } +1381 # return false +1382 b8/copy-to-eax 0/imm32 +1383 e9/jump $mu-stmt-matches-primitive?:end/disp32 +1384 } +1385 # if (curr2 == 0) return false +1386 { +1387 81 7/subop/compare %edi 0/imm32 +1388 75/jump-if-not-equal break/disp8 +1389 b8/copy-to-eax 0/imm32 +1390 e9/jump $mu-stmt-matches-primitive?:end/disp32 +1391 } +1392 # if (curr != curr2) return false 1393 { -1394 81 7/subop/compare %esi 0/imm32 -1395 75/jump-if-not-equal break/disp8 -1396 { -1397 81 7/subop/compare %edi 0/imm32 -1398 75/jump-if-not-equal break/disp8 -1399 # return true -1400 b8/copy-to-eax 1/imm32 -1401 e9/jump $mu-stmt-matches-primitive?:end/disp32 -1402 } -1403 # return false -1404 b8/copy-to-eax 0/imm32 -1405 e9/jump $mu-stmt-matches-primitive?:end/disp32 -1406 } -1407 # if (curr2 == 0) return false -1408 { -1409 81 7/subop/compare %edi 0/imm32 -1410 75/jump-if-not-equal break/disp8 -1411 b8/copy-to-eax 0/imm32 -1412 e9/jump $mu-stmt-matches-primitive?:end/disp32 -1413 } -1414 # if (curr != curr2) return false -1415 { -1416 (operand-matches-primitive? *esi *edi) # => eax -1417 3d/compare-eax-and 0/imm32 +1394 (operand-matches-primitive? *esi *edi) # => eax +1395 3d/compare-eax-and 0/imm32 +1396 75/jump-if-not-equal break/disp8 +1397 b8/copy-to-eax 0/imm32 +1398 e9/jump $mu-stmt-matches-primitive?:end/disp32 +1399 } +1400 # curr=curr->next +1401 8b/-> *(ecx+4) 1/r32/ecx # Operand-next +1402 # curr2=curr2->next +1403 8b/-> *(edx+4) 2/r32/edx # Operand-next +1404 } +1405 $mu-stmt-matches-primitive?:check-outputs: +1406 # ecx = stmt +1407 8b/-> *(ebp+8) 1/r32/ecx +1408 # edx = primitive +1409 8b/-> *(ebp+0xc) 2/r32/edx +1410 # curr = stmt->outputs +1411 8b/-> *(ecx+8) 6/r32/esi # Stmt-outputs +1412 # curr2 = primitive->outputs +1413 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs +1414 { +1415 # if (curr == 0) return (curr2 == 0) +1416 { +1417 81 7/subop/compare %esi 0/imm32 1418 75/jump-if-not-equal break/disp8 -1419 b8/copy-to-eax 0/imm32 -1420 e9/jump $mu-stmt-matches-primitive?:end/disp32 -1421 } -1422 # curr=curr->next -1423 8b/-> *(ecx+4) 1/r32/ecx # Operand-next -1424 # curr2=curr2->next -1425 8b/-> *(edx+4) 2/r32/edx # Operand-next -1426 } -1427 $mu-stmt-matches-primitive?:return-true: -1428 b8/copy-to-eax 1/imm32 -1429 $mu-stmt-matches-primitive?:end: -1430 # . restore registers -1431 5f/pop-to-edi -1432 5e/pop-to-esi -1433 5b/pop-to-ebx -1434 5a/pop-to-edx -1435 59/pop-to-ecx -1436 # . epilogue -1437 89/<- %esp 5/r32/ebp -1438 5d/pop-to-ebp -1439 c3/return -1440 -1441 operand-matches-primitive?: # var : (address var), primout-var : (address var) => result/eax : boolean -1442 # . prologue -1443 55/push-ebp -1444 89/<- %ebp 4/r32/esp -1445 # . save registers -1446 56/push-esi -1447 57/push-edi -1448 # esi = var -1449 8b/-> *(ebp+8) 6/r32/esi -1450 # edi = primout-var -1451 8b/-> *(ebp+0xc) 7/r32/edi -1452 # if (var->type != primout-var->type) return false -1453 # TODO -1454 # return false if var->register doesn't match primout-var->register -1455 { -1456 # if addresses are equal, don't return here -1457 8b/-> *(esi+0x10) 0/r32/eax -1458 39/compare *(edi+0x10) 0/r32/eax -1459 74/jump-if-equal break/disp8 -1460 # if either address is 0, return false -1461 3d/compare-eax-and 0/imm32 -1462 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -1463 81 7/subop/compare *(edi+0x10) 0/imm32 -1464 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -1465 # if primout-var->register is "*", return true -1466 (string-equal? *(edi+0x10) "*") # Var-register -1467 3d/compare-eax-and 0/imm32 -1468 b8/copy-to-eax 1/imm32/true -1469 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 -1470 # if string contents don't match, return false -1471 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register -1472 3d/compare-eax-and 0/imm32 -1473 b8/copy-to-eax 0/imm32/false -1474 74/jump-if-equal $operand-matches-primitive?:end/disp8 -1475 } -1476 # return true -1477 b8/copy-to-eax 1/imm32/true -1478 $operand-matches-primitive?:end: -1479 # . restore registers -1480 5f/pop-to-edi -1481 5e/pop-to-esi -1482 # . epilogue -1483 89/<- %esp 5/r32/ebp -1484 5d/pop-to-ebp -1485 c3/return -1486 -1487 test-emit-subx-statement-primitive: -1488 # Primitive operation on a variable on the stack. -1489 # increment foo -1490 # => -1491 # ff 0/subop/increment *(ebp-8) -1492 # -1493 # There's a variable on the var stack as follows: -1494 # name: 'foo' -1495 # type: int -1496 # stack-offset: -8 -1497 # -1498 # There's a primitive with this info: -1499 # name: 'increment' -1500 # inouts: int/mem -1501 # value: 'ff 0/subop/increment' -1502 # -1503 # There's nothing in functions. -1504 # -1505 # . prologue -1506 55/push-ebp -1507 89/<- %ebp 4/r32/esp -1508 # setup -1509 (clear-stream _test-output-stream) -1510 (clear-stream _test-output-buffered-file->buffer) -1511 # var-foo/ecx : var -1512 68/push 0/imm32/no-register -1513 68/push -8/imm32/stack-offset -1514 68/push 1/imm32/block-depth -1515 68/push 1/imm32/type-int -1516 68/push "foo"/imm32 -1517 89/<- %ecx 4/r32/esp -1518 #? $aa-var-in-ecx: -1519 # vars/edx : (stack 1) -1520 51/push-ecx/var-foo -1521 68/push 1/imm32/data-length -1522 68/push 1/imm32/top -1523 89/<- %edx 4/r32/esp -1524 #? $aa-vars-in-edx: -1525 # operand/ebx : (list var) -1526 68/push 0/imm32/next -1527 51/push-ecx/var-foo -1528 89/<- %ebx 4/r32/esp -1529 #? $aa-stmt-operand-in-ebx: -1530 # stmt/esi : statement -1531 68/push 0/imm32/next -1532 68/push 0/imm32/outputs -1533 53/push-ebx/operands -1534 68/push "increment"/imm32/operation -1535 89/<- %esi 4/r32/esp -1536 #? $aa-stmt-in-esi: -1537 # primitives/ebx : primitive -1538 68/push 0/imm32/next -1539 68/push 0/imm32/no-imm32 -1540 68/push 0/imm32/no-r32 -1541 68/push 1/imm32/rm32-is-first-inout -1542 68/push "ff 0/subop/increment"/imm32/subx-name -1543 68/push 0/imm32/outputs -1544 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call -1545 68/push "increment"/imm32/name -1546 89/<- %ebx 4/r32/esp -1547 $aa-primitive-in-ebx: -1548 # convert -1549 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) -1550 (flush _test-output-buffered-file) -1551 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -1557 # check output -1558 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") -1559 # . epilogue -1560 89/<- %esp 5/r32/ebp -1561 5d/pop-to-ebp -1562 c3/return -1563 -1564 test-emit-subx-statement-primitive-register: -1565 # Primitive operation on a variable in a register. -1566 # foo <- increment -1567 # => -1568 # ff 0/subop/increment %eax # sub-optimal, but should suffice -1569 # -1570 # There's a variable on the var stack as follows: -1571 # name: 'foo' -1572 # type: int -1573 # register: 'eax' -1574 # -1575 # There's a primitive with this info: -1576 # name: 'increment' -1577 # out: int/reg -1578 # value: 'ff 0/subop/increment' -1579 # -1580 # There's nothing in functions. -1581 # -1582 # . prologue -1583 55/push-ebp -1584 89/<- %ebp 4/r32/esp -1585 # setup -1586 (clear-stream _test-output-stream) -1587 (clear-stream _test-output-buffered-file->buffer) -1588 # var-foo/ecx : var in eax -1589 68/push "eax"/imm32/register -1590 68/push 0/imm32/no-stack-offset -1591 68/push 1/imm32/block-depth -1592 68/push 1/imm32/type-int -1593 68/push "foo"/imm32 -1594 89/<- %ecx 4/r32/esp -1595 # vars/edx : (stack 1) -1596 51/push-ecx/var-foo -1597 68/push 1/imm32/data-length -1598 68/push 1/imm32/top -1599 89/<- %edx 4/r32/esp -1600 # operand/ebx : (list var) -1601 68/push 0/imm32/next -1602 51/push-ecx/var-foo -1603 89/<- %ebx 4/r32/esp -1604 # stmt/esi : statement -1605 68/push 0/imm32/next -1606 53/push-ebx/outputs -1607 68/push 0/imm32/inouts -1608 68/push "increment"/imm32/operation -1609 89/<- %esi 4/r32/esp -1610 # formal-var/ebx : var in any register -1611 68/push Any-register/imm32 -1612 68/push 0/imm32/no-stack-offset -1613 68/push 1/imm32/block-depth -1614 68/push 1/imm32/type-int -1615 68/push "dummy"/imm32 -1616 89/<- %ebx 4/r32/esp -1617 # operand/ebx : (list var) -1618 68/push 0/imm32/next -1619 53/push-ebx/formal-var -1620 89/<- %ebx 4/r32/esp -1621 # primitives/ebx : primitive -1622 68/push 0/imm32/next -1623 68/push 0/imm32/no-imm32 -1624 68/push 0/imm32/no-r32 -1625 68/push 3/imm32/rm32-in-first-output -1626 68/push "ff 0/subop/increment"/imm32/subx-name -1627 53/push-ebx/outputs -1628 68/push 0/imm32/inouts -1629 68/push "increment"/imm32/name -1630 89/<- %ebx 4/r32/esp -1631 # convert -1632 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) -1633 (flush _test-output-buffered-file) -1634 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -1640 # check output -1641 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") -1642 # . epilogue -1643 89/<- %esp 5/r32/ebp -1644 5d/pop-to-ebp -1645 c3/return -1646 -1647 test-emit-subx-statement-select-primitive: -1648 # Select the right primitive between overloads. -1649 # foo <- increment -1650 # => -1651 # ff 0/subop/increment %eax # sub-optimal, but should suffice -1652 # -1653 # There's a variable on the var stack as follows: -1654 # name: 'foo' -1655 # type: int -1656 # register: 'eax' -1657 # -1658 # There's two primitives, as follows: -1659 # - name: 'increment' -1660 # out: int/reg -1661 # value: 'ff 0/subop/increment' -1662 # - name: 'increment' -1663 # inout: int/mem -1664 # value: 'ff 0/subop/increment' -1665 # -1666 # There's nothing in functions. -1667 # -1668 # . prologue -1669 55/push-ebp -1670 89/<- %ebp 4/r32/esp -1671 # setup -1672 (clear-stream _test-output-stream) -1673 (clear-stream _test-output-buffered-file->buffer) -1674 # var-foo/ecx : var in eax -1675 68/push "eax"/imm32/register -1676 68/push 0/imm32/no-stack-offset -1677 68/push 1/imm32/block-depth -1678 68/push 1/imm32/type-int -1679 68/push "foo"/imm32 -1680 89/<- %ecx 4/r32/esp -1681 # vars/edx : (stack 1) -1682 51/push-ecx/var-foo -1683 68/push 1/imm32/data-length -1684 68/push 1/imm32/top -1685 89/<- %edx 4/r32/esp -1686 # real-outputs/edi : (list var) -1687 68/push 0/imm32/next -1688 51/push-ecx/var-foo -1689 89/<- %edi 4/r32/esp -1690 # stmt/esi : statement -1691 68/push 0/imm32/next -1692 57/push-edi/outputs -1693 68/push 0/imm32/inouts -1694 68/push "increment"/imm32/operation -1695 89/<- %esi 4/r32/esp -1696 # formal-var/ebx : var in any register -1697 68/push Any-register/imm32 -1698 68/push 0/imm32/no-stack-offset -1699 68/push 1/imm32/block-depth -1700 68/push 1/imm32/type-int -1701 68/push "dummy"/imm32 -1702 89/<- %ebx 4/r32/esp -1703 # formal-outputs/ebx : (list var) -1704 68/push 0/imm32/next -1705 53/push-ebx/formal-var -1706 89/<- %ebx 4/r32/esp -1707 # primitive1/ebx : primitive -1708 68/push 0/imm32/next -1709 68/push 0/imm32/no-imm32 -1710 68/push 0/imm32/no-r32 -1711 68/push 3/imm32/rm32-in-first-output -1712 68/push "ff 0/subop/increment"/imm32/subx-name -1713 53/push-ebx/outputs/formal-outputs -1714 68/push 0/imm32/inouts -1715 68/push "increment"/imm32/name -1716 89/<- %ebx 4/r32/esp -1717 # primitives/ebx : primitive -1718 53/push-ebx/next -1719 68/push 0/imm32/no-imm32 -1720 68/push 0/imm32/no-r32 -1721 68/push 1/imm32/rm32-is-first-inout -1722 68/push "ff 0/subop/increment"/imm32/subx-name -1723 68/push 0/imm32/outputs -1724 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -1725 68/push "increment"/imm32/name -1726 89/<- %ebx 4/r32/esp -1727 # convert -1728 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) -1729 (flush _test-output-buffered-file) -1730 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -1736 # check output -1737 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") -1738 # . epilogue -1739 89/<- %esp 5/r32/ebp -1740 5d/pop-to-ebp -1741 c3/return -1742 -1743 test-emit-subx-statement-select-primitive-2: -1744 # Select the right primitive between overloads. -1745 # foo <- increment -1746 # => -1747 # ff 0/subop/increment %eax # sub-optimal, but should suffice -1748 # -1749 # There's a variable on the var stack as follows: -1750 # name: 'foo' -1751 # type: int -1752 # register: 'eax' -1753 # -1754 # There's two primitives, as follows: -1755 # - name: 'increment' -1756 # out: int/reg -1757 # value: 'ff 0/subop/increment' -1758 # - name: 'increment' -1759 # inout: int/mem -1760 # value: 'ff 0/subop/increment' -1761 # -1762 # There's nothing in functions. -1763 # -1764 # . prologue -1765 55/push-ebp -1766 89/<- %ebp 4/r32/esp -1767 # setup -1768 (clear-stream _test-output-stream) -1769 (clear-stream _test-output-buffered-file->buffer) -1770 # var-foo/ecx : var in eax -1771 68/push "eax"/imm32/register -1772 68/push 0/imm32/no-stack-offset -1773 68/push 1/imm32/block-depth -1774 68/push 1/imm32/type-int -1775 68/push "foo"/imm32 -1776 89/<- %ecx 4/r32/esp -1777 # vars/edx : (stack 1) -1778 51/push-ecx/var-foo -1779 68/push 1/imm32/data-length -1780 68/push 1/imm32/top -1781 89/<- %edx 4/r32/esp -1782 # inouts/edi : (list var) -1783 68/push 0/imm32/next -1784 51/push-ecx/var-foo -1785 89/<- %edi 4/r32/esp -1786 # stmt/esi : statement -1787 68/push 0/imm32/next -1788 68/push 0/imm32/outputs -1789 57/push-edi/inouts -1790 68/push "increment"/imm32/operation -1791 89/<- %esi 4/r32/esp -1792 # formal-var/ebx : var in any register -1793 68/push Any-register/imm32 -1794 68/push 0/imm32/no-stack-offset -1795 68/push 1/imm32/block-depth -1796 68/push 1/imm32/type-int -1797 68/push "dummy"/imm32 -1798 89/<- %ebx 4/r32/esp -1799 # operand/ebx : (list var) -1800 68/push 0/imm32/next -1801 53/push-ebx/formal-var -1802 89/<- %ebx 4/r32/esp -1803 # primitive1/ebx : primitive -1804 68/push 0/imm32/next -1805 68/push 0/imm32/no-imm32 -1806 68/push 0/imm32/no-r32 -1807 68/push 3/imm32/rm32-in-first-output -1808 68/push "ff 0/subop/increment"/imm32/subx-name -1809 53/push-ebx/outputs/formal-outputs -1810 68/push 0/imm32/inouts -1811 68/push "increment"/imm32/name -1812 89/<- %ebx 4/r32/esp -1813 # primitives/ebx : primitive -1814 53/push-ebx/next -1815 68/push 0/imm32/no-imm32 -1816 68/push 0/imm32/no-r32 -1817 68/push 1/imm32/rm32-is-first-inout -1818 68/push "ff 0/subop/increment"/imm32/subx-name -1819 68/push 0/imm32/outputs -1820 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -1821 68/push "increment"/imm32/name -1822 89/<- %ebx 4/r32/esp -1823 # convert -1824 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) -1825 (flush _test-output-buffered-file) -1826 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -1832 # check output -1833 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") -1834 # . epilogue -1835 89/<- %esp 5/r32/ebp -1836 5d/pop-to-ebp -1837 c3/return -1838 -1839 test-increment-register: -1840 # Select the right primitive between overloads. -1841 # foo <- increment -1842 # => -1843 # ff 0/subop/increment %eax # sub-optimal, but should suffice -1844 # -1845 # There's a variable on the var stack as follows: -1846 # name: 'foo' -1847 # type: int -1848 # register: 'eax' -1849 # -1850 # Primitives are the global definitions. -1851 # -1852 # There are no functions defined. -1853 # -1854 # . prologue -1855 55/push-ebp -1856 89/<- %ebp 4/r32/esp -1857 # setup -1858 (clear-stream _test-output-stream) -1859 (clear-stream _test-output-buffered-file->buffer) -1860 # var-foo/ecx : var in eax -1861 68/push "eax"/imm32/register -1862 68/push 0/imm32/no-stack-offset -1863 68/push 1/imm32/block-depth -1864 68/push 1/imm32/type-int -1865 68/push "foo"/imm32 -1866 89/<- %ecx 4/r32/esp -1867 # vars/edx : (stack 1) -1868 51/push-ecx/var-foo -1869 68/push 1/imm32/data-length -1870 68/push 1/imm32/top -1871 89/<- %edx 4/r32/esp -1872 # real-outputs/edi : (list var) -1873 68/push 0/imm32/next -1874 51/push-ecx/var-foo -1875 89/<- %edi 4/r32/esp -1876 # stmt/esi : statement -1877 68/push 0/imm32/next -1878 57/push-edi/outputs -1879 68/push 0/imm32/inouts -1880 68/push "increment"/imm32/operation -1881 89/<- %esi 4/r32/esp -1882 # convert -1883 (emit-subx-statement _test-output-buffered-file %esi %edx Primitives 0) -1884 (flush _test-output-buffered-file) -1885 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -1891 # check output -1892 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-register") -1893 # . epilogue -1894 89/<- %esp 5/r32/ebp -1895 5d/pop-to-ebp -1896 c3/return -1897 -1898 test-increment-var: -1899 # Select the right primitive between overloads. -1900 # foo <- increment -1901 # => -1902 # ff 0/subop/increment %eax # sub-optimal, but should suffice -1903 # -1904 # There's a variable on the var stack as follows: -1905 # name: 'foo' -1906 # type: int -1907 # register: 'eax' -1908 # -1909 # Primitives are the global definitions. -1910 # -1911 # There are no functions defined. -1912 # -1913 # . prologue -1914 55/push-ebp -1915 89/<- %ebp 4/r32/esp -1916 # setup -1917 (clear-stream _test-output-stream) -1918 (clear-stream _test-output-buffered-file->buffer) -1919 # var-foo/ecx : var in eax -1920 68/push "eax"/imm32/register -1921 68/push 0/imm32/no-stack-offset -1922 68/push 1/imm32/block-depth -1923 68/push 1/imm32/type-int -1924 68/push "foo"/imm32 -1925 89/<- %ecx 4/r32/esp -1926 # vars/edx : (stack 1) -1927 51/push-ecx/var-foo -1928 68/push 1/imm32/data-length -1929 68/push 1/imm32/top -1930 89/<- %edx 4/r32/esp -1931 # inouts/edi : (list var) -1932 68/push 0/imm32/next -1933 51/push-ecx/var-foo -1934 89/<- %edi 4/r32/esp -1935 # stmt/esi : statement -1936 68/push 0/imm32/next -1937 68/push 0/imm32/outputs -1938 57/push-edi/inouts -1939 68/push "increment"/imm32/operation -1940 89/<- %esi 4/r32/esp -1941 # convert -1942 (emit-subx-statement _test-output-buffered-file %esi %edx Primitives 0) -1943 (flush _test-output-buffered-file) -1944 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -1950 # check output -1951 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") -1952 # . epilogue -1953 89/<- %esp 5/r32/ebp -1954 5d/pop-to-ebp -1955 c3/return -1956 -1957 test-add-reg-to-reg: -1958 # var1/reg <- add var2/reg -1959 # => -1960 # 01 %var1 var2 -1961 # -1962 # . prologue -1963 55/push-ebp -1964 89/<- %ebp 4/r32/esp -1965 # setup -1966 (clear-stream _test-output-stream) -1967 (clear-stream _test-output-buffered-file->buffer) -1968 # var-var1/ecx : var in eax -1969 68/push "eax"/imm32/register -1970 68/push 0/imm32/no-stack-offset -1971 68/push 1/imm32/block-depth -1972 68/push 1/imm32/type-int -1973 68/push "var1"/imm32 -1974 89/<- %ecx 4/r32/esp -1975 # var-var2/edx : var in ecx -1976 68/push "ecx"/imm32/register -1977 68/push 0/imm32/no-stack-offset -1978 68/push 1/imm32/block-depth -1979 68/push 1/imm32/type-int -1980 68/push "var2"/imm32 -1981 89/<- %edx 4/r32/esp -1982 # inouts/esi : (list var2) -1983 68/push 0/imm32/next -1984 52/push-edx/var-var2 -1985 89/<- %esi 4/r32/esp -1986 # outputs/edi : (list var1) -1987 68/push 0/imm32/next -1988 51/push-ecx/var-var1 -1989 89/<- %edi 4/r32/esp -1990 # stmt/esi : statement -1991 68/push 0/imm32/next -1992 57/push-edi/outputs -1993 56/push-esi/inouts -1994 68/push "add"/imm32/operation -1995 89/<- %esi 4/r32/esp -1996 # convert -1997 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) -1998 (flush _test-output-buffered-file) -1999 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -2005 # check output -2006 (check-next-stream-line-equal _test-output-stream "01 %eax 0x00000001/r32" "F - test-add-reg-to-reg") -2007 # . epilogue -2008 89/<- %esp 5/r32/ebp -2009 5d/pop-to-ebp -2010 c3/return -2011 -2012 test-emit-subx-statement-function-call: -2013 # Call a function on a variable on the stack. -2014 # f foo -2015 # => -2016 # (f2 *(ebp-8)) -2017 # (Changing the function name supports overloading in general, but here it -2018 # just serves to help disambiguate things.) -2019 # -2020 # There's a variable on the var stack as follows: -2021 # name: 'foo' -2022 # type: int -2023 # stack-offset: -8 -2024 # -2025 # There's nothing in primitives. -2026 # -2027 # There's a function with this info: -2028 # name: 'f' -2029 # inout: int/mem -2030 # value: 'f2' -2031 # -2032 # . prologue -2033 55/push-ebp -2034 89/<- %ebp 4/r32/esp -2035 # setup -2036 (clear-stream _test-output-stream) -2037 (clear-stream _test-output-buffered-file->buffer) -2038 # var-foo/ecx : var -2039 68/push 0/imm32/no-register -2040 68/push -8/imm32/stack-offset -2041 68/push 0/imm32/block-depth -2042 68/push 1/imm32/type-int -2043 68/push "foo"/imm32 -2044 89/<- %ecx 4/r32/esp -2045 # vars/edx = (stack 1) -2046 51/push-ecx/var-foo -2047 68/push 1/imm32/data-length -2048 68/push 1/imm32/top -2049 89/<- %edx 4/r32/esp -2050 # operands/esi : (list var) -2051 68/push 0/imm32/next -2052 51/push-ecx/var-foo -2053 89/<- %esi 4/r32/esp -2054 # stmt/esi : statement -2055 68/push 0/imm32/next -2056 68/push 0/imm32/outputs -2057 56/push-esi/inouts -2058 68/push "f"/imm32/operation -2059 89/<- %esi 4/r32/esp -2060 # functions/ebx : function +1419 { +1420 81 7/subop/compare %edi 0/imm32 +1421 75/jump-if-not-equal break/disp8 +1422 # return true +1423 b8/copy-to-eax 1/imm32 +1424 e9/jump $mu-stmt-matches-primitive?:end/disp32 +1425 } +1426 # return false +1427 b8/copy-to-eax 0/imm32 +1428 e9/jump $mu-stmt-matches-primitive?:end/disp32 +1429 } +1430 # if (curr2 == 0) return false +1431 { +1432 81 7/subop/compare %edi 0/imm32 +1433 75/jump-if-not-equal break/disp8 +1434 b8/copy-to-eax 0/imm32 +1435 e9/jump $mu-stmt-matches-primitive?:end/disp32 +1436 } +1437 # if (curr != curr2) return false +1438 { +1439 (operand-matches-primitive? *esi *edi) # => eax +1440 3d/compare-eax-and 0/imm32 +1441 75/jump-if-not-equal break/disp8 +1442 b8/copy-to-eax 0/imm32 +1443 e9/jump $mu-stmt-matches-primitive?:end/disp32 +1444 } +1445 # curr=curr->next +1446 8b/-> *(ecx+4) 1/r32/ecx # Operand-next +1447 # curr2=curr2->next +1448 8b/-> *(edx+4) 2/r32/edx # Operand-next +1449 } +1450 $mu-stmt-matches-primitive?:return-true: +1451 b8/copy-to-eax 1/imm32 +1452 $mu-stmt-matches-primitive?:end: +1453 # . restore registers +1454 5f/pop-to-edi +1455 5e/pop-to-esi +1456 5b/pop-to-ebx +1457 5a/pop-to-edx +1458 59/pop-to-ecx +1459 # . epilogue +1460 89/<- %esp 5/r32/ebp +1461 5d/pop-to-ebp +1462 c3/return +1463 +1464 operand-matches-primitive?: # var : (address var), primout-var : (address var) => result/eax : boolean +1465 # . prologue +1466 55/push-ebp +1467 89/<- %ebp 4/r32/esp +1468 # . save registers +1469 56/push-esi +1470 57/push-edi +1471 # esi = var +1472 8b/-> *(ebp+8) 6/r32/esi +1473 # edi = primout-var +1474 8b/-> *(ebp+0xc) 7/r32/edi +1475 # if (var->type != primout-var->type) return false +1476 # TODO +1477 # return false if var->register doesn't match primout-var->register +1478 { +1479 # if addresses are equal, don't return here +1480 8b/-> *(esi+0x10) 0/r32/eax +1481 39/compare *(edi+0x10) 0/r32/eax +1482 74/jump-if-equal break/disp8 +1483 # if either address is 0, return false +1484 3d/compare-eax-and 0/imm32 +1485 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +1486 81 7/subop/compare *(edi+0x10) 0/imm32 +1487 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +1488 # if primout-var->register is "*", return true +1489 (string-equal? *(edi+0x10) "*") # Var-register +1490 3d/compare-eax-and 0/imm32 +1491 b8/copy-to-eax 1/imm32/true +1492 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 +1493 # if string contents don't match, return false +1494 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register +1495 3d/compare-eax-and 0/imm32 +1496 b8/copy-to-eax 0/imm32/false +1497 74/jump-if-equal $operand-matches-primitive?:end/disp8 +1498 } +1499 # return true +1500 b8/copy-to-eax 1/imm32/true +1501 $operand-matches-primitive?:end: +1502 # . restore registers +1503 5f/pop-to-edi +1504 5e/pop-to-esi +1505 # . epilogue +1506 89/<- %esp 5/r32/ebp +1507 5d/pop-to-ebp +1508 c3/return +1509 +1510 test-emit-subx-statement-primitive: +1511 # Primitive operation on a variable on the stack. +1512 # increment foo +1513 # => +1514 # ff 0/subop/increment *(ebp-8) +1515 # +1516 # There's a variable on the var stack as follows: +1517 # name: 'foo' +1518 # type: int +1519 # stack-offset: -8 +1520 # +1521 # There's a primitive with this info: +1522 # name: 'increment' +1523 # inouts: int/mem +1524 # value: 'ff 0/subop/increment' +1525 # +1526 # There's nothing in functions. +1527 # +1528 # . prologue +1529 55/push-ebp +1530 89/<- %ebp 4/r32/esp +1531 # setup +1532 (clear-stream _test-output-stream) +1533 (clear-stream _test-output-buffered-file->buffer) +1534 # var-foo/ecx : var +1535 68/push 0/imm32/no-register +1536 68/push -8/imm32/stack-offset +1537 68/push 1/imm32/block-depth +1538 68/push 1/imm32/type-int +1539 68/push "foo"/imm32 +1540 89/<- %ecx 4/r32/esp +1541 #? $aa-var-in-ecx: +1542 # vars/edx : (stack 1) +1543 51/push-ecx/var-foo +1544 68/push 1/imm32/data-length +1545 68/push 1/imm32/top +1546 89/<- %edx 4/r32/esp +1547 #? $aa-vars-in-edx: +1548 # operand/ebx : (list var) +1549 68/push 0/imm32/next +1550 51/push-ecx/var-foo +1551 89/<- %ebx 4/r32/esp +1552 #? $aa-stmt-operand-in-ebx: +1553 # stmt/esi : statement +1554 68/push 0/imm32/next +1555 68/push 0/imm32/outputs +1556 53/push-ebx/operands +1557 68/push "increment"/imm32/operation +1558 89/<- %esi 4/r32/esp +1559 #? $aa-stmt-in-esi: +1560 # primitives/ebx : primitive +1561 68/push 0/imm32/next +1562 68/push 0/imm32/no-imm32 +1563 68/push 0/imm32/no-r32 +1564 68/push 1/imm32/rm32-is-first-inout +1565 68/push "ff 0/subop/increment"/imm32/subx-name +1566 68/push 0/imm32/outputs +1567 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call +1568 68/push "increment"/imm32/name +1569 89/<- %ebx 4/r32/esp +1570 $aa-primitive-in-ebx: +1571 # convert +1572 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) +1573 (flush _test-output-buffered-file) +1574 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +1580 # check output +1581 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") +1582 # . epilogue +1583 89/<- %esp 5/r32/ebp +1584 5d/pop-to-ebp +1585 c3/return +1586 +1587 test-emit-subx-statement-primitive-register: +1588 # Primitive operation on a variable in a register. +1589 # foo <- increment +1590 # => +1591 # ff 0/subop/increment %eax # sub-optimal, but should suffice +1592 # +1593 # There's a variable on the var stack as follows: +1594 # name: 'foo' +1595 # type: int +1596 # register: 'eax' +1597 # +1598 # There's a primitive with this info: +1599 # name: 'increment' +1600 # out: int/reg +1601 # value: 'ff 0/subop/increment' +1602 # +1603 # There's nothing in functions. +1604 # +1605 # . prologue +1606 55/push-ebp +1607 89/<- %ebp 4/r32/esp +1608 # setup +1609 (clear-stream _test-output-stream) +1610 (clear-stream _test-output-buffered-file->buffer) +1611 # var-foo/ecx : var in eax +1612 68/push "eax"/imm32/register +1613 68/push 0/imm32/no-stack-offset +1614 68/push 1/imm32/block-depth +1615 68/push 1/imm32/type-int +1616 68/push "foo"/imm32 +1617 89/<- %ecx 4/r32/esp +1618 # vars/edx : (stack 1) +1619 51/push-ecx/var-foo +1620 68/push 1/imm32/data-length +1621 68/push 1/imm32/top +1622 89/<- %edx 4/r32/esp +1623 # operand/ebx : (list var) +1624 68/push 0/imm32/next +1625 51/push-ecx/var-foo +1626 89/<- %ebx 4/r32/esp +1627 # stmt/esi : statement +1628 68/push 0/imm32/next +1629 53/push-ebx/outputs +1630 68/push 0/imm32/inouts +1631 68/push "increment"/imm32/operation +1632 89/<- %esi 4/r32/esp +1633 # formal-var/ebx : var in any register +1634 68/push Any-register/imm32 +1635 68/push 0/imm32/no-stack-offset +1636 68/push 1/imm32/block-depth +1637 68/push 1/imm32/type-int +1638 68/push "dummy"/imm32 +1639 89/<- %ebx 4/r32/esp +1640 # operand/ebx : (list var) +1641 68/push 0/imm32/next +1642 53/push-ebx/formal-var +1643 89/<- %ebx 4/r32/esp +1644 # primitives/ebx : primitive +1645 68/push 0/imm32/next +1646 68/push 0/imm32/no-imm32 +1647 68/push 0/imm32/no-r32 +1648 68/push 3/imm32/rm32-in-first-output +1649 68/push "ff 0/subop/increment"/imm32/subx-name +1650 53/push-ebx/outputs +1651 68/push 0/imm32/inouts +1652 68/push "increment"/imm32/name +1653 89/<- %ebx 4/r32/esp +1654 # convert +1655 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) +1656 (flush _test-output-buffered-file) +1657 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +1663 # check output +1664 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") +1665 # . epilogue +1666 89/<- %esp 5/r32/ebp +1667 5d/pop-to-ebp +1668 c3/return +1669 +1670 test-emit-subx-statement-select-primitive: +1671 # Select the right primitive between overloads. +1672 # foo <- increment +1673 # => +1674 # ff 0/subop/increment %eax # sub-optimal, but should suffice +1675 # +1676 # There's a variable on the var stack as follows: +1677 # name: 'foo' +1678 # type: int +1679 # register: 'eax' +1680 # +1681 # There's two primitives, as follows: +1682 # - name: 'increment' +1683 # out: int/reg +1684 # value: 'ff 0/subop/increment' +1685 # - name: 'increment' +1686 # inout: int/mem +1687 # value: 'ff 0/subop/increment' +1688 # +1689 # There's nothing in functions. +1690 # +1691 # . prologue +1692 55/push-ebp +1693 89/<- %ebp 4/r32/esp +1694 # setup +1695 (clear-stream _test-output-stream) +1696 (clear-stream _test-output-buffered-file->buffer) +1697 # var-foo/ecx : var in eax +1698 68/push "eax"/imm32/register +1699 68/push 0/imm32/no-stack-offset +1700 68/push 1/imm32/block-depth +1701 68/push 1/imm32/type-int +1702 68/push "foo"/imm32 +1703 89/<- %ecx 4/r32/esp +1704 # vars/edx : (stack 1) +1705 51/push-ecx/var-foo +1706 68/push 1/imm32/data-length +1707 68/push 1/imm32/top +1708 89/<- %edx 4/r32/esp +1709 # real-outputs/edi : (list var) +1710 68/push 0/imm32/next +1711 51/push-ecx/var-foo +1712 89/<- %edi 4/r32/esp +1713 # stmt/esi : statement +1714 68/push 0/imm32/next +1715 57/push-edi/outputs +1716 68/push 0/imm32/inouts +1717 68/push "increment"/imm32/operation +1718 89/<- %esi 4/r32/esp +1719 # formal-var/ebx : var in any register +1720 68/push Any-register/imm32 +1721 68/push 0/imm32/no-stack-offset +1722 68/push 1/imm32/block-depth +1723 68/push 1/imm32/type-int +1724 68/push "dummy"/imm32 +1725 89/<- %ebx 4/r32/esp +1726 # formal-outputs/ebx : (list var) +1727 68/push 0/imm32/next +1728 53/push-ebx/formal-var +1729 89/<- %ebx 4/r32/esp +1730 # primitive1/ebx : primitive +1731 68/push 0/imm32/next +1732 68/push 0/imm32/no-imm32 +1733 68/push 0/imm32/no-r32 +1734 68/push 3/imm32/rm32-in-first-output +1735 68/push "ff 0/subop/increment"/imm32/subx-name +1736 53/push-ebx/outputs/formal-outputs +1737 68/push 0/imm32/inouts +1738 68/push "increment"/imm32/name +1739 89/<- %ebx 4/r32/esp +1740 # primitives/ebx : primitive +1741 53/push-ebx/next +1742 68/push 0/imm32/no-imm32 +1743 68/push 0/imm32/no-r32 +1744 68/push 1/imm32/rm32-is-first-inout +1745 68/push "ff 0/subop/increment"/imm32/subx-name +1746 68/push 0/imm32/outputs +1747 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +1748 68/push "increment"/imm32/name +1749 89/<- %ebx 4/r32/esp +1750 # convert +1751 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) +1752 (flush _test-output-buffered-file) +1753 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +1759 # check output +1760 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") +1761 # . epilogue +1762 89/<- %esp 5/r32/ebp +1763 5d/pop-to-ebp +1764 c3/return +1765 +1766 test-emit-subx-statement-select-primitive-2: +1767 # Select the right primitive between overloads. +1768 # foo <- increment +1769 # => +1770 # ff 0/subop/increment %eax # sub-optimal, but should suffice +1771 # +1772 # There's a variable on the var stack as follows: +1773 # name: 'foo' +1774 # type: int +1775 # register: 'eax' +1776 # +1777 # There's two primitives, as follows: +1778 # - name: 'increment' +1779 # out: int/reg +1780 # value: 'ff 0/subop/increment' +1781 # - name: 'increment' +1782 # inout: int/mem +1783 # value: 'ff 0/subop/increment' +1784 # +1785 # There's nothing in functions. +1786 # +1787 # . prologue +1788 55/push-ebp +1789 89/<- %ebp 4/r32/esp +1790 # setup +1791 (clear-stream _test-output-stream) +1792 (clear-stream _test-output-buffered-file->buffer) +1793 # var-foo/ecx : var in eax +1794 68/push "eax"/imm32/register +1795 68/push 0/imm32/no-stack-offset +1796 68/push 1/imm32/block-depth +1797 68/push 1/imm32/type-int +1798 68/push "foo"/imm32 +1799 89/<- %ecx 4/r32/esp +1800 # vars/edx : (stack 1) +1801 51/push-ecx/var-foo +1802 68/push 1/imm32/data-length +1803 68/push 1/imm32/top +1804 89/<- %edx 4/r32/esp +1805 # inouts/edi : (list var) +1806 68/push 0/imm32/next +1807 51/push-ecx/var-foo +1808 89/<- %edi 4/r32/esp +1809 # stmt/esi : statement +1810 68/push 0/imm32/next +1811 68/push 0/imm32/outputs +1812 57/push-edi/inouts +1813 68/push "increment"/imm32/operation +1814 89/<- %esi 4/r32/esp +1815 # formal-var/ebx : var in any register +1816 68/push Any-register/imm32 +1817 68/push 0/imm32/no-stack-offset +1818 68/push 1/imm32/block-depth +1819 68/push 1/imm32/type-int +1820 68/push "dummy"/imm32 +1821 89/<- %ebx 4/r32/esp +1822 # operand/ebx : (list var) +1823 68/push 0/imm32/next +1824 53/push-ebx/formal-var +1825 89/<- %ebx 4/r32/esp +1826 # primitive1/ebx : primitive +1827 68/push 0/imm32/next +1828 68/push 0/imm32/no-imm32 +1829 68/push 0/imm32/no-r32 +1830 68/push 3/imm32/rm32-in-first-output +1831 68/push "ff 0/subop/increment"/imm32/subx-name +1832 53/push-ebx/outputs/formal-outputs +1833 68/push 0/imm32/inouts +1834 68/push "increment"/imm32/name +1835 89/<- %ebx 4/r32/esp +1836 # primitives/ebx : primitive +1837 53/push-ebx/next +1838 68/push 0/imm32/no-imm32 +1839 68/push 0/imm32/no-r32 +1840 68/push 1/imm32/rm32-is-first-inout +1841 68/push "ff 0/subop/increment"/imm32/subx-name +1842 68/push 0/imm32/outputs +1843 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +1844 68/push "increment"/imm32/name +1845 89/<- %ebx 4/r32/esp +1846 # convert +1847 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) +1848 (flush _test-output-buffered-file) +1849 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +1855 # check output +1856 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") +1857 # . epilogue +1858 89/<- %esp 5/r32/ebp +1859 5d/pop-to-ebp +1860 c3/return +1861 +1862 test-increment-register: +1863 # Select the right primitive between overloads. +1864 # foo <- increment +1865 # => +1866 # ff 0/subop/increment %eax # sub-optimal, but should suffice +1867 # +1868 # There's a variable on the var stack as follows: +1869 # name: 'foo' +1870 # type: int +1871 # register: 'eax' +1872 # +1873 # Primitives are the global definitions. +1874 # +1875 # There are no functions defined. +1876 # +1877 # . prologue +1878 55/push-ebp +1879 89/<- %ebp 4/r32/esp +1880 # setup +1881 (clear-stream _test-output-stream) +1882 (clear-stream _test-output-buffered-file->buffer) +1883 # var-foo/ecx : var in eax +1884 68/push "eax"/imm32/register +1885 68/push 0/imm32/no-stack-offset +1886 68/push 1/imm32/block-depth +1887 68/push 1/imm32/type-int +1888 68/push "foo"/imm32 +1889 89/<- %ecx 4/r32/esp +1890 # vars/edx : (stack 1) +1891 51/push-ecx/var-foo +1892 68/push 1/imm32/data-length +1893 68/push 1/imm32/top +1894 89/<- %edx 4/r32/esp +1895 # real-outputs/edi : (list var) +1896 68/push 0/imm32/next +1897 51/push-ecx/var-foo +1898 89/<- %edi 4/r32/esp +1899 # stmt/esi : statement +1900 68/push 0/imm32/next +1901 57/push-edi/outputs +1902 68/push 0/imm32/inouts +1903 68/push "increment"/imm32/operation +1904 89/<- %esi 4/r32/esp +1905 # convert +1906 (emit-subx-statement _test-output-buffered-file %esi %edx Primitives 0) +1907 (flush _test-output-buffered-file) +1908 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +1914 # check output +1915 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-register") +1916 # . epilogue +1917 89/<- %esp 5/r32/ebp +1918 5d/pop-to-ebp +1919 c3/return +1920 +1921 test-increment-var: +1922 # Select the right primitive between overloads. +1923 # foo <- increment +1924 # => +1925 # ff 0/subop/increment %eax # sub-optimal, but should suffice +1926 # +1927 # There's a variable on the var stack as follows: +1928 # name: 'foo' +1929 # type: int +1930 # register: 'eax' +1931 # +1932 # Primitives are the global definitions. +1933 # +1934 # There are no functions defined. +1935 # +1936 # . prologue +1937 55/push-ebp +1938 89/<- %ebp 4/r32/esp +1939 # setup +1940 (clear-stream _test-output-stream) +1941 (clear-stream _test-output-buffered-file->buffer) +1942 # var-foo/ecx : var in eax +1943 68/push "eax"/imm32/register +1944 68/push 0/imm32/no-stack-offset +1945 68/push 1/imm32/block-depth +1946 68/push 1/imm32/type-int +1947 68/push "foo"/imm32 +1948 89/<- %ecx 4/r32/esp +1949 # vars/edx : (stack 1) +1950 51/push-ecx/var-foo +1951 68/push 1/imm32/data-length +1952 68/push 1/imm32/top +1953 89/<- %edx 4/r32/esp +1954 # inouts/edi : (list var) +1955 68/push 0/imm32/next +1956 51/push-ecx/var-foo +1957 89/<- %edi 4/r32/esp +1958 # stmt/esi : statement +1959 68/push 0/imm32/next +1960 68/push 0/imm32/outputs +1961 57/push-edi/inouts +1962 68/push "increment"/imm32/operation +1963 89/<- %esi 4/r32/esp +1964 # convert +1965 (emit-subx-statement _test-output-buffered-file %esi %edx Primitives 0) +1966 (flush _test-output-buffered-file) +1967 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +1973 # check output +1974 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") +1975 # . epilogue +1976 89/<- %esp 5/r32/ebp +1977 5d/pop-to-ebp +1978 c3/return +1979 +1980 test-add-reg-to-reg: +1981 # var1/reg <- add var2/reg +1982 # => +1983 # 01 %var1 var2 +1984 # +1985 # . prologue +1986 55/push-ebp +1987 89/<- %ebp 4/r32/esp +1988 # setup +1989 (clear-stream _test-output-stream) +1990 (clear-stream _test-output-buffered-file->buffer) +1991 # var-var1/ecx : var in eax +1992 68/push "eax"/imm32/register +1993 68/push 0/imm32/no-stack-offset +1994 68/push 1/imm32/block-depth +1995 68/push 1/imm32/type-int +1996 68/push "var1"/imm32 +1997 89/<- %ecx 4/r32/esp +1998 # var-var2/edx : var in ecx +1999 68/push "ecx"/imm32/register +2000 68/push 0/imm32/no-stack-offset +2001 68/push 1/imm32/block-depth +2002 68/push 1/imm32/type-int +2003 68/push "var2"/imm32 +2004 89/<- %edx 4/r32/esp +2005 # inouts/esi : (list var2) +2006 68/push 0/imm32/next +2007 52/push-edx/var-var2 +2008 89/<- %esi 4/r32/esp +2009 # outputs/edi : (list var1) +2010 68/push 0/imm32/next +2011 51/push-ecx/var-var1 +2012 89/<- %edi 4/r32/esp +2013 # stmt/esi : statement +2014 68/push 0/imm32/next +2015 57/push-edi/outputs +2016 56/push-esi/inouts +2017 68/push "add"/imm32/operation +2018 89/<- %esi 4/r32/esp +2019 # convert +2020 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) +2021 (flush _test-output-buffered-file) +2022 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +2028 # check output +2029 (check-next-stream-line-equal _test-output-stream "01 %eax 0x00000001/r32" "F - test-add-reg-to-reg") +2030 # . epilogue +2031 89/<- %esp 5/r32/ebp +2032 5d/pop-to-ebp +2033 c3/return +2034 +2035 test-add-literal-to-reg: +2036 # var1/eax <- add 0x34 +2037 # => +2038 # 81 0/subop/add %eax 0x34/imm32 +2039 # +2040 # . prologue +2041 55/push-ebp +2042 89/<- %ebp 4/r32/esp +2043 # setup +2044 (clear-stream _test-output-stream) +2045 (clear-stream _test-output-buffered-file->buffer) +2046 # var-var1/ecx : var in eax +2047 68/push "eax"/imm32/register +2048 68/push 0/imm32/no-stack-offset +2049 68/push 1/imm32/block-depth +2050 68/push 1/imm32/type-int +2051 68/push "var1"/imm32 +2052 89/<- %ecx 4/r32/esp +2053 # var-var2/edx : var literal +2054 68/push 0/imm32/no-register +2055 68/push 0/imm32/no-stack-offset +2056 68/push 1/imm32/block-depth +2057 68/push 0/imm32/type-literal +2058 68/push "0x34"/imm32 +2059 89/<- %edx 4/r32/esp +2060 # inouts/esi : (list var2) 2061 68/push 0/imm32/next -2062 68/push 0/imm32/body -2063 68/push 0/imm32/outputs -2064 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -2065 68/push "f2"/imm32/subx-name -2066 68/push "f"/imm32/name -2067 89/<- %ebx 4/r32/esp -2068 # convert -2069 (emit-subx-statement _test-output-buffered-file %esi %edx 0 %ebx) -2070 (flush _test-output-buffered-file) -2071 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -2077 # check output -2078 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") -2079 # . epilogue -2080 89/<- %esp 5/r32/ebp -2081 5d/pop-to-ebp -2082 c3/return -2083 -2084 emit-subx-prologue: # out : (address buffered-file) -2085 # . prologue -2086 55/push-ebp -2087 89/<- %ebp 4/r32/esp -2088 # -2089 (write-buffered *(ebp+8) "# . prologue\n") -2090 (write-buffered *(ebp+8) "55/push-ebp\n") -2091 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") -2092 $emit-subx-prologue:end: -2093 # . epilogue -2094 89/<- %esp 5/r32/ebp -2095 5d/pop-to-ebp -2096 c3/return -2097 -2098 emit-subx-epilogue: # out : (address buffered-file) -2099 # . prologue -2100 55/push-ebp -2101 89/<- %ebp 4/r32/esp +2062 52/push-edx/var-var2 +2063 89/<- %esi 4/r32/esp +2064 # outputs/edi : (list var1) +2065 68/push 0/imm32/next +2066 51/push-ecx/var-var1 +2067 89/<- %edi 4/r32/esp +2068 # stmt/esi : statement +2069 68/push 0/imm32/next +2070 57/push-edi/outputs +2071 56/push-esi/inouts +2072 68/push "add"/imm32/operation +2073 89/<- %esi 4/r32/esp +2074 # convert +2075 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) +2076 (flush _test-output-buffered-file) +2077 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +2083 # check output +2084 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %eax 0x34/imm32" "F - test-add-literal-to-reg") +2085 # . epilogue +2086 89/<- %esp 5/r32/ebp +2087 5d/pop-to-ebp +2088 c3/return +2089 +2090 test-emit-subx-statement-function-call: +2091 # Call a function on a variable on the stack. +2092 # f foo +2093 # => +2094 # (f2 *(ebp-8)) +2095 # (Changing the function name supports overloading in general, but here it +2096 # just serves to help disambiguate things.) +2097 # +2098 # There's a variable on the var stack as follows: +2099 # name: 'foo' +2100 # type: int +2101 # stack-offset: -8 2102 # -2103 (write-buffered *(ebp+8) "# . epilogue\n") -2104 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") -2105 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") -2106 (write-buffered *(ebp+8) "c3/return\n") -2107 $emit-subx-epilogue:end: -2108 # . epilogue -2109 89/<- %esp 5/r32/ebp -2110 5d/pop-to-ebp -2111 c3/return +2103 # There's nothing in primitives. +2104 # +2105 # There's a function with this info: +2106 # name: 'f' +2107 # inout: int/mem +2108 # value: 'f2' +2109 # +2110 # . prologue +2111 55/push-ebp +2112 89/<- %ebp 4/r32/esp +2113 # setup +2114 (clear-stream _test-output-stream) +2115 (clear-stream _test-output-buffered-file->buffer) +2116 # var-foo/ecx : var +2117 68/push 0/imm32/no-register +2118 68/push -8/imm32/stack-offset +2119 68/push 0/imm32/block-depth +2120 68/push 1/imm32/type-int +2121 68/push "foo"/imm32 +2122 89/<- %ecx 4/r32/esp +2123 # vars/edx = (stack 1) +2124 51/push-ecx/var-foo +2125 68/push 1/imm32/data-length +2126 68/push 1/imm32/top +2127 89/<- %edx 4/r32/esp +2128 # operands/esi : (list var) +2129 68/push 0/imm32/next +2130 51/push-ecx/var-foo +2131 89/<- %esi 4/r32/esp +2132 # stmt/esi : statement +2133 68/push 0/imm32/next +2134 68/push 0/imm32/outputs +2135 56/push-esi/inouts +2136 68/push "f"/imm32/operation +2137 89/<- %esi 4/r32/esp +2138 # functions/ebx : function +2139 68/push 0/imm32/next +2140 68/push 0/imm32/body +2141 68/push 0/imm32/outputs +2142 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +2143 68/push "f2"/imm32/subx-name +2144 68/push "f"/imm32/name +2145 89/<- %ebx 4/r32/esp +2146 # convert +2147 (emit-subx-statement _test-output-buffered-file %esi %edx 0 %ebx) +2148 (flush _test-output-buffered-file) +2149 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +2155 # check output +2156 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") +2157 # . epilogue +2158 89/<- %esp 5/r32/ebp +2159 5d/pop-to-ebp +2160 c3/return +2161 +2162 emit-subx-prologue: # out : (address buffered-file) +2163 # . prologue +2164 55/push-ebp +2165 89/<- %ebp 4/r32/esp +2166 # +2167 (write-buffered *(ebp+8) "# . prologue\n") +2168 (write-buffered *(ebp+8) "55/push-ebp\n") +2169 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") +2170 $emit-subx-prologue:end: +2171 # . epilogue +2172 89/<- %esp 5/r32/ebp +2173 5d/pop-to-ebp +2174 c3/return +2175 +2176 emit-subx-epilogue: # out : (address buffered-file) +2177 # . prologue +2178 55/push-ebp +2179 89/<- %ebp 4/r32/esp +2180 # +2181 (write-buffered *(ebp+8) "# . epilogue\n") +2182 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") +2183 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") +2184 (write-buffered *(ebp+8) "c3/return\n") +2185 $emit-subx-epilogue:end: +2186 # . epilogue +2187 89/<- %esp 5/r32/ebp +2188 5d/pop-to-ebp +2189 c3/return -- cgit 1.4.1-2-gfad0