From 1d8849e52d9d07ebfb6113ab6cea3308ece429cd Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 27 Jan 2020 02:08:47 -0800 Subject: 5930 --- html/apps/mu.subx.html | 10422 ++++++++++++++++++++++++----------------------- 1 file changed, 5290 insertions(+), 5132 deletions(-) (limited to 'html/apps/*.subx.html') diff --git a/html/apps/mu.subx.html b/html/apps/mu.subx.html index 5c360a39..ec780501 100644 --- a/html/apps/mu.subx.html +++ b/html/apps/mu.subx.html @@ -455,9 +455,9 @@ if ('onhashchange' in window) { 393 55/push-ebp 394 89/<- %ebp 4/r32/esp 395 # - 396 (parse-mu *(ebp+8)) - 397 (check-mu-types) - 398 (emit-subx *(ebp+0xc)) + 396 (parse-mu *(ebp+8)) + 397 (check-mu-types) + 398 (emit-subx *(ebp+0xc)) 399 $convert-mu:end: 400 # . epilogue 401 89/<- %esp 5/r32/ebp @@ -975,5148 +975,5306 @@ if ('onhashchange' in window) { 958 5d/pop-to-ebp 959 c3/return 960 - 961 ####################################################### - 962 # Parsing - 963 ####################################################### - 964 - 965 parse-mu: # in: (addr buffered-file) - 966 # pseudocode - 967 # var curr-function: (addr (handle function)) = Program - 968 # var line: (stream byte 512) - 969 # var word-slice: slice - 970 # while true # line loop - 971 # clear-stream(line) - 972 # read-line-buffered(in, line) - 973 # if (line->write == 0) break # end of file - 974 # word-slice = next-word-or-string(line) - 975 # if slice-empty?(word-slice) # end of line - 976 # continue - 977 # else if slice-starts-with?(word-slice, "#") # comment - 978 # continue # end of line - 979 # else if slice-equal(word-slice, "fn") - 980 # var new-function: (handle function) = allocate(function) - 981 # var vars: (stack (addr var) 256) - 982 # populate-mu-function-header(in, new-function, vars) - 983 # populate-mu-function-body(in, new-function, vars) - 984 # assert(vars->top == 0) - 985 # *curr-function = new-function - 986 # curr-function = &new-function->next - 987 # else - 988 # abort() + 961 test-convert-function-with-local-var-in-mem: + 962 # empty function decl => function prologue and epilogue + 963 # fn foo { + 964 # var x: int + 965 # increment x + 966 # } + 967 # => + 968 # foo: + 969 # # . prologue + 970 # 55/push-ebp + 971 # 89/<- %ebp 4/r32/esp + 972 # { + 973 # 68/push 0/imm32 + 974 # ff 0/subop/increment *(ebp-4) + 975 # 81 0/subop/add %esp 4/imm32 + 976 # } + 977 # # . epilogue + 978 # 89/<- %esp 5/r32/ebp + 979 # 5d/pop-to-ebp + 980 # c3/return + 981 # . prologue + 982 55/push-ebp + 983 89/<- %ebp 4/r32/esp + 984 # setup + 985 (clear-stream _test-input-stream) + 986 (clear-stream $_test-input-buffered-file->buffer) + 987 (clear-stream _test-output-stream) + 988 (clear-stream $_test-output-buffered-file->buffer) 989 # - 990 # . prologue - 991 55/push-ebp - 992 89/<- %ebp 4/r32/esp - 993 # . save registers - 994 50/push-eax - 995 51/push-ecx - 996 52/push-edx - 997 53/push-ebx - 998 57/push-edi - 999 # var line/ecx: (stream byte 512) -1000 81 5/subop/subtract %esp 0x200/imm32 -1001 68/push 0x200/imm32/length -1002 68/push 0/imm32/read -1003 68/push 0/imm32/write -1004 89/<- %ecx 4/r32/esp -1005 # var word-slice/edx: slice -1006 68/push 0/imm32/end -1007 68/push 0/imm32/start -1008 89/<- %edx 4/r32/esp -1009 # var curr-function/edi: (addr (handle function)) = Program -1010 bf/copy-to-edi Program/imm32 -1011 # var vars/ebx: (stack (addr var) 256) -1012 81 5/subop/subtract %esp 0x400/imm32 -1013 68/push 0x400/imm32/length -1014 68/push 0/imm32/top -1015 89/<- %ebx 4/r32/esp -1016 { -1017 $parse-mu:line-loop: -1018 (clear-stream %ecx) -1019 (read-line-buffered *(ebp+8) %ecx) -1020 # if (line->write == 0) break -1021 81 7/subop/compare *ecx 0/imm32 -1022 0f 84/jump-if-= break/disp32 -1023 +-- 6 lines: #? # dump line --------------------------------------------------------------------------------------------------------------------------- -1029 (next-word-or-string %ecx %edx) -1030 # if slice-empty?(word-slice) continue -1031 (slice-empty? %edx) -1032 3d/compare-eax-and 0/imm32 -1033 0f 85/jump-if-!= loop/disp32 -1034 # if (*word-slice->start == "#") continue -1035 # . eax = *word-slice->start -1036 8b/-> *edx 0/r32/eax -1037 8a/copy-byte *eax 0/r32/AL -1038 81 4/subop/and %eax 0xff/imm32 -1039 # . if (eax == '#') continue -1040 3d/compare-eax-and 0x23/imm32/hash -1041 0f 84/jump-if-= loop/disp32 -1042 # if (slice-equal?(word-slice, "fn")) parse a function -1043 { -1044 $parse-mu:fn: -1045 (slice-equal? %edx "fn") -1046 3d/compare-eax-and 0/imm32 -1047 0f 84/jump-if-= break/disp32 -1048 # var new-function/eax: (handle function) = populate-mu-function(in, new-function, vars) -1049 (allocate Heap *Function-size) # => eax -1050 (zero-out %eax *Function-size) -1051 (clear-stack %ebx) -1052 (populate-mu-function-header %ecx %eax %ebx) -1053 (populate-mu-function-body *(ebp+8) %eax %ebx) -1054 # *curr-function = new-function -1055 89/<- *edi 0/r32/eax -1056 # curr-function = &new-function->next -1057 8d/address-> *(eax+0x14) 7/r32/edi # Function-next -1058 e9/jump $parse-mu:line-loop/disp32 -1059 } -1060 # otherwise abort -1061 e9/jump $parse-mu:error1/disp32 -1062 } # end line loop -1063 $parse-mu:end: -1064 # . reclaim locals -1065 81 0/subop/add %esp 0x630/imm32 -1066 # . restore registers -1067 5f/pop-to-edi -1068 5b/pop-to-ebx -1069 5a/pop-to-edx -1070 59/pop-to-ecx -1071 58/pop-to-eax -1072 # . epilogue -1073 89/<- %esp 5/r32/ebp -1074 5d/pop-to-ebp -1075 c3/return -1076 -1077 $parse-mu:error1: -1078 # error("unexpected top-level command: " word-slice "\n") -1079 (write-buffered Stderr "unexpected top-level command: ") -1080 (write-slice-buffered Stderr %edx) -1081 (write-buffered Stderr "\n") -1082 (flush Stderr) -1083 # . syscall(exit, 1) -1084 bb/copy-to-ebx 1/imm32 -1085 b8/copy-to-eax 1/imm32/exit -1086 cd/syscall 0x80/imm8 -1087 # never gets here -1088 -1089 $parse-mu:error2: -1090 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") -1091 (print-int32-buffered Stderr *ebx) -1092 (write-buffered Stderr " vars not reclaimed after fn '") -1093 (write-slice-buffered Stderr *eax) # Function-name -1094 (write-buffered Stderr "'\n") -1095 (flush Stderr) -1096 # . syscall(exit, 1) -1097 bb/copy-to-ebx 1/imm32 -1098 b8/copy-to-eax 1/imm32/exit -1099 cd/syscall 0x80/imm8 -1100 # never gets here -1101 -1102 # scenarios considered: -1103 # ✗ fn foo # no block -1104 # ✓ fn foo { -1105 # ✗ fn foo { { -1106 # ✗ fn foo { } -1107 # ✗ fn foo { } { -1108 # ✗ fn foo x { -1109 # ✗ fn foo x: { -1110 # ✓ fn foo x: int { -1111 # ✓ fn foo x: int { -1112 # ✓ fn foo x: int -> y/eax: int { -1113 populate-mu-function-header: # first-line: (addr stream byte), out: (handle function), vars: (addr stack (handle var)) -1114 # pseudocode: -1115 # var name: slice -1116 # next-word(first-line, name) -1117 # assert(name not in '{' '}' '->') -1118 # out->name = slice-to-string(name) -1119 # var next-offset: int = 8 -1120 # ## inouts -1121 # while true -1122 # ## name -1123 # name = next-word(first-line) -1124 # if (name == '{') goto done -1125 # if (name == '->') break -1126 # assert(name != '}') -1127 # var v: (handle var) = parse-var-with-type(name, first-line) -1128 # assert(v->register == null) -1129 # v->stack-offset = next-offset -1130 # next-offset += size-of(v) -1131 # out->inouts = append(out->inouts, v) -1132 # push(vars, v) -1133 # ## outputs -1134 # while true -1135 # ## name -1136 # name = next-word(first-line) -1137 # assert(name not in '{' '}' '->') -1138 # var v: (handle var) = parse-var-with-type(name, first-line) -1139 # assert(v->register != null) -1140 # out->outputs = append(out->outputs, v) -1141 # done: -1142 # -1143 # . prologue -1144 55/push-ebp -1145 89/<- %ebp 4/r32/esp -1146 # . save registers -1147 50/push-eax -1148 51/push-ecx -1149 52/push-edx -1150 53/push-ebx -1151 57/push-edi -1152 # edi = out -1153 8b/-> *(ebp+0xc) 7/r32/edi -1154 # var word-slice/ecx: slice -1155 68/push 0/imm32/end -1156 68/push 0/imm32/start -1157 89/<- %ecx 4/r32/esp -1158 # var next-offset/edx = 8 -1159 ba/copy-to-edx 8/imm32 -1160 # read function name -1161 (next-word *(ebp+8) %ecx) -1162 # error checking -1163 # if (word-slice == '{') abort -1164 (slice-equal? %ecx "{") # => eax -1165 3d/compare-eax-and 0/imm32 -1166 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1167 # if (word-slice == '->') abort -1168 (slice-equal? %ecx "->") # => eax -1169 3d/compare-eax-and 0/imm32 -1170 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1171 # if (word-slice == '}') abort -1172 (slice-equal? %ecx "}") # => eax -1173 3d/compare-eax-and 0/imm32 -1174 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1175 # save function name -1176 (slice-to-string Heap %ecx) # => eax -1177 89/<- *edi 0/r32/eax # Function-name -1178 # initialize default subx-name as well -1179 89/<- *(edi+4) 0/r32/eax # Function-subx-name -1180 # save function inouts -1181 { -1182 $populate-mu-function-header:check-for-inout: -1183 (next-word *(ebp+8) %ecx) -1184 # if (word-slice == '{') goto done -1185 (slice-equal? %ecx "{") # => eax -1186 3d/compare-eax-and 0/imm32 -1187 0f 85/jump-if-!= $populate-mu-function-header:done/disp32 -1188 # if (word-slice == '->') break -1189 (slice-equal? %ecx "->") # => eax -1190 3d/compare-eax-and 0/imm32 -1191 0f 85/jump-if-!= break/disp32 -1192 # if (word-slice == '}') abort -1193 (slice-equal? %ecx "}") # => eax -1194 3d/compare-eax-and 0/imm32 -1195 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1196 # var v/ebx: (handle var) = parse-var-with-type(word-slice, first-line) -1197 (parse-var-with-type %ecx *(ebp+8)) # => eax -1198 89/<- %ebx 0/r32/eax -1199 # assert(v->register == null) -1200 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register -1201 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 -1202 # v->stack-offset = next-offset -1203 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset -1204 # next-offset += size-of(v) -1205 (size-of %ebx) # => eax -1206 01/add %edx 0/r32/eax -1207 # -1208 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax -1209 89/<- *(edi+8) 0/r32/eax # Function-inouts -1210 (push *(ebp+0x10) %ebx) -1211 # -1212 e9/jump loop/disp32 -1213 } -1214 # save function outputs -1215 { -1216 $parse-var-with-type:check-for-out: -1217 (next-word *(ebp+8) %ecx) -1218 # if (word-slice == '{') break -1219 (slice-equal? %ecx "{") # => eax -1220 3d/compare-eax-and 0/imm32 -1221 0f 85/jump-if-!= break/disp32 -1222 # if (word-slice == '->') abort -1223 (slice-equal? %ecx "->") # => eax -1224 3d/compare-eax-and 0/imm32 -1225 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1226 # if (word-slice == '}') abort -1227 (slice-equal? %ecx "}") # => eax -1228 3d/compare-eax-and 0/imm32 -1229 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1230 # -1231 (parse-var-with-type %ecx *(ebp+8)) # => eax -1232 89/<- %ebx 0/r32/eax -1233 # assert(var->register != null) -1234 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register -1235 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 -1236 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax -1237 89/<- *(edi+0xc) 0/r32/eax # Function-outputs -1238 e9/jump loop/disp32 -1239 } -1240 $populate-mu-function-header:done: -1241 (check-no-tokens-left *(ebp+8)) -1242 $populate-mu-function-header:end: -1243 # . reclaim locals -1244 81 0/subop/add %esp 8/imm32 -1245 # . restore registers -1246 5f/pop-to-edi -1247 5b/pop-to-ebx -1248 5a/pop-to-edx -1249 59/pop-to-ecx -1250 58/pop-to-eax -1251 # . epilogue -1252 89/<- %esp 5/r32/ebp -1253 5d/pop-to-ebp -1254 c3/return -1255 -1256 $populate-mu-function-header:error1: -1257 # error("function header not in form 'fn <name> {'") -1258 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") -1259 (flush Stderr) -1260 (rewind-stream *(ebp+8)) -1261 (write-stream 2 *(ebp+8)) -1262 (write-buffered Stderr "'\n") -1263 (flush Stderr) -1264 # . syscall(exit, 1) -1265 bb/copy-to-ebx 1/imm32 -1266 b8/copy-to-eax 1/imm32/exit -1267 cd/syscall 0x80/imm8 -1268 # never gets here -1269 -1270 $populate-mu-function-header:error2: -1271 # error("function input '" var "' cannot be in a register") -1272 (write-buffered Stderr "function input '") -1273 (write-buffered Stderr *ebx) # Var-name -1274 (write-buffered Stderr "' cannot be in a register") -1275 (flush Stderr) -1276 # . syscall(exit, 1) -1277 bb/copy-to-ebx 1/imm32 -1278 b8/copy-to-eax 1/imm32/exit -1279 cd/syscall 0x80/imm8 -1280 # never gets here -1281 -1282 $populate-mu-function-header:error3: -1283 # error("function input '" var "' must be in a register") -1284 (write-buffered Stderr "function input '") -1285 (write-buffered Stderr *eax) # Var-name -1286 (write-buffered Stderr " must be in a register'") -1287 (flush Stderr) -1288 (rewind-stream *(ebp+8)) -1289 (write-stream 2 *(ebp+8)) -1290 (write-buffered Stderr "'\n") -1291 (flush Stderr) -1292 # . syscall(exit, 1) -1293 bb/copy-to-ebx 1/imm32 -1294 b8/copy-to-eax 1/imm32/exit -1295 cd/syscall 0x80/imm8 -1296 # never gets here -1297 -1298 test-function-header-with-arg: -1299 # 'foo n : int {' -1300 # . prologue -1301 55/push-ebp -1302 89/<- %ebp 4/r32/esp -1303 # setup -1304 (clear-stream _test-input-stream) -1305 (write _test-input-stream "foo n : int {\n") -1306 # var result/ecx: function -1307 2b/subtract-> *Function-size 4/r32/esp -1308 89/<- %ecx 4/r32/esp -1309 (zero-out %ecx *Function-size) -1310 # var vars/ebx: (stack (addr var) 16) -1311 81 5/subop/subtract %esp 0x10/imm32 -1312 68/push 0x10/imm32/length -1313 68/push 0/imm32/top -1314 89/<- %ebx 4/r32/esp -1315 # convert -1316 (populate-mu-function-header _test-input-stream %ecx %ebx) -1317 # check result -1318 (check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name -1319 # edx: (handle list var) = result->inouts -1320 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1321 # ebx: (handle var) = result->inouts->value -1322 8b/-> *edx 3/r32/ebx # List-value -1323 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name -1324 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1325 (check-ints-equal *ebx 1 "F - test-function-header-with-arg/inout:0/type:0") # Tree-left -1326 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-arg/inout:0/type:1") # Tree-right -1327 # . epilogue -1328 89/<- %esp 5/r32/ebp -1329 5d/pop-to-ebp -1330 c3/return -1331 -1332 test-function-header-with-multiple-args: -1333 # 'fn foo a: int, b: int, c: int {' -1334 # . prologue -1335 55/push-ebp -1336 89/<- %ebp 4/r32/esp -1337 # setup -1338 (clear-stream _test-input-stream) -1339 (write _test-input-stream "foo a: int, b: int c: int {\n") -1340 # result/ecx: (handle function) -1341 2b/subtract-> *Function-size 4/r32/esp -1342 89/<- %ecx 4/r32/esp -1343 (zero-out %ecx *Function-size) -1344 # var vars/ebx: (stack (addr var) 16) -1345 81 5/subop/subtract %esp 0x10/imm32 -1346 68/push 0x10/imm32/length -1347 68/push 0/imm32/top -1348 89/<- %ebx 4/r32/esp -1349 # convert -1350 (populate-mu-function-header _test-input-stream %ecx %ebx) -1351 # check result -1352 (check-strings-equal *ecx "foo") # Function-name -1353 # edx: (handle list var) = result->inouts -1354 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1355 $test-function-header-with-multiple-args:inout0: -1356 # ebx: (handle var) = result->inouts->value -1357 8b/-> *edx 3/r32/ebx # List-value -1358 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name -1359 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1360 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Tree-left -1361 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-right -1362 # edx = result->inouts->next -1363 8b/-> *(edx+4) 2/r32/edx # List-next -1364 $test-function-header-with-multiple-args:inout1: -1365 # ebx = result->inouts->next->value -1366 8b/-> *edx 3/r32/ebx # List-value -1367 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name -1368 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1369 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Tree-left -1370 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-right -1371 # edx = result->inouts->next->next -1372 8b/-> *(edx+4) 2/r32/edx # List-next -1373 $test-function-header-with-multiple-args:inout2: -1374 # ebx = result->inouts->next->next->value -1375 8b/-> *edx 3/r32/ebx # List-value -1376 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name -1377 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1378 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Tree-left -1379 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-right -1380 # . epilogue -1381 89/<- %esp 5/r32/ebp -1382 5d/pop-to-ebp -1383 c3/return -1384 -1385 test-function-with-multiple-args-and-outputs: -1386 # fn foo a: int, b: int, c: int -> x: int, y: int { -1387 # . prologue -1388 55/push-ebp -1389 89/<- %ebp 4/r32/esp -1390 # setup -1391 (clear-stream _test-input-stream) -1392 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n") -1393 # result/ecx: (handle function) -1394 2b/subtract-> *Function-size 4/r32/esp -1395 89/<- %ecx 4/r32/esp -1396 (zero-out %ecx *Function-size) -1397 # var vars/ebx: (stack (addr var) 16) -1398 81 5/subop/subtract %esp 0x10/imm32 -1399 68/push 0x10/imm32/length -1400 68/push 0/imm32/top -1401 89/<- %ebx 4/r32/esp -1402 # convert -1403 (populate-mu-function-header _test-input-stream %ecx %ebx) -1404 # check result -1405 (check-strings-equal *ecx "foo") # Function-name -1406 # edx: (handle list var) = result->inouts -1407 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1408 # ebx: (handle var) = result->inouts->value -1409 8b/-> *edx 3/r32/ebx # List-value -1410 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") # Var-name -1411 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1412 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Tree-left -1413 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-right -1414 # edx = result->inouts->next -1415 8b/-> *(edx+4) 2/r32/edx # List-next -1416 # ebx = result->inouts->next->value -1417 8b/-> *edx 3/r32/ebx # List-value -1418 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") # Var-name -1419 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1420 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Tree-left -1421 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-right -1422 # edx = result->inouts->next->next -1423 8b/-> *(edx+4) 2/r32/edx # List-next -1424 # ebx = result->inouts->next->next->value -1425 8b/-> *edx 3/r32/ebx # List-value -1426 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") # Var-name -1427 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1428 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Tree-left -1429 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-right -1430 # edx: (handle list var) = result->outputs -1431 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs -1432 # ebx: (handle var) = result->outputs->value -1433 8b/-> *edx 3/r32/ebx # List-value -1434 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") # Var-name -1435 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register -1436 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1437 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-left -1438 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-right -1439 # edx = result->outputs->next -1440 8b/-> *(edx+4) 2/r32/edx # List-next -1441 # ebx = result->outputs->next->value -1442 8b/-> *edx 3/r32/ebx # List-value -1443 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") # Var-name -1444 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register -1445 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1446 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-left -1447 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-right -1448 # . epilogue -1449 89/<- %esp 5/r32/ebp -1450 5d/pop-to-ebp -1451 c3/return -1452 -1453 # format for variables with types -1454 # x: int -1455 # x: int -1456 # x: int, -1457 # ignores at most one trailing colon or comma -1458 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte) -> result/eax: (handle var) -1459 # pseudocode: -1460 # var v: (handle var) = allocate(Heap, Var-size) -1461 # var s: slice -1462 # next-token-from-slice(name->start, name->end, '/', s) -1463 # var end: (addr byte) = s->end -1464 # if (slice-ends-with(s, ":")) -1465 # decrement s->end -1466 # if (slice-ends-with(s, ",")) -1467 # decrement s->end -1468 # v->name = slice-to-string(s) -1469 # ## register -1470 # next-token-from-slice(end, name->end, '/', s) -1471 # if (slice-ends-with(s, ":")) -1472 # decrement s->end -1473 # if (slice-ends-with(s, ",")) -1474 # decrement s->end -1475 # if (!slice-empty?(s)) -1476 # v->register = slice-to-string(s) -1477 # ## type -1478 # var type: (handle tree type-id) = parse-type(first-line) -1479 # v->type = type -1480 # return v -1481 # -1482 # . prologue -1483 55/push-ebp -1484 89/<- %ebp 4/r32/esp -1485 # . save registers -1486 51/push-ecx -1487 52/push-edx -1488 53/push-ebx -1489 56/push-esi -1490 57/push-edi -1491 # var result/edi: (handle var) = allocate(Heap, Var-size) -1492 (allocate Heap *Var-size) # => eax -1493 (zero-out %eax *Var-size) -1494 89/<- %edi 0/r32/eax -1495 # esi = name -1496 8b/-> *(ebp+8) 6/r32/esi -1497 # var s/ecx: slice -1498 68/push 0/imm32/end -1499 68/push 0/imm32/start -1500 89/<- %ecx 4/r32/esp -1501 $parse-var-with-type:save-name: -1502 # save v->name -1503 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' -1504 # . end/edx = s->end -1505 8b/-> *(ecx+4) 2/r32/edx -1506 # . if s ends with ':', decrement s->end -1507 { -1508 8b/-> *(ecx+4) 0/r32/eax -1509 48/decrement-eax -1510 8a/copy-byte *eax 3/r32/BL -1511 81 4/subop/and %ebx 0xff/imm32 -1512 81 7/subop/compare %ebx 0x3a/imm32/colon -1513 75/jump-if-!= break/disp8 -1514 89/<- *(ecx+4) 0/r32/eax -1515 } -1516 # . if s ends with ',', decrement s->end -1517 { -1518 8b/-> *(ecx+4) 0/r32/eax -1519 48/decrement-eax -1520 8a/copy-byte *eax 3/r32/BL -1521 81 4/subop/and %ebx 0xff/imm32 -1522 81 7/subop/compare %ebx 0x2c/imm32/comma -1523 75/jump-if-!= break/disp8 -1524 89/<- *(ecx+4) 0/r32/eax -1525 } -1526 $parse-var-with-type:write-name: -1527 (slice-to-string Heap %ecx) # => eax -1528 89/<- *edi 0/r32/eax # Var-name -1529 # save v->register -1530 $parse-var-with-type:save-register: -1531 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' -1532 # . if s ends with ':', decrement s->end -1533 { -1534 8b/-> *(ecx+4) 0/r32/eax -1535 48/decrement-eax -1536 8a/copy-byte *eax 3/r32/BL -1537 81 4/subop/and %ebx 0xff/imm32 -1538 81 7/subop/compare %ebx 0x3a/imm32/colon -1539 75/jump-if-!= break/disp8 -1540 89/<- *(ecx+4) 0/r32/eax -1541 } -1542 # . if s ends with ',', decrement s->end -1543 { -1544 8b/-> *(ecx+4) 0/r32/eax -1545 48/decrement-eax -1546 8a/copy-byte *eax 3/r32/BL -1547 81 4/subop/and %ebx 0xff/imm32 -1548 81 7/subop/compare %ebx 0x2c/imm32/comma -1549 75/jump-if-!= break/disp8 -1550 89/<- *(ecx+4) 0/r32/eax -1551 } -1552 # if (!slice-empty?(s)) v->register = slice-to-string(s) -1553 { -1554 $parse-var-with-type:write-register: -1555 # HACK: s->end can be less than s->start with all the decrements above -1556 # That's probably a sign we have the wrong algorithm for this function. -1557 8b/-> *ecx 0/r32/eax -1558 39/compare 0/r32/eax *(ecx+4) -1559 76/jump-if-<= break/disp8 -1560 (slice-to-string Heap %ecx) -1561 89/<- *(edi+0x10) 0/r32/eax # Var-register -1562 } -1563 $parse-var-with-type:save-type: -1564 (parse-type Heap *(ebp+0xc)) # => eax -1565 89/<- *(edi+4) 0/r32/eax # Var-type -1566 $parse-var-with-type:end: -1567 # return result -1568 89/<- %eax 7/r32/edi -1569 # . reclaim locals -1570 81 0/subop/add %esp 8/imm32 -1571 # . restore registers -1572 5f/pop-to-edi -1573 5e/pop-to-esi -1574 5b/pop-to-ebx -1575 5a/pop-to-edx -1576 59/pop-to-ecx -1577 # . epilogue -1578 89/<- %esp 5/r32/ebp -1579 5d/pop-to-ebp -1580 c3/return -1581 -1582 $parse-var-with-type:abort: -1583 # error("function header not in form 'fn <name> {'") -1584 (write-buffered Stderr "var should have form 'name: type' in '") -1585 (flush Stderr) -1586 (rewind-stream *(ebp+0xc)) -1587 (write-stream 2 *(ebp+0xc)) -1588 (write-buffered Stderr "'\n") -1589 (flush Stderr) -1590 # . syscall(exit, 1) -1591 bb/copy-to-ebx 1/imm32 -1592 b8/copy-to-eax 1/imm32/exit -1593 cd/syscall 0x80/imm8 -1594 # never gets here -1595 -1596 parse-type: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) -1597 # pseudocode: -1598 # var s: slice = next-mu-token(in) -1599 # assert s != "" -1600 # assert s != "->" -1601 # assert s != "{" -1602 # assert s != "}" -1603 # if s == ")" -1604 # return 0 -1605 # result = allocate(Tree) -1606 # zero-out(result, *Tree-size) -1607 # if s != "(" -1608 # result->left = pos-slice(Type-id, s) -1609 # return -1610 # result->left = parse-type(ad, in) -1611 # result->right = parse-type-tree(ad, in) -1612 # -1613 # . prologue -1614 55/push-ebp -1615 89/<- %ebp 4/r32/esp -1616 # . save registers -1617 51/push-ecx -1618 52/push-edx -1619 # var s/ecx: slice -1620 68/push 0/imm32 -1621 68/push 0/imm32 -1622 89/<- %ecx 4/r32/esp -1623 # s = next-mu-token(in) -1624 (next-mu-token *(ebp+0xc) %ecx) -1625 #? (write-buffered Stderr "tok: ") -1626 #? (write-slice-buffered Stderr %ecx) -1627 #? (write-buffered Stderr "$\n") -1628 #? (flush Stderr) -1629 # assert s != "" -1630 (slice-equal? %ecx "") -1631 3d/compare-eax-and 0/imm32 -1632 0f 85/jump-if-not-equal $parse-type:abort/disp32 -1633 # assert s != "{" -1634 (slice-equal? %ecx "{") -1635 3d/compare-eax-and 0/imm32 -1636 0f 85/jump-if-not-equal $parse-type:abort/disp32 -1637 # assert s != "}" -1638 (slice-equal? %ecx "}") -1639 3d/compare-eax-and 0/imm32 -1640 0f 85/jump-if-not-equal $parse-type:abort/disp32 -1641 # assert s != "->" -1642 (slice-equal? %ecx "->") -1643 3d/compare-eax-and 0/imm32 -1644 0f 85/jump-if-not-equal $parse-type:abort/disp32 -1645 # if (s == ")") return 0 -1646 (slice-equal? %ecx ")") -1647 3d/compare-eax-and 0/imm32 -1648 b8/copy-to-eax 0/imm32 -1649 0f 85/jump-if-not-equal $parse-type:end/disp32 -1650 # var result/edx: (handle tree type-id) -1651 (allocate *(ebp+8) *Tree-size) # => eax -1652 (zero-out %eax *Tree-size) -1653 89/<- %edx 0/r32/eax -1654 { -1655 # if (s != "(") break -1656 (slice-equal? %ecx "(") -1657 3d/compare-eax-and 0/imm32 -1658 75/jump-if-not-equal break/disp8 -1659 # result->left = pos-slice(Type-id, s) -1660 (pos-slice Type-id %ecx) -1661 #? (write-buffered Stderr "=> {") -1662 #? (print-int32-buffered Stderr %eax) -1663 #? (write-buffered Stderr ", 0}\n") -1664 #? (flush Stderr) -1665 89/<- *edx 0/r32/eax # Tree-left -1666 e9/jump $parse-type:return-edx/disp32 -1667 } -1668 # otherwise s == "(" -1669 # result->left = parse-type(ad, in) -1670 (parse-type *(ebp+8) *(ebp+0xc)) -1671 #? (write-buffered Stderr "=> {") -1672 #? (print-int32-buffered Stderr %eax) -1673 89/<- *edx 0/r32/eax # Tree-left -1674 # result->right = parse-type-tree(ad, in) -1675 (parse-type-tree *(ebp+8) *(ebp+0xc)) -1676 #? (write-buffered Stderr Space) -1677 #? (print-int32-buffered Stderr %eax) -1678 #? (write-buffered Stderr "}\n") -1679 #? (flush Stderr) -1680 89/<- *(edx+4) 0/r32/eax # Tree-right -1681 $parse-type:return-edx: -1682 89/<- %eax 2/r32/edx -1683 $parse-type:end: -1684 # . reclaim locals -1685 81 0/subop/add %esp 8/imm32 -1686 # . restore registers -1687 5a/pop-to-edx -1688 59/pop-to-ecx -1689 # . epilogue -1690 89/<- %esp 5/r32/ebp -1691 5d/pop-to-ebp -1692 c3/return -1693 -1694 $parse-type:abort: -1695 # error("unexpected token when parsing type: '" s "'\n") -1696 (write-buffered Stderr "unexpected token when parsing type: '") -1697 (write-slice-buffered Stderr %ecx) -1698 (write-buffered Stderr "'\n") -1699 (flush Stderr) -1700 # . syscall(exit, 1) -1701 bb/copy-to-ebx 1/imm32 -1702 b8/copy-to-eax 1/imm32/exit -1703 cd/syscall 0x80/imm8 -1704 # never gets here -1705 -1706 parse-type-tree: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) -1707 # pseudocode: -1708 # var tmp: (handle tree type-id) = parse-type(ad, in) -1709 # if tmp == 0 -1710 # return 0 -1711 # result = allocate(Tree) -1712 # zero-out(result, *Tree-size) -1713 # result->left = tmp -1714 # result->right = parse-type-tree(ad, in) -1715 # -1716 # . prologue -1717 55/push-ebp -1718 89/<- %ebp 4/r32/esp -1719 # . save registers -1720 51/push-ecx -1721 52/push-edx -1722 # var tmp/eax: (handle tree type-id) = parse-type(ad, in) -1723 (parse-type *(ebp+8) *(ebp+0xc)) -1724 # if (tmp == 0) return tmp -1725 3d/compare-eax-and 0/imm32 -1726 74/jump-if-equal $parse-type-tree:end/disp8 -1727 # var tmp2/ecx = tmp -1728 89/<- %ecx 0/r32/eax -1729 # var result/edx: (handle tree type-id) -1730 (allocate *(ebp+8) *Tree-size) # => eax -1731 (zero-out %eax *Tree-size) -1732 89/<- %edx 0/r32/eax -1733 # result->left = tmp2 -1734 89/<- *edx 1/r32/ecx # Tree-left + 990 (write _test-input-stream "fn foo {\n") + 991 (write _test-input-stream "var x: int\n") + 992 (write _test-input-stream "increment x\n") + 993 (write _test-input-stream "}\n") + 994 # convert + 995 (convert-mu _test-input-buffered-file _test-output-buffered-file) + 996 (flush _test-output-buffered-file) + 997 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +1003 # check output +1004 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-mem/0") +1005 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-with-local-var-in-mem/1") +1006 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-with-local-var-in-mem/2") +1007 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-mem/3") +1008 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-with-local-var-in-mem/4") +1009 (check-next-stream-line-equal _test-output-stream "68/push 0/imm32" "F - test-convert-function-with-local-var-in-mem/5") +1010 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-local-var-in-mem/6") +1011 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-local-var-in-mem/7") +1012 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-with-local-var-in-mem/8") +1013 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-with-local-var-in-mem/9") +1014 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-mem/10") +1015 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-mem/11") +1016 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-with-local-var-in-mem/12") +1017 # . epilogue +1018 89/<- %esp 5/r32/ebp +1019 5d/pop-to-ebp +1020 c3/return +1021 +1022 ####################################################### +1023 # Parsing +1024 ####################################################### +1025 +1026 parse-mu: # in: (addr buffered-file) +1027 # pseudocode +1028 # var curr-function: (addr (handle function)) = Program +1029 # var line: (stream byte 512) +1030 # var word-slice: slice +1031 # while true # line loop +1032 # clear-stream(line) +1033 # read-line-buffered(in, line) +1034 # if (line->write == 0) break # end of file +1035 # word-slice = next-word-or-string(line) +1036 # if slice-empty?(word-slice) # end of line +1037 # continue +1038 # else if slice-starts-with?(word-slice, "#") # comment +1039 # continue # end of line +1040 # else if slice-equal(word-slice, "fn") +1041 # var new-function: (handle function) = allocate(function) +1042 # var vars: (stack (addr var) 256) +1043 # populate-mu-function-header(in, new-function, vars) +1044 # populate-mu-function-body(in, new-function, vars) +1045 # assert(vars->top == 0) +1046 # *curr-function = new-function +1047 # curr-function = &new-function->next +1048 # else +1049 # abort() +1050 # +1051 # . prologue +1052 55/push-ebp +1053 89/<- %ebp 4/r32/esp +1054 # . save registers +1055 50/push-eax +1056 51/push-ecx +1057 52/push-edx +1058 53/push-ebx +1059 57/push-edi +1060 # var line/ecx: (stream byte 512) +1061 81 5/subop/subtract %esp 0x200/imm32 +1062 68/push 0x200/imm32/length +1063 68/push 0/imm32/read +1064 68/push 0/imm32/write +1065 89/<- %ecx 4/r32/esp +1066 # var word-slice/edx: slice +1067 68/push 0/imm32/end +1068 68/push 0/imm32/start +1069 89/<- %edx 4/r32/esp +1070 # var curr-function/edi: (addr (handle function)) = Program +1071 bf/copy-to-edi Program/imm32 +1072 # var vars/ebx: (stack (addr var) 256) +1073 81 5/subop/subtract %esp 0x400/imm32 +1074 68/push 0x400/imm32/length +1075 68/push 0/imm32/top +1076 89/<- %ebx 4/r32/esp +1077 { +1078 $parse-mu:line-loop: +1079 (clear-stream %ecx) +1080 (read-line-buffered *(ebp+8) %ecx) +1081 # if (line->write == 0) break +1082 81 7/subop/compare *ecx 0/imm32 +1083 0f 84/jump-if-= break/disp32 +1084 +-- 6 lines: #? # dump line --------------------------------------------------------------------------------------------------------------------------- +1090 (next-word-or-string %ecx %edx) +1091 # if slice-empty?(word-slice) continue +1092 (slice-empty? %edx) +1093 3d/compare-eax-and 0/imm32 +1094 0f 85/jump-if-!= loop/disp32 +1095 # if (*word-slice->start == "#") continue +1096 # . eax = *word-slice->start +1097 8b/-> *edx 0/r32/eax +1098 8a/copy-byte *eax 0/r32/AL +1099 81 4/subop/and %eax 0xff/imm32 +1100 # . if (eax == '#') continue +1101 3d/compare-eax-and 0x23/imm32/hash +1102 0f 84/jump-if-= loop/disp32 +1103 # if (slice-equal?(word-slice, "fn")) parse a function +1104 { +1105 $parse-mu:fn: +1106 (slice-equal? %edx "fn") +1107 3d/compare-eax-and 0/imm32 +1108 0f 84/jump-if-= break/disp32 +1109 # var new-function/eax: (handle function) = populate-mu-function(in, new-function, vars) +1110 (allocate Heap *Function-size) # => eax +1111 (zero-out %eax *Function-size) +1112 (clear-stack %ebx) +1113 (populate-mu-function-header %ecx %eax %ebx) +1114 (populate-mu-function-body *(ebp+8) %eax %ebx) +1115 # *curr-function = new-function +1116 89/<- *edi 0/r32/eax +1117 # curr-function = &new-function->next +1118 8d/address-> *(eax+0x14) 7/r32/edi # Function-next +1119 e9/jump $parse-mu:line-loop/disp32 +1120 } +1121 # otherwise abort +1122 e9/jump $parse-mu:error1/disp32 +1123 } # end line loop +1124 $parse-mu:end: +1125 # . reclaim locals +1126 81 0/subop/add %esp 0x630/imm32 +1127 # . restore registers +1128 5f/pop-to-edi +1129 5b/pop-to-ebx +1130 5a/pop-to-edx +1131 59/pop-to-ecx +1132 58/pop-to-eax +1133 # . epilogue +1134 89/<- %esp 5/r32/ebp +1135 5d/pop-to-ebp +1136 c3/return +1137 +1138 $parse-mu:error1: +1139 # error("unexpected top-level command: " word-slice "\n") +1140 (write-buffered Stderr "unexpected top-level command: ") +1141 (write-slice-buffered Stderr %edx) +1142 (write-buffered Stderr "\n") +1143 (flush Stderr) +1144 # . syscall(exit, 1) +1145 bb/copy-to-ebx 1/imm32 +1146 b8/copy-to-eax 1/imm32/exit +1147 cd/syscall 0x80/imm8 +1148 # never gets here +1149 +1150 $parse-mu:error2: +1151 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") +1152 (print-int32-buffered Stderr *ebx) +1153 (write-buffered Stderr " vars not reclaimed after fn '") +1154 (write-slice-buffered Stderr *eax) # Function-name +1155 (write-buffered Stderr "'\n") +1156 (flush Stderr) +1157 # . syscall(exit, 1) +1158 bb/copy-to-ebx 1/imm32 +1159 b8/copy-to-eax 1/imm32/exit +1160 cd/syscall 0x80/imm8 +1161 # never gets here +1162 +1163 # scenarios considered: +1164 # ✗ fn foo # no block +1165 # ✓ fn foo { +1166 # ✗ fn foo { { +1167 # ✗ fn foo { } +1168 # ✗ fn foo { } { +1169 # ✗ fn foo x { +1170 # ✗ fn foo x: { +1171 # ✓ fn foo x: int { +1172 # ✓ fn foo x: int { +1173 # ✓ fn foo x: int -> y/eax: int { +1174 populate-mu-function-header: # first-line: (addr stream byte), out: (handle function), vars: (addr stack (handle var)) +1175 # pseudocode: +1176 # var name: slice +1177 # next-word(first-line, name) +1178 # assert(name not in '{' '}' '->') +1179 # out->name = slice-to-string(name) +1180 # var next-offset: int = 8 +1181 # ## inouts +1182 # while true +1183 # ## name +1184 # name = next-word(first-line) +1185 # if (name == '{') goto done +1186 # if (name == '->') break +1187 # assert(name != '}') +1188 # var v: (handle var) = parse-var-with-type(name, first-line) +1189 # assert(v->register == null) +1190 # v->stack-offset = next-offset +1191 # next-offset += size-of(v) +1192 # out->inouts = append(out->inouts, v) +1193 # push(vars, v) +1194 # ## outputs +1195 # while true +1196 # ## name +1197 # name = next-word(first-line) +1198 # assert(name not in '{' '}' '->') +1199 # var v: (handle var) = parse-var-with-type(name, first-line) +1200 # assert(v->register != null) +1201 # out->outputs = append(out->outputs, v) +1202 # done: +1203 # +1204 # . prologue +1205 55/push-ebp +1206 89/<- %ebp 4/r32/esp +1207 # . save registers +1208 50/push-eax +1209 51/push-ecx +1210 52/push-edx +1211 53/push-ebx +1212 57/push-edi +1213 # edi = out +1214 8b/-> *(ebp+0xc) 7/r32/edi +1215 # var word-slice/ecx: slice +1216 68/push 0/imm32/end +1217 68/push 0/imm32/start +1218 89/<- %ecx 4/r32/esp +1219 # var next-offset/edx = 8 +1220 ba/copy-to-edx 8/imm32 +1221 # read function name +1222 (next-word *(ebp+8) %ecx) +1223 # error checking +1224 # if (word-slice == '{') abort +1225 (slice-equal? %ecx "{") # => eax +1226 3d/compare-eax-and 0/imm32 +1227 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1228 # if (word-slice == '->') abort +1229 (slice-equal? %ecx "->") # => eax +1230 3d/compare-eax-and 0/imm32 +1231 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1232 # if (word-slice == '}') abort +1233 (slice-equal? %ecx "}") # => eax +1234 3d/compare-eax-and 0/imm32 +1235 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1236 # save function name +1237 (slice-to-string Heap %ecx) # => eax +1238 89/<- *edi 0/r32/eax # Function-name +1239 # initialize default subx-name as well +1240 89/<- *(edi+4) 0/r32/eax # Function-subx-name +1241 # save function inouts +1242 { +1243 $populate-mu-function-header:check-for-inout: +1244 (next-word *(ebp+8) %ecx) +1245 # if (word-slice == '{') goto done +1246 (slice-equal? %ecx "{") # => eax +1247 3d/compare-eax-and 0/imm32 +1248 0f 85/jump-if-!= $populate-mu-function-header:done/disp32 +1249 # if (word-slice == '->') break +1250 (slice-equal? %ecx "->") # => eax +1251 3d/compare-eax-and 0/imm32 +1252 0f 85/jump-if-!= break/disp32 +1253 # if (word-slice == '}') abort +1254 (slice-equal? %ecx "}") # => eax +1255 3d/compare-eax-and 0/imm32 +1256 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1257 # var v/ebx: (handle var) = parse-var-with-type(word-slice, first-line) +1258 (parse-var-with-type %ecx *(ebp+8)) # => eax +1259 89/<- %ebx 0/r32/eax +1260 # assert(v->register == null) +1261 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +1262 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 +1263 # v->stack-offset = next-offset +1264 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset +1265 # next-offset += size-of(v) +1266 (size-of %ebx) # => eax +1267 01/add %edx 0/r32/eax +1268 # +1269 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax +1270 89/<- *(edi+8) 0/r32/eax # Function-inouts +1271 (push *(ebp+0x10) %ebx) +1272 # +1273 e9/jump loop/disp32 +1274 } +1275 # save function outputs +1276 { +1277 $parse-var-with-type:check-for-out: +1278 (next-word *(ebp+8) %ecx) +1279 # if (word-slice == '{') break +1280 (slice-equal? %ecx "{") # => eax +1281 3d/compare-eax-and 0/imm32 +1282 0f 85/jump-if-!= break/disp32 +1283 # if (word-slice == '->') abort +1284 (slice-equal? %ecx "->") # => eax +1285 3d/compare-eax-and 0/imm32 +1286 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1287 # if (word-slice == '}') abort +1288 (slice-equal? %ecx "}") # => eax +1289 3d/compare-eax-and 0/imm32 +1290 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1291 # +1292 (parse-var-with-type %ecx *(ebp+8)) # => eax +1293 89/<- %ebx 0/r32/eax +1294 # assert(var->register != null) +1295 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +1296 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 +1297 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax +1298 89/<- *(edi+0xc) 0/r32/eax # Function-outputs +1299 e9/jump loop/disp32 +1300 } +1301 $populate-mu-function-header:done: +1302 (check-no-tokens-left *(ebp+8)) +1303 $populate-mu-function-header:end: +1304 # . reclaim locals +1305 81 0/subop/add %esp 8/imm32 +1306 # . restore registers +1307 5f/pop-to-edi +1308 5b/pop-to-ebx +1309 5a/pop-to-edx +1310 59/pop-to-ecx +1311 58/pop-to-eax +1312 # . epilogue +1313 89/<- %esp 5/r32/ebp +1314 5d/pop-to-ebp +1315 c3/return +1316 +1317 $populate-mu-function-header:error1: +1318 # error("function header not in form 'fn <name> {'") +1319 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") +1320 (flush Stderr) +1321 (rewind-stream *(ebp+8)) +1322 (write-stream 2 *(ebp+8)) +1323 (write-buffered Stderr "'\n") +1324 (flush Stderr) +1325 # . syscall(exit, 1) +1326 bb/copy-to-ebx 1/imm32 +1327 b8/copy-to-eax 1/imm32/exit +1328 cd/syscall 0x80/imm8 +1329 # never gets here +1330 +1331 $populate-mu-function-header:error2: +1332 # error("function input '" var "' cannot be in a register") +1333 (write-buffered Stderr "function input '") +1334 (write-buffered Stderr *ebx) # Var-name +1335 (write-buffered Stderr "' cannot be in a register") +1336 (flush Stderr) +1337 # . syscall(exit, 1) +1338 bb/copy-to-ebx 1/imm32 +1339 b8/copy-to-eax 1/imm32/exit +1340 cd/syscall 0x80/imm8 +1341 # never gets here +1342 +1343 $populate-mu-function-header:error3: +1344 # error("function input '" var "' must be in a register") +1345 (write-buffered Stderr "function input '") +1346 (write-buffered Stderr *eax) # Var-name +1347 (write-buffered Stderr " must be in a register'") +1348 (flush Stderr) +1349 (rewind-stream *(ebp+8)) +1350 (write-stream 2 *(ebp+8)) +1351 (write-buffered Stderr "'\n") +1352 (flush Stderr) +1353 # . syscall(exit, 1) +1354 bb/copy-to-ebx 1/imm32 +1355 b8/copy-to-eax 1/imm32/exit +1356 cd/syscall 0x80/imm8 +1357 # never gets here +1358 +1359 test-function-header-with-arg: +1360 # 'foo n : int {' +1361 # . prologue +1362 55/push-ebp +1363 89/<- %ebp 4/r32/esp +1364 # setup +1365 (clear-stream _test-input-stream) +1366 (write _test-input-stream "foo n : int {\n") +1367 # var result/ecx: function +1368 2b/subtract-> *Function-size 4/r32/esp +1369 89/<- %ecx 4/r32/esp +1370 (zero-out %ecx *Function-size) +1371 # var vars/ebx: (stack (addr var) 16) +1372 81 5/subop/subtract %esp 0x10/imm32 +1373 68/push 0x10/imm32/length +1374 68/push 0/imm32/top +1375 89/<- %ebx 4/r32/esp +1376 # convert +1377 (populate-mu-function-header _test-input-stream %ecx %ebx) +1378 # check result +1379 (check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name +1380 # edx: (handle list var) = result->inouts +1381 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1382 # ebx: (handle var) = result->inouts->value +1383 8b/-> *edx 3/r32/ebx # List-value +1384 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name +1385 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1386 (check-ints-equal *ebx 1 "F - test-function-header-with-arg/inout:0/type:0") # Tree-left +1387 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-arg/inout:0/type:1") # Tree-right +1388 # . epilogue +1389 89/<- %esp 5/r32/ebp +1390 5d/pop-to-ebp +1391 c3/return +1392 +1393 test-function-header-with-multiple-args: +1394 # 'fn foo a: int, b: int, c: int {' +1395 # . prologue +1396 55/push-ebp +1397 89/<- %ebp 4/r32/esp +1398 # setup +1399 (clear-stream _test-input-stream) +1400 (write _test-input-stream "foo a: int, b: int c: int {\n") +1401 # result/ecx: (handle function) +1402 2b/subtract-> *Function-size 4/r32/esp +1403 89/<- %ecx 4/r32/esp +1404 (zero-out %ecx *Function-size) +1405 # var vars/ebx: (stack (addr var) 16) +1406 81 5/subop/subtract %esp 0x10/imm32 +1407 68/push 0x10/imm32/length +1408 68/push 0/imm32/top +1409 89/<- %ebx 4/r32/esp +1410 # convert +1411 (populate-mu-function-header _test-input-stream %ecx %ebx) +1412 # check result +1413 (check-strings-equal *ecx "foo") # Function-name +1414 # edx: (handle list var) = result->inouts +1415 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1416 $test-function-header-with-multiple-args:inout0: +1417 # ebx: (handle var) = result->inouts->value +1418 8b/-> *edx 3/r32/ebx # List-value +1419 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name +1420 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1421 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Tree-left +1422 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-right +1423 # edx = result->inouts->next +1424 8b/-> *(edx+4) 2/r32/edx # List-next +1425 $test-function-header-with-multiple-args:inout1: +1426 # ebx = result->inouts->next->value +1427 8b/-> *edx 3/r32/ebx # List-value +1428 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name +1429 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1430 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Tree-left +1431 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-right +1432 # edx = result->inouts->next->next +1433 8b/-> *(edx+4) 2/r32/edx # List-next +1434 $test-function-header-with-multiple-args:inout2: +1435 # ebx = result->inouts->next->next->value +1436 8b/-> *edx 3/r32/ebx # List-value +1437 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name +1438 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1439 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Tree-left +1440 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-right +1441 # . epilogue +1442 89/<- %esp 5/r32/ebp +1443 5d/pop-to-ebp +1444 c3/return +1445 +1446 test-function-with-multiple-args-and-outputs: +1447 # fn foo a: int, b: int, c: int -> x: int, y: int { +1448 # . prologue +1449 55/push-ebp +1450 89/<- %ebp 4/r32/esp +1451 # setup +1452 (clear-stream _test-input-stream) +1453 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n") +1454 # result/ecx: (handle function) +1455 2b/subtract-> *Function-size 4/r32/esp +1456 89/<- %ecx 4/r32/esp +1457 (zero-out %ecx *Function-size) +1458 # var vars/ebx: (stack (addr var) 16) +1459 81 5/subop/subtract %esp 0x10/imm32 +1460 68/push 0x10/imm32/length +1461 68/push 0/imm32/top +1462 89/<- %ebx 4/r32/esp +1463 # convert +1464 (populate-mu-function-header _test-input-stream %ecx %ebx) +1465 # check result +1466 (check-strings-equal *ecx "foo") # Function-name +1467 # edx: (handle list var) = result->inouts +1468 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1469 # ebx: (handle var) = result->inouts->value +1470 8b/-> *edx 3/r32/ebx # List-value +1471 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") # Var-name +1472 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1473 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Tree-left +1474 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-right +1475 # edx = result->inouts->next +1476 8b/-> *(edx+4) 2/r32/edx # List-next +1477 # ebx = result->inouts->next->value +1478 8b/-> *edx 3/r32/ebx # List-value +1479 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") # Var-name +1480 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1481 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Tree-left +1482 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-right +1483 # edx = result->inouts->next->next +1484 8b/-> *(edx+4) 2/r32/edx # List-next +1485 # ebx = result->inouts->next->next->value +1486 8b/-> *edx 3/r32/ebx # List-value +1487 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") # Var-name +1488 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1489 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Tree-left +1490 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-right +1491 # edx: (handle list var) = result->outputs +1492 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs +1493 # ebx: (handle var) = result->outputs->value +1494 8b/-> *edx 3/r32/ebx # List-value +1495 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") # Var-name +1496 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register +1497 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1498 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-left +1499 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-right +1500 # edx = result->outputs->next +1501 8b/-> *(edx+4) 2/r32/edx # List-next +1502 # ebx = result->outputs->next->value +1503 8b/-> *edx 3/r32/ebx # List-value +1504 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") # Var-name +1505 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register +1506 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1507 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-left +1508 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-right +1509 # . epilogue +1510 89/<- %esp 5/r32/ebp +1511 5d/pop-to-ebp +1512 c3/return +1513 +1514 # format for variables with types +1515 # x: int +1516 # x: int +1517 # x: int, +1518 # ignores at most one trailing colon or comma +1519 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte) -> result/eax: (handle var) +1520 # pseudocode: +1521 # var v: (handle var) = allocate(Heap, Var-size) +1522 # var s: slice +1523 # next-token-from-slice(name->start, name->end, '/', s) +1524 # var end: (addr byte) = s->end +1525 # if (slice-ends-with(s, ":")) +1526 # decrement s->end +1527 # if (slice-ends-with(s, ",")) +1528 # decrement s->end +1529 # v->name = slice-to-string(s) +1530 # ## register +1531 # next-token-from-slice(end, name->end, '/', s) +1532 # if (slice-ends-with(s, ":")) +1533 # decrement s->end +1534 # if (slice-ends-with(s, ",")) +1535 # decrement s->end +1536 # if (!slice-empty?(s)) +1537 # v->register = slice-to-string(s) +1538 # ## type +1539 # var type: (handle tree type-id) = parse-type(first-line) +1540 # v->type = type +1541 # return v +1542 # +1543 # . prologue +1544 55/push-ebp +1545 89/<- %ebp 4/r32/esp +1546 # . save registers +1547 51/push-ecx +1548 52/push-edx +1549 53/push-ebx +1550 56/push-esi +1551 57/push-edi +1552 # var result/edi: (handle var) = allocate(Heap, Var-size) +1553 (allocate Heap *Var-size) # => eax +1554 (zero-out %eax *Var-size) +1555 89/<- %edi 0/r32/eax +1556 # esi = name +1557 8b/-> *(ebp+8) 6/r32/esi +1558 # var s/ecx: slice +1559 68/push 0/imm32/end +1560 68/push 0/imm32/start +1561 89/<- %ecx 4/r32/esp +1562 $parse-var-with-type:save-name: +1563 # save v->name +1564 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' +1565 # . end/edx = s->end +1566 8b/-> *(ecx+4) 2/r32/edx +1567 # . if s ends with ':', decrement s->end +1568 { +1569 8b/-> *(ecx+4) 0/r32/eax +1570 48/decrement-eax +1571 8a/copy-byte *eax 3/r32/BL +1572 81 4/subop/and %ebx 0xff/imm32 +1573 81 7/subop/compare %ebx 0x3a/imm32/colon +1574 75/jump-if-!= break/disp8 +1575 89/<- *(ecx+4) 0/r32/eax +1576 } +1577 # . if s ends with ',', decrement s->end +1578 { +1579 8b/-> *(ecx+4) 0/r32/eax +1580 48/decrement-eax +1581 8a/copy-byte *eax 3/r32/BL +1582 81 4/subop/and %ebx 0xff/imm32 +1583 81 7/subop/compare %ebx 0x2c/imm32/comma +1584 75/jump-if-!= break/disp8 +1585 89/<- *(ecx+4) 0/r32/eax +1586 } +1587 $parse-var-with-type:write-name: +1588 (slice-to-string Heap %ecx) # => eax +1589 89/<- *edi 0/r32/eax # Var-name +1590 # save v->register +1591 $parse-var-with-type:save-register: +1592 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' +1593 # . if s ends with ':', decrement s->end +1594 { +1595 8b/-> *(ecx+4) 0/r32/eax +1596 48/decrement-eax +1597 8a/copy-byte *eax 3/r32/BL +1598 81 4/subop/and %ebx 0xff/imm32 +1599 81 7/subop/compare %ebx 0x3a/imm32/colon +1600 75/jump-if-!= break/disp8 +1601 89/<- *(ecx+4) 0/r32/eax +1602 } +1603 # . if s ends with ',', decrement s->end +1604 { +1605 8b/-> *(ecx+4) 0/r32/eax +1606 48/decrement-eax +1607 8a/copy-byte *eax 3/r32/BL +1608 81 4/subop/and %ebx 0xff/imm32 +1609 81 7/subop/compare %ebx 0x2c/imm32/comma +1610 75/jump-if-!= break/disp8 +1611 89/<- *(ecx+4) 0/r32/eax +1612 } +1613 # if (!slice-empty?(s)) v->register = slice-to-string(s) +1614 { +1615 $parse-var-with-type:write-register: +1616 # HACK: s->end can be less than s->start with all the decrements above +1617 # That's probably a sign we have the wrong algorithm for this function. +1618 8b/-> *ecx 0/r32/eax +1619 39/compare 0/r32/eax *(ecx+4) +1620 76/jump-if-<= break/disp8 +1621 (slice-to-string Heap %ecx) +1622 89/<- *(edi+0x10) 0/r32/eax # Var-register +1623 } +1624 $parse-var-with-type:save-type: +1625 (parse-type Heap *(ebp+0xc)) # => eax +1626 89/<- *(edi+4) 0/r32/eax # Var-type +1627 $parse-var-with-type:end: +1628 # return result +1629 89/<- %eax 7/r32/edi +1630 # . reclaim locals +1631 81 0/subop/add %esp 8/imm32 +1632 # . restore registers +1633 5f/pop-to-edi +1634 5e/pop-to-esi +1635 5b/pop-to-ebx +1636 5a/pop-to-edx +1637 59/pop-to-ecx +1638 # . epilogue +1639 89/<- %esp 5/r32/ebp +1640 5d/pop-to-ebp +1641 c3/return +1642 +1643 $parse-var-with-type:abort: +1644 # error("function header not in form 'fn <name> {'") +1645 (write-buffered Stderr "var should have form 'name: type' in '") +1646 (flush Stderr) +1647 (rewind-stream *(ebp+0xc)) +1648 (write-stream 2 *(ebp+0xc)) +1649 (write-buffered Stderr "'\n") +1650 (flush Stderr) +1651 # . syscall(exit, 1) +1652 bb/copy-to-ebx 1/imm32 +1653 b8/copy-to-eax 1/imm32/exit +1654 cd/syscall 0x80/imm8 +1655 # never gets here +1656 +1657 parse-type: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) +1658 # pseudocode: +1659 # var s: slice = next-mu-token(in) +1660 # assert s != "" +1661 # assert s != "->" +1662 # assert s != "{" +1663 # assert s != "}" +1664 # if s == ")" +1665 # return 0 +1666 # result = allocate(Tree) +1667 # zero-out(result, *Tree-size) +1668 # if s != "(" +1669 # result->left = pos-slice(Type-id, s) +1670 # return +1671 # result->left = parse-type(ad, in) +1672 # result->right = parse-type-tree(ad, in) +1673 # +1674 # . prologue +1675 55/push-ebp +1676 89/<- %ebp 4/r32/esp +1677 # . save registers +1678 51/push-ecx +1679 52/push-edx +1680 # var s/ecx: slice +1681 68/push 0/imm32 +1682 68/push 0/imm32 +1683 89/<- %ecx 4/r32/esp +1684 # s = next-mu-token(in) +1685 (next-mu-token *(ebp+0xc) %ecx) +1686 #? (write-buffered Stderr "tok: ") +1687 #? (write-slice-buffered Stderr %ecx) +1688 #? (write-buffered Stderr "$\n") +1689 #? (flush Stderr) +1690 # assert s != "" +1691 (slice-equal? %ecx "") +1692 3d/compare-eax-and 0/imm32 +1693 0f 85/jump-if-!= $parse-type:abort/disp32 +1694 # assert s != "{" +1695 (slice-equal? %ecx "{") +1696 3d/compare-eax-and 0/imm32 +1697 0f 85/jump-if-!= $parse-type:abort/disp32 +1698 # assert s != "}" +1699 (slice-equal? %ecx "}") +1700 3d/compare-eax-and 0/imm32 +1701 0f 85/jump-if-!= $parse-type:abort/disp32 +1702 # assert s != "->" +1703 (slice-equal? %ecx "->") +1704 3d/compare-eax-and 0/imm32 +1705 0f 85/jump-if-!= $parse-type:abort/disp32 +1706 # if (s == ")") return 0 +1707 (slice-equal? %ecx ")") +1708 3d/compare-eax-and 0/imm32 +1709 b8/copy-to-eax 0/imm32 +1710 0f 85/jump-if-!= $parse-type:end/disp32 +1711 # var result/edx: (handle tree type-id) +1712 (allocate *(ebp+8) *Tree-size) # => eax +1713 (zero-out %eax *Tree-size) +1714 89/<- %edx 0/r32/eax +1715 { +1716 # if (s != "(") break +1717 (slice-equal? %ecx "(") +1718 3d/compare-eax-and 0/imm32 +1719 75/jump-if-!= break/disp8 +1720 # result->left = pos-slice(Type-id, s) +1721 (pos-slice Type-id %ecx) +1722 #? (write-buffered Stderr "=> {") +1723 #? (print-int32-buffered Stderr %eax) +1724 #? (write-buffered Stderr ", 0}\n") +1725 #? (flush Stderr) +1726 89/<- *edx 0/r32/eax # Tree-left +1727 e9/jump $parse-type:return-edx/disp32 +1728 } +1729 # otherwise s == "(" +1730 # result->left = parse-type(ad, in) +1731 (parse-type *(ebp+8) *(ebp+0xc)) +1732 #? (write-buffered Stderr "=> {") +1733 #? (print-int32-buffered Stderr %eax) +1734 89/<- *edx 0/r32/eax # Tree-left 1735 # result->right = parse-type-tree(ad, in) -1736 (parse-type-tree *(ebp+8) *(ebp+0xc)) -1737 89/<- *(edx+4) 0/r32/eax # Tree-right -1738 $parse-type-tree:return-edx: -1739 89/<- %eax 2/r32/edx -1740 $parse-type-tree:end: -1741 # . restore registers -1742 5a/pop-to-edx -1743 59/pop-to-ecx -1744 # . epilogue -1745 89/<- %esp 5/r32/ebp -1746 5d/pop-to-ebp -1747 c3/return -1748 -1749 next-mu-token: # in: (addr stream byte), out: (addr slice) -1750 # pseudocode: -1751 # start: -1752 # skip-chars-matching-whitespace(in) -1753 # if in->read >= in->write # end of in -1754 # out = {0, 0} -1755 # return -1756 # out->start = &in->data[in->read] -1757 # var curr-byte/eax: byte = in->data[in->read] -1758 # if curr->byte == ':' # comment token -1759 # ++in->read -1760 # goto start -1761 # if curr->byte == ',' # comment token -1762 # ++in->read -1763 # goto start -1764 # if curr-byte == '#' # comment -1765 # in->read = in->write # skip to end of in -1766 # goto done -1767 # if curr-byte == '"' # string literal -1768 # skip-string(in) -1769 # goto done # no metadata -1770 # if curr-byte == '(' -1771 # ++in->read -1772 # goto done -1773 # if curr-byte == ')' -1774 # ++in->read -1775 # goto done -1776 # # read a word -1777 # while true -1778 # if in->read >= in->write -1779 # break -1780 # curr-byte = in->data[in->read] -1781 # if curr-byte == ' ' -1782 # break -1783 # if curr-byte == '\r' -1784 # break -1785 # if curr-byte == '\n' -1786 # break -1787 # if curr-byte == '(' -1788 # break -1789 # if curr-byte == ')' -1790 # break -1791 # if curr-byte == ':' -1792 # break -1793 # if curr-byte == ',' -1794 # break -1795 # ++in->read -1796 # done: -1797 # out->end = &in->data[in->read] -1798 # # hack: skip a few trailing delimiters, because we don't always use -1799 # # this correct tokenizer in later tokens -1800 # while true -1801 # if in->read >= in->write -1802 # break -1803 # curr-byte = in->data[in->read] -1804 # if curr-byte == ':' -1805 # ++in->read -1806 # else if curr-byte == ',' -1807 # ++in->read -1808 # else -1809 # break -1810 # -1811 # . prologue -1812 55/push-ebp -1813 89/<- %ebp 4/r32/esp -1814 # . save registers -1815 50/push-eax -1816 51/push-ecx -1817 56/push-esi -1818 57/push-edi -1819 # esi = in -1820 8b/-> *(ebp+8) 6/r32/esi -1821 # edi = out -1822 8b/-> *(ebp+0xc) 7/r32/edi -1823 $next-mu-token:start: -1824 (skip-chars-matching-whitespace %esi) -1825 $next-mu-token:check0: -1826 # if (in->read >= in->write) return out = {0, 0} -1827 # . ecx = in->read -1828 8b/-> *(esi+4) 1/r32/ecx -1829 # . if (ecx >= in->write) return out = {0, 0} -1830 3b/compare 1/r32/ecx *esi -1831 c7 0/subop/copy *edi 0/imm32 -1832 c7 0/subop/copy *(edi+4) 0/imm32 -1833 0f 8d/jump-if->= $next-mu-token:end/disp32 -1834 # out->start = &in->data[in->read] -1835 8d/copy-address *(esi+ecx+0xc) 0/r32/eax -1836 89/<- *edi 0/r32/eax -1837 # var curr-byte/eax: byte = in->data[in->read] -1838 31/xor %eax 0/r32/eax -1839 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL -1840 { -1841 $next-mu-token:check-for-colon: -1842 # if (curr-byte != ':') break -1843 3d/compare-eax-and 0x3a/imm32/colon -1844 75/jump-if-!= break/disp8 -1845 # ++in->read -1846 ff 0/subop/increment *(esi+4) -1847 # restart -1848 e9/jump $next-mu-token:start/disp32 -1849 } -1850 { -1851 $next-mu-token:check-for-comma: -1852 # if (curr-byte != ',') break -1853 3d/compare-eax-and 0x2c/imm32/comma -1854 75/jump-if-!= break/disp8 -1855 # ++in->read -1856 ff 0/subop/increment *(esi+4) -1857 # restart -1858 e9/jump $next-mu-token:start/disp32 -1859 } -1860 { -1861 $next-mu-token:check-for-comment: -1862 # if (curr-byte != '#') break -1863 3d/compare-eax-and 0x23/imm32/pound -1864 75/jump-if-!= break/disp8 -1865 # in->read = in->write # skip rest of in -1866 8b/-> *esi 0/r32/eax -1867 89/<- *(esi+4) 0/r32/eax -1868 # return -1869 e9/jump $next-mu-token:done/disp32 -1870 } -1871 { -1872 $next-mu-token:check-for-string-literal: -1873 # if (curr-byte != '"') break -1874 3d/compare-eax-and 0x22/imm32/dquote -1875 75/jump-if-!= break/disp8 -1876 (skip-string %esi) -1877 # return -1878 e9/jump $next-mu-token:done/disp32 -1879 } -1880 { -1881 $next-mu-token:check-for-open-paren: -1882 # if (curr-byte != '(') break -1883 3d/compare-eax-and 0x28/imm32/open-paren -1884 75/jump-if-!= break/disp8 -1885 # ++in->read -1886 ff 0/subop/increment *(esi+4) -1887 # return -1888 e9/jump $next-mu-token:done/disp32 -1889 } -1890 { -1891 $next-mu-token:check-for-close-paren: -1892 # if (curr-byte != ')') break -1893 3d/compare-eax-and 0x29/imm32/close-paren -1894 75/jump-if-!= break/disp8 -1895 # ++in->read -1896 ff 0/subop/increment *(esi+4) -1897 # return -1898 e9/jump $next-mu-token:done/disp32 -1899 } -1900 { -1901 $next-mu-token:regular-word-without-metadata: -1902 # if (in->read >= in->write) break -1903 # . ecx = in->read -1904 8b/-> *(esi+4) 1/r32/ecx -1905 # . if (ecx >= in->write) break -1906 3b/compare *esi 1/r32/ecx -1907 7d/jump-if->= break/disp8 -1908 # var c/eax: byte = in->data[in->read] -1909 31/xor %eax 0/r32/eax -1910 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL -1911 # if (c == ' ') break -1912 3d/compare-eax-and 0x20/imm32/space -1913 74/jump-if-= break/disp8 -1914 # if (c == '\r') break -1915 3d/compare-eax-and 0xd/imm32/carriage-return -1916 74/jump-if-= break/disp8 -1917 # if (c == '\n') break -1918 3d/compare-eax-and 0xa/imm32/newline -1919 74/jump-if-= break/disp8 -1920 # if (c == '(') break -1921 3d/compare-eax-and 0x28/imm32/open-paren -1922 0f 84/jump-if-= break/disp32 -1923 # if (c == ')') break -1924 3d/compare-eax-and 0x29/imm32/close-paren -1925 0f 84/jump-if-= break/disp32 -1926 # if (c == ':') break -1927 3d/compare-eax-and 0x3a/imm32/colon -1928 0f 84/jump-if-= break/disp32 -1929 # if (c == ',') break -1930 3d/compare-eax-and 0x2c/imm32/comma -1931 0f 84/jump-if-= break/disp32 -1932 # ++in->read -1933 ff 0/subop/increment *(esi+4) -1934 # -1935 e9/jump loop/disp32 -1936 } -1937 $next-mu-token:done: -1938 # out->end = &in->data[in->read] -1939 8b/-> *(esi+4) 1/r32/ecx -1940 8d/copy-address *(esi+ecx+0xc) 0/r32/eax -1941 89/<- *(edi+4) 0/r32/eax -1942 { -1943 $next-mu-token:skip-trailing-delimiters: -1944 # if (in->read >= in->write) break -1945 # . ecx = in->read -1946 8b/-> *(esi+4) 1/r32/ecx -1947 # . if (ecx >= in->write) break -1948 3b/compare *esi 1/r32/ecx -1949 7d/jump-if->= break/disp8 -1950 # var c/eax: byte = in->data[in->read] -1951 31/xor %eax 0/r32/eax -1952 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL -1953 # if (c == ':') ++in->read and loop -1954 { -1955 3d/compare-eax-and 0x3a/imm32/colon -1956 75/jump-if-!= break/disp8 -1957 # ++in->read -1958 ff 0/subop/increment *(esi+4) -1959 # -1960 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 -1961 } -1962 # if (c == ',') ++in->read and loop -1963 { -1964 3d/compare-eax-and 0x2c/imm32/comma -1965 75/jump-if-!= break/disp8 -1966 # ++in->read -1967 ff 0/subop/increment *(esi+4) -1968 # -1969 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 -1970 } -1971 # else break -1972 } -1973 $next-mu-token:end: -1974 # . restore registers -1975 5f/pop-to-edi -1976 5e/pop-to-esi -1977 59/pop-to-ecx -1978 58/pop-to-eax -1979 # . epilogue -1980 89/<- %esp 5/r32/ebp -1981 5d/pop-to-ebp -1982 c3/return -1983 -1984 # return the index in an array of strings matching 's' -1985 # index is denominated in elements, not bytes -1986 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int -1987 # . prologue -1988 55/push-ebp -1989 89/<- %ebp 4/r32/esp -1990 # . save registers -1991 51/push-ecx -1992 52/push-edx -1993 53/push-ebx -1994 56/push-esi -1995 #? (write-buffered Stderr "pos-slice: ") -1996 #? (write-slice-buffered Stderr *(ebp+0xc)) -1997 #? (write-buffered Stderr "\n") -1998 #? (flush Stderr) -1999 # esi = arr -2000 8b/-> *(ebp+8) 6/r32/esi -2001 # var index/ecx: int = 0 -2002 b9/copy-to-ecx 0/imm32 -2003 # var curr/edx: (addr (addr array byte)) = arr->data -2004 8d/copy-address *(esi+0xc) 2/r32/edx -2005 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] -2006 8b/-> *esi 3/r32/ebx -2007 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx -2008 { -2009 #? (write-buffered Stderr " ") -2010 #? (print-int32-buffered Stderr %ecx) -2011 #? (write-buffered Stderr "\n") -2012 #? (flush Stderr) -2013 # if (curr >= max) return -1 -2014 39/compare %edx 3/r32/ebx -2015 b8/copy-to-eax -1/imm32 -2016 73/jump-if-addr>= $pos-slice:end/disp8 -2017 # if (slice-equal?(s, *curr)) break -2018 (slice-equal? *(ebp+0xc) *edx) # => eax -2019 3d/compare-eax-and 0/imm32 -2020 75/jump-if-!= break/disp8 -2021 # ++index -2022 41/increment-ecx -2023 # curr += 4 -2024 81 0/subop/add %edx 4/imm32 -2025 # -2026 eb/jump loop/disp8 -2027 } -2028 # return index -2029 89/<- %eax 1/r32/ecx -2030 $pos-slice:end: -2031 #? (write-buffered Stderr "=> ") -2032 #? (print-int32-buffered Stderr %eax) -2033 #? (write-buffered Stderr "\n") -2034 # . restore registers -2035 5e/pop-to-esi -2036 5b/pop-to-ebx -2037 5a/pop-to-edx +1736 (parse-type-tree *(ebp+8) *(ebp+0xc)) +1737 #? (write-buffered Stderr Space) +1738 #? (print-int32-buffered Stderr %eax) +1739 #? (write-buffered Stderr "}\n") +1740 #? (flush Stderr) +1741 89/<- *(edx+4) 0/r32/eax # Tree-right +1742 $parse-type:return-edx: +1743 89/<- %eax 2/r32/edx +1744 $parse-type:end: +1745 # . reclaim locals +1746 81 0/subop/add %esp 8/imm32 +1747 # . restore registers +1748 5a/pop-to-edx +1749 59/pop-to-ecx +1750 # . epilogue +1751 89/<- %esp 5/r32/ebp +1752 5d/pop-to-ebp +1753 c3/return +1754 +1755 $parse-type:abort: +1756 # error("unexpected token when parsing type: '" s "'\n") +1757 (write-buffered Stderr "unexpected token when parsing type: '") +1758 (write-slice-buffered Stderr %ecx) +1759 (write-buffered Stderr "'\n") +1760 (flush Stderr) +1761 # . syscall(exit, 1) +1762 bb/copy-to-ebx 1/imm32 +1763 b8/copy-to-eax 1/imm32/exit +1764 cd/syscall 0x80/imm8 +1765 # never gets here +1766 +1767 parse-type-tree: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) +1768 # pseudocode: +1769 # var tmp: (handle tree type-id) = parse-type(ad, in) +1770 # if tmp == 0 +1771 # return 0 +1772 # result = allocate(Tree) +1773 # zero-out(result, *Tree-size) +1774 # result->left = tmp +1775 # result->right = parse-type-tree(ad, in) +1776 # +1777 # . prologue +1778 55/push-ebp +1779 89/<- %ebp 4/r32/esp +1780 # . save registers +1781 51/push-ecx +1782 52/push-edx +1783 # var tmp/eax: (handle tree type-id) = parse-type(ad, in) +1784 (parse-type *(ebp+8) *(ebp+0xc)) +1785 # if (tmp == 0) return tmp +1786 3d/compare-eax-and 0/imm32 +1787 74/jump-if-= $parse-type-tree:end/disp8 +1788 # var tmp2/ecx = tmp +1789 89/<- %ecx 0/r32/eax +1790 # var result/edx: (handle tree type-id) +1791 (allocate *(ebp+8) *Tree-size) # => eax +1792 (zero-out %eax *Tree-size) +1793 89/<- %edx 0/r32/eax +1794 # result->left = tmp2 +1795 89/<- *edx 1/r32/ecx # Tree-left +1796 # result->right = parse-type-tree(ad, in) +1797 (parse-type-tree *(ebp+8) *(ebp+0xc)) +1798 89/<- *(edx+4) 0/r32/eax # Tree-right +1799 $parse-type-tree:return-edx: +1800 89/<- %eax 2/r32/edx +1801 $parse-type-tree:end: +1802 # . restore registers +1803 5a/pop-to-edx +1804 59/pop-to-ecx +1805 # . epilogue +1806 89/<- %esp 5/r32/ebp +1807 5d/pop-to-ebp +1808 c3/return +1809 +1810 next-mu-token: # in: (addr stream byte), out: (addr slice) +1811 # pseudocode: +1812 # start: +1813 # skip-chars-matching-whitespace(in) +1814 # if in->read >= in->write # end of in +1815 # out = {0, 0} +1816 # return +1817 # out->start = &in->data[in->read] +1818 # var curr-byte/eax: byte = in->data[in->read] +1819 # if curr->byte == ':' # comment token +1820 # ++in->read +1821 # goto start +1822 # if curr->byte == ',' # comment token +1823 # ++in->read +1824 # goto start +1825 # if curr-byte == '#' # comment +1826 # in->read = in->write # skip to end of in +1827 # goto done +1828 # if curr-byte == '"' # string literal +1829 # skip-string(in) +1830 # goto done # no metadata +1831 # if curr-byte == '(' +1832 # ++in->read +1833 # goto done +1834 # if curr-byte == ')' +1835 # ++in->read +1836 # goto done +1837 # # read a word +1838 # while true +1839 # if in->read >= in->write +1840 # break +1841 # curr-byte = in->data[in->read] +1842 # if curr-byte == ' ' +1843 # break +1844 # if curr-byte == '\r' +1845 # break +1846 # if curr-byte == '\n' +1847 # break +1848 # if curr-byte == '(' +1849 # break +1850 # if curr-byte == ')' +1851 # break +1852 # if curr-byte == ':' +1853 # break +1854 # if curr-byte == ',' +1855 # break +1856 # ++in->read +1857 # done: +1858 # out->end = &in->data[in->read] +1859 # # hack: skip a few trailing delimiters, because we don't always use +1860 # # this correct tokenizer in later tokens +1861 # while true +1862 # if in->read >= in->write +1863 # break +1864 # curr-byte = in->data[in->read] +1865 # if curr-byte == ':' +1866 # ++in->read +1867 # else if curr-byte == ',' +1868 # ++in->read +1869 # else +1870 # break +1871 # +1872 # . prologue +1873 55/push-ebp +1874 89/<- %ebp 4/r32/esp +1875 # . save registers +1876 50/push-eax +1877 51/push-ecx +1878 56/push-esi +1879 57/push-edi +1880 # esi = in +1881 8b/-> *(ebp+8) 6/r32/esi +1882 # edi = out +1883 8b/-> *(ebp+0xc) 7/r32/edi +1884 $next-mu-token:start: +1885 (skip-chars-matching-whitespace %esi) +1886 $next-mu-token:check0: +1887 # if (in->read >= in->write) return out = {0, 0} +1888 # . ecx = in->read +1889 8b/-> *(esi+4) 1/r32/ecx +1890 # . if (ecx >= in->write) return out = {0, 0} +1891 3b/compare 1/r32/ecx *esi +1892 c7 0/subop/copy *edi 0/imm32 +1893 c7 0/subop/copy *(edi+4) 0/imm32 +1894 0f 8d/jump-if->= $next-mu-token:end/disp32 +1895 # out->start = &in->data[in->read] +1896 8d/copy-address *(esi+ecx+0xc) 0/r32/eax +1897 89/<- *edi 0/r32/eax +1898 # var curr-byte/eax: byte = in->data[in->read] +1899 31/xor %eax 0/r32/eax +1900 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +1901 { +1902 $next-mu-token:check-for-colon: +1903 # if (curr-byte != ':') break +1904 3d/compare-eax-and 0x3a/imm32/colon +1905 75/jump-if-!= break/disp8 +1906 # ++in->read +1907 ff 0/subop/increment *(esi+4) +1908 # restart +1909 e9/jump $next-mu-token:start/disp32 +1910 } +1911 { +1912 $next-mu-token:check-for-comma: +1913 # if (curr-byte != ',') break +1914 3d/compare-eax-and 0x2c/imm32/comma +1915 75/jump-if-!= break/disp8 +1916 # ++in->read +1917 ff 0/subop/increment *(esi+4) +1918 # restart +1919 e9/jump $next-mu-token:start/disp32 +1920 } +1921 { +1922 $next-mu-token:check-for-comment: +1923 # if (curr-byte != '#') break +1924 3d/compare-eax-and 0x23/imm32/pound +1925 75/jump-if-!= break/disp8 +1926 # in->read = in->write # skip rest of in +1927 8b/-> *esi 0/r32/eax +1928 89/<- *(esi+4) 0/r32/eax +1929 # return +1930 e9/jump $next-mu-token:done/disp32 +1931 } +1932 { +1933 $next-mu-token:check-for-string-literal: +1934 # if (curr-byte != '"') break +1935 3d/compare-eax-and 0x22/imm32/dquote +1936 75/jump-if-!= break/disp8 +1937 (skip-string %esi) +1938 # return +1939 e9/jump $next-mu-token:done/disp32 +1940 } +1941 { +1942 $next-mu-token:check-for-open-paren: +1943 # if (curr-byte != '(') break +1944 3d/compare-eax-and 0x28/imm32/open-paren +1945 75/jump-if-!= break/disp8 +1946 # ++in->read +1947 ff 0/subop/increment *(esi+4) +1948 # return +1949 e9/jump $next-mu-token:done/disp32 +1950 } +1951 { +1952 $next-mu-token:check-for-close-paren: +1953 # if (curr-byte != ')') break +1954 3d/compare-eax-and 0x29/imm32/close-paren +1955 75/jump-if-!= break/disp8 +1956 # ++in->read +1957 ff 0/subop/increment *(esi+4) +1958 # return +1959 e9/jump $next-mu-token:done/disp32 +1960 } +1961 { +1962 $next-mu-token:regular-word-without-metadata: +1963 # if (in->read >= in->write) break +1964 # . ecx = in->read +1965 8b/-> *(esi+4) 1/r32/ecx +1966 # . if (ecx >= in->write) break +1967 3b/compare *esi 1/r32/ecx +1968 7d/jump-if->= break/disp8 +1969 # var c/eax: byte = in->data[in->read] +1970 31/xor %eax 0/r32/eax +1971 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +1972 # if (c == ' ') break +1973 3d/compare-eax-and 0x20/imm32/space +1974 74/jump-if-= break/disp8 +1975 # if (c == '\r') break +1976 3d/compare-eax-and 0xd/imm32/carriage-return +1977 74/jump-if-= break/disp8 +1978 # if (c == '\n') break +1979 3d/compare-eax-and 0xa/imm32/newline +1980 74/jump-if-= break/disp8 +1981 # if (c == '(') break +1982 3d/compare-eax-and 0x28/imm32/open-paren +1983 0f 84/jump-if-= break/disp32 +1984 # if (c == ')') break +1985 3d/compare-eax-and 0x29/imm32/close-paren +1986 0f 84/jump-if-= break/disp32 +1987 # if (c == ':') break +1988 3d/compare-eax-and 0x3a/imm32/colon +1989 0f 84/jump-if-= break/disp32 +1990 # if (c == ',') break +1991 3d/compare-eax-and 0x2c/imm32/comma +1992 0f 84/jump-if-= break/disp32 +1993 # ++in->read +1994 ff 0/subop/increment *(esi+4) +1995 # +1996 e9/jump loop/disp32 +1997 } +1998 $next-mu-token:done: +1999 # out->end = &in->data[in->read] +2000 8b/-> *(esi+4) 1/r32/ecx +2001 8d/copy-address *(esi+ecx+0xc) 0/r32/eax +2002 89/<- *(edi+4) 0/r32/eax +2003 { +2004 $next-mu-token:skip-trailing-delimiters: +2005 # if (in->read >= in->write) break +2006 # . ecx = in->read +2007 8b/-> *(esi+4) 1/r32/ecx +2008 # . if (ecx >= in->write) break +2009 3b/compare *esi 1/r32/ecx +2010 7d/jump-if->= break/disp8 +2011 # var c/eax: byte = in->data[in->read] +2012 31/xor %eax 0/r32/eax +2013 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +2014 # if (c == ':') ++in->read and loop +2015 { +2016 3d/compare-eax-and 0x3a/imm32/colon +2017 75/jump-if-!= break/disp8 +2018 # ++in->read +2019 ff 0/subop/increment *(esi+4) +2020 # +2021 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 +2022 } +2023 # if (c == ',') ++in->read and loop +2024 { +2025 3d/compare-eax-and 0x2c/imm32/comma +2026 75/jump-if-!= break/disp8 +2027 # ++in->read +2028 ff 0/subop/increment *(esi+4) +2029 # +2030 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 +2031 } +2032 # else break +2033 } +2034 $next-mu-token:end: +2035 # . restore registers +2036 5f/pop-to-edi +2037 5e/pop-to-esi 2038 59/pop-to-ecx -2039 # . epilogue -2040 89/<- %esp 5/r32/ebp -2041 5d/pop-to-ebp -2042 c3/return -2043 -2044 == data -2045 -2046 Type-id: # (stream (address array byte)) -2047 0x18/imm32/write -2048 0/imm32/read -2049 0x100/imm32/length -2050 # data -2051 "literal"/imm32 # 0 -2052 "int"/imm32 # 1 -2053 "addr"/imm32 # 2 -2054 "array"/imm32 # 3 -2055 "handle"/imm32 # 4 -2056 "bool"/imm32 # 5 -2057 0/imm32 -2058 0/imm32 -2059 # 0x20 -2060 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2061 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2062 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2063 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2064 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2065 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2066 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2067 -2068 == code -2069 -2070 test-parse-var-with-type: -2071 # . prologue -2072 55/push-ebp -2073 89/<- %ebp 4/r32/esp -2074 # (eax..ecx) = "x:" -2075 b8/copy-to-eax "x:"/imm32 -2076 8b/-> *eax 1/r32/ecx -2077 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2078 05/add-to-eax 4/imm32 -2079 # var slice/ecx: slice = {eax, ecx} -2080 51/push-ecx -2081 50/push-eax -2082 89/<- %ecx 4/r32/esp -2083 # _test-input-stream contains "int" -2084 (clear-stream _test-input-stream) -2085 (write _test-input-stream "int") -2086 # -2087 (parse-var-with-type %ecx _test-input-stream) -2088 8b/-> *eax 2/r32/edx # Var-name -2089 (check-strings-equal %edx "x" "F - test-var-with-type/name") -2090 8b/-> *(eax+4) 2/r32/edx # Var-type -2091 (check-ints-equal *edx 1 "F - test-var-with-type/type") -2092 (check-ints-equal *(edx+4) 0 "F - test-var-with-type/type") -2093 # . epilogue -2094 89/<- %esp 5/r32/ebp -2095 5d/pop-to-ebp -2096 c3/return -2097 -2098 test-parse-var-with-type-and-register: -2099 # . prologue -2100 55/push-ebp -2101 89/<- %ebp 4/r32/esp -2102 # (eax..ecx) = "x/eax" -2103 b8/copy-to-eax "x/eax"/imm32 -2104 8b/-> *eax 1/r32/ecx -2105 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2106 05/add-to-eax 4/imm32 -2107 # var slice/ecx: slice = {eax, ecx} -2108 51/push-ecx -2109 50/push-eax -2110 89/<- %ecx 4/r32/esp -2111 # _test-input-stream contains ": int" -2112 (clear-stream _test-input-stream) -2113 (write _test-input-stream ": int") -2114 # -2115 (parse-var-with-type %ecx _test-input-stream) -2116 8b/-> *eax 2/r32/edx # Var-name -2117 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") -2118 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2119 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") -2120 8b/-> *(eax+4) 2/r32/edx # Var-type -2121 (check-ints-equal *edx 1 "F - test-var-with-type-and-register/type") -2122 (check-ints-equal *(edx+4) 0 "F - test-var-with-type-and-register/type") -2123 # . epilogue -2124 89/<- %esp 5/r32/ebp -2125 5d/pop-to-ebp -2126 c3/return -2127 -2128 test-parse-var-with-trailing-characters: -2129 # . prologue -2130 55/push-ebp -2131 89/<- %ebp 4/r32/esp -2132 # (eax..ecx) = "x:" -2133 b8/copy-to-eax "x:"/imm32 -2134 8b/-> *eax 1/r32/ecx -2135 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2136 05/add-to-eax 4/imm32 -2137 # var slice/ecx: slice = {eax, ecx} -2138 51/push-ecx -2139 50/push-eax -2140 89/<- %ecx 4/r32/esp -2141 # _test-input-stream contains "int," -2142 (clear-stream _test-input-stream) -2143 (write _test-input-stream "int,") -2144 # -2145 (parse-var-with-type %ecx _test-input-stream) -2146 8b/-> *eax 2/r32/edx # Var-name -2147 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") -2148 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2149 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") -2150 8b/-> *(eax+4) 2/r32/edx # Var-type -2151 (check-ints-equal *edx 1 "F - test-var-with-trailing-characters/type") -2152 (check-ints-equal *(edx+4) 0 "F - test-var-with-trailing-characters/type") -2153 # . epilogue -2154 89/<- %esp 5/r32/ebp -2155 5d/pop-to-ebp -2156 c3/return -2157 -2158 test-parse-var-with-register-and-trailing-characters: -2159 # . prologue -2160 55/push-ebp -2161 89/<- %ebp 4/r32/esp -2162 # (eax..ecx) = "x/eax:" -2163 b8/copy-to-eax "x/eax:"/imm32 -2164 8b/-> *eax 1/r32/ecx -2165 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2166 05/add-to-eax 4/imm32 -2167 # var slice/ecx: slice = {eax, ecx} -2168 51/push-ecx -2169 50/push-eax -2170 89/<- %ecx 4/r32/esp -2171 # _test-input-stream contains "int," -2172 (clear-stream _test-input-stream) -2173 (write _test-input-stream "int,") -2174 # -2175 (parse-var-with-type %ecx _test-input-stream) -2176 8b/-> *eax 2/r32/edx # Var-name -2177 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") -2178 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2179 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") -2180 8b/-> *(eax+4) 2/r32/edx # Var-type -2181 (check-ints-equal *edx 1 "F - test-var-with-register-and-trailing-characters/type") -2182 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") -2183 # . epilogue -2184 89/<- %esp 5/r32/ebp -2185 5d/pop-to-ebp -2186 c3/return -2187 -2188 test-parse-var-with-compound-type: -2189 # . prologue -2190 55/push-ebp -2191 89/<- %ebp 4/r32/esp -2192 # (eax..ecx) = "x:" -2193 b8/copy-to-eax "x:"/imm32 -2194 8b/-> *eax 1/r32/ecx -2195 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2196 05/add-to-eax 4/imm32 -2197 # var slice/ecx: slice = {eax, ecx} -2198 51/push-ecx -2199 50/push-eax -2200 89/<- %ecx 4/r32/esp -2201 # _test-input-stream contains "(addr int)" -2202 (clear-stream _test-input-stream) -2203 (write _test-input-stream "(addr int)") -2204 # -2205 (parse-var-with-type %ecx _test-input-stream) -2206 8b/-> *eax 2/r32/edx # Var-name -2207 (check-strings-equal %edx "x" "F - test-var-with-compound-type/name") -2208 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2209 (check-ints-equal %edx 0 "F - test-var-with-compound-type/register") -2210 # var type/edx: (handle tree type-id) = var->type +2039 58/pop-to-eax +2040 # . epilogue +2041 89/<- %esp 5/r32/ebp +2042 5d/pop-to-ebp +2043 c3/return +2044 +2045 # return the index in an array of strings matching 's' +2046 # index is denominated in elements, not bytes +2047 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int +2048 # . prologue +2049 55/push-ebp +2050 89/<- %ebp 4/r32/esp +2051 # . save registers +2052 51/push-ecx +2053 52/push-edx +2054 53/push-ebx +2055 56/push-esi +2056 #? (write-buffered Stderr "pos-slice: ") +2057 #? (write-slice-buffered Stderr *(ebp+0xc)) +2058 #? (write-buffered Stderr "\n") +2059 #? (flush Stderr) +2060 # esi = arr +2061 8b/-> *(ebp+8) 6/r32/esi +2062 # var index/ecx: int = 0 +2063 b9/copy-to-ecx 0/imm32 +2064 # var curr/edx: (addr (addr array byte)) = arr->data +2065 8d/copy-address *(esi+0xc) 2/r32/edx +2066 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] +2067 8b/-> *esi 3/r32/ebx +2068 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx +2069 { +2070 #? (write-buffered Stderr " ") +2071 #? (print-int32-buffered Stderr %ecx) +2072 #? (write-buffered Stderr "\n") +2073 #? (flush Stderr) +2074 # if (curr >= max) return -1 +2075 39/compare %edx 3/r32/ebx +2076 b8/copy-to-eax -1/imm32 +2077 73/jump-if-addr>= $pos-slice:end/disp8 +2078 # if (slice-equal?(s, *curr)) break +2079 (slice-equal? *(ebp+0xc) *edx) # => eax +2080 3d/compare-eax-and 0/imm32 +2081 75/jump-if-!= break/disp8 +2082 # ++index +2083 41/increment-ecx +2084 # curr += 4 +2085 81 0/subop/add %edx 4/imm32 +2086 # +2087 eb/jump loop/disp8 +2088 } +2089 # return index +2090 89/<- %eax 1/r32/ecx +2091 $pos-slice:end: +2092 #? (write-buffered Stderr "=> ") +2093 #? (print-int32-buffered Stderr %eax) +2094 #? (write-buffered Stderr "\n") +2095 # . restore registers +2096 5e/pop-to-esi +2097 5b/pop-to-ebx +2098 5a/pop-to-edx +2099 59/pop-to-ecx +2100 # . epilogue +2101 89/<- %esp 5/r32/ebp +2102 5d/pop-to-ebp +2103 c3/return +2104 +2105 == data +2106 +2107 Type-id: # (stream (address array byte)) +2108 0x18/imm32/write +2109 0/imm32/read +2110 0x100/imm32/length +2111 # data +2112 "literal"/imm32 # 0 +2113 "int"/imm32 # 1 +2114 "addr"/imm32 # 2 +2115 "array"/imm32 # 3 +2116 "handle"/imm32 # 4 +2117 "bool"/imm32 # 5 +2118 0/imm32 +2119 0/imm32 +2120 # 0x20 +2121 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2122 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2123 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2124 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2125 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2126 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2127 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2128 +2129 == code +2130 +2131 test-parse-var-with-type: +2132 # . prologue +2133 55/push-ebp +2134 89/<- %ebp 4/r32/esp +2135 # (eax..ecx) = "x:" +2136 b8/copy-to-eax "x:"/imm32 +2137 8b/-> *eax 1/r32/ecx +2138 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2139 05/add-to-eax 4/imm32 +2140 # var slice/ecx: slice = {eax, ecx} +2141 51/push-ecx +2142 50/push-eax +2143 89/<- %ecx 4/r32/esp +2144 # _test-input-stream contains "int" +2145 (clear-stream _test-input-stream) +2146 (write _test-input-stream "int") +2147 # +2148 (parse-var-with-type %ecx _test-input-stream) +2149 8b/-> *eax 2/r32/edx # Var-name +2150 (check-strings-equal %edx "x" "F - test-var-with-type/name") +2151 8b/-> *(eax+4) 2/r32/edx # Var-type +2152 (check-ints-equal *edx 1 "F - test-var-with-type/type") +2153 (check-ints-equal *(edx+4) 0 "F - test-var-with-type/type") +2154 # . epilogue +2155 89/<- %esp 5/r32/ebp +2156 5d/pop-to-ebp +2157 c3/return +2158 +2159 test-parse-var-with-type-and-register: +2160 # . prologue +2161 55/push-ebp +2162 89/<- %ebp 4/r32/esp +2163 # (eax..ecx) = "x/eax" +2164 b8/copy-to-eax "x/eax"/imm32 +2165 8b/-> *eax 1/r32/ecx +2166 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2167 05/add-to-eax 4/imm32 +2168 # var slice/ecx: slice = {eax, ecx} +2169 51/push-ecx +2170 50/push-eax +2171 89/<- %ecx 4/r32/esp +2172 # _test-input-stream contains ": int" +2173 (clear-stream _test-input-stream) +2174 (write _test-input-stream ": int") +2175 # +2176 (parse-var-with-type %ecx _test-input-stream) +2177 8b/-> *eax 2/r32/edx # Var-name +2178 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") +2179 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2180 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") +2181 8b/-> *(eax+4) 2/r32/edx # Var-type +2182 (check-ints-equal *edx 1 "F - test-var-with-type-and-register/type") +2183 (check-ints-equal *(edx+4) 0 "F - test-var-with-type-and-register/type") +2184 # . epilogue +2185 89/<- %esp 5/r32/ebp +2186 5d/pop-to-ebp +2187 c3/return +2188 +2189 test-parse-var-with-trailing-characters: +2190 # . prologue +2191 55/push-ebp +2192 89/<- %ebp 4/r32/esp +2193 # (eax..ecx) = "x:" +2194 b8/copy-to-eax "x:"/imm32 +2195 8b/-> *eax 1/r32/ecx +2196 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2197 05/add-to-eax 4/imm32 +2198 # var slice/ecx: slice = {eax, ecx} +2199 51/push-ecx +2200 50/push-eax +2201 89/<- %ecx 4/r32/esp +2202 # _test-input-stream contains "int," +2203 (clear-stream _test-input-stream) +2204 (write _test-input-stream "int,") +2205 # +2206 (parse-var-with-type %ecx _test-input-stream) +2207 8b/-> *eax 2/r32/edx # Var-name +2208 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") +2209 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2210 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") 2211 8b/-> *(eax+4) 2/r32/edx # Var-type -2212 # type->left == atom(addr) -2213 8b/-> *edx 0/r32/eax # Atom-value -2214 (check-ints-equal *eax 2 "F - test-var-with-compound-type/type:0") # Tree-left -2215 # type->right->left == atom(int) -2216 8b/-> *(edx+4) 2/r32/edx # Tree-right -2217 8b/-> *edx 0/r32/eax # Tree-left -2218 (check-ints-equal *eax 1 "F - test-var-with-compound-type/type:1") # Atom-value -2219 # type->right->right == null -2220 (check-ints-equal *(edx+4) 0 "F - test-var-with-compound-type/type:2") # Tree-right -2221 # . epilogue -2222 89/<- %esp 5/r32/ebp -2223 5d/pop-to-ebp -2224 c3/return -2225 -2226 # identifier starts with a letter or '$' or '_' -2227 # no constraints at the moment on later letters -2228 # all we really want to do so far is exclude '{', '}' and '->' -2229 is-identifier?: # in: (addr slice) -> result/eax: boolean -2230 # . prologue -2231 55/push-ebp -2232 89/<- %ebp 4/r32/esp -2233 # if (slice-empty?(in)) return false -2234 (slice-empty? *(ebp+8)) # => eax -2235 3d/compare-eax-and 0/imm32 -2236 75/jump-if-!= $is-identifier?:false/disp8 -2237 # var c/eax: byte = *in->start -2238 8b/-> *(ebp+8) 0/r32/eax -2239 8b/-> *eax 0/r32/eax -2240 8a/copy-byte *eax 0/r32/AL -2241 81 4/subop/and %eax 0xff/imm32 -2242 # if (c == '$') return true -2243 3d/compare-eax-and 0x24/imm32/$ -2244 74/jump-if-= $is-identifier?:true/disp8 -2245 # if (c == '_') return true -2246 3d/compare-eax-and 0x5f/imm32/_ -2247 74/jump-if-= $is-identifier?:true/disp8 -2248 # drop case -2249 25/and-eax-with 0x5f/imm32 -2250 # if (c < 'A') return false -2251 3d/compare-eax-and 0x41/imm32/A -2252 7c/jump-if-< $is-identifier?:false/disp8 -2253 # if (c > 'Z') return false -2254 3d/compare-eax-and 0x5a/imm32/Z -2255 7f/jump-if-> $is-identifier?:false/disp8 -2256 # otherwise return true -2257 $is-identifier?:true: -2258 b8/copy-to-eax 1/imm32/true -2259 eb/jump $is-identifier?:end/disp8 -2260 $is-identifier?:false: -2261 b8/copy-to-eax 0/imm32/false -2262 $is-identifier?:end: -2263 # . epilogue -2264 89/<- %esp 5/r32/ebp -2265 5d/pop-to-ebp -2266 c3/return -2267 -2268 test-is-identifier-dollar: -2269 # . prologue -2270 55/push-ebp -2271 89/<- %ebp 4/r32/esp -2272 # (eax..ecx) = "$a" -2273 b8/copy-to-eax "$a"/imm32 -2274 8b/-> *eax 1/r32/ecx -2275 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2276 05/add-to-eax 4/imm32 -2277 # var slice/ecx: slice = {eax, ecx} -2278 51/push-ecx -2279 50/push-eax -2280 89/<- %ecx 4/r32/esp -2281 # -2282 (is-identifier? %ecx) -2283 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") -2284 # . epilogue -2285 89/<- %esp 5/r32/ebp -2286 5d/pop-to-ebp -2287 c3/return -2288 -2289 test-is-identifier-underscore: -2290 # . prologue -2291 55/push-ebp -2292 89/<- %ebp 4/r32/esp -2293 # (eax..ecx) = "_a" -2294 b8/copy-to-eax "_a"/imm32 -2295 8b/-> *eax 1/r32/ecx -2296 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2297 05/add-to-eax 4/imm32 -2298 # var slice/ecx: slice = {eax, ecx} -2299 51/push-ecx -2300 50/push-eax -2301 89/<- %ecx 4/r32/esp -2302 # -2303 (is-identifier? %ecx) -2304 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") -2305 # . epilogue -2306 89/<- %esp 5/r32/ebp -2307 5d/pop-to-ebp -2308 c3/return -2309 -2310 test-is-identifier-a: -2311 # . prologue -2312 55/push-ebp -2313 89/<- %ebp 4/r32/esp -2314 # (eax..ecx) = "a$" -2315 b8/copy-to-eax "a$"/imm32 -2316 8b/-> *eax 1/r32/ecx -2317 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2318 05/add-to-eax 4/imm32 -2319 # var slice/ecx: slice = {eax, ecx} -2320 51/push-ecx -2321 50/push-eax -2322 89/<- %ecx 4/r32/esp -2323 # -2324 (is-identifier? %ecx) -2325 (check-ints-equal %eax 1 "F - test-is-identifier-a") -2326 # . epilogue -2327 89/<- %esp 5/r32/ebp -2328 5d/pop-to-ebp -2329 c3/return -2330 -2331 test-is-identifier-z: -2332 # . prologue -2333 55/push-ebp -2334 89/<- %ebp 4/r32/esp -2335 # (eax..ecx) = "z$" -2336 b8/copy-to-eax "z$"/imm32 -2337 8b/-> *eax 1/r32/ecx -2338 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2339 05/add-to-eax 4/imm32 -2340 # var slice/ecx: slice = {eax, ecx} -2341 51/push-ecx -2342 50/push-eax -2343 89/<- %ecx 4/r32/esp -2344 # -2345 (is-identifier? %ecx) -2346 (check-ints-equal %eax 1 "F - test-is-identifier-z") -2347 # . epilogue -2348 89/<- %esp 5/r32/ebp -2349 5d/pop-to-ebp -2350 c3/return -2351 -2352 test-is-identifier-A: -2353 # . prologue -2354 55/push-ebp -2355 89/<- %ebp 4/r32/esp -2356 # (eax..ecx) = "A$" -2357 b8/copy-to-eax "A$"/imm32 -2358 8b/-> *eax 1/r32/ecx -2359 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2360 05/add-to-eax 4/imm32 -2361 # var slice/ecx: slice = {eax, ecx} -2362 51/push-ecx -2363 50/push-eax -2364 89/<- %ecx 4/r32/esp -2365 # -2366 (is-identifier? %ecx) -2367 (check-ints-equal %eax 1 "F - test-is-identifier-A") -2368 # . epilogue -2369 89/<- %esp 5/r32/ebp -2370 5d/pop-to-ebp -2371 c3/return -2372 -2373 test-is-identifier-Z: -2374 # . prologue -2375 55/push-ebp -2376 89/<- %ebp 4/r32/esp -2377 # (eax..ecx) = "Z$" -2378 b8/copy-to-eax "Z$"/imm32 -2379 8b/-> *eax 1/r32/ecx -2380 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2381 05/add-to-eax 4/imm32 -2382 # var slice/ecx: slice = {eax, ecx} -2383 51/push-ecx -2384 50/push-eax -2385 89/<- %ecx 4/r32/esp -2386 # -2387 (is-identifier? %ecx) -2388 (check-ints-equal %eax 1 "F - test-is-identifier-Z") -2389 # . epilogue -2390 89/<- %esp 5/r32/ebp -2391 5d/pop-to-ebp -2392 c3/return -2393 -2394 test-is-identifier-@: -2395 # character before 'A' is invalid -2396 # . prologue -2397 55/push-ebp -2398 89/<- %ebp 4/r32/esp -2399 # (eax..ecx) = "@a" -2400 b8/copy-to-eax "@a"/imm32 -2401 8b/-> *eax 1/r32/ecx -2402 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2403 05/add-to-eax 4/imm32 -2404 # var slice/ecx: slice = {eax, ecx} -2405 51/push-ecx -2406 50/push-eax -2407 89/<- %ecx 4/r32/esp -2408 # -2409 (is-identifier? %ecx) -2410 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2411 # . epilogue -2412 89/<- %esp 5/r32/ebp -2413 5d/pop-to-ebp -2414 c3/return -2415 -2416 test-is-identifier-square-bracket: -2417 # character after 'Z' is invalid -2418 # . prologue -2419 55/push-ebp -2420 89/<- %ebp 4/r32/esp -2421 # (eax..ecx) = "[a" -2422 b8/copy-to-eax "[a"/imm32 -2423 8b/-> *eax 1/r32/ecx -2424 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2425 05/add-to-eax 4/imm32 -2426 # var slice/ecx: slice = {eax, ecx} -2427 51/push-ecx -2428 50/push-eax -2429 89/<- %ecx 4/r32/esp -2430 # -2431 (is-identifier? %ecx) -2432 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2433 # . epilogue -2434 89/<- %esp 5/r32/ebp -2435 5d/pop-to-ebp -2436 c3/return -2437 -2438 test-is-identifier-backtick: -2439 # character before 'a' is invalid -2440 # . prologue -2441 55/push-ebp -2442 89/<- %ebp 4/r32/esp -2443 # (eax..ecx) = "`a" -2444 b8/copy-to-eax "`a"/imm32 -2445 8b/-> *eax 1/r32/ecx -2446 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2447 05/add-to-eax 4/imm32 -2448 # var slice/ecx: slice = {eax, ecx} -2449 51/push-ecx -2450 50/push-eax -2451 89/<- %ecx 4/r32/esp -2452 # -2453 (is-identifier? %ecx) -2454 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") -2455 # . epilogue -2456 89/<- %esp 5/r32/ebp -2457 5d/pop-to-ebp -2458 c3/return -2459 -2460 test-is-identifier-curly-brace-open: -2461 # character after 'z' is invalid; also used for blocks -2462 # . prologue -2463 55/push-ebp -2464 89/<- %ebp 4/r32/esp -2465 # (eax..ecx) = "{a" -2466 b8/copy-to-eax "{a"/imm32 -2467 8b/-> *eax 1/r32/ecx -2468 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2469 05/add-to-eax 4/imm32 -2470 # var slice/ecx: slice = {eax, ecx} -2471 51/push-ecx -2472 50/push-eax -2473 89/<- %ecx 4/r32/esp -2474 # -2475 (is-identifier? %ecx) -2476 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") -2477 # . epilogue -2478 89/<- %esp 5/r32/ebp -2479 5d/pop-to-ebp -2480 c3/return -2481 -2482 test-is-identifier-curly-brace-close: -2483 # . prologue -2484 55/push-ebp -2485 89/<- %ebp 4/r32/esp -2486 # (eax..ecx) = "}a" -2487 b8/copy-to-eax "}a"/imm32 -2488 8b/-> *eax 1/r32/ecx -2489 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2490 05/add-to-eax 4/imm32 -2491 # var slice/ecx: slice = {eax, ecx} -2492 51/push-ecx -2493 50/push-eax -2494 89/<- %ecx 4/r32/esp -2495 # -2496 (is-identifier? %ecx) -2497 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") -2498 # . epilogue -2499 89/<- %esp 5/r32/ebp -2500 5d/pop-to-ebp -2501 c3/return -2502 -2503 test-is-identifier-hyphen: -2504 # disallow leading '-' since '->' has special meaning -2505 # . prologue -2506 55/push-ebp -2507 89/<- %ebp 4/r32/esp -2508 # (eax..ecx) = "-a" -2509 b8/copy-to-eax "-a"/imm32 -2510 8b/-> *eax 1/r32/ecx -2511 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2512 05/add-to-eax 4/imm32 -2513 # var slice/ecx: slice = {eax, ecx} -2514 51/push-ecx -2515 50/push-eax -2516 89/<- %ecx 4/r32/esp -2517 # -2518 (is-identifier? %ecx) -2519 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") -2520 # . epilogue -2521 89/<- %esp 5/r32/ebp -2522 5d/pop-to-ebp -2523 c3/return -2524 -2525 populate-mu-function-body: # in: (addr buffered-file), out: (handle function), vars: (addr stack (handle var)) -2526 # . prologue -2527 55/push-ebp -2528 89/<- %ebp 4/r32/esp -2529 # . save registers -2530 50/push-eax -2531 56/push-esi -2532 57/push-edi -2533 # esi = in -2534 8b/-> *(ebp+8) 6/r32/esi -2535 # edi = out -2536 8b/-> *(ebp+0xc) 7/r32/edi -2537 # var eax: (handle block) = parse-mu-block(in, vars) -2538 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax -2539 # out->body = eax -2540 89/<- *(edi+0x10) 0/r32/eax # Function-body -2541 $populate-mu-function-body:end: -2542 # . restore registers -2543 5f/pop-to-edi -2544 5e/pop-to-esi -2545 58/pop-to-eax -2546 # . epilogue -2547 89/<- %esp 5/r32/ebp -2548 5d/pop-to-ebp -2549 c3/return -2550 -2551 # parses a block, assuming that the leading '{' has already been read by the caller -2552 parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle block) -2553 # pseudocode: -2554 # var line: (stream byte 512) -2555 # var word-slice: slice -2556 # result/eax = allocate(Heap, Stmt-size) -2557 # result->tag = 0/Block -2558 # while true # line loop -2559 # clear-stream(line) -2560 # read-line-buffered(in, line) -2561 # if (line->write == 0) break # end of file -2562 # word-slice = next-word(line) -2563 # if slice-empty?(word-slice) # end of line -2564 # continue -2565 # else if slice-starts-with?(word-slice, "#") -2566 # continue -2567 # else if slice-equal?(word-slice, "{") -2568 # assert(no-tokens-in(line)) -2569 # block = parse-mu-block(in, vars, fn) -2570 # append-to-block(result, block) -2571 # else if slice-equal?(word-slice, "}") -2572 # break -2573 # else if slice-ends-with?(word-slice, ":") -2574 # named-block = parse-mu-named-block(word-slice, line, in, vars, fn) -2575 # append-to-block(result, named-block) -2576 # else if slice-equal?(word-slice, "var") -2577 # var-def = parse-mu-var-def(line, vars) -2578 # append-to-block(result, var-def) -2579 # else -2580 # stmt = parse-mu-stmt(line, vars, fn) -2581 # append-to-block(result, stmt) -2582 # return result -2583 # -2584 # . prologue -2585 55/push-ebp -2586 89/<- %ebp 4/r32/esp -2587 # . save registers -2588 51/push-ecx -2589 52/push-edx -2590 53/push-ebx -2591 57/push-edi -2592 # var line/ecx: (stream byte 512) -2593 81 5/subop/subtract %esp 0x200/imm32 -2594 68/push 0x200/imm32/length -2595 68/push 0/imm32/read -2596 68/push 0/imm32/write -2597 89/<- %ecx 4/r32/esp -2598 # var word-slice/edx: slice -2599 68/push 0/imm32/end -2600 68/push 0/imm32/start -2601 89/<- %edx 4/r32/esp -2602 # edi = result -2603 (allocate Heap *Stmt-size) # => eax -2604 (zero-out %eax *Stmt-size) -2605 89/<- %edi 0/r32/eax -2606 { # line loop -2607 $parse-mu-block:line-loop: -2608 # line = read-line-buffered(in) -2609 (clear-stream %ecx) -2610 (read-line-buffered *(ebp+8) %ecx) -2611 #? (write-buffered Stderr "line: ") -2612 #? (write-stream-data Stderr %ecx) -2613 #? (write-buffered Stderr Newline) -2614 #? (flush Stderr) -2615 # if (line->write == 0) break -2616 81 7/subop/compare *ecx 0/imm32 -2617 0f 84/jump-if-= break/disp32 -2618 # word-slice = next-word(line) -2619 (next-word %ecx %edx) -2620 #? (write-buffered Stderr "word: ") -2621 #? (write-slice-buffered Stderr %edx) -2622 #? (write-buffered Stderr Newline) -2623 #? (flush Stderr) -2624 # if slice-empty?(word-slice) continue -2625 (slice-empty? %edx) -2626 3d/compare-eax-and 0/imm32 -2627 0f 85/jump-if-!= loop/disp32 -2628 # if (slice-starts-with?(word-slice, '#') continue -2629 # . eax = *word-slice->start -2630 8b/-> *edx 0/r32/eax -2631 8a/copy-byte *eax 0/r32/AL -2632 81 4/subop/and %eax 0xff/imm32 -2633 # . if (eax == '#') continue -2634 3d/compare-eax-and 0x23/imm32/hash -2635 0f 84/jump-if-= loop/disp32 -2636 # if slice-equal?(word-slice, "{") -2637 { -2638 $parse-mu-block:check-for-block: -2639 (slice-equal? %edx "{") -2640 3d/compare-eax-and 0/imm32 -2641 74/jump-if-= break/disp8 -2642 (check-no-tokens-left %ecx) -2643 # parse new block and append -2644 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -2645 (append-to-block Heap %edi %eax) -2646 e9/jump $parse-mu-block:line-loop/disp32 -2647 } -2648 # if slice-equal?(word-slice, "}") break -2649 $parse-mu-block:check-for-end: -2650 (slice-equal? %edx "}") -2651 3d/compare-eax-and 0/imm32 -2652 0f 85/jump-if-!= break/disp32 -2653 # if slice-ends-with?(word-slice, ":") parse named block and append -2654 { -2655 $parse-mu-block:check-for-named-block: -2656 # . eax = *word-slice->end -2657 8b/-> *(edx+4) 0/r32/eax -2658 8a/copy-byte *eax 0/r32/AL -2659 81 4/subop/and %eax 0xff/imm32 -2660 # . if (eax != ':') break -2661 3d/compare-eax-and 0x23/imm32/hash -2662 0f 85/jump-if-!= break/disp32 -2663 # -2664 (parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -2665 (append-to-block Heap %edi %eax) -2666 e9/jump $parse-mu-block:line-loop/disp32 -2667 } -2668 # if slice-equal?(word-slice, "var") -2669 { -2670 $parse-mu-block:check-for-var: -2671 (slice-equal? %edx "var") -2672 3d/compare-eax-and 0/imm32 -2673 74/jump-if-= break/disp8 -2674 # -2675 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax -2676 (append-to-block Heap %edi %eax) -2677 e9/jump $parse-mu-block:line-loop/disp32 -2678 } -2679 $parse-mu-block:regular-stmt: -2680 # otherwise -2681 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -2682 (append-to-block Heap %edi %eax) -2683 e9/jump loop/disp32 -2684 } # end line loop -2685 # return result -2686 89/<- %eax 7/r32/edi -2687 $parse-mu-block:end: -2688 # . reclaim locals -2689 81 0/subop/add %esp 0x214/imm32 -2690 # . restore registers -2691 5f/pop-to-edi -2692 5b/pop-to-ebx -2693 5a/pop-to-edx -2694 59/pop-to-ecx -2695 # . epilogue -2696 89/<- %esp 5/r32/ebp -2697 5d/pop-to-ebp -2698 c3/return -2699 -2700 $parse-mu-block:abort: -2701 # error("'{' or '}' should be on its own line, but got '") -2702 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2703 (rewind-stream %ecx) -2704 (write-stream 2 %ecx) -2705 (write-buffered Stderr "'\n") -2706 (flush Stderr) -2707 # . syscall(exit, 1) -2708 bb/copy-to-ebx 1/imm32 -2709 b8/copy-to-eax 1/imm32/exit -2710 cd/syscall 0x80/imm8 -2711 # never gets here -2712 -2713 check-no-tokens-left: # line: (addr stream byte) -2714 # . prologue -2715 55/push-ebp -2716 89/<- %ebp 4/r32/esp -2717 # . save registers -2718 50/push-eax -2719 51/push-ecx -2720 # var s/ecx: slice -2721 68/push 0/imm32/end -2722 68/push 0/imm32/start -2723 89/<- %ecx 4/r32/esp -2724 # -2725 (next-word *(ebp+8) %ecx) -2726 # if slice-empty?(s) return -2727 (slice-empty? %ecx) -2728 3d/compare-eax-and 0/imm32 -2729 75/jump-if-!= $check-no-tokens-left:end/disp8 -2730 # if (slice-starts-with?(s, '#') return -2731 # . eax = *s->start -2732 8b/-> *edx 0/r32/eax -2733 8a/copy-byte *eax 0/r32/AL -2734 81 4/subop/and %eax 0xff/imm32 -2735 # . if (eax == '#') continue -2736 3d/compare-eax-and 0x23/imm32/hash -2737 74/jump-if-= $check-no-tokens-left:end/disp8 -2738 # abort -2739 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2740 (rewind-stream %ecx) -2741 (write-stream 2 %ecx) -2742 (write-buffered Stderr "'\n") -2743 (flush Stderr) -2744 # . syscall(exit, 1) -2745 bb/copy-to-ebx 1/imm32 -2746 b8/copy-to-eax 1/imm32/exit -2747 cd/syscall 0x80/imm8 -2748 # never gets here -2749 $check-no-tokens-left:end: -2750 # . reclaim locals -2751 81 0/subop/add %esp 8/imm32 -2752 # . restore registers -2753 59/pop-to-ecx -2754 58/pop-to-eax -2755 # . epilogue -2756 89/<- %esp 5/r32/ebp -2757 5d/pop-to-ebp -2758 c3/return -2759 -2760 parse-mu-named-block: # name: (addr slice), first-line: (addr stream byte), in: (addr buffered-file), vars: (addr stack (handle var)) -> result/eax: (handle stmt) -2761 # pseudocode: -2762 # var line: (stream byte 512) -2763 # var word-slice: slice -2764 # result/eax = allocate(Heap, Stmt-size) -2765 # result->tag = 4/Named-block -2766 # result->name = name -2767 # assert(next-word(first-line) == "{") -2768 # assert(no-tokens-in(first-line)) -2769 # while true # line loop -2770 # clear-stream(line) -2771 # read-line-buffered(in, line) -2772 # if (line->write == 0) break # end of file -2773 # word-slice = next-word(line) -2774 # if slice-empty?(word-slice) # end of line -2775 # break -2776 # else if slice-equal?(word-slice, "{") -2777 # block = parse-mu-block(in, vars) -2778 # append-to-block(result, block) -2779 # else if slice-equal?(word-slice, "}") -2780 # break -2781 # else if slice-ends-with?(word-slice, ":") -2782 # named-block = parse-mu-named-block(word-slice, in, vars) -2783 # append-to-block(result, named-block) -2784 # else if slice-equal?(word-slice, "var") -2785 # var-def = parse-mu-var-def(line, vars) -2786 # append-to-block(result, var-def) -2787 # else -2788 # stmt = parse-mu-stmt(line, vars, fn) -2789 # append-to-block(result, stmt) -2790 # return result -2791 # -2792 # . prologue -2793 55/push-ebp -2794 89/<- %ebp 4/r32/esp -2795 # . save registers -2796 $parse-mu-named-block:end: -2797 # . reclaim locals -2798 # . restore registers -2799 # . epilogue -2800 89/<- %esp 5/r32/ebp -2801 5d/pop-to-ebp -2802 c3/return -2803 -2804 parse-mu-var-def: # line: (addr stream byte), vars: (addr stack (handle var)) -> result/eax: (handle stmt) -2805 # pseudocode: -2806 # -2807 # . prologue -2808 55/push-ebp -2809 89/<- %ebp 4/r32/esp -2810 # . save registers -2811 51/push-ecx -2812 52/push-edx -2813 # var word-slice/ecx: slice -2814 68/push 0/imm32/end -2815 68/push 0/imm32/start -2816 89/<- %ecx 4/r32/esp -2817 # var v/edx: (handle var) = parse-var-with-type(line) -2818 (next-word *(ebp+8) %ecx) -2819 (parse-var-with-type %ecx *(ebp+8)) # => eax -2820 89/<- %edx 0/r32/eax -2821 # either v has no register and there's no more to this line -2822 8b/-> *(edx+0x10) 0/r32/eax # Var-register -2823 3d/compare-eax-and 0/imm32 -2824 { -2825 75/jump-if-not-equal break/disp8 -2826 # TODO: ensure that there's nothing else on this line -2827 (new-vardef Heap %edx) # => eax -2828 eb/jump $parse-mu-var-def:end/disp8 -2829 } -2830 # or v has a register and there's more to this line -2831 { -2832 74/jump-if-equal break/disp8 -2833 # ensure that the next word is '<-' -2834 (next-word *(ebp+8) %ecx) -2835 (slice-equal? %ecx "<-") # => eax -2836 3d/compare-eax-and 0/imm32 -2837 74/jump-if-equal $parse-mu-var-def:abort/disp8 -2838 # -2839 (new-regvardef Heap %edx) # => eax -2840 (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc)) -2841 } -2842 $parse-mu-var-def:end: -2843 # . reclaim locals -2844 81 0/subop/add %esp 8/imm32 -2845 # . restore registers -2846 5a/pop-to-edx -2847 59/pop-to-ecx -2848 # . epilogue -2849 89/<- %esp 5/r32/ebp -2850 5d/pop-to-ebp -2851 c3/return -2852 -2853 $parse-mu-var-def:abort: -2854 (rewind-stream *(ebp+8)) -2855 # error("register variable requires a valid instruction to initialize but got '" line "'\n") -2856 (write-buffered Stderr "register variable requires a valid instruction to initialize but got '") -2857 (flush Stderr) -2858 (write-stream 2 *(ebp+8)) -2859 (write-buffered Stderr "'\n") -2860 (flush Stderr) -2861 # . syscall(exit, 1) -2862 bb/copy-to-ebx 1/imm32 -2863 b8/copy-to-eax 1/imm32/exit -2864 cd/syscall 0x80/imm8 -2865 # never gets here -2866 -2867 test-parse-mu-var-def: -2868 # 'var n: int' -2869 # . prologue -2870 55/push-ebp -2871 89/<- %ebp 4/r32/esp -2872 # setup -2873 (clear-stream _test-input-stream) -2874 (write _test-input-stream "n: int\n") # caller has consumed the 'var' -2875 # var vars/ecx: (stack (addr var) 4) -2876 81 5/subop/subtract %esp 0x10/imm32 -2877 68/push 0x10/imm32/length -2878 68/push 0/imm32/top -2879 89/<- %ecx 4/r32/esp -2880 (clear-stack %ecx) -2881 # convert -2882 (parse-mu-var-def _test-input-stream %ecx) # => eax -2883 # check result -2884 (check-ints-equal *eax 2 "F - test-parse-mu-var-def/tag") # Stmt-tag is vardef -2885 8b/-> *(eax+4) 0/r32/eax # Vardef-var -2886 (check-strings-equal *eax "n" "F - test-parse-mu-var-def/var-name") # Var-name -2887 (check-ints-equal *(eax+0x10) 0 "F - test-parse-mu-var-def/var-register") # Var-register -2888 # TODO: ensure stack-offset is -4 -2889 # TODO: ensure block-depth is 1 -2890 # ensure type is int -2891 8b/-> *(eax+4) 0/r32/eax # Var-type -2892 (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0") # Tree-left -2893 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-var-def/var-type:0") # Tree-right -2894 # . epilogue -2895 89/<- %esp 5/r32/ebp -2896 5d/pop-to-ebp -2897 c3/return -2898 -2899 test-parse-mu-reg-var-def: -2900 # 'var n/eax: int <- copy 0' -2901 # . prologue -2902 55/push-ebp -2903 89/<- %ebp 4/r32/esp -2904 # setup -2905 (clear-stream _test-input-stream) -2906 (write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var' -2907 # var vars/ecx: (stack (addr var) 4) -2908 81 5/subop/subtract %esp 0x10/imm32 -2909 68/push 0x10/imm32/length -2910 68/push 0/imm32/top -2911 89/<- %ecx 4/r32/esp -2912 (clear-stack %ecx) -2913 # convert -2914 (parse-mu-var-def _test-input-stream %ecx) # => eax -2915 # check result -2916 (check-ints-equal *eax 3 "F - test-parse-mu-reg-var-def/tag") # Stmt-tag is regvardef -2917 8b/-> *(eax+0xc) 0/r32/eax # Regvardef-var -2918 (check-strings-equal *eax "n" "F - test-parse-mu-reg-var-def/var-name") # Var-name -2919 (check-strings-equal *(eax+0x10) "eax" "F - test-parse-mu-reg-var-def/var-register") # Var-register -2920 # TODO: ensure stack-offset is -4 -2921 # TODO: ensure block-depth is 1 -2922 # ensure type is int -2923 8b/-> *(eax+4) 0/r32/eax # Var-type -2924 (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/var-type:0") # Tree-left -2925 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/var-type:0") # Tree-right -2926 # . epilogue -2927 89/<- %esp 5/r32/ebp -2928 5d/pop-to-ebp -2929 c3/return -2930 -2931 parse-mu-stmt: # line: (addr stream byte), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) -2932 # pseudocode: -2933 # var name: slice -2934 # result = allocate(Heap, Stmt-size) -2935 # if stmt-has-outputs?(line) -2936 # while true -2937 # name = next-word(line) -2938 # if (name == '<-') break -2939 # assert(is-identifier?(name)) -2940 # var v: (handle var) = lookup-or-define-var(name, vars, fn) # regular stmts may define vars in fn outputs -2941 # result->outputs = append(result->outputs, v) -2942 # add-operation-and-inputs-to-stmt(result, line, vars) -2943 # -2944 # . prologue -2945 55/push-ebp -2946 89/<- %ebp 4/r32/esp -2947 # . save registers -2948 51/push-ecx -2949 57/push-edi -2950 # var name/ecx: slice -2951 68/push 0/imm32/end -2952 68/push 0/imm32/start -2953 89/<- %ecx 4/r32/esp -2954 # result/edi: (handle stmt) -2955 (allocate Heap *Stmt-size) # => eax -2956 (zero-out %eax *Stmt-size) -2957 89/<- %edi 0/r32/eax -2958 # result->tag = 1/stmt -2959 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag -2960 { -2961 (stmt-has-outputs? *(ebp+8)) -2962 3d/compare-eax-and 0/imm32 -2963 0f 84/jump-if-= break/disp32 -2964 { -2965 $parse-mu-stmt:read-outputs: -2966 # name = next-word(line) -2967 (next-word *(ebp+8) %ecx) -2968 # if slice-empty?(word-slice) break -2969 (slice-empty? %ecx) -2970 3d/compare-eax-and 0/imm32 -2971 0f 85/jump-if-!= break/disp32 -2972 # if (name == "<-") break -2973 (slice-equal? %ecx "<-") -2974 3d/compare-eax-and 0/imm32 -2975 75/jump-if-!= break/disp8 -2976 # assert(is-identifier?(name)) -2977 (is-identifier? %ecx) -2978 3d/compare-eax-and 0/imm32 -2979 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 -2980 # -2981 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -2982 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax -2983 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs -2984 e9/jump loop/disp32 -2985 } -2986 } -2987 (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc)) -2988 $parse-mu-stmt:end: -2989 # return result -2990 89/<- %eax 7/r32/edi -2991 # . reclaim locals -2992 81 0/subop/add %esp 8/imm32 -2993 # . restore registers -2994 5f/pop-to-edi -2995 59/pop-to-ecx -2996 # . epilogue -2997 89/<- %esp 5/r32/ebp -2998 5d/pop-to-ebp -2999 c3/return -3000 -3001 $parse-mu-stmt:abort: -3002 # error("invalid identifier '" name "'\n") -3003 (write-buffered Stderr "invalid identifier '") -3004 (write-slice-buffered Stderr %ecx) -3005 (write-buffered Stderr "'\n") -3006 (flush Stderr) -3007 # . syscall(exit, 1) -3008 bb/copy-to-ebx 1/imm32 -3009 b8/copy-to-eax 1/imm32/exit -3010 cd/syscall 0x80/imm8 -3011 # never gets here -3012 -3013 add-operation-and-inputs-to-stmt: # stmt: (handle stmt), line: (addr stream byte) -3014 # pseudocode: -3015 # stmt->name = slice-to-string(next-word(line)) -3016 # while true -3017 # name = next-word-or-string(line) -3018 # v = lookup-var-or-literal(name) -3019 # stmt->inouts = append(stmt->inouts, v) -3020 # -3021 # . prologue -3022 55/push-ebp -3023 89/<- %ebp 4/r32/esp -3024 # . save registers -3025 50/push-eax -3026 51/push-ecx -3027 57/push-edi -3028 # edi = stmt -3029 8b/-> *(ebp+8) 7/r32/edi -3030 # var name/ecx: slice -3031 68/push 0/imm32/end -3032 68/push 0/imm32/start -3033 89/<- %ecx 4/r32/esp -3034 $add-operation-and-inputs-to-stmt:read-operation: -3035 (next-word *(ebp+0xc) %ecx) -3036 (slice-to-string Heap %ecx) # => eax -3037 89/<- *(edi+4) 0/r32/eax # Stmt1-operation or Regvardef-operation -3038 { -3039 $add-operation-and-inputs-to-stmt:read-inouts: -3040 # name = next-word-or-string(line) -3041 (next-word-or-string *(ebp+0xc) %ecx) -3042 # if slice-empty?(word-slice) break -3043 (slice-empty? %ecx) # => eax -3044 3d/compare-eax-and 0/imm32 -3045 0f 85/jump-if-!= break/disp32 -3046 # if (name == "<-") abort -3047 (slice-equal? %ecx "<-") -3048 3d/compare-eax-and 0/imm32 -3049 0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32 -3050 # -3051 (lookup-var-or-literal %ecx *(ebp+0x10)) # => eax -3052 (append-list Heap %eax *(edi+8)) # Stmt1-inouts or Regvardef-inouts => eax -3053 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts -3054 e9/jump loop/disp32 -3055 } -3056 $add-operation-and-inputs-to-stmt:end: -3057 # . reclaim locals -3058 81 0/subop/add %esp 8/imm32 -3059 # . restore registers -3060 5f/pop-to-edi -3061 59/pop-to-ecx -3062 58/pop-to-eax -3063 # . epilogue -3064 89/<- %esp 5/r32/ebp -3065 5d/pop-to-ebp -3066 c3/return -3067 -3068 $add-operation-and-inputs-to-stmt:abort: -3069 # error("invalid statement '" line "'\n") -3070 (rewind-stream *(ebp+8)) -3071 (write-buffered Stderr "invalid identifier '") -3072 (flush Stderr) -3073 (write-stream 2 *(ebp+8)) -3074 (write-buffered Stderr "'\n") -3075 (flush Stderr) -3076 # . syscall(exit, 1) -3077 bb/copy-to-ebx 1/imm32 -3078 b8/copy-to-eax 1/imm32/exit -3079 cd/syscall 0x80/imm8 -3080 # never gets here +2212 (check-ints-equal *edx 1 "F - test-var-with-trailing-characters/type") +2213 (check-ints-equal *(edx+4) 0 "F - test-var-with-trailing-characters/type") +2214 # . epilogue +2215 89/<- %esp 5/r32/ebp +2216 5d/pop-to-ebp +2217 c3/return +2218 +2219 test-parse-var-with-register-and-trailing-characters: +2220 # . prologue +2221 55/push-ebp +2222 89/<- %ebp 4/r32/esp +2223 # (eax..ecx) = "x/eax:" +2224 b8/copy-to-eax "x/eax:"/imm32 +2225 8b/-> *eax 1/r32/ecx +2226 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2227 05/add-to-eax 4/imm32 +2228 # var slice/ecx: slice = {eax, ecx} +2229 51/push-ecx +2230 50/push-eax +2231 89/<- %ecx 4/r32/esp +2232 # _test-input-stream contains "int," +2233 (clear-stream _test-input-stream) +2234 (write _test-input-stream "int,") +2235 # +2236 (parse-var-with-type %ecx _test-input-stream) +2237 8b/-> *eax 2/r32/edx # Var-name +2238 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") +2239 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2240 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") +2241 8b/-> *(eax+4) 2/r32/edx # Var-type +2242 (check-ints-equal *edx 1 "F - test-var-with-register-and-trailing-characters/type") +2243 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") +2244 # . epilogue +2245 89/<- %esp 5/r32/ebp +2246 5d/pop-to-ebp +2247 c3/return +2248 +2249 test-parse-var-with-compound-type: +2250 # . prologue +2251 55/push-ebp +2252 89/<- %ebp 4/r32/esp +2253 # (eax..ecx) = "x:" +2254 b8/copy-to-eax "x:"/imm32 +2255 8b/-> *eax 1/r32/ecx +2256 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2257 05/add-to-eax 4/imm32 +2258 # var slice/ecx: slice = {eax, ecx} +2259 51/push-ecx +2260 50/push-eax +2261 89/<- %ecx 4/r32/esp +2262 # _test-input-stream contains "(addr int)" +2263 (clear-stream _test-input-stream) +2264 (write _test-input-stream "(addr int)") +2265 # +2266 (parse-var-with-type %ecx _test-input-stream) +2267 8b/-> *eax 2/r32/edx # Var-name +2268 (check-strings-equal %edx "x" "F - test-var-with-compound-type/name") +2269 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2270 (check-ints-equal %edx 0 "F - test-var-with-compound-type/register") +2271 # var type/edx: (handle tree type-id) = var->type +2272 8b/-> *(eax+4) 2/r32/edx # Var-type +2273 # type->left == atom(addr) +2274 8b/-> *edx 0/r32/eax # Atom-value +2275 (check-ints-equal *eax 2 "F - test-var-with-compound-type/type:0") # Tree-left +2276 # type->right->left == atom(int) +2277 8b/-> *(edx+4) 2/r32/edx # Tree-right +2278 8b/-> *edx 0/r32/eax # Tree-left +2279 (check-ints-equal *eax 1 "F - test-var-with-compound-type/type:1") # Atom-value +2280 # type->right->right == null +2281 (check-ints-equal *(edx+4) 0 "F - test-var-with-compound-type/type:2") # Tree-right +2282 # . epilogue +2283 89/<- %esp 5/r32/ebp +2284 5d/pop-to-ebp +2285 c3/return +2286 +2287 # identifier starts with a letter or '$' or '_' +2288 # no constraints at the moment on later letters +2289 # all we really want to do so far is exclude '{', '}' and '->' +2290 is-identifier?: # in: (addr slice) -> result/eax: boolean +2291 # . prologue +2292 55/push-ebp +2293 89/<- %ebp 4/r32/esp +2294 # if (slice-empty?(in)) return false +2295 (slice-empty? *(ebp+8)) # => eax +2296 3d/compare-eax-and 0/imm32 +2297 75/jump-if-!= $is-identifier?:false/disp8 +2298 # var c/eax: byte = *in->start +2299 8b/-> *(ebp+8) 0/r32/eax +2300 8b/-> *eax 0/r32/eax +2301 8a/copy-byte *eax 0/r32/AL +2302 81 4/subop/and %eax 0xff/imm32 +2303 # if (c == '$') return true +2304 3d/compare-eax-and 0x24/imm32/$ +2305 74/jump-if-= $is-identifier?:true/disp8 +2306 # if (c == '_') return true +2307 3d/compare-eax-and 0x5f/imm32/_ +2308 74/jump-if-= $is-identifier?:true/disp8 +2309 # drop case +2310 25/and-eax-with 0x5f/imm32 +2311 # if (c < 'A') return false +2312 3d/compare-eax-and 0x41/imm32/A +2313 7c/jump-if-< $is-identifier?:false/disp8 +2314 # if (c > 'Z') return false +2315 3d/compare-eax-and 0x5a/imm32/Z +2316 7f/jump-if-> $is-identifier?:false/disp8 +2317 # otherwise return true +2318 $is-identifier?:true: +2319 b8/copy-to-eax 1/imm32/true +2320 eb/jump $is-identifier?:end/disp8 +2321 $is-identifier?:false: +2322 b8/copy-to-eax 0/imm32/false +2323 $is-identifier?:end: +2324 # . epilogue +2325 89/<- %esp 5/r32/ebp +2326 5d/pop-to-ebp +2327 c3/return +2328 +2329 test-is-identifier-dollar: +2330 # . prologue +2331 55/push-ebp +2332 89/<- %ebp 4/r32/esp +2333 # (eax..ecx) = "$a" +2334 b8/copy-to-eax "$a"/imm32 +2335 8b/-> *eax 1/r32/ecx +2336 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2337 05/add-to-eax 4/imm32 +2338 # var slice/ecx: slice = {eax, ecx} +2339 51/push-ecx +2340 50/push-eax +2341 89/<- %ecx 4/r32/esp +2342 # +2343 (is-identifier? %ecx) +2344 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") +2345 # . epilogue +2346 89/<- %esp 5/r32/ebp +2347 5d/pop-to-ebp +2348 c3/return +2349 +2350 test-is-identifier-underscore: +2351 # . prologue +2352 55/push-ebp +2353 89/<- %ebp 4/r32/esp +2354 # (eax..ecx) = "_a" +2355 b8/copy-to-eax "_a"/imm32 +2356 8b/-> *eax 1/r32/ecx +2357 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2358 05/add-to-eax 4/imm32 +2359 # var slice/ecx: slice = {eax, ecx} +2360 51/push-ecx +2361 50/push-eax +2362 89/<- %ecx 4/r32/esp +2363 # +2364 (is-identifier? %ecx) +2365 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") +2366 # . epilogue +2367 89/<- %esp 5/r32/ebp +2368 5d/pop-to-ebp +2369 c3/return +2370 +2371 test-is-identifier-a: +2372 # . prologue +2373 55/push-ebp +2374 89/<- %ebp 4/r32/esp +2375 # (eax..ecx) = "a$" +2376 b8/copy-to-eax "a$"/imm32 +2377 8b/-> *eax 1/r32/ecx +2378 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2379 05/add-to-eax 4/imm32 +2380 # var slice/ecx: slice = {eax, ecx} +2381 51/push-ecx +2382 50/push-eax +2383 89/<- %ecx 4/r32/esp +2384 # +2385 (is-identifier? %ecx) +2386 (check-ints-equal %eax 1 "F - test-is-identifier-a") +2387 # . epilogue +2388 89/<- %esp 5/r32/ebp +2389 5d/pop-to-ebp +2390 c3/return +2391 +2392 test-is-identifier-z: +2393 # . prologue +2394 55/push-ebp +2395 89/<- %ebp 4/r32/esp +2396 # (eax..ecx) = "z$" +2397 b8/copy-to-eax "z$"/imm32 +2398 8b/-> *eax 1/r32/ecx +2399 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2400 05/add-to-eax 4/imm32 +2401 # var slice/ecx: slice = {eax, ecx} +2402 51/push-ecx +2403 50/push-eax +2404 89/<- %ecx 4/r32/esp +2405 # +2406 (is-identifier? %ecx) +2407 (check-ints-equal %eax 1 "F - test-is-identifier-z") +2408 # . epilogue +2409 89/<- %esp 5/r32/ebp +2410 5d/pop-to-ebp +2411 c3/return +2412 +2413 test-is-identifier-A: +2414 # . prologue +2415 55/push-ebp +2416 89/<- %ebp 4/r32/esp +2417 # (eax..ecx) = "A$" +2418 b8/copy-to-eax "A$"/imm32 +2419 8b/-> *eax 1/r32/ecx +2420 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2421 05/add-to-eax 4/imm32 +2422 # var slice/ecx: slice = {eax, ecx} +2423 51/push-ecx +2424 50/push-eax +2425 89/<- %ecx 4/r32/esp +2426 # +2427 (is-identifier? %ecx) +2428 (check-ints-equal %eax 1 "F - test-is-identifier-A") +2429 # . epilogue +2430 89/<- %esp 5/r32/ebp +2431 5d/pop-to-ebp +2432 c3/return +2433 +2434 test-is-identifier-Z: +2435 # . prologue +2436 55/push-ebp +2437 89/<- %ebp 4/r32/esp +2438 # (eax..ecx) = "Z$" +2439 b8/copy-to-eax "Z$"/imm32 +2440 8b/-> *eax 1/r32/ecx +2441 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2442 05/add-to-eax 4/imm32 +2443 # var slice/ecx: slice = {eax, ecx} +2444 51/push-ecx +2445 50/push-eax +2446 89/<- %ecx 4/r32/esp +2447 # +2448 (is-identifier? %ecx) +2449 (check-ints-equal %eax 1 "F - test-is-identifier-Z") +2450 # . epilogue +2451 89/<- %esp 5/r32/ebp +2452 5d/pop-to-ebp +2453 c3/return +2454 +2455 test-is-identifier-@: +2456 # character before 'A' is invalid +2457 # . prologue +2458 55/push-ebp +2459 89/<- %ebp 4/r32/esp +2460 # (eax..ecx) = "@a" +2461 b8/copy-to-eax "@a"/imm32 +2462 8b/-> *eax 1/r32/ecx +2463 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2464 05/add-to-eax 4/imm32 +2465 # var slice/ecx: slice = {eax, ecx} +2466 51/push-ecx +2467 50/push-eax +2468 89/<- %ecx 4/r32/esp +2469 # +2470 (is-identifier? %ecx) +2471 (check-ints-equal %eax 0 "F - test-is-identifier-@") +2472 # . epilogue +2473 89/<- %esp 5/r32/ebp +2474 5d/pop-to-ebp +2475 c3/return +2476 +2477 test-is-identifier-square-bracket: +2478 # character after 'Z' is invalid +2479 # . prologue +2480 55/push-ebp +2481 89/<- %ebp 4/r32/esp +2482 # (eax..ecx) = "[a" +2483 b8/copy-to-eax "[a"/imm32 +2484 8b/-> *eax 1/r32/ecx +2485 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2486 05/add-to-eax 4/imm32 +2487 # var slice/ecx: slice = {eax, ecx} +2488 51/push-ecx +2489 50/push-eax +2490 89/<- %ecx 4/r32/esp +2491 # +2492 (is-identifier? %ecx) +2493 (check-ints-equal %eax 0 "F - test-is-identifier-@") +2494 # . epilogue +2495 89/<- %esp 5/r32/ebp +2496 5d/pop-to-ebp +2497 c3/return +2498 +2499 test-is-identifier-backtick: +2500 # character before 'a' is invalid +2501 # . prologue +2502 55/push-ebp +2503 89/<- %ebp 4/r32/esp +2504 # (eax..ecx) = "`a" +2505 b8/copy-to-eax "`a"/imm32 +2506 8b/-> *eax 1/r32/ecx +2507 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2508 05/add-to-eax 4/imm32 +2509 # var slice/ecx: slice = {eax, ecx} +2510 51/push-ecx +2511 50/push-eax +2512 89/<- %ecx 4/r32/esp +2513 # +2514 (is-identifier? %ecx) +2515 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") +2516 # . epilogue +2517 89/<- %esp 5/r32/ebp +2518 5d/pop-to-ebp +2519 c3/return +2520 +2521 test-is-identifier-curly-brace-open: +2522 # character after 'z' is invalid; also used for blocks +2523 # . prologue +2524 55/push-ebp +2525 89/<- %ebp 4/r32/esp +2526 # (eax..ecx) = "{a" +2527 b8/copy-to-eax "{a"/imm32 +2528 8b/-> *eax 1/r32/ecx +2529 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2530 05/add-to-eax 4/imm32 +2531 # var slice/ecx: slice = {eax, ecx} +2532 51/push-ecx +2533 50/push-eax +2534 89/<- %ecx 4/r32/esp +2535 # +2536 (is-identifier? %ecx) +2537 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") +2538 # . epilogue +2539 89/<- %esp 5/r32/ebp +2540 5d/pop-to-ebp +2541 c3/return +2542 +2543 test-is-identifier-curly-brace-close: +2544 # . prologue +2545 55/push-ebp +2546 89/<- %ebp 4/r32/esp +2547 # (eax..ecx) = "}a" +2548 b8/copy-to-eax "}a"/imm32 +2549 8b/-> *eax 1/r32/ecx +2550 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2551 05/add-to-eax 4/imm32 +2552 # var slice/ecx: slice = {eax, ecx} +2553 51/push-ecx +2554 50/push-eax +2555 89/<- %ecx 4/r32/esp +2556 # +2557 (is-identifier? %ecx) +2558 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") +2559 # . epilogue +2560 89/<- %esp 5/r32/ebp +2561 5d/pop-to-ebp +2562 c3/return +2563 +2564 test-is-identifier-hyphen: +2565 # disallow leading '-' since '->' has special meaning +2566 # . prologue +2567 55/push-ebp +2568 89/<- %ebp 4/r32/esp +2569 # (eax..ecx) = "-a" +2570 b8/copy-to-eax "-a"/imm32 +2571 8b/-> *eax 1/r32/ecx +2572 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2573 05/add-to-eax 4/imm32 +2574 # var slice/ecx: slice = {eax, ecx} +2575 51/push-ecx +2576 50/push-eax +2577 89/<- %ecx 4/r32/esp +2578 # +2579 (is-identifier? %ecx) +2580 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") +2581 # . epilogue +2582 89/<- %esp 5/r32/ebp +2583 5d/pop-to-ebp +2584 c3/return +2585 +2586 populate-mu-function-body: # in: (addr buffered-file), out: (handle function), vars: (addr stack (handle var)) +2587 # . prologue +2588 55/push-ebp +2589 89/<- %ebp 4/r32/esp +2590 # . save registers +2591 50/push-eax +2592 56/push-esi +2593 57/push-edi +2594 # esi = in +2595 8b/-> *(ebp+8) 6/r32/esi +2596 # edi = out +2597 8b/-> *(ebp+0xc) 7/r32/edi +2598 # initialize some global state +2599 c7 0/subop/copy *Curr-block-depth 0/imm32 +2600 c7 0/subop/copy *Next-local-stack-offset -4/imm32 +2601 # var eax: (handle block) = parse-mu-block(in, vars) +2602 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax +2603 # out->body = eax +2604 89/<- *(edi+0x10) 0/r32/eax # Function-body +2605 $populate-mu-function-body:end: +2606 # . restore registers +2607 5f/pop-to-edi +2608 5e/pop-to-esi +2609 58/pop-to-eax +2610 # . epilogue +2611 89/<- %esp 5/r32/ebp +2612 5d/pop-to-ebp +2613 c3/return +2614 +2615 == data +2616 +2617 # Global state when parsing a function +2618 Curr-block-depth: # (addr int) +2619 0/imm32 +2620 Next-local-stack-offset: # (addr int) +2621 -4/imm32 +2622 +2623 == code +2624 +2625 # parses a block, assuming that the leading '{' has already been read by the caller +2626 parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle block) +2627 # pseudocode: +2628 # var line: (stream byte 512) +2629 # var word-slice: slice +2630 # result/eax = allocate(Heap, Stmt-size) +2631 # result->tag = 0/Block +2632 # while true # line loop +2633 # clear-stream(line) +2634 # read-line-buffered(in, line) +2635 # if (line->write == 0) break # end of file +2636 # word-slice = next-word(line) +2637 # if slice-empty?(word-slice) # end of line +2638 # continue +2639 # else if slice-starts-with?(word-slice, "#") +2640 # continue +2641 # else if slice-equal?(word-slice, "{") +2642 # assert(no-tokens-in(line)) +2643 # block = parse-mu-block(in, vars, fn) +2644 # append-to-block(result, block) +2645 # else if slice-equal?(word-slice, "}") +2646 # break +2647 # else if slice-ends-with?(word-slice, ":") +2648 # named-block = parse-mu-named-block(word-slice, line, in, vars, fn) +2649 # append-to-block(result, named-block) +2650 # else if slice-equal?(word-slice, "var") +2651 # var-def = parse-mu-var-def(line, vars) +2652 # append-to-block(result, var-def) +2653 # else +2654 # stmt = parse-mu-stmt(line, vars, fn) +2655 # append-to-block(result, stmt) +2656 # TODO: reclaim locals +2657 # return result +2658 # +2659 # . prologue +2660 55/push-ebp +2661 89/<- %ebp 4/r32/esp +2662 # . save registers +2663 51/push-ecx +2664 52/push-edx +2665 53/push-ebx +2666 57/push-edi +2667 # var line/ecx: (stream byte 512) +2668 81 5/subop/subtract %esp 0x200/imm32 +2669 68/push 0x200/imm32/length +2670 68/push 0/imm32/read +2671 68/push 0/imm32/write +2672 89/<- %ecx 4/r32/esp +2673 # var word-slice/edx: slice +2674 68/push 0/imm32/end +2675 68/push 0/imm32/start +2676 89/<- %edx 4/r32/esp +2677 # edi = result +2678 (allocate Heap *Stmt-size) # => eax +2679 (zero-out %eax *Stmt-size) +2680 89/<- %edi 0/r32/eax +2681 { # line loop +2682 $parse-mu-block:line-loop: +2683 # line = read-line-buffered(in) +2684 (clear-stream %ecx) +2685 (read-line-buffered *(ebp+8) %ecx) +2686 #? (write-buffered Stderr "line: ") +2687 #? (write-stream-data Stderr %ecx) +2688 #? (write-buffered Stderr Newline) +2689 #? (flush Stderr) +2690 # if (line->write == 0) break +2691 81 7/subop/compare *ecx 0/imm32 +2692 0f 84/jump-if-= break/disp32 +2693 # word-slice = next-word(line) +2694 (next-word %ecx %edx) +2695 #? (write-buffered Stderr "word: ") +2696 #? (write-slice-buffered Stderr %edx) +2697 #? (write-buffered Stderr Newline) +2698 #? (flush Stderr) +2699 # if slice-empty?(word-slice) continue +2700 (slice-empty? %edx) +2701 3d/compare-eax-and 0/imm32 +2702 0f 85/jump-if-!= loop/disp32 +2703 # if (slice-starts-with?(word-slice, '#') continue +2704 # . eax = *word-slice->start +2705 8b/-> *edx 0/r32/eax +2706 8a/copy-byte *eax 0/r32/AL +2707 81 4/subop/and %eax 0xff/imm32 +2708 # . if (eax == '#') continue +2709 3d/compare-eax-and 0x23/imm32/hash +2710 0f 84/jump-if-= loop/disp32 +2711 # if slice-equal?(word-slice, "{") +2712 { +2713 $parse-mu-block:check-for-block: +2714 (slice-equal? %edx "{") +2715 3d/compare-eax-and 0/imm32 +2716 74/jump-if-= break/disp8 +2717 (check-no-tokens-left %ecx) +2718 # parse new block and append +2719 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2720 (append-to-block Heap %edi %eax) +2721 e9/jump $parse-mu-block:line-loop/disp32 +2722 } +2723 # if slice-equal?(word-slice, "}") break +2724 $parse-mu-block:check-for-end: +2725 (slice-equal? %edx "}") +2726 3d/compare-eax-and 0/imm32 +2727 0f 85/jump-if-!= break/disp32 +2728 # if slice-ends-with?(word-slice, ":") parse named block and append +2729 { +2730 $parse-mu-block:check-for-named-block: +2731 # . eax = *word-slice->end +2732 8b/-> *(edx+4) 0/r32/eax +2733 8a/copy-byte *eax 0/r32/AL +2734 81 4/subop/and %eax 0xff/imm32 +2735 # . if (eax != ':') break +2736 3d/compare-eax-and 0x23/imm32/hash +2737 0f 85/jump-if-!= break/disp32 +2738 # +2739 (parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2740 (append-to-block Heap %edi %eax) +2741 e9/jump $parse-mu-block:line-loop/disp32 +2742 } +2743 # if slice-equal?(word-slice, "var") +2744 { +2745 $parse-mu-block:check-for-var: +2746 (slice-equal? %edx "var") +2747 3d/compare-eax-and 0/imm32 +2748 74/jump-if-= break/disp8 +2749 # +2750 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax +2751 (append-to-block Heap %edi %eax) +2752 e9/jump $parse-mu-block:line-loop/disp32 +2753 } +2754 $parse-mu-block:regular-stmt: +2755 # otherwise +2756 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +2757 (append-to-block Heap %edi %eax) +2758 e9/jump loop/disp32 +2759 } # end line loop +2760 # return result +2761 89/<- %eax 7/r32/edi +2762 $parse-mu-block:end: +2763 # . reclaim locals +2764 81 0/subop/add %esp 0x214/imm32 +2765 # . restore registers +2766 5f/pop-to-edi +2767 5b/pop-to-ebx +2768 5a/pop-to-edx +2769 59/pop-to-ecx +2770 # . epilogue +2771 89/<- %esp 5/r32/ebp +2772 5d/pop-to-ebp +2773 c3/return +2774 +2775 $parse-mu-block:abort: +2776 # error("'{' or '}' should be on its own line, but got '") +2777 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +2778 (rewind-stream %ecx) +2779 (write-stream 2 %ecx) +2780 (write-buffered Stderr "'\n") +2781 (flush Stderr) +2782 # . syscall(exit, 1) +2783 bb/copy-to-ebx 1/imm32 +2784 b8/copy-to-eax 1/imm32/exit +2785 cd/syscall 0x80/imm8 +2786 # never gets here +2787 +2788 check-no-tokens-left: # line: (addr stream byte) +2789 # . prologue +2790 55/push-ebp +2791 89/<- %ebp 4/r32/esp +2792 # . save registers +2793 50/push-eax +2794 51/push-ecx +2795 # var s/ecx: slice +2796 68/push 0/imm32/end +2797 68/push 0/imm32/start +2798 89/<- %ecx 4/r32/esp +2799 # +2800 (next-word *(ebp+8) %ecx) +2801 # if slice-empty?(s) return +2802 (slice-empty? %ecx) +2803 3d/compare-eax-and 0/imm32 +2804 75/jump-if-!= $check-no-tokens-left:end/disp8 +2805 # if (slice-starts-with?(s, '#') return +2806 # . eax = *s->start +2807 8b/-> *edx 0/r32/eax +2808 8a/copy-byte *eax 0/r32/AL +2809 81 4/subop/and %eax 0xff/imm32 +2810 # . if (eax == '#') continue +2811 3d/compare-eax-and 0x23/imm32/hash +2812 74/jump-if-= $check-no-tokens-left:end/disp8 +2813 # abort +2814 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +2815 (rewind-stream %ecx) +2816 (write-stream 2 %ecx) +2817 (write-buffered Stderr "'\n") +2818 (flush Stderr) +2819 # . syscall(exit, 1) +2820 bb/copy-to-ebx 1/imm32 +2821 b8/copy-to-eax 1/imm32/exit +2822 cd/syscall 0x80/imm8 +2823 # never gets here +2824 $check-no-tokens-left:end: +2825 # . reclaim locals +2826 81 0/subop/add %esp 8/imm32 +2827 # . restore registers +2828 59/pop-to-ecx +2829 58/pop-to-eax +2830 # . epilogue +2831 89/<- %esp 5/r32/ebp +2832 5d/pop-to-ebp +2833 c3/return +2834 +2835 parse-mu-named-block: # name: (addr slice), first-line: (addr stream byte), in: (addr buffered-file), vars: (addr stack (handle var)) -> result/eax: (handle stmt) +2836 # pseudocode: +2837 # var line: (stream byte 512) +2838 # var word-slice: slice +2839 # result/eax = allocate(Heap, Stmt-size) +2840 # result->tag = 4/Named-block +2841 # result->name = name +2842 # assert(next-word(first-line) == "{") +2843 # assert(no-tokens-in(first-line)) +2844 # while true # line loop +2845 # clear-stream(line) +2846 # read-line-buffered(in, line) +2847 # if (line->write == 0) break # end of file +2848 # word-slice = next-word(line) +2849 # if slice-empty?(word-slice) # end of line +2850 # break +2851 # else if slice-equal?(word-slice, "{") +2852 # block = parse-mu-block(in, vars) +2853 # append-to-block(result, block) +2854 # else if slice-equal?(word-slice, "}") +2855 # break +2856 # else if slice-ends-with?(word-slice, ":") +2857 # named-block = parse-mu-named-block(word-slice, in, vars) +2858 # append-to-block(result, named-block) +2859 # else if slice-equal?(word-slice, "var") +2860 # var-def = parse-mu-var-def(line, vars) +2861 # append-to-block(result, var-def) +2862 # else +2863 # stmt = parse-mu-stmt(line, vars, fn) +2864 # append-to-block(result, stmt) +2865 # return result +2866 # +2867 # . prologue +2868 55/push-ebp +2869 89/<- %ebp 4/r32/esp +2870 # . save registers +2871 $parse-mu-named-block:end: +2872 # . reclaim locals +2873 # . restore registers +2874 # . epilogue +2875 89/<- %esp 5/r32/ebp +2876 5d/pop-to-ebp +2877 c3/return +2878 +2879 parse-mu-var-def: # line: (addr stream byte), vars: (addr stack (handle var)) -> result/eax: (handle stmt) +2880 # . prologue +2881 55/push-ebp +2882 89/<- %ebp 4/r32/esp +2883 # . save registers +2884 51/push-ecx +2885 52/push-edx +2886 # var word-slice/ecx: slice +2887 68/push 0/imm32/end +2888 68/push 0/imm32/start +2889 89/<- %ecx 4/r32/esp +2890 # var v/edx: (handle var) = parse-var-with-type(line) +2891 (next-word *(ebp+8) %ecx) +2892 (parse-var-with-type %ecx *(ebp+8)) # => eax +2893 89/<- %edx 0/r32/eax +2894 # v->stack-offset = *Next-local-stack-offset +2895 8b/-> *Next-local-stack-offset 0/r32/eax +2896 89/<- *(edx+0xc) 0/r32/eax # Var-stack-offset +2897 # *Next-local-stack-offset -= size-of(v) +2898 (size-of %edx) +2899 29/subtract-from *Next-local-stack-offset 0/r32/eax +2900 # +2901 (push *(ebp+0xc) %edx) +2902 # either v has no register and there's no more to this line +2903 8b/-> *(edx+0x10) 0/r32/eax # Var-register +2904 3d/compare-eax-and 0/imm32 +2905 { +2906 75/jump-if-!= break/disp8 +2907 # TODO: ensure that there's nothing else on this line +2908 (new-vardef Heap %edx) # => eax +2909 eb/jump $parse-mu-var-def:end/disp8 +2910 } +2911 # or v has a register and there's more to this line +2912 { +2913 74/jump-if-= break/disp8 +2914 # ensure that the next word is '<-' +2915 (next-word *(ebp+8) %ecx) +2916 (slice-equal? %ecx "<-") # => eax +2917 3d/compare-eax-and 0/imm32 +2918 74/jump-if-= $parse-mu-var-def:abort/disp8 +2919 # +2920 (new-regvardef Heap %edx) # => eax +2921 (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc)) +2922 } +2923 $parse-mu-var-def:end: +2924 # . reclaim locals +2925 81 0/subop/add %esp 8/imm32 +2926 # . restore registers +2927 5a/pop-to-edx +2928 59/pop-to-ecx +2929 # . epilogue +2930 89/<- %esp 5/r32/ebp +2931 5d/pop-to-ebp +2932 c3/return +2933 +2934 $parse-mu-var-def:abort: +2935 (rewind-stream *(ebp+8)) +2936 # error("register variable requires a valid instruction to initialize but got '" line "'\n") +2937 (write-buffered Stderr "register variable requires a valid instruction to initialize but got '") +2938 (flush Stderr) +2939 (write-stream 2 *(ebp+8)) +2940 (write-buffered Stderr "'\n") +2941 (flush Stderr) +2942 # . syscall(exit, 1) +2943 bb/copy-to-ebx 1/imm32 +2944 b8/copy-to-eax 1/imm32/exit +2945 cd/syscall 0x80/imm8 +2946 # never gets here +2947 +2948 test-parse-mu-var-def: +2949 # 'var n: int' +2950 # . prologue +2951 55/push-ebp +2952 89/<- %ebp 4/r32/esp +2953 # setup +2954 (clear-stream _test-input-stream) +2955 (write _test-input-stream "n: int\n") # caller has consumed the 'var' +2956 # var vars/ecx: (stack (addr var) 4) +2957 81 5/subop/subtract %esp 0x10/imm32 +2958 68/push 0x10/imm32/length +2959 68/push 0/imm32/top +2960 89/<- %ecx 4/r32/esp +2961 (clear-stack %ecx) +2962 # convert +2963 (parse-mu-var-def _test-input-stream %ecx) # => eax +2964 # check result +2965 (check-ints-equal *eax 2 "F - test-parse-mu-var-def/tag") # Stmt-tag is vardef +2966 8b/-> *(eax+4) 0/r32/eax # Vardef-var +2967 (check-strings-equal *eax "n" "F - test-parse-mu-var-def/var-name") # Var-name +2968 (check-ints-equal *(eax+0x10) 0 "F - test-parse-mu-var-def/var-register") # Var-register +2969 # TODO: ensure stack-offset is -4 +2970 # TODO: ensure block-depth is 1 +2971 # ensure type is int +2972 8b/-> *(eax+4) 0/r32/eax # Var-type +2973 (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0") # Tree-left +2974 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-var-def/var-type:0") # Tree-right +2975 # . epilogue +2976 89/<- %esp 5/r32/ebp +2977 5d/pop-to-ebp +2978 c3/return +2979 +2980 test-parse-mu-reg-var-def: +2981 # 'var n/eax: int <- copy 0' +2982 # . prologue +2983 55/push-ebp +2984 89/<- %ebp 4/r32/esp +2985 # setup +2986 (clear-stream _test-input-stream) +2987 (write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var' +2988 # var vars/ecx: (stack (addr var) 4) +2989 81 5/subop/subtract %esp 0x10/imm32 +2990 68/push 0x10/imm32/length +2991 68/push 0/imm32/top +2992 89/<- %ecx 4/r32/esp +2993 (clear-stack %ecx) +2994 # convert +2995 (parse-mu-var-def _test-input-stream %ecx) # => eax +2996 # check result +2997 (check-ints-equal *eax 3 "F - test-parse-mu-reg-var-def/tag") # Stmt-tag is regvardef +2998 8b/-> *(eax+0xc) 0/r32/eax # Regvardef-var +2999 (check-strings-equal *eax "n" "F - test-parse-mu-reg-var-def/var-name") # Var-name +3000 (check-strings-equal *(eax+0x10) "eax" "F - test-parse-mu-reg-var-def/var-register") # Var-register +3001 # TODO: ensure stack-offset is -4 +3002 # TODO: ensure block-depth is 1 +3003 # ensure type is int +3004 8b/-> *(eax+4) 0/r32/eax # Var-type +3005 (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/var-type:0") # Tree-left +3006 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/var-type:0") # Tree-right +3007 # . epilogue +3008 89/<- %esp 5/r32/ebp +3009 5d/pop-to-ebp +3010 c3/return +3011 +3012 parse-mu-stmt: # line: (addr stream byte), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) +3013 # pseudocode: +3014 # var name: slice +3015 # result = allocate(Heap, Stmt-size) +3016 # if stmt-has-outputs?(line) +3017 # while true +3018 # name = next-word(line) +3019 # if (name == '<-') break +3020 # assert(is-identifier?(name)) +3021 # var v: (handle var) = lookup-or-define-var(name, vars, fn) # regular stmts may define vars in fn outputs +3022 # result->outputs = append(result->outputs, v) +3023 # add-operation-and-inputs-to-stmt(result, line, vars) +3024 # +3025 # . prologue +3026 55/push-ebp +3027 89/<- %ebp 4/r32/esp +3028 # . save registers +3029 51/push-ecx +3030 57/push-edi +3031 # var name/ecx: slice +3032 68/push 0/imm32/end +3033 68/push 0/imm32/start +3034 89/<- %ecx 4/r32/esp +3035 # result/edi: (handle stmt) +3036 (allocate Heap *Stmt-size) # => eax +3037 (zero-out %eax *Stmt-size) +3038 89/<- %edi 0/r32/eax +3039 # result->tag = 1/stmt +3040 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag +3041 { +3042 (stmt-has-outputs? *(ebp+8)) +3043 3d/compare-eax-and 0/imm32 +3044 0f 84/jump-if-= break/disp32 +3045 { +3046 $parse-mu-stmt:read-outputs: +3047 # name = next-word(line) +3048 (next-word *(ebp+8) %ecx) +3049 # if slice-empty?(word-slice) break +3050 (slice-empty? %ecx) +3051 3d/compare-eax-and 0/imm32 +3052 0f 85/jump-if-!= break/disp32 +3053 # if (name == "<-") break +3054 (slice-equal? %ecx "<-") +3055 3d/compare-eax-and 0/imm32 +3056 75/jump-if-!= break/disp8 +3057 # assert(is-identifier?(name)) +3058 (is-identifier? %ecx) +3059 3d/compare-eax-and 0/imm32 +3060 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 +3061 # +3062 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +3063 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax +3064 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs +3065 e9/jump loop/disp32 +3066 } +3067 } +3068 (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc)) +3069 $parse-mu-stmt:end: +3070 # return result +3071 89/<- %eax 7/r32/edi +3072 # . reclaim locals +3073 81 0/subop/add %esp 8/imm32 +3074 # . restore registers +3075 5f/pop-to-edi +3076 59/pop-to-ecx +3077 # . epilogue +3078 89/<- %esp 5/r32/ebp +3079 5d/pop-to-ebp +3080 c3/return 3081 -3082 stmt-has-outputs?: # line: (addr stream byte) -> result/eax: boolean -3083 # . prologue -3084 55/push-ebp -3085 89/<- %ebp 4/r32/esp -3086 # . save registers -3087 51/push-ecx -3088 # var word-slice/ecx: slice -3089 68/push 0/imm32/end -3090 68/push 0/imm32/start -3091 89/<- %ecx 4/r32/esp -3092 # result = false -3093 b8/copy-to-eax 0/imm32/false -3094 (rewind-stream *(ebp+8)) -3095 { -3096 (next-word-or-string *(ebp+8) %ecx) -3097 # if slice-empty?(word-slice) break -3098 (slice-empty? %ecx) -3099 3d/compare-eax-and 0/imm32 -3100 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -3101 0f 85/jump-if-!= break/disp32 -3102 # if slice-starts-with?(word-slice, '#') break -3103 # . eax = *word-slice->start -3104 8b/-> *ecx 0/r32/eax -3105 8a/copy-byte *eax 0/r32/AL -3106 81 4/subop/and %eax 0xff/imm32 -3107 # . if (eax == '#') break -3108 3d/compare-eax-and 0x23/imm32/hash -3109 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -3110 0f 84/jump-if-= break/disp32 -3111 # if slice-equal?(word-slice, '<-') return true -3112 (slice-equal? %ecx "<-") -3113 3d/compare-eax-and 0/imm32 -3114 74/jump-if-= loop/disp8 -3115 b8/copy-to-eax 1/imm32/true -3116 } -3117 $stmt-has-outputs:end: -3118 (rewind-stream *(ebp+8)) -3119 # . reclaim locals -3120 81 0/subop/add %esp 8/imm32 -3121 # . restore registers -3122 59/pop-to-ecx -3123 # . epilogue -3124 89/<- %esp 5/r32/ebp -3125 5d/pop-to-ebp -3126 c3/return -3127 -3128 # if 'name' starts with a digit, create a new literal var for it -3129 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found -3130 lookup-var-or-literal: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) -3131 # . prologue -3132 55/push-ebp -3133 89/<- %ebp 4/r32/esp -3134 # . save registers -3135 51/push-ecx -3136 56/push-esi -3137 # esi = name -3138 8b/-> *(ebp+8) 6/r32/esi -3139 # if slice-empty?(name) abort -3140 (slice-empty? %esi) # => eax -3141 3d/compare-eax-and 0/imm32 -3142 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 -3143 # var ecx: byte = *name->start -3144 8b/-> *esi 1/r32/ecx -3145 8a/copy-byte *ecx 1/r32/CL -3146 81 4/subop/and %ecx 0xff/imm32 -3147 # if is-decimal-digit?(*name->start) return new var(name) -3148 (is-decimal-digit? %ecx) # => eax -3149 81 7/subop/compare %eax 0/imm32 -3150 { -3151 74/jump-if-= break/disp8 -3152 (new-literal-integer Heap %esi) # => eax -3153 } -3154 # otherwise return lookup-var(name, vars) -3155 { -3156 75/jump-if-!= break/disp8 -3157 (lookup-var %esi *(ebp+0xc)) # => eax -3158 } -3159 $lookup-var-or-literal:end: -3160 # . restore registers -3161 5e/pop-to-esi -3162 59/pop-to-ecx -3163 # . epilogue -3164 89/<- %esp 5/r32/ebp -3165 5d/pop-to-ebp -3166 c3/return -3167 -3168 $lookup-var-or-literal:abort: -3169 (write-buffered Stderr "empty variable!") -3170 (flush Stderr) -3171 # . syscall(exit, 1) -3172 bb/copy-to-ebx 1/imm32 -3173 b8/copy-to-eax 1/imm32/exit -3174 cd/syscall 0x80/imm8 -3175 # never gets here -3176 -3177 # return first 'name' from the top (back) of 'vars' and abort if not found -3178 lookup-var: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) -3179 # . prologue -3180 55/push-ebp -3181 89/<- %ebp 4/r32/esp -3182 # var target/eax: (handle array byte) = slice-to-string(name) -3183 (slice-to-string Heap *(ebp+8)) # => eax -3184 # -3185 (lookup-var-helper %eax *(ebp+0xc)) # => eax -3186 # if (result == 0) abort -3187 3d/compare-eax-and 0/imm32 -3188 74/jump-if-= $lookup-var:abort/disp8 -3189 $lookup-var:end: -3190 # . epilogue -3191 89/<- %esp 5/r32/ebp -3192 5d/pop-to-ebp -3193 c3/return -3194 -3195 $lookup-var:abort: -3196 (write-buffered Stderr "unknown variable '") -3197 (write-slice-buffered Stderr *(ebp+8)) -3198 (write-buffered Stderr "'\n") -3199 (flush Stderr) -3200 # . syscall(exit, 1) -3201 bb/copy-to-ebx 1/imm32 -3202 b8/copy-to-eax 1/imm32/exit -3203 cd/syscall 0x80/imm8 -3204 # never gets here -3205 -3206 # return first 'name' from the top (back) of 'vars', and 0/null if not found -3207 lookup-var-helper: # name: (addr array byte), vars: (addr stack (handle var)) -> result/eax: (handle var) -3208 # pseudocode: -3209 # var curr: (addr handle var) = &vars->data[vars->top - 4] -3210 # var min = vars->data -3211 # while curr >= min -3212 # var v: (handle var) = *curr -3213 # if v->name == name -3214 # return v -3215 # return 0 -3216 # -3217 # . prologue -3218 55/push-ebp -3219 89/<- %ebp 4/r32/esp -3220 # . save registers -3221 52/push-edx -3222 53/push-ebx -3223 56/push-esi -3224 # esi = vars -3225 8b/-> *(ebp+0xc) 6/r32/esi -3226 # ebx = vars->top -3227 8b/-> *esi 3/r32/ebx -3228 # if (vars->top > vars->length) abort -3229 3b/compare 0/r32/eax *(esi+4) -3230 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 -3231 # var min/edx: (addr handle var) = vars->data -3232 8d/copy-address *(esi+8) 2/r32/edx -3233 # var curr/ebx: (addr handle var) = &vars->data[vars->top - 4] -3234 81 5/subop/subtract %ebx 4/imm32 -3235 8d/copy-address *(esi+ebx+8) 3/r32/ebx +3082 $parse-mu-stmt:abort: +3083 # error("invalid identifier '" name "'\n") +3084 (write-buffered Stderr "invalid identifier '") +3085 (write-slice-buffered Stderr %ecx) +3086 (write-buffered Stderr "'\n") +3087 (flush Stderr) +3088 # . syscall(exit, 1) +3089 bb/copy-to-ebx 1/imm32 +3090 b8/copy-to-eax 1/imm32/exit +3091 cd/syscall 0x80/imm8 +3092 # never gets here +3093 +3094 add-operation-and-inputs-to-stmt: # stmt: (handle stmt), line: (addr stream byte) +3095 # pseudocode: +3096 # stmt->name = slice-to-string(next-word(line)) +3097 # while true +3098 # name = next-word-or-string(line) +3099 # v = lookup-var-or-literal(name) +3100 # stmt->inouts = append(stmt->inouts, v) +3101 # +3102 # . prologue +3103 55/push-ebp +3104 89/<- %ebp 4/r32/esp +3105 # . save registers +3106 50/push-eax +3107 51/push-ecx +3108 57/push-edi +3109 # edi = stmt +3110 8b/-> *(ebp+8) 7/r32/edi +3111 # var name/ecx: slice +3112 68/push 0/imm32/end +3113 68/push 0/imm32/start +3114 89/<- %ecx 4/r32/esp +3115 $add-operation-and-inputs-to-stmt:read-operation: +3116 (next-word *(ebp+0xc) %ecx) +3117 (slice-to-string Heap %ecx) # => eax +3118 89/<- *(edi+4) 0/r32/eax # Stmt1-operation or Regvardef-operation +3119 { +3120 $add-operation-and-inputs-to-stmt:read-inouts: +3121 # name = next-word-or-string(line) +3122 (next-word-or-string *(ebp+0xc) %ecx) +3123 # if slice-empty?(word-slice) break +3124 (slice-empty? %ecx) # => eax +3125 3d/compare-eax-and 0/imm32 +3126 0f 85/jump-if-!= break/disp32 +3127 # if (name == "<-") abort +3128 (slice-equal? %ecx "<-") +3129 3d/compare-eax-and 0/imm32 +3130 0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32 +3131 # +3132 (lookup-var-or-literal %ecx *(ebp+0x10)) # => eax +3133 (append-list Heap %eax *(edi+8)) # Stmt1-inouts or Regvardef-inouts => eax +3134 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts +3135 e9/jump loop/disp32 +3136 } +3137 $add-operation-and-inputs-to-stmt:end: +3138 # . reclaim locals +3139 81 0/subop/add %esp 8/imm32 +3140 # . restore registers +3141 5f/pop-to-edi +3142 59/pop-to-ecx +3143 58/pop-to-eax +3144 # . epilogue +3145 89/<- %esp 5/r32/ebp +3146 5d/pop-to-ebp +3147 c3/return +3148 +3149 $add-operation-and-inputs-to-stmt:abort: +3150 # error("invalid statement '" line "'\n") +3151 (rewind-stream *(ebp+8)) +3152 (write-buffered Stderr "invalid identifier '") +3153 (flush Stderr) +3154 (write-stream 2 *(ebp+8)) +3155 (write-buffered Stderr "'\n") +3156 (flush Stderr) +3157 # . syscall(exit, 1) +3158 bb/copy-to-ebx 1/imm32 +3159 b8/copy-to-eax 1/imm32/exit +3160 cd/syscall 0x80/imm8 +3161 # never gets here +3162 +3163 stmt-has-outputs?: # line: (addr stream byte) -> result/eax: boolean +3164 # . prologue +3165 55/push-ebp +3166 89/<- %ebp 4/r32/esp +3167 # . save registers +3168 51/push-ecx +3169 # var word-slice/ecx: slice +3170 68/push 0/imm32/end +3171 68/push 0/imm32/start +3172 89/<- %ecx 4/r32/esp +3173 # result = false +3174 b8/copy-to-eax 0/imm32/false +3175 (rewind-stream *(ebp+8)) +3176 { +3177 (next-word-or-string *(ebp+8) %ecx) +3178 # if slice-empty?(word-slice) break +3179 (slice-empty? %ecx) +3180 3d/compare-eax-and 0/imm32 +3181 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +3182 0f 85/jump-if-!= break/disp32 +3183 # if slice-starts-with?(word-slice, '#') break +3184 # . eax = *word-slice->start +3185 8b/-> *ecx 0/r32/eax +3186 8a/copy-byte *eax 0/r32/AL +3187 81 4/subop/and %eax 0xff/imm32 +3188 # . if (eax == '#') break +3189 3d/compare-eax-and 0x23/imm32/hash +3190 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +3191 0f 84/jump-if-= break/disp32 +3192 # if slice-equal?(word-slice, '<-') return true +3193 (slice-equal? %ecx "<-") +3194 3d/compare-eax-and 0/imm32 +3195 74/jump-if-= loop/disp8 +3196 b8/copy-to-eax 1/imm32/true +3197 } +3198 $stmt-has-outputs:end: +3199 (rewind-stream *(ebp+8)) +3200 # . reclaim locals +3201 81 0/subop/add %esp 8/imm32 +3202 # . restore registers +3203 59/pop-to-ecx +3204 # . epilogue +3205 89/<- %esp 5/r32/ebp +3206 5d/pop-to-ebp +3207 c3/return +3208 +3209 # if 'name' starts with a digit, create a new literal var for it +3210 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found +3211 lookup-var-or-literal: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) +3212 # . prologue +3213 55/push-ebp +3214 89/<- %ebp 4/r32/esp +3215 # . save registers +3216 51/push-ecx +3217 56/push-esi +3218 # esi = name +3219 8b/-> *(ebp+8) 6/r32/esi +3220 # if slice-empty?(name) abort +3221 (slice-empty? %esi) # => eax +3222 3d/compare-eax-and 0/imm32 +3223 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 +3224 # var ecx: byte = *name->start +3225 8b/-> *esi 1/r32/ecx +3226 8a/copy-byte *ecx 1/r32/CL +3227 81 4/subop/and %ecx 0xff/imm32 +3228 # if is-decimal-digit?(*name->start) return new var(name) +3229 (is-decimal-digit? %ecx) # => eax +3230 81 7/subop/compare %eax 0/imm32 +3231 { +3232 74/jump-if-= break/disp8 +3233 (new-literal-integer Heap %esi) # => eax +3234 } +3235 # otherwise return lookup-var(name, vars) 3236 { -3237 # if (curr < min) return 0 -3238 39/compare %ebx 2/r32/edx -3239 b8/copy-to-eax 0/imm32 -3240 0f 82/jump-if-addr< break/disp32 -3241 # var v/eax: (handle var) = *curr -3242 8b/-> *ebx 0/r32/eax -3243 # if (v->name == name) return v -3244 (string-equal? *eax *(ebp+8)) # Var-name -3245 3d/compare-eax-and 0/imm32 -3246 8b/-> *ebx 0/r32/eax -3247 75/jump-if-!= break/disp8 -3248 # curr -= 4 -3249 81 5/subop/subtract %ebx 4/imm32 -3250 e9/jump loop/disp32 -3251 } -3252 $lookup-var-helper:end: -3253 # . restore registers -3254 5e/pop-to-esi -3255 5b/pop-to-ebx -3256 5a/pop-to-edx -3257 # . epilogue -3258 89/<- %esp 5/r32/ebp -3259 5d/pop-to-ebp -3260 c3/return -3261 -3262 $lookup-var-helper:error1: -3263 (write-buffered Stderr "malformed stack when looking up '") -3264 (write-slice-buffered Stderr *(ebp+8)) -3265 (write-buffered Stderr "'\n") -3266 (flush Stderr) -3267 # . syscall(exit, 1) -3268 bb/copy-to-ebx 1/imm32 -3269 b8/copy-to-eax 1/imm32/exit -3270 cd/syscall 0x80/imm8 -3271 # never gets here -3272 -3273 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found -3274 lookup-or-define-var: # name: (addr slice), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle var) -3275 # . prologue -3276 55/push-ebp -3277 89/<- %ebp 4/r32/esp -3278 # . save registers -3279 51/push-ecx -3280 # var target/ecx: (handle array byte) = slice-to-string(name) -3281 (slice-to-string Heap *(ebp+8)) # => eax -3282 89/<- %ecx 0/r32/eax -3283 # -3284 (lookup-var-helper *(ebp+8) *(ebp+0xc)) # => eax -3285 { -3286 # if (result != 0) return -3287 3d/compare-eax-and 0/imm32 -3288 75/jump-if-!= break/disp8 -3289 # if name is one of fn's outputs, return it -3290 { -3291 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax -3292 3d/compare-eax-and 0/imm32 -3293 # otherwise abort -3294 0f 84/jump-if-!= $lookup-var:abort/disp32 -3295 } -3296 } -3297 $lookup-or-define-var:end: -3298 # . restore registers -3299 59/pop-to-ecx -3300 # . epilogue -3301 89/<- %esp 5/r32/ebp -3302 5d/pop-to-ebp -3303 c3/return -3304 -3305 find-in-function-outputs: # fn: (handle function), name: (handle array byte) => result/eax: (handle var) -3306 # . prologue -3307 55/push-ebp -3308 89/<- %ebp 4/r32/esp -3309 # . save registers -3310 51/push-ecx -3311 # var curr/ecx: (handle list var) = fn->outputs -3312 8b/-> *(ebp+8) 1/r32/ecx -3313 8b/-> *(ecx+0xc) 1/r32/ecx -3314 # while curr != null -3315 { -3316 81 7/subop/compare %ecx 0/imm32 -3317 74/jump-if-= break/disp8 -3318 # var v: (handle var) = *curr -3319 8b/-> *ecx 0/r32/eax # List-value -3320 # if (curr->name == name) return curr -3321 50/push-eax -3322 (string-equal? *eax *(ebp+0xc)) -3323 3d/compare-eax-and 0/imm32 -3324 58/pop-to-eax -3325 75/jump-if-!= $find-in-function-outputs:end/disp8 -3326 # curr = curr->next -3327 8b/-> *(ecx+4) 1/r32/ecx # List-next -3328 eb/jump loop/disp8 -3329 } -3330 b8/copy-to-eax 0/imm32 -3331 $find-in-function-outputs:end: -3332 # . restore registers -3333 59/pop-to-ecx -3334 # . epilogue -3335 89/<- %esp 5/r32/ebp -3336 5d/pop-to-ebp -3337 c3/return -3338 -3339 test-parse-mu-stmt: -3340 # 'increment n' -3341 # . prologue -3342 55/push-ebp -3343 89/<- %ebp 4/r32/esp -3344 # setup -3345 (clear-stream _test-input-stream) -3346 (write _test-input-stream "increment n\n") -3347 # var vars/ecx: (stack (addr var) 4) -3348 81 5/subop/subtract %esp 0x10/imm32 -3349 68/push 0x10/imm32/length -3350 68/push 0/imm32/top -3351 89/<- %ecx 4/r32/esp -3352 (clear-stack %ecx) -3353 # var v/edx: var -3354 81 5/subop/subtract %esp 0x14/imm32 # Var-size -3355 89/<- %edx 4/r32/esp -3356 (zero-out %edx 0x14) -3357 # v->name = "n" -3358 c7 0/subop/copy *edx "n"/imm32 # Var-name -3359 # -3360 (push %ecx %edx) -3361 # convert -3362 (parse-mu-stmt _test-input-stream %ecx) # => eax -3363 # check result -3364 (check-ints-equal *eax 1 "F - test-parse-mu-stmt/tag") # Stmt-tag is Stmt1 -3365 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation -3366 # edx: (handle list var) = result->inouts -3367 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts -3368 # ebx: (handle var) = result->inouts->value -3369 8b/-> *edx 3/r32/ebx # List-value -3370 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name -3371 # . epilogue -3372 89/<- %esp 5/r32/ebp -3373 5d/pop-to-ebp -3374 c3/return -3375 -3376 new-function: # ad: (addr allocation-descriptor), name: (addr array byte), subx-name: (addr array byte), inouts: (handle list var), outputs: (handle list var), body: (handle block), next: (handle function) -> result/eax: (handle function) -3377 # . prologue -3378 55/push-ebp -3379 89/<- %ebp 4/r32/esp -3380 # . save registers -3381 51/push-ecx -3382 # -3383 (allocate *(ebp+8) *Function-size) # => eax -3384 8b/-> *(ebp+0xc) 1/r32/ecx -3385 89/<- *eax 1/r32/ecx # Function-name -3386 8b/-> *(ebp+0x10) 1/r32/ecx -3387 89/<- *(eax+4) 1/r32/ecx # Function-subx-name -3388 8b/-> *(ebp+0x14) 1/r32/ecx -3389 89/<- *(eax+8) 1/r32/ecx # Function-inouts -3390 8b/-> *(ebp+0x18) 1/r32/ecx -3391 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs -3392 8b/-> *(ebp+0x1c) 1/r32/ecx -3393 89/<- *(eax+0x10) 1/r32/ecx # Function-body -3394 8b/-> *(ebp+0x20) 1/r32/ecx -3395 89/<- *(eax+0x14) 1/r32/ecx # Function-next -3396 $new-function:end: -3397 # . restore registers -3398 59/pop-to-ecx -3399 # . epilogue -3400 89/<- %esp 5/r32/ebp -3401 5d/pop-to-ebp -3402 c3/return -3403 -3404 new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, block: int, stack-offset: int, register: (addr array byte) -> result/eax: (handle var) -3405 # . prologue -3406 55/push-ebp -3407 89/<- %ebp 4/r32/esp -3408 # . save registers -3409 51/push-ecx -3410 # -3411 (allocate *(ebp+8) *Var-size) # => eax -3412 8b/-> *(ebp+0xc) 1/r32/ecx -3413 89/<- *eax 1/r32/ecx # Var-name -3414 8b/-> *(ebp+0x10) 1/r32/ecx -3415 89/<- *(eax+4) 1/r32/ecx # Var-type -3416 8b/-> *(ebp+0x14) 1/r32/ecx -3417 89/<- *(eax+8) 1/r32/ecx # Var-block -3418 8b/-> *(ebp+0x18) 1/r32/ecx -3419 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset -3420 8b/-> *(ebp+0x1c) 1/r32/ecx -3421 89/<- *(eax+0x10) 1/r32/ecx # Var-register -3422 $new-var:end: -3423 # . restore registers -3424 59/pop-to-ecx -3425 # . epilogue -3426 89/<- %esp 5/r32/ebp -3427 5d/pop-to-ebp -3428 c3/return -3429 -3430 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) -3431 # . prologue -3432 55/push-ebp -3433 89/<- %ebp 4/r32/esp -3434 # . save registers -3435 51/push-ecx -3436 # if (!is-hex-int?(name)) abort -3437 (is-hex-int? *(ebp+0xc)) # => eax -3438 3d/compare-eax-and 0/imm32 -3439 0f 84/jump-if-= $new-literal-integer:abort/disp32 -3440 # var s/ecx: (addr array byte) -3441 (slice-to-string Heap *(ebp+0xc)) # => eax -3442 89/<- %ecx 0/r32/eax -3443 # -3444 (allocate *(ebp+8) *Var-size) # => eax -3445 89/<- *eax 1/r32/ecx # Var-name -3446 89/<- %ecx 0/r32/eax -3447 (allocate *(ebp+8) *Tree-size) # => eax -3448 89/<- *(ecx+4) 0/r32/eax # Var-type -3449 89/<- %eax 1/r32/ecx -3450 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block -3451 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset -3452 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register -3453 $new-literal-integer:end: -3454 # . restore registers -3455 59/pop-to-ecx -3456 # . epilogue -3457 89/<- %esp 5/r32/ebp -3458 5d/pop-to-ebp -3459 c3/return -3460 -3461 $new-literal-integer:abort: -3462 (write-buffered Stderr "variable cannot begin with a digit '") -3463 (write-slice-buffered Stderr *(ebp+0xc)) -3464 (write-buffered Stderr "'\n") -3465 (flush Stderr) -3466 # . syscall(exit, 1) -3467 bb/copy-to-ebx 1/imm32 -3468 b8/copy-to-eax 1/imm32/exit -3469 cd/syscall 0x80/imm8 -3470 # never gets here -3471 -3472 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) -3473 # . prologue -3474 55/push-ebp -3475 89/<- %ebp 4/r32/esp -3476 # . save registers -3477 51/push-ecx -3478 # -3479 (allocate *(ebp+8) *Stmt-size) # => eax -3480 (zero-out %eax *Stmt-size) -3481 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag -3482 8b/-> *(ebp+0xc) 1/r32/ecx -3483 89/<- *(eax+4) 1/r32/ecx # Block-statements -3484 $new-block:end: -3485 # . restore registers -3486 59/pop-to-ecx -3487 # . epilogue -3488 89/<- %esp 5/r32/ebp -3489 5d/pop-to-ebp -3490 c3/return -3491 -3492 new-vardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) -3493 # . prologue -3494 55/push-ebp -3495 89/<- %ebp 4/r32/esp -3496 # . save registers -3497 51/push-ecx -3498 # -3499 (allocate *(ebp+8) *Stmt-size) # => eax -3500 (zero-out %eax *Stmt-size) -3501 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag -3502 # result->var = var -3503 8b/-> *(ebp+0xc) 1/r32/ecx -3504 89/<- *(eax+4) 1/r32/ecx # Vardef-var -3505 $new-vardef:end: -3506 # . restore registers -3507 59/pop-to-ecx -3508 # . epilogue -3509 89/<- %esp 5/r32/ebp -3510 5d/pop-to-ebp -3511 c3/return -3512 -3513 new-regvardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) -3514 # . prologue -3515 55/push-ebp -3516 89/<- %ebp 4/r32/esp -3517 # . save registers -3518 51/push-ecx -3519 # -3520 (allocate *(ebp+8) *Stmt-size) # => eax -3521 (zero-out %eax *Stmt-size) -3522 c7 0/subop/copy *eax 3/imm32/tag/var-in-register # Stmt-tag -3523 8b/-> *(ebp+0xc) 1/r32/ecx -3524 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-var -3525 $new-regvardef:end: -3526 # . restore registers -3527 59/pop-to-ecx -3528 # . epilogue -3529 89/<- %esp 5/r32/ebp -3530 5d/pop-to-ebp -3531 c3/return -3532 -3533 new-named-block: # ad: (addr allocation-descriptor), name: (addr array byte), data: (handle list statement) -> result/eax: (handle statement) -3534 # . prologue -3535 55/push-ebp -3536 89/<- %ebp 4/r32/esp -3537 # . save registers -3538 51/push-ecx -3539 # -3540 (allocate *(ebp+8) *Stmt-size) # => eax -3541 (zero-out %eax *Stmt-size) -3542 c7 0/subop/copy *eax 4/imm32/tag/named-block -3543 8b/-> *(ebp+0xc) 1/r32/ecx -3544 89/<- *(eax+4) 1/r32/ecx # Named-block-name -3545 8b/-> *(ebp+0x10) 1/r32/ecx -3546 89/<- *(eax+8) 1/r32/ecx # Named-block-statements -3547 $new-named-block:end: -3548 # . restore registers -3549 59/pop-to-ecx -3550 # . epilogue -3551 89/<- %esp 5/r32/ebp -3552 5d/pop-to-ebp -3553 c3/return -3554 -3555 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax: (handle list _type) -3556 # . prologue -3557 55/push-ebp -3558 89/<- %ebp 4/r32/esp -3559 # . save registers -3560 51/push-ecx -3561 # -3562 (allocate *(ebp+8) *List-size) # => eax +3237 75/jump-if-!= break/disp8 +3238 (lookup-var %esi *(ebp+0xc)) # => eax +3239 } +3240 $lookup-var-or-literal:end: +3241 # . restore registers +3242 5e/pop-to-esi +3243 59/pop-to-ecx +3244 # . epilogue +3245 89/<- %esp 5/r32/ebp +3246 5d/pop-to-ebp +3247 c3/return +3248 +3249 $lookup-var-or-literal:abort: +3250 (write-buffered Stderr "empty variable!") +3251 (flush Stderr) +3252 # . syscall(exit, 1) +3253 bb/copy-to-ebx 1/imm32 +3254 b8/copy-to-eax 1/imm32/exit +3255 cd/syscall 0x80/imm8 +3256 # never gets here +3257 +3258 # return first 'name' from the top (back) of 'vars' and abort if not found +3259 lookup-var: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) +3260 # . prologue +3261 55/push-ebp +3262 89/<- %ebp 4/r32/esp +3263 # var target/eax: (handle array byte) = slice-to-string(name) +3264 (slice-to-string Heap *(ebp+8)) # => eax +3265 # +3266 (lookup-var-helper %eax *(ebp+0xc)) # => eax +3267 # if (result == 0) abort +3268 3d/compare-eax-and 0/imm32 +3269 74/jump-if-= $lookup-var:abort/disp8 +3270 $lookup-var:end: +3271 # . epilogue +3272 89/<- %esp 5/r32/ebp +3273 5d/pop-to-ebp +3274 c3/return +3275 +3276 $lookup-var:abort: +3277 (write-buffered Stderr "unknown variable '") +3278 (write-slice-buffered Stderr *(ebp+8)) +3279 (write-buffered Stderr "'\n") +3280 (flush Stderr) +3281 # . syscall(exit, 1) +3282 bb/copy-to-ebx 1/imm32 +3283 b8/copy-to-eax 1/imm32/exit +3284 cd/syscall 0x80/imm8 +3285 # never gets here +3286 +3287 # return first 'name' from the top (back) of 'vars', and 0/null if not found +3288 lookup-var-helper: # name: (addr array byte), vars: (addr stack (handle var)) -> result/eax: (handle var) +3289 # pseudocode: +3290 # var curr: (addr handle var) = &vars->data[vars->top - 4] +3291 # var min = vars->data +3292 # while curr >= min +3293 # var v: (handle var) = *curr +3294 # if v->name == name +3295 # return v +3296 # return 0 +3297 # +3298 # . prologue +3299 55/push-ebp +3300 89/<- %ebp 4/r32/esp +3301 # . save registers +3302 52/push-edx +3303 53/push-ebx +3304 56/push-esi +3305 # esi = vars +3306 8b/-> *(ebp+0xc) 6/r32/esi +3307 # ebx = vars->top +3308 8b/-> *esi 3/r32/ebx +3309 # if (vars->top > vars->length) abort +3310 3b/compare 0/r32/eax *(esi+4) +3311 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 +3312 # var min/edx: (addr handle var) = vars->data +3313 8d/copy-address *(esi+8) 2/r32/edx +3314 # var curr/ebx: (addr handle var) = &vars->data[vars->top - 4] +3315 81 5/subop/subtract %ebx 4/imm32 +3316 8d/copy-address *(esi+ebx+8) 3/r32/ebx +3317 { +3318 # if (curr < min) return 0 +3319 39/compare %ebx 2/r32/edx +3320 b8/copy-to-eax 0/imm32 +3321 0f 82/jump-if-addr< break/disp32 +3322 # var v/eax: (handle var) = *curr +3323 8b/-> *ebx 0/r32/eax +3324 # if (v->name == name) return v +3325 (string-equal? *eax *(ebp+8)) # Var-name +3326 3d/compare-eax-and 0/imm32 +3327 8b/-> *ebx 0/r32/eax +3328 75/jump-if-!= break/disp8 +3329 # curr -= 4 +3330 81 5/subop/subtract %ebx 4/imm32 +3331 e9/jump loop/disp32 +3332 } +3333 $lookup-var-helper:end: +3334 # . restore registers +3335 5e/pop-to-esi +3336 5b/pop-to-ebx +3337 5a/pop-to-edx +3338 # . epilogue +3339 89/<- %esp 5/r32/ebp +3340 5d/pop-to-ebp +3341 c3/return +3342 +3343 $lookup-var-helper:error1: +3344 (write-buffered Stderr "malformed stack when looking up '") +3345 (write-slice-buffered Stderr *(ebp+8)) +3346 (write-buffered Stderr "'\n") +3347 (flush Stderr) +3348 # . syscall(exit, 1) +3349 bb/copy-to-ebx 1/imm32 +3350 b8/copy-to-eax 1/imm32/exit +3351 cd/syscall 0x80/imm8 +3352 # never gets here +3353 +3354 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found +3355 lookup-or-define-var: # name: (addr slice), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle var) +3356 # . prologue +3357 55/push-ebp +3358 89/<- %ebp 4/r32/esp +3359 # . save registers +3360 51/push-ecx +3361 # var target/ecx: (handle array byte) = slice-to-string(name) +3362 (slice-to-string Heap *(ebp+8)) # => eax +3363 89/<- %ecx 0/r32/eax +3364 # +3365 (lookup-var-helper *(ebp+8) *(ebp+0xc)) # => eax +3366 { +3367 # if (result != 0) return +3368 3d/compare-eax-and 0/imm32 +3369 75/jump-if-!= break/disp8 +3370 # if name is one of fn's outputs, return it +3371 { +3372 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax +3373 3d/compare-eax-and 0/imm32 +3374 # otherwise abort +3375 0f 84/jump-if-!= $lookup-var:abort/disp32 +3376 } +3377 } +3378 $lookup-or-define-var:end: +3379 # . restore registers +3380 59/pop-to-ecx +3381 # . epilogue +3382 89/<- %esp 5/r32/ebp +3383 5d/pop-to-ebp +3384 c3/return +3385 +3386 find-in-function-outputs: # fn: (handle function), name: (handle array byte) => result/eax: (handle var) +3387 # . prologue +3388 55/push-ebp +3389 89/<- %ebp 4/r32/esp +3390 # . save registers +3391 51/push-ecx +3392 # var curr/ecx: (handle list var) = fn->outputs +3393 8b/-> *(ebp+8) 1/r32/ecx +3394 8b/-> *(ecx+0xc) 1/r32/ecx +3395 # while curr != null +3396 { +3397 81 7/subop/compare %ecx 0/imm32 +3398 74/jump-if-= break/disp8 +3399 # var v: (handle var) = *curr +3400 8b/-> *ecx 0/r32/eax # List-value +3401 # if (curr->name == name) return curr +3402 50/push-eax +3403 (string-equal? *eax *(ebp+0xc)) +3404 3d/compare-eax-and 0/imm32 +3405 58/pop-to-eax +3406 75/jump-if-!= $find-in-function-outputs:end/disp8 +3407 # curr = curr->next +3408 8b/-> *(ecx+4) 1/r32/ecx # List-next +3409 eb/jump loop/disp8 +3410 } +3411 b8/copy-to-eax 0/imm32 +3412 $find-in-function-outputs:end: +3413 # . restore registers +3414 59/pop-to-ecx +3415 # . epilogue +3416 89/<- %esp 5/r32/ebp +3417 5d/pop-to-ebp +3418 c3/return +3419 +3420 test-parse-mu-stmt: +3421 # 'increment n' +3422 # . prologue +3423 55/push-ebp +3424 89/<- %ebp 4/r32/esp +3425 # setup +3426 (clear-stream _test-input-stream) +3427 (write _test-input-stream "increment n\n") +3428 # var vars/ecx: (stack (addr var) 4) +3429 81 5/subop/subtract %esp 0x10/imm32 +3430 68/push 0x10/imm32/length +3431 68/push 0/imm32/top +3432 89/<- %ecx 4/r32/esp +3433 (clear-stack %ecx) +3434 # var v/edx: var +3435 81 5/subop/subtract %esp 0x14/imm32 # Var-size +3436 89/<- %edx 4/r32/esp +3437 (zero-out %edx 0x14) +3438 # v->name = "n" +3439 c7 0/subop/copy *edx "n"/imm32 # Var-name +3440 # +3441 (push %ecx %edx) +3442 # convert +3443 (parse-mu-stmt _test-input-stream %ecx) # => eax +3444 # check result +3445 (check-ints-equal *eax 1 "F - test-parse-mu-stmt/tag") # Stmt-tag is Stmt1 +3446 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation +3447 # edx: (handle list var) = result->inouts +3448 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts +3449 # ebx: (handle var) = result->inouts->value +3450 8b/-> *edx 3/r32/ebx # List-value +3451 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name +3452 # . epilogue +3453 89/<- %esp 5/r32/ebp +3454 5d/pop-to-ebp +3455 c3/return +3456 +3457 new-function: # ad: (addr allocation-descriptor), name: (addr array byte), subx-name: (addr array byte), inouts: (handle list var), outputs: (handle list var), body: (handle block), next: (handle function) -> result/eax: (handle function) +3458 # . prologue +3459 55/push-ebp +3460 89/<- %ebp 4/r32/esp +3461 # . save registers +3462 51/push-ecx +3463 # +3464 (allocate *(ebp+8) *Function-size) # => eax +3465 8b/-> *(ebp+0xc) 1/r32/ecx +3466 89/<- *eax 1/r32/ecx # Function-name +3467 8b/-> *(ebp+0x10) 1/r32/ecx +3468 89/<- *(eax+4) 1/r32/ecx # Function-subx-name +3469 8b/-> *(ebp+0x14) 1/r32/ecx +3470 89/<- *(eax+8) 1/r32/ecx # Function-inouts +3471 8b/-> *(ebp+0x18) 1/r32/ecx +3472 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs +3473 8b/-> *(ebp+0x1c) 1/r32/ecx +3474 89/<- *(eax+0x10) 1/r32/ecx # Function-body +3475 8b/-> *(ebp+0x20) 1/r32/ecx +3476 89/<- *(eax+0x14) 1/r32/ecx # Function-next +3477 $new-function:end: +3478 # . restore registers +3479 59/pop-to-ecx +3480 # . epilogue +3481 89/<- %esp 5/r32/ebp +3482 5d/pop-to-ebp +3483 c3/return +3484 +3485 new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, block: int, stack-offset: int, register: (addr array byte) -> result/eax: (handle var) +3486 # . prologue +3487 55/push-ebp +3488 89/<- %ebp 4/r32/esp +3489 # . save registers +3490 51/push-ecx +3491 # +3492 (allocate *(ebp+8) *Var-size) # => eax +3493 8b/-> *(ebp+0xc) 1/r32/ecx +3494 89/<- *eax 1/r32/ecx # Var-name +3495 8b/-> *(ebp+0x10) 1/r32/ecx +3496 89/<- *(eax+4) 1/r32/ecx # Var-type +3497 8b/-> *(ebp+0x14) 1/r32/ecx +3498 89/<- *(eax+8) 1/r32/ecx # Var-block +3499 8b/-> *(ebp+0x18) 1/r32/ecx +3500 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset +3501 8b/-> *(ebp+0x1c) 1/r32/ecx +3502 89/<- *(eax+0x10) 1/r32/ecx # Var-register +3503 $new-var:end: +3504 # . restore registers +3505 59/pop-to-ecx +3506 # . epilogue +3507 89/<- %esp 5/r32/ebp +3508 5d/pop-to-ebp +3509 c3/return +3510 +3511 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) +3512 # . prologue +3513 55/push-ebp +3514 89/<- %ebp 4/r32/esp +3515 # . save registers +3516 51/push-ecx +3517 # if (!is-hex-int?(name)) abort +3518 (is-hex-int? *(ebp+0xc)) # => eax +3519 3d/compare-eax-and 0/imm32 +3520 0f 84/jump-if-= $new-literal-integer:abort/disp32 +3521 # var s/ecx: (addr array byte) +3522 (slice-to-string Heap *(ebp+0xc)) # => eax +3523 89/<- %ecx 0/r32/eax +3524 # +3525 (allocate *(ebp+8) *Var-size) # => eax +3526 89/<- *eax 1/r32/ecx # Var-name +3527 89/<- %ecx 0/r32/eax +3528 (allocate *(ebp+8) *Tree-size) # => eax +3529 89/<- *(ecx+4) 0/r32/eax # Var-type +3530 89/<- %eax 1/r32/ecx +3531 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block +3532 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset +3533 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register +3534 $new-literal-integer:end: +3535 # . restore registers +3536 59/pop-to-ecx +3537 # . epilogue +3538 89/<- %esp 5/r32/ebp +3539 5d/pop-to-ebp +3540 c3/return +3541 +3542 $new-literal-integer:abort: +3543 (write-buffered Stderr "variable cannot begin with a digit '") +3544 (write-slice-buffered Stderr *(ebp+0xc)) +3545 (write-buffered Stderr "'\n") +3546 (flush Stderr) +3547 # . syscall(exit, 1) +3548 bb/copy-to-ebx 1/imm32 +3549 b8/copy-to-eax 1/imm32/exit +3550 cd/syscall 0x80/imm8 +3551 # never gets here +3552 +3553 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) +3554 # . prologue +3555 55/push-ebp +3556 89/<- %ebp 4/r32/esp +3557 # . save registers +3558 51/push-ecx +3559 # +3560 (allocate *(ebp+8) *Stmt-size) # => eax +3561 (zero-out %eax *Stmt-size) +3562 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag 3563 8b/-> *(ebp+0xc) 1/r32/ecx -3564 89/<- *eax 1/r32/ecx # List-value -3565 8b/-> *(ebp+0x10) 1/r32/ecx -3566 89/<- *(eax+4) 1/r32/ecx # List-next -3567 $new-list:end: -3568 # . restore registers -3569 59/pop-to-ecx -3570 # . epilogue -3571 89/<- %esp 5/r32/ebp -3572 5d/pop-to-ebp -3573 c3/return -3574 -3575 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax: (handle list _type) -3576 # . prologue -3577 55/push-ebp -3578 89/<- %ebp 4/r32/esp -3579 # . save registers -3580 51/push-ecx -3581 # -3582 (allocate *(ebp+8) *List-size) # => eax -3583 8b/-> *(ebp+0xc) 1/r32/ecx -3584 89/<- *eax 1/r32/ecx # List-value -3585 # if (list == null) return result -3586 81 7/subop/compare *(ebp+0x10) 0/imm32 -3587 74/jump-if-= $new-list:end/disp8 -3588 # otherwise append -3589 # var curr/ecx = list -3590 8b/-> *(ebp+0x10) 1/r32/ecx -3591 # while (curr->next != null) curr = curr->next -3592 { -3593 81 7/subop/compare *(ecx+4) 0/imm32 # List-next -3594 74/jump-if-= break/disp8 -3595 # curr = curr->next -3596 8b/-> *(ecx+4) 1/r32/ecx -3597 eb/jump loop/disp8 -3598 } -3599 # curr->next = result -3600 89/<- *(ecx+4) 0/r32/eax -3601 # return list -3602 8b/-> *(ebp+0x10) 0/r32/eax -3603 $append-list:end: -3604 # . restore registers -3605 59/pop-to-ecx -3606 # . epilogue -3607 89/<- %esp 5/r32/ebp -3608 5d/pop-to-ebp -3609 c3/return -3610 -3611 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) -3612 # . prologue -3613 55/push-ebp -3614 89/<- %ebp 4/r32/esp -3615 # . save registers -3616 56/push-esi -3617 # esi = block -3618 8b/-> *(ebp+0xc) 6/r32/esi -3619 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements -3620 89/<- *(esi+4) 0/r32/eax # Block-statements -3621 $append-to-block:end: -3622 # . restore registers -3623 5e/pop-to-esi -3624 # . epilogue -3625 89/<- %esp 5/r32/ebp -3626 5d/pop-to-ebp -3627 c3/return -3628 -3629 ####################################################### -3630 # Type-checking -3631 ####################################################### -3632 -3633 check-mu-types: -3634 # . prologue -3635 55/push-ebp -3636 89/<- %ebp 4/r32/esp -3637 # -3638 $check-mu-types:end: -3639 # . epilogue -3640 89/<- %esp 5/r32/ebp -3641 5d/pop-to-ebp -3642 c3/return -3643 -3644 size-of: # n: (addr var) -3645 # . prologue -3646 55/push-ebp -3647 89/<- %ebp 4/r32/esp -3648 # hard-coded since we only support 'int' types for now -3649 b8/copy-to-eax 4/imm32 -3650 $size-of:end: +3564 89/<- *(eax+4) 1/r32/ecx # Block-statements +3565 $new-block:end: +3566 # . restore registers +3567 59/pop-to-ecx +3568 # . epilogue +3569 89/<- %esp 5/r32/ebp +3570 5d/pop-to-ebp +3571 c3/return +3572 +3573 new-vardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) +3574 # . prologue +3575 55/push-ebp +3576 89/<- %ebp 4/r32/esp +3577 # . save registers +3578 51/push-ecx +3579 # +3580 (allocate *(ebp+8) *Stmt-size) # => eax +3581 (zero-out %eax *Stmt-size) +3582 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag +3583 # result->var = var +3584 8b/-> *(ebp+0xc) 1/r32/ecx +3585 89/<- *(eax+4) 1/r32/ecx # Vardef-var +3586 $new-vardef:end: +3587 # . restore registers +3588 59/pop-to-ecx +3589 # . epilogue +3590 89/<- %esp 5/r32/ebp +3591 5d/pop-to-ebp +3592 c3/return +3593 +3594 new-regvardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) +3595 # . prologue +3596 55/push-ebp +3597 89/<- %ebp 4/r32/esp +3598 # . save registers +3599 51/push-ecx +3600 # +3601 (allocate *(ebp+8) *Stmt-size) # => eax +3602 (zero-out %eax *Stmt-size) +3603 c7 0/subop/copy *eax 3/imm32/tag/var-in-register # Stmt-tag +3604 8b/-> *(ebp+0xc) 1/r32/ecx +3605 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-var +3606 $new-regvardef:end: +3607 # . restore registers +3608 59/pop-to-ecx +3609 # . epilogue +3610 89/<- %esp 5/r32/ebp +3611 5d/pop-to-ebp +3612 c3/return +3613 +3614 new-named-block: # ad: (addr allocation-descriptor), name: (addr array byte), data: (handle list statement) -> result/eax: (handle statement) +3615 # . prologue +3616 55/push-ebp +3617 89/<- %ebp 4/r32/esp +3618 # . save registers +3619 51/push-ecx +3620 # +3621 (allocate *(ebp+8) *Stmt-size) # => eax +3622 (zero-out %eax *Stmt-size) +3623 c7 0/subop/copy *eax 4/imm32/tag/named-block +3624 8b/-> *(ebp+0xc) 1/r32/ecx +3625 89/<- *(eax+4) 1/r32/ecx # Named-block-name +3626 8b/-> *(ebp+0x10) 1/r32/ecx +3627 89/<- *(eax+8) 1/r32/ecx # Named-block-statements +3628 $new-named-block:end: +3629 # . restore registers +3630 59/pop-to-ecx +3631 # . epilogue +3632 89/<- %esp 5/r32/ebp +3633 5d/pop-to-ebp +3634 c3/return +3635 +3636 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax: (handle list _type) +3637 # . prologue +3638 55/push-ebp +3639 89/<- %ebp 4/r32/esp +3640 # . save registers +3641 51/push-ecx +3642 # +3643 (allocate *(ebp+8) *List-size) # => eax +3644 8b/-> *(ebp+0xc) 1/r32/ecx +3645 89/<- *eax 1/r32/ecx # List-value +3646 8b/-> *(ebp+0x10) 1/r32/ecx +3647 89/<- *(eax+4) 1/r32/ecx # List-next +3648 $new-list:end: +3649 # . restore registers +3650 59/pop-to-ecx 3651 # . epilogue 3652 89/<- %esp 5/r32/ebp 3653 5d/pop-to-ebp 3654 c3/return 3655 -3656 ####################################################### -3657 # Code-generation -3658 ####################################################### -3659 -3660 emit-subx: # out: (addr buffered-file) -3661 # . prologue -3662 55/push-ebp -3663 89/<- %ebp 4/r32/esp -3664 # . save registers -3665 50/push-eax -3666 51/push-ecx -3667 57/push-edi -3668 # edi = out -3669 8b/-> *(ebp+8) 7/r32/edi -3670 # var curr/ecx: (handle function) = *Program -3671 8b/-> *Program 1/r32/ecx -3672 { -3673 # if (curr == null) break -3674 81 7/subop/compare %ecx 0/imm32 -3675 0f 84/jump-if-= break/disp32 -3676 (emit-subx-function %edi %ecx) -3677 # curr = curr->next -3678 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -3679 e9/jump loop/disp32 -3680 } -3681 $emit-subx:end: -3682 # . restore registers -3683 5f/pop-to-edi -3684 59/pop-to-ecx -3685 58/pop-to-eax -3686 # . epilogue -3687 89/<- %esp 5/r32/ebp -3688 5d/pop-to-ebp -3689 c3/return -3690 -3691 emit-subx-function: # out: (addr buffered-file), f: (handle function) -3692 # . prologue -3693 55/push-ebp -3694 89/<- %ebp 4/r32/esp -3695 # . save registers -3696 50/push-eax -3697 51/push-ecx -3698 57/push-edi -3699 # edi = out -3700 8b/-> *(ebp+8) 7/r32/edi -3701 # ecx = f -3702 8b/-> *(ebp+0xc) 1/r32/ecx -3703 # -3704 (write-buffered %edi *ecx) -3705 (write-buffered %edi ":\n") -3706 (emit-subx-prologue %edi) -3707 (emit-subx-block %edi *(ecx+0x10)) # Function-body -3708 (emit-subx-epilogue %edi) -3709 $emit-subx-function:end: -3710 # . restore registers -3711 5f/pop-to-edi -3712 59/pop-to-ecx -3713 58/pop-to-eax -3714 # . epilogue -3715 89/<- %esp 5/r32/ebp -3716 5d/pop-to-ebp -3717 c3/return -3718 -3719 emit-subx-block: # out: (addr buffered-file), block: (handle block) -3720 # . prologue -3721 55/push-ebp -3722 89/<- %ebp 4/r32/esp -3723 # . save registers -3724 50/push-eax -3725 56/push-esi -3726 # var stmts/esi: (handle list statement) = block->statements -3727 8b/-> *(ebp+0xc) 6/r32/esi -3728 8b/-> *(esi+4) 6/r32/esi # Block-statements -3729 # -3730 { -3731 $emit-subx-block:check-empty: -3732 81 7/subop/compare %esi 0/imm32 -3733 0f 84/jump-if-= break/disp32 -3734 (write-buffered *(ebp+8) "{\n") -3735 { -3736 $emit-subx-block:loop: -3737 81 7/subop/compare %esi 0/imm32 -3738 74/jump-if-= break/disp8 -3739 # var curr/eax = stmts->value -3740 8b/-> *esi 0/r32/eax # List-value -3741 { -3742 $emit-subx-block:check-for-block: -3743 81 7/subop/compare *eax 0/imm32/block # Stmt-tag -3744 75/jump-if-not-equal break/disp8 -3745 $emit-subx-block:block: -3746 # TODO -3747 } -3748 { -3749 $emit-subx-block:check-for-stmt: -3750 81 7/subop/compare *eax 1/imm32/stmt1 # Stmt-tag -3751 75/jump-if-not-equal break/disp8 -3752 $emit-subx-block:stmt: -3753 (emit-subx-statement *(ebp+8) %eax Primitives *Program) -3754 } -3755 { -3756 $emit-subx-block:check-for-vardef: -3757 81 7/subop/compare *eax 2/imm32/vardef # Stmt-tag -3758 75/jump-if-not-equal break/disp8 -3759 $emit-subx-block:vardef: -3760 # TODO -3761 } -3762 { -3763 $emit-subx-block:check-for-regvardef: -3764 81 7/subop/compare *eax 3/imm32/regvardef # Stmt-tag -3765 75/jump-if-not-equal break/disp8 -3766 $emit-subx-block:regvardef: -3767 # TODO -3768 } -3769 { -3770 $emit-subx-block:check-for-named-block: -3771 81 7/subop/compare *eax 4/imm32/named-block # Stmt-tag -3772 75/jump-if-not-equal break/disp8 -3773 $emit-subx-block:named-block: -3774 # TODO -3775 } -3776 (write-buffered *(ebp+8) Newline) -3777 8b/-> *(esi+4) 6/r32/esi # List-next -3778 eb/jump loop/disp8 -3779 } -3780 (write-buffered *(ebp+8) "}\n") -3781 } -3782 $emit-subx-block:end: -3783 # . restore registers -3784 5e/pop-to-esi -3785 58/pop-to-eax -3786 # . epilogue -3787 89/<- %esp 5/r32/ebp -3788 5d/pop-to-ebp -3789 c3/return -3790 -3791 emit-subx-statement: # out: (addr buffered-file), stmt: (handle statement), primitives: (handle primitive), functions: (handle function) -3792 # . prologue -3793 55/push-ebp -3794 89/<- %ebp 4/r32/esp -3795 # . save registers -3796 50/push-eax -3797 51/push-ecx -3798 # if stmt matches a primitive, emit it -3799 { -3800 $emit-subx-statement:primitive: -3801 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax -3802 3d/compare-eax-and 0/imm32 -3803 74/jump-if-= break/disp8 -3804 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -3805 e9/jump $emit-subx-statement:end/disp32 -3806 } -3807 # else if stmt matches a function, emit a call to it -3808 { -3809 $emit-subx-statement:call: -3810 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax -3811 3d/compare-eax-and 0/imm32 -3812 74/jump-if-= break/disp8 -3813 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -3814 e9/jump $emit-subx-statement:end/disp32 -3815 } -3816 # else abort -3817 e9/jump $emit-subx-statement:abort/disp32 -3818 $emit-subx-statement:end: -3819 # . restore registers -3820 59/pop-to-ecx -3821 58/pop-to-eax -3822 # . epilogue -3823 89/<- %esp 5/r32/ebp -3824 5d/pop-to-ebp -3825 c3/return -3826 -3827 $emit-subx-statement:abort: -3828 # error("couldn't translate '" stmt "'\n") -3829 (write-buffered Stderr "couldn't translate '") -3830 #? (emit-string Stderr *(ebp+0xc)) # TODO -3831 (write-buffered Stderr "'\n") -3832 (flush Stderr) -3833 # . syscall(exit, 1) -3834 bb/copy-to-ebx 1/imm32 -3835 b8/copy-to-eax 1/imm32/exit -3836 cd/syscall 0x80/imm8 -3837 # never gets here -3838 -3839 # Primitives supported -3840 # For each operation, put variants with hard-coded registers before flexible ones. -3841 == data -3842 Primitives: -3843 # - increment/decrement -3844 _Primitive-inc-eax: -3845 # var/eax <- increment => 40/increment-eax -3846 "increment"/imm32/name -3847 0/imm32/no-inouts -3848 Single-int-var-in-eax/imm32/outputs -3849 "40/increment-eax"/imm32/subx-name -3850 0/imm32/no-rm32 -3851 0/imm32/no-r32 -3852 0/imm32/no-imm32 -3853 0/imm32/output-is-write-only -3854 _Primitive-inc-ecx/imm32/next -3855 _Primitive-inc-ecx: -3856 # var/ecx <- increment => 41/increment-ecx -3857 "increment"/imm32/name -3858 0/imm32/no-inouts -3859 Single-int-var-in-ecx/imm32/outputs -3860 "41/increment-ecx"/imm32/subx-name -3861 0/imm32/no-rm32 -3862 0/imm32/no-r32 -3863 0/imm32/no-imm32 -3864 0/imm32/output-is-write-only -3865 _Primitive-inc-edx/imm32/next -3866 _Primitive-inc-edx: -3867 # var/edx <- increment => 42/increment-edx -3868 "increment"/imm32/name -3869 0/imm32/no-inouts -3870 Single-int-var-in-edx/imm32/outputs -3871 "42/increment-edx"/imm32/subx-name -3872 0/imm32/no-rm32 -3873 0/imm32/no-r32 -3874 0/imm32/no-imm32 -3875 0/imm32/output-is-write-only -3876 _Primitive-inc-ebx/imm32/next -3877 _Primitive-inc-ebx: -3878 # var/ebx <- increment => 43/increment-ebx -3879 "increment"/imm32/name -3880 0/imm32/no-inouts -3881 Single-int-var-in-ebx/imm32/outputs -3882 "43/increment-ebx"/imm32/subx-name -3883 0/imm32/no-rm32 -3884 0/imm32/no-r32 -3885 0/imm32/no-imm32 -3886 0/imm32/output-is-write-only -3887 _Primitive-inc-esi/imm32/next -3888 _Primitive-inc-esi: -3889 # var/esi <- increment => 46/increment-esi -3890 "increment"/imm32/name -3891 0/imm32/no-inouts -3892 Single-int-var-in-esi/imm32/outputs -3893 "46/increment-esi"/imm32/subx-name -3894 0/imm32/no-rm32 -3895 0/imm32/no-r32 -3896 0/imm32/no-imm32 -3897 0/imm32/output-is-write-only -3898 _Primitive-inc-edi/imm32/next -3899 _Primitive-inc-edi: -3900 # var/edi <- increment => 47/increment-edi -3901 "increment"/imm32/name -3902 0/imm32/no-inouts -3903 Single-int-var-in-edi/imm32/outputs -3904 "47/increment-edi"/imm32/subx-name -3905 0/imm32/no-rm32 -3906 0/imm32/no-r32 -3907 0/imm32/no-imm32 -3908 0/imm32/output-is-write-only -3909 _Primitive-dec-eax/imm32/next -3910 _Primitive-dec-eax: -3911 # var/eax <- decrement => 48/decrement-eax -3912 "decrement"/imm32/name -3913 0/imm32/no-inouts -3914 Single-int-var-in-eax/imm32/outputs -3915 "48/decrement-eax"/imm32/subx-name -3916 0/imm32/no-rm32 -3917 0/imm32/no-r32 -3918 0/imm32/no-imm32 -3919 0/imm32/output-is-write-only -3920 _Primitive-dec-ecx/imm32/next -3921 _Primitive-dec-ecx: -3922 # var/ecx <- decrement => 49/decrement-ecx -3923 "decrement"/imm32/name -3924 0/imm32/no-inouts -3925 Single-int-var-in-ecx/imm32/outputs -3926 "49/decrement-ecx"/imm32/subx-name -3927 0/imm32/no-rm32 -3928 0/imm32/no-r32 -3929 0/imm32/no-imm32 -3930 0/imm32/output-is-write-only -3931 _Primitive-dec-edx/imm32/next -3932 _Primitive-dec-edx: -3933 # var/edx <- decrement => 4a/decrement-edx -3934 "decrement"/imm32/name -3935 0/imm32/no-inouts -3936 Single-int-var-in-edx/imm32/outputs -3937 "4a/decrement-edx"/imm32/subx-name -3938 0/imm32/no-rm32 -3939 0/imm32/no-r32 -3940 0/imm32/no-imm32 -3941 0/imm32/output-is-write-only -3942 _Primitive-dec-ebx/imm32/next -3943 _Primitive-dec-ebx: -3944 # var/ebx <- decrement => 4b/decrement-ebx -3945 "decrement"/imm32/name -3946 0/imm32/no-inouts -3947 Single-int-var-in-ebx/imm32/outputs -3948 "4b/decrement-ebx"/imm32/subx-name -3949 0/imm32/no-rm32 -3950 0/imm32/no-r32 -3951 0/imm32/no-imm32 -3952 0/imm32/output-is-write-only -3953 _Primitive-dec-esi/imm32/next -3954 _Primitive-dec-esi: -3955 # var/esi <- decrement => 4e/decrement-esi -3956 "decrement"/imm32/name -3957 0/imm32/no-inouts -3958 Single-int-var-in-esi/imm32/outputs -3959 "4e/decrement-esi"/imm32/subx-name -3960 0/imm32/no-rm32 -3961 0/imm32/no-r32 -3962 0/imm32/no-imm32 -3963 0/imm32/output-is-write-only -3964 _Primitive-dec-edi/imm32/next -3965 _Primitive-dec-edi: -3966 # var/edi <- decrement => 4f/decrement-edi -3967 "decrement"/imm32/name -3968 0/imm32/no-inouts -3969 Single-int-var-in-edi/imm32/outputs -3970 "4f/decrement-edi"/imm32/subx-name -3971 0/imm32/no-rm32 -3972 0/imm32/no-r32 -3973 0/imm32/no-imm32 -3974 0/imm32/output-is-write-only -3975 _Primitive-inc-mem/imm32/next -3976 _Primitive-inc-mem: -3977 # increment var => ff 0/subop/increment *(ebp+__) -3978 "increment"/imm32/name -3979 Single-int-var-on-stack/imm32/inouts -3980 0/imm32/no-outputs -3981 "ff 0/subop/increment"/imm32/subx-name -3982 1/imm32/rm32-is-first-inout -3983 0/imm32/no-r32 -3984 0/imm32/no-imm32 -3985 0/imm32/output-is-write-only -3986 _Primitive-inc-reg/imm32/next -3987 _Primitive-inc-reg: -3988 # var/reg <- increment => ff 0/subop/increment %__ -3989 "increment"/imm32/name -3990 0/imm32/no-inouts -3991 Single-int-var-in-some-register/imm32/outputs -3992 "ff 0/subop/increment"/imm32/subx-name -3993 3/imm32/rm32-is-first-output -3994 0/imm32/no-r32 -3995 0/imm32/no-imm32 -3996 0/imm32/output-is-write-only -3997 _Primitive-dec-mem/imm32/next -3998 _Primitive-dec-mem: -3999 # decrement var => ff 1/subop/decrement *(ebp+__) -4000 "decrement"/imm32/name -4001 Single-int-var-on-stack/imm32/inouts -4002 0/imm32/no-outputs -4003 "ff 1/subop/decrement"/imm32/subx-name -4004 1/imm32/rm32-is-first-inout -4005 0/imm32/no-r32 -4006 0/imm32/no-imm32 -4007 0/imm32/output-is-write-only -4008 _Primitive-dec-reg/imm32/next -4009 _Primitive-dec-reg: -4010 # var/reg <- decrement => ff 1/subop/decrement %__ -4011 "decrement"/imm32/name -4012 0/imm32/no-inouts -4013 Single-int-var-in-some-register/imm32/outputs -4014 "ff 1/subop/decrement"/imm32/subx-name -4015 3/imm32/rm32-is-first-output -4016 0/imm32/no-r32 -4017 0/imm32/no-imm32 -4018 0/imm32/output-is-write-only -4019 _Primitive-add-to-eax/imm32/next -4020 # - add -4021 _Primitive-add-to-eax: -4022 # var/eax <- add lit => 05/add-to-eax lit/imm32 -4023 "add"/imm32/name -4024 Single-lit-var/imm32/inouts -4025 Single-int-var-in-eax/imm32/outputs -4026 "05/add-to-eax"/imm32/subx-name -4027 0/imm32/no-rm32 -4028 0/imm32/no-r32 -4029 1/imm32/imm32-is-first-inout -4030 0/imm32/output-is-write-only -4031 _Primitive-add-reg-to-reg/imm32/next -4032 _Primitive-add-reg-to-reg: -4033 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 -4034 "add"/imm32/name -4035 Single-int-var-in-some-register/imm32/inouts -4036 Single-int-var-in-some-register/imm32/outputs -4037 "01/add-to"/imm32/subx-name -4038 3/imm32/rm32-is-first-output -4039 1/imm32/r32-is-first-inout -4040 0/imm32/no-imm32 -4041 0/imm32/output-is-write-only -4042 _Primitive-add-reg-to-mem/imm32/next -4043 _Primitive-add-reg-to-mem: -4044 # add-to var1 var2/reg => 01/add-to var1 var2/r32 -4045 "add-to"/imm32/name -4046 Int-var-and-second-int-var-in-some-register/imm32/inouts -4047 0/imm32/outputs -4048 "01/add-to"/imm32/subx-name -4049 1/imm32/rm32-is-first-inout -4050 2/imm32/r32-is-second-inout -4051 0/imm32/no-imm32 -4052 0/imm32/output-is-write-only -4053 _Primitive-add-mem-to-reg/imm32/next -4054 _Primitive-add-mem-to-reg: -4055 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 -4056 "add"/imm32/name -4057 Single-int-var-on-stack/imm32/inouts -4058 Single-int-var-in-some-register/imm32/outputs -4059 "03/add"/imm32/subx-name -4060 1/imm32/rm32-is-first-inout -4061 3/imm32/r32-is-first-output -4062 0/imm32/no-imm32 -4063 0/imm32/output-is-write-only -4064 _Primitive-add-lit-to-reg/imm32/next -4065 _Primitive-add-lit-to-reg: -4066 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 -4067 "add"/imm32/name -4068 Single-lit-var/imm32/inouts -4069 Single-int-var-in-some-register/imm32/outputs -4070 "81 0/subop/add"/imm32/subx-name -4071 3/imm32/rm32-is-first-output -4072 0/imm32/no-r32 -4073 1/imm32/imm32-is-first-inout -4074 0/imm32/output-is-write-only -4075 _Primitive-add-lit-to-mem/imm32/next -4076 _Primitive-add-lit-to-mem: -4077 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 -4078 "add-to"/imm32/name -4079 Int-var-and-literal/imm32/inouts -4080 0/imm32/outputs -4081 "81 0/subop/add"/imm32/subx-name -4082 1/imm32/rm32-is-first-inout -4083 0/imm32/no-r32 -4084 2/imm32/imm32-is-first-inout -4085 0/imm32/output-is-write-only -4086 _Primitive-subtract-from-eax/imm32/next -4087 # - subtract -4088 _Primitive-subtract-from-eax: -4089 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 -4090 "subtract"/imm32/name -4091 Single-lit-var/imm32/inouts -4092 Single-int-var-in-eax/imm32/outputs -4093 "2d/subtract-from-eax"/imm32/subx-name -4094 0/imm32/no-rm32 -4095 0/imm32/no-r32 -4096 1/imm32/imm32-is-first-inout -4097 0/imm32/output-is-write-only -4098 _Primitive-subtract-reg-from-reg/imm32/next -4099 _Primitive-subtract-reg-from-reg: -4100 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 -4101 "subtract"/imm32/name -4102 Single-int-var-in-some-register/imm32/inouts -4103 Single-int-var-in-some-register/imm32/outputs -4104 "29/subtract-from"/imm32/subx-name -4105 3/imm32/rm32-is-first-output -4106 1/imm32/r32-is-first-inout -4107 0/imm32/no-imm32 -4108 0/imm32/output-is-write-only -4109 _Primitive-subtract-reg-from-mem/imm32/next -4110 _Primitive-subtract-reg-from-mem: -4111 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 -4112 "subtract-from"/imm32/name -4113 Int-var-and-second-int-var-in-some-register/imm32/inouts -4114 0/imm32/outputs -4115 "29/subtract-from"/imm32/subx-name -4116 1/imm32/rm32-is-first-inout -4117 2/imm32/r32-is-second-inout -4118 0/imm32/no-imm32 -4119 0/imm32/output-is-write-only -4120 _Primitive-subtract-mem-from-reg/imm32/next -4121 _Primitive-subtract-mem-from-reg: -4122 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 -4123 "subtract"/imm32/name -4124 Single-int-var-on-stack/imm32/inouts -4125 Single-int-var-in-some-register/imm32/outputs -4126 "2b/subtract"/imm32/subx-name -4127 1/imm32/rm32-is-first-inout -4128 3/imm32/r32-is-first-output -4129 0/imm32/no-imm32 -4130 0/imm32/output-is-write-only -4131 _Primitive-subtract-lit-from-reg/imm32/next -4132 _Primitive-subtract-lit-from-reg: -4133 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 -4134 "subtract"/imm32/name -4135 Single-lit-var/imm32/inouts -4136 Single-int-var-in-some-register/imm32/outputs -4137 "81 5/subop/subtract"/imm32/subx-name -4138 3/imm32/rm32-is-first-output -4139 0/imm32/no-r32 -4140 1/imm32/imm32-is-first-inout -4141 0/imm32/output-is-write-only -4142 _Primitive-subtract-lit-from-mem/imm32/next -4143 _Primitive-subtract-lit-from-mem: -4144 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 -4145 "subtract-from"/imm32/name -4146 Int-var-and-literal/imm32/inouts -4147 0/imm32/outputs -4148 "81 5/subop/subtract"/imm32/subx-name -4149 1/imm32/rm32-is-first-inout -4150 0/imm32/no-r32 -4151 2/imm32/imm32-is-first-inout -4152 0/imm32/output-is-write-only -4153 _Primitive-and-with-eax/imm32/next -4154 # - and -4155 _Primitive-and-with-eax: -4156 # var/eax <- and lit => 25/and-with-eax lit/imm32 -4157 "and"/imm32/name -4158 Single-lit-var/imm32/inouts -4159 Single-int-var-in-eax/imm32/outputs -4160 "25/and-with-eax"/imm32/subx-name -4161 0/imm32/no-rm32 -4162 0/imm32/no-r32 -4163 1/imm32/imm32-is-first-inout -4164 0/imm32/output-is-write-only -4165 _Primitive-and-reg-with-reg/imm32/next -4166 _Primitive-and-reg-with-reg: -4167 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 -4168 "and"/imm32/name -4169 Single-int-var-in-some-register/imm32/inouts -4170 Single-int-var-in-some-register/imm32/outputs -4171 "21/and-with"/imm32/subx-name -4172 3/imm32/rm32-is-first-output -4173 1/imm32/r32-is-first-inout -4174 0/imm32/no-imm32 -4175 0/imm32/output-is-write-only -4176 _Primitive-and-reg-with-mem/imm32/next -4177 _Primitive-and-reg-with-mem: -4178 # and-with var1 var2/reg => 21/and-with var1 var2/r32 -4179 "and-with"/imm32/name -4180 Int-var-and-second-int-var-in-some-register/imm32/inouts -4181 0/imm32/outputs -4182 "21/and-with"/imm32/subx-name -4183 1/imm32/rm32-is-first-inout -4184 2/imm32/r32-is-second-inout -4185 0/imm32/no-imm32 -4186 0/imm32/output-is-write-only -4187 _Primitive-and-mem-with-reg/imm32/next -4188 _Primitive-and-mem-with-reg: -4189 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 -4190 "and"/imm32/name -4191 Single-int-var-on-stack/imm32/inouts -4192 Single-int-var-in-some-register/imm32/outputs -4193 "23/and"/imm32/subx-name -4194 1/imm32/rm32-is-first-inout -4195 3/imm32/r32-is-first-output -4196 0/imm32/no-imm32 -4197 0/imm32/output-is-write-only -4198 _Primitive-and-lit-with-reg/imm32/next -4199 _Primitive-and-lit-with-reg: -4200 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 -4201 "and"/imm32/name -4202 Single-lit-var/imm32/inouts -4203 Single-int-var-in-some-register/imm32/outputs -4204 "81 4/subop/and"/imm32/subx-name -4205 3/imm32/rm32-is-first-output -4206 0/imm32/no-r32 -4207 1/imm32/imm32-is-first-inout -4208 0/imm32/output-is-write-only -4209 _Primitive-and-lit-with-mem/imm32/next -4210 _Primitive-and-lit-with-mem: -4211 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 -4212 "and-with"/imm32/name -4213 Int-var-and-literal/imm32/inouts -4214 0/imm32/outputs -4215 "81 4/subop/and"/imm32/subx-name -4216 1/imm32/rm32-is-first-inout -4217 0/imm32/no-r32 -4218 2/imm32/imm32-is-first-inout -4219 0/imm32/output-is-write-only -4220 _Primitive-or-with-eax/imm32/next -4221 # - or -4222 _Primitive-or-with-eax: -4223 # var/eax <- or lit => 0d/or-with-eax lit/imm32 -4224 "or"/imm32/name -4225 Single-lit-var/imm32/inouts -4226 Single-int-var-in-eax/imm32/outputs -4227 "0d/or-with-eax"/imm32/subx-name -4228 0/imm32/no-rm32 -4229 0/imm32/no-r32 -4230 1/imm32/imm32-is-first-inout -4231 0/imm32/output-is-write-only -4232 _Primitive-or-reg-with-reg/imm32/next -4233 _Primitive-or-reg-with-reg: -4234 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 -4235 "or"/imm32/name -4236 Single-int-var-in-some-register/imm32/inouts -4237 Single-int-var-in-some-register/imm32/outputs -4238 "09/or-with"/imm32/subx-name -4239 3/imm32/rm32-is-first-output -4240 1/imm32/r32-is-first-inout -4241 0/imm32/no-imm32 -4242 0/imm32/output-is-write-only -4243 _Primitive-or-reg-with-mem/imm32/next -4244 _Primitive-or-reg-with-mem: -4245 # or-with var1 var2/reg => 09/or-with var1 var2/r32 -4246 "or-with"/imm32/name -4247 Int-var-and-second-int-var-in-some-register/imm32/inouts -4248 0/imm32/outputs -4249 "09/or-with"/imm32/subx-name -4250 1/imm32/rm32-is-first-inout -4251 2/imm32/r32-is-second-inout -4252 0/imm32/no-imm32 -4253 0/imm32/output-is-write-only -4254 _Primitive-or-mem-with-reg/imm32/next -4255 _Primitive-or-mem-with-reg: -4256 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 -4257 "or"/imm32/name -4258 Single-int-var-on-stack/imm32/inouts -4259 Single-int-var-in-some-register/imm32/outputs -4260 "0b/or"/imm32/subx-name -4261 1/imm32/rm32-is-first-inout -4262 3/imm32/r32-is-first-output -4263 0/imm32/no-imm32 -4264 0/imm32/output-is-write-only -4265 _Primitive-or-lit-with-reg/imm32/next -4266 _Primitive-or-lit-with-reg: -4267 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 -4268 "or"/imm32/name -4269 Single-lit-var/imm32/inouts -4270 Single-int-var-in-some-register/imm32/outputs -4271 "81 4/subop/or"/imm32/subx-name -4272 3/imm32/rm32-is-first-output -4273 0/imm32/no-r32 -4274 1/imm32/imm32-is-first-inout -4275 0/imm32/output-is-write-only -4276 _Primitive-or-lit-with-mem/imm32/next -4277 _Primitive-or-lit-with-mem: -4278 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 -4279 "or-with"/imm32/name -4280 Int-var-and-literal/imm32/inouts -4281 0/imm32/outputs -4282 "81 4/subop/or"/imm32/subx-name -4283 1/imm32/rm32-is-first-inout -4284 0/imm32/no-r32 -4285 2/imm32/imm32-is-first-inout -4286 0/imm32/output-is-write-only -4287 _Primitive-xor-with-eax/imm32/next -4288 # - xor -4289 _Primitive-xor-with-eax: -4290 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 -4291 "xor"/imm32/name -4292 Single-lit-var/imm32/inouts -4293 Single-int-var-in-eax/imm32/outputs -4294 "35/xor-with-eax"/imm32/subx-name -4295 0/imm32/no-rm32 -4296 0/imm32/no-r32 -4297 1/imm32/imm32-is-first-inout -4298 0/imm32/output-is-write-only -4299 _Primitive-xor-reg-with-reg/imm32/next -4300 _Primitive-xor-reg-with-reg: -4301 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 -4302 "xor"/imm32/name -4303 Single-int-var-in-some-register/imm32/inouts -4304 Single-int-var-in-some-register/imm32/outputs -4305 "31/xor-with"/imm32/subx-name -4306 3/imm32/rm32-is-first-output -4307 1/imm32/r32-is-first-inout -4308 0/imm32/no-imm32 -4309 0/imm32/output-is-write-only -4310 _Primitive-xor-reg-with-mem/imm32/next -4311 _Primitive-xor-reg-with-mem: -4312 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 -4313 "xor-with"/imm32/name -4314 Int-var-and-second-int-var-in-some-register/imm32/inouts -4315 0/imm32/outputs -4316 "31/xor-with"/imm32/subx-name -4317 1/imm32/rm32-is-first-inout -4318 2/imm32/r32-is-second-inout -4319 0/imm32/no-imm32 -4320 0/imm32/output-is-write-only -4321 _Primitive-xor-mem-with-reg/imm32/next -4322 _Primitive-xor-mem-with-reg: -4323 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 -4324 "xor"/imm32/name -4325 Single-int-var-on-stack/imm32/inouts -4326 Single-int-var-in-some-register/imm32/outputs -4327 "33/xor"/imm32/subx-name -4328 1/imm32/rm32-is-first-inout -4329 3/imm32/r32-is-first-output -4330 0/imm32/no-imm32 -4331 0/imm32/output-is-write-only -4332 _Primitive-xor-lit-with-reg/imm32/next -4333 _Primitive-xor-lit-with-reg: -4334 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 -4335 "xor"/imm32/name -4336 Single-lit-var/imm32/inouts -4337 Single-int-var-in-some-register/imm32/outputs -4338 "81 4/subop/xor"/imm32/subx-name -4339 3/imm32/rm32-is-first-output -4340 0/imm32/no-r32 -4341 1/imm32/imm32-is-first-inout -4342 0/imm32/output-is-write-only -4343 _Primitive-xor-lit-with-mem/imm32/next -4344 _Primitive-xor-lit-with-mem: -4345 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 -4346 "xor-with"/imm32/name -4347 Int-var-and-literal/imm32/inouts -4348 0/imm32/outputs -4349 "81 4/subop/xor"/imm32/subx-name -4350 1/imm32/rm32-is-first-inout -4351 0/imm32/no-r32 -4352 2/imm32/imm32-is-first-inout -4353 0/imm32/output-is-write-only -4354 _Primitive-copy-to-eax/imm32/next -4355 # - copy -4356 _Primitive-copy-to-eax: -4357 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 -4358 "copy"/imm32/name -4359 Single-lit-var/imm32/inouts -4360 Single-int-var-in-eax/imm32/outputs -4361 "b8/copy-to-eax"/imm32/subx-name -4362 0/imm32/no-rm32 -4363 0/imm32/no-r32 -4364 1/imm32/imm32-is-first-inout -4365 1/imm32/output-is-write-only -4366 _Primitive-copy-to-ecx/imm32/next -4367 _Primitive-copy-to-ecx: -4368 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 -4369 "copy"/imm32/name -4370 Single-lit-var/imm32/inouts -4371 Single-int-var-in-ecx/imm32/outputs -4372 "b9/copy-to-ecx"/imm32/subx-name -4373 0/imm32/no-rm32 -4374 0/imm32/no-r32 -4375 1/imm32/imm32-is-first-inout -4376 1/imm32/output-is-write-only -4377 _Primitive-copy-to-edx/imm32/next -4378 _Primitive-copy-to-edx: -4379 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 -4380 "copy"/imm32/name -4381 Single-lit-var/imm32/inouts -4382 Single-int-var-in-edx/imm32/outputs -4383 "ba/copy-to-edx"/imm32/subx-name -4384 0/imm32/no-rm32 -4385 0/imm32/no-r32 -4386 1/imm32/imm32-is-first-inout -4387 1/imm32/output-is-write-only -4388 _Primitive-copy-to-ebx/imm32/next -4389 _Primitive-copy-to-ebx: -4390 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 -4391 "copy"/imm32/name -4392 Single-lit-var/imm32/inouts -4393 Single-int-var-in-ebx/imm32/outputs -4394 "bb/copy-to-ebx"/imm32/subx-name -4395 0/imm32/no-rm32 -4396 0/imm32/no-r32 -4397 1/imm32/imm32-is-first-inout -4398 1/imm32/output-is-write-only -4399 _Primitive-copy-to-esi/imm32/next -4400 _Primitive-copy-to-esi: -4401 # var/esi <- copy lit => be/copy-to-esi lit/imm32 -4402 "copy"/imm32/name -4403 Single-lit-var/imm32/inouts -4404 Single-int-var-in-esi/imm32/outputs -4405 "be/copy-to-esi"/imm32/subx-name -4406 0/imm32/no-rm32 -4407 0/imm32/no-r32 -4408 1/imm32/imm32-is-first-inout -4409 1/imm32/output-is-write-only -4410 _Primitive-copy-to-edi/imm32/next -4411 _Primitive-copy-to-edi: -4412 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 -4413 "copy"/imm32/name -4414 Single-lit-var/imm32/inouts -4415 Single-int-var-in-edi/imm32/outputs -4416 "bf/copy-to-edi"/imm32/subx-name -4417 0/imm32/no-rm32 -4418 0/imm32/no-r32 -4419 1/imm32/imm32-is-first-inout -4420 1/imm32/output-is-write-only -4421 _Primitive-copy-reg-to-reg/imm32/next -4422 _Primitive-copy-reg-to-reg: -4423 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 -4424 "copy"/imm32/name -4425 Single-int-var-in-some-register/imm32/inouts -4426 Single-int-var-in-some-register/imm32/outputs -4427 "89/copy-to"/imm32/subx-name -4428 3/imm32/rm32-is-first-output -4429 1/imm32/r32-is-first-inout -4430 0/imm32/no-imm32 -4431 1/imm32/output-is-write-only -4432 _Primitive-copy-reg-to-mem/imm32/next -4433 _Primitive-copy-reg-to-mem: -4434 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 -4435 "copy-to"/imm32/name -4436 Int-var-and-second-int-var-in-some-register/imm32/inouts -4437 0/imm32/outputs -4438 "89/copy-to"/imm32/subx-name -4439 1/imm32/rm32-is-first-inout -4440 2/imm32/r32-is-second-inout -4441 0/imm32/no-imm32 -4442 1/imm32/output-is-write-only -4443 _Primitive-copy-mem-to-reg/imm32/next -4444 _Primitive-copy-mem-to-reg: -4445 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 -4446 "copy"/imm32/name -4447 Single-int-var-on-stack/imm32/inouts -4448 Single-int-var-in-some-register/imm32/outputs -4449 "8b/copy-from"/imm32/subx-name -4450 1/imm32/rm32-is-first-inout -4451 3/imm32/r32-is-first-output -4452 0/imm32/no-imm32 -4453 1/imm32/output-is-write-only -4454 _Primitive-copy-lit-to-reg/imm32/next -4455 _Primitive-copy-lit-to-reg: -4456 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 -4457 "copy"/imm32/name -4458 Single-lit-var/imm32/inouts -4459 Single-int-var-in-some-register/imm32/outputs -4460 "c7 0/subop/copy"/imm32/subx-name -4461 3/imm32/rm32-is-first-output -4462 0/imm32/no-r32 -4463 1/imm32/imm32-is-first-inout -4464 1/imm32/output-is-write-only -4465 _Primitive-copy-lit-to-mem/imm32/next -4466 _Primitive-copy-lit-to-mem: -4467 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 -4468 "copy-to"/imm32/name -4469 Int-var-and-literal/imm32/inouts -4470 0/imm32/outputs -4471 "c7 0/subop/copy"/imm32/subx-name -4472 1/imm32/rm32-is-first-inout -4473 0/imm32/no-r32 -4474 2/imm32/imm32-is-first-inout -4475 1/imm32/output-is-write-only -4476 0/imm32/next -4477 -4478 Single-int-var-on-stack: -4479 Int-var-on-stack/imm32 -4480 0/imm32/next -4481 -4482 Int-var-on-stack: -4483 "arg1"/imm32/name -4484 Type-int/imm32 -4485 1/imm32/some-block-depth -4486 1/imm32/some-stack-offset -4487 0/imm32/no-register -4488 -4489 Int-var-and-second-int-var-in-some-register: -4490 Int-var-on-stack/imm32 -4491 Single-int-var-in-some-register/imm32/next -4492 -4493 Int-var-and-literal: -4494 Int-var-on-stack/imm32 -4495 Single-lit-var/imm32/next -4496 -4497 Single-int-var-in-some-register: -4498 Int-var-in-some-register/imm32 -4499 0/imm32/next -4500 -4501 Int-var-in-some-register: -4502 "arg1"/imm32/name -4503 Type-int/imm32 -4504 1/imm32/some-block-depth -4505 0/imm32/no-stack-offset -4506 "*"/imm32/register -4507 -4508 Single-int-var-in-eax: -4509 Int-var-in-eax/imm32 -4510 0/imm32/next -4511 -4512 Int-var-in-eax: -4513 "arg1"/imm32/name -4514 Type-int/imm32 -4515 1/imm32/some-block-depth -4516 0/imm32/no-stack-offset -4517 "eax"/imm32/register -4518 -4519 Single-int-var-in-ecx: -4520 Int-var-in-ecx/imm32 -4521 0/imm32/next -4522 -4523 Int-var-in-ecx: -4524 "arg1"/imm32/name -4525 Type-int/imm32 -4526 1/imm32/some-block-depth -4527 0/imm32/no-stack-offset -4528 "ecx"/imm32/register -4529 -4530 Single-int-var-in-edx: -4531 Int-var-in-edx/imm32 -4532 0/imm32/next -4533 -4534 Int-var-in-edx: -4535 "arg1"/imm32/name -4536 Type-int/imm32 -4537 1/imm32/some-block-depth -4538 0/imm32/no-stack-offset -4539 "edx"/imm32/register -4540 -4541 Single-int-var-in-ebx: -4542 Int-var-in-ebx/imm32 -4543 0/imm32/next -4544 -4545 Int-var-in-ebx: -4546 "arg1"/imm32/name -4547 Type-int/imm32 -4548 1/imm32/some-block-depth -4549 0/imm32/no-stack-offset -4550 "ebx"/imm32/register -4551 -4552 Single-int-var-in-esi: -4553 Int-var-in-esi/imm32 -4554 0/imm32/next -4555 -4556 Int-var-in-esi: -4557 "arg1"/imm32/name -4558 Type-int/imm32 -4559 1/imm32/some-block-depth -4560 0/imm32/no-stack-offset -4561 "esi"/imm32/register -4562 -4563 Single-int-var-in-edi: -4564 Int-var-in-edi/imm32 -4565 0/imm32/next -4566 -4567 Int-var-in-edi: -4568 "arg1"/imm32/name -4569 Type-int/imm32 -4570 1/imm32/some-block-depth -4571 0/imm32/no-stack-offset -4572 "edi"/imm32/register -4573 -4574 Single-lit-var: -4575 Lit-var/imm32 -4576 0/imm32/next -4577 -4578 Lit-var: -4579 "literal"/imm32/name -4580 Type-literal/imm32 -4581 1/imm32/some-block-depth -4582 0/imm32/no-stack-offset -4583 0/imm32/no-register -4584 -4585 Type-int: -4586 1/imm32/left/int -4587 0/imm32/right/null -4588 -4589 Type-literal: -4590 0/imm32/left/literal -4591 0/imm32/right/null -4592 -4593 == code -4594 emit-subx-primitive: # out: (addr buffered-file), stmt: (handle statement), primitive: (handle function) -4595 # . prologue -4596 55/push-ebp -4597 89/<- %ebp 4/r32/esp -4598 # . save registers -4599 50/push-eax -4600 51/push-ecx -4601 # ecx = primitive -4602 8b/-> *(ebp+0x10) 1/r32/ecx -4603 # emit primitive name -4604 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name -4605 # emit rm32 if necessary -4606 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt -4607 # emit r32 if necessary -4608 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt -4609 # emit imm32 if necessary -4610 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt -4611 $emit-subx-primitive:end: -4612 # . restore registers -4613 59/pop-to-ecx -4614 58/pop-to-eax -4615 # . epilogue -4616 89/<- %esp 5/r32/ebp -4617 5d/pop-to-ebp -4618 c3/return -4619 -4620 emit-subx-rm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) -4621 # . prologue -4622 55/push-ebp -4623 89/<- %ebp 4/r32/esp -4624 # . save registers -4625 50/push-eax -4626 # if (l == 0) return -4627 81 7/subop/compare *(ebp+0xc) 0/imm32 -4628 74/jump-if-= $emit-subx-rm32:end/disp8 -4629 # -4630 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4631 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var -4632 $emit-subx-rm32:end: -4633 # . restore registers -4634 58/pop-to-eax -4635 # . epilogue -4636 89/<- %esp 5/r32/ebp -4637 5d/pop-to-ebp -4638 c3/return -4639 -4640 get-stmt-operand-from-arg-location: # stmt: (handle statement), l: arg-location -> var/eax: (handle variable) -4641 # . prologue -4642 55/push-ebp -4643 89/<- %ebp 4/r32/esp -4644 # . save registers -4645 51/push-ecx -4646 # eax = l -4647 8b/-> *(ebp+0xc) 0/r32/eax -4648 # ecx = stmt -4649 8b/-> *(ebp+8) 1/r32/ecx -4650 # if (l == 1) return stmt->inouts->var -4651 { -4652 3d/compare-eax-and 1/imm32 -4653 75/jump-if-!= break/disp8 -4654 $get-stmt-operand-from-arg-location:1: -4655 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -4656 8b/-> *eax 0/r32/eax # Operand-var -4657 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4658 } -4659 # if (l == 2) return stmt->inouts->next->var -4660 { -4661 3d/compare-eax-and 2/imm32 -4662 75/jump-if-!= break/disp8 -4663 $get-stmt-operand-from-arg-location:2: -4664 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -4665 8b/-> *(eax+4) 0/r32/eax # Operand-next -4666 8b/-> *eax 0/r32/eax # Operand-var -4667 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4668 } -4669 # if (l == 3) return stmt->outputs -4670 { -4671 3d/compare-eax-and 3/imm32 -4672 75/jump-if-!= break/disp8 -4673 $get-stmt-operand-from-arg-location:3: -4674 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs -4675 8b/-> *eax 0/r32/eax # Operand-var -4676 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4677 } -4678 # abort -4679 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 -4680 $get-stmt-operand-from-arg-location:end: -4681 # . restore registers -4682 59/pop-to-ecx -4683 # . epilogue -4684 89/<- %esp 5/r32/ebp -4685 5d/pop-to-ebp -4686 c3/return -4687 -4688 $get-stmt-operand-from-arg-location:abort: -4689 # error("invalid arg-location " eax) -4690 (write-buffered Stderr "invalid arg-location ") -4691 (print-int32-buffered Stderr %eax) -4692 (write-buffered Stderr "\n") -4693 (flush Stderr) -4694 # . syscall(exit, 1) -4695 bb/copy-to-ebx 1/imm32 -4696 b8/copy-to-eax 1/imm32/exit -4697 cd/syscall 0x80/imm8 -4698 # never gets here -4699 -4700 emit-subx-r32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) -4701 # . prologue -4702 55/push-ebp -4703 89/<- %ebp 4/r32/esp -4704 # . save registers -4705 50/push-eax -4706 51/push-ecx -4707 # if (location == 0) return -4708 81 7/subop/compare *(ebp+0xc) 0/imm32 -4709 0f 84/jump-if-= $emit-subx-r32:end/disp32 -4710 # -4711 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4712 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax: (addr register-index) -4713 (write-buffered *(ebp+8) Space) -4714 (print-int32-buffered *(ebp+8) *eax) -4715 (write-buffered *(ebp+8) "/r32") -4716 $emit-subx-r32:end: -4717 # . restore registers -4718 59/pop-to-ecx -4719 58/pop-to-eax -4720 # . epilogue -4721 89/<- %esp 5/r32/ebp -4722 5d/pop-to-ebp -4723 c3/return -4724 -4725 emit-subx-imm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) -4726 # . prologue -4727 55/push-ebp -4728 89/<- %ebp 4/r32/esp -4729 # . save registers -4730 50/push-eax -4731 51/push-ecx -4732 # if (location == 0) return -4733 81 7/subop/compare *(ebp+0xc) 0/imm32 -4734 74/jump-if-= $emit-subx-imm32:end/disp8 -4735 # -4736 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4737 (write-buffered *(ebp+8) Space) -4738 (write-buffered *(ebp+8) *eax) # Var-name -4739 (write-buffered *(ebp+8) "/imm32") -4740 $emit-subx-imm32:end: -4741 # . restore registers -4742 59/pop-to-ecx -4743 58/pop-to-eax -4744 # . epilogue -4745 89/<- %esp 5/r32/ebp -4746 5d/pop-to-ebp -4747 c3/return -4748 -4749 emit-subx-call: # out: (addr buffered-file), stmt: (handle statement), callee: (handle function) -4750 # . prologue -4751 55/push-ebp -4752 89/<- %ebp 4/r32/esp -4753 # . save registers -4754 50/push-eax -4755 51/push-ecx -4756 # -4757 (write-buffered *(ebp+8) "(") -4758 # - emit function name -4759 8b/-> *(ebp+0x10) 1/r32/ecx -4760 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name -4761 # - emit arguments -4762 # var curr/ecx: (handle list var) = stmt->inouts -4763 8b/-> *(ebp+0xc) 1/r32/ecx -4764 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts -4765 { -4766 # if (curr == null) break -4767 81 7/subop/compare %ecx 0/imm32 -4768 74/jump-if-= break/disp8 -4769 # -4770 (emit-subx-call-operand *(ebp+8) *ecx) -4771 # curr = curr->next -4772 8b/-> *(ecx+4) 1/r32/ecx -4773 eb/jump loop/disp8 -4774 } -4775 # -4776 (write-buffered *(ebp+8) ")") -4777 $emit-subx-call:end: -4778 # . restore registers -4779 59/pop-to-ecx -4780 58/pop-to-eax -4781 # . epilogue -4782 89/<- %esp 5/r32/ebp -4783 5d/pop-to-ebp -4784 c3/return -4785 -4786 emit-subx-call-operand: # out: (addr buffered-file), operand: (handle variable) -4787 # . prologue -4788 55/push-ebp -4789 89/<- %ebp 4/r32/esp -4790 # . save registers -4791 50/push-eax -4792 # eax = operand -4793 8b/-> *(ebp+0xc) 0/r32/eax -4794 # if (operand->register) emit "%__" -4795 { -4796 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -4797 74/jump-if-= break/disp8 -4798 $emit-subx-call-operand:register: -4799 (write-buffered *(ebp+8) " %") -4800 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -4801 e9/jump $emit-subx-call-operand:end/disp32 -4802 } -4803 # else if (operand->stack-offset) emit "*(ebp+__)" -4804 { -4805 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -4806 74/jump-if-= break/disp8 -4807 $emit-subx-call-operand:stack: -4808 (write-buffered *(ebp+8) Space) -4809 (write-buffered *(ebp+8) "*(ebp+") -4810 8b/-> *(ebp+0xc) 0/r32/eax -4811 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -4812 (write-buffered *(ebp+8) ")") -4813 e9/jump $emit-subx-call-operand:end/disp32 -4814 } -4815 # else if (operand->type == literal) emit "__" -4816 { -4817 50/push-eax -4818 8b/-> *(eax+4) 0/r32/eax # Var-type -4819 81 7/subop/compare *eax 0/imm32 # Tree-left -4820 58/pop-to-eax -4821 75/jump-if-!= break/disp8 -4822 $emit-subx-call-operand:literal: -4823 (write-buffered *(ebp+8) Space) -4824 (write-buffered *(ebp+8) *eax) -4825 } -4826 $emit-subx-call-operand:end: -4827 # . restore registers -4828 58/pop-to-eax -4829 # . epilogue -4830 89/<- %esp 5/r32/ebp -4831 5d/pop-to-ebp -4832 c3/return -4833 -4834 emit-subx-var-as-rm32: # out: (addr buffered-file), operand: (handle variable) -4835 # . prologue -4836 55/push-ebp -4837 89/<- %ebp 4/r32/esp -4838 # . save registers -4839 50/push-eax -4840 # eax = operand -4841 8b/-> *(ebp+0xc) 0/r32/eax -4842 # if (operand->register) emit "%__" -4843 { -4844 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -4845 74/jump-if-= break/disp8 -4846 $emit-subx-var-as-rm32:register: -4847 (write-buffered *(ebp+8) " %") -4848 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -4849 } -4850 # else if (operand->stack-offset) emit "*(ebp+__)" -4851 { -4852 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -4853 74/jump-if-= break/disp8 -4854 $emit-subx-var-as-rm32:stack: -4855 (write-buffered *(ebp+8) Space) -4856 (write-buffered *(ebp+8) "*(ebp+") -4857 8b/-> *(ebp+0xc) 0/r32/eax -4858 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -4859 (write-buffered *(ebp+8) ")") -4860 } -4861 $emit-subx-var-as-rm32:end: -4862 # . restore registers -4863 58/pop-to-eax -4864 # . epilogue -4865 89/<- %esp 5/r32/ebp -4866 5d/pop-to-ebp -4867 c3/return -4868 -4869 find-matching-function: # functions: (addr function), stmt: (handle statement) -> result/eax: (handle function) -4870 # . prologue -4871 55/push-ebp -4872 89/<- %ebp 4/r32/esp -4873 # . save registers -4874 51/push-ecx -4875 # var curr/ecx: (handle function) = functions -4876 8b/-> *(ebp+8) 1/r32/ecx -4877 { -4878 # if (curr == null) break -4879 81 7/subop/compare %ecx 0/imm32 -4880 74/jump-if-= break/disp8 -4881 # if match(stmt, curr) return curr -4882 { -4883 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax -4884 3d/compare-eax-and 0/imm32 -4885 74/jump-if-= break/disp8 -4886 89/<- %eax 1/r32/ecx -4887 eb/jump $find-matching-function:end/disp8 -4888 } -4889 # curr = curr->next -4890 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -4891 eb/jump loop/disp8 -4892 } -4893 # return null -4894 b8/copy-to-eax 0/imm32 -4895 $find-matching-function:end: -4896 # . restore registers -4897 59/pop-to-ecx -4898 # . epilogue -4899 89/<- %esp 5/r32/ebp -4900 5d/pop-to-ebp -4901 c3/return -4902 -4903 find-matching-primitive: # primitives: (handle primitive), stmt: (handle statement) -> result/eax: (handle primitive) -4904 # . prologue -4905 55/push-ebp -4906 89/<- %ebp 4/r32/esp -4907 # . save registers -4908 51/push-ecx -4909 # var curr/ecx: (handle primitive) = primitives -4910 8b/-> *(ebp+8) 1/r32/ecx -4911 { -4912 $find-matching-primitive:loop: -4913 # if (curr == null) break -4914 81 7/subop/compare %ecx 0/imm32 -4915 0f 84/jump-if-= break/disp32 -4916 #? (write-buffered Stderr "prim: ") -4917 #? (write-buffered Stderr *ecx) # Primitive-name -4918 #? (write-buffered Stderr " => ") -4919 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name -4920 #? (write-buffered Stderr "\n") -4921 #? (flush Stderr) -4922 # if match(curr, stmt) return curr -4923 { -4924 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax -4925 3d/compare-eax-and 0/imm32 -4926 74/jump-if-= break/disp8 -4927 89/<- %eax 1/r32/ecx -4928 eb/jump $find-matching-primitive:end/disp8 -4929 } -4930 $find-matching-primitive:next-primitive: -4931 # curr = curr->next -4932 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next -4933 e9/jump loop/disp32 -4934 } -4935 # return null -4936 b8/copy-to-eax 0/imm32 -4937 $find-matching-primitive:end: -4938 # . restore registers -4939 59/pop-to-ecx -4940 # . epilogue -4941 89/<- %esp 5/r32/ebp -4942 5d/pop-to-ebp -4943 c3/return -4944 -4945 mu-stmt-matches-function?: # stmt: (handle statement), function: (handle function) => result/eax: boolean -4946 # . prologue -4947 55/push-ebp -4948 89/<- %ebp 4/r32/esp -4949 # . save registers -4950 51/push-ecx -4951 # return function->name == stmt->operation -4952 8b/-> *(ebp+8) 1/r32/ecx -4953 8b/-> *(ebp+0xc) 0/r32/eax -4954 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax -4955 $mu-stmt-matches-function?:end: -4956 # . restore registers -4957 59/pop-to-ecx -4958 # . epilogue -4959 89/<- %esp 5/r32/ebp -4960 5d/pop-to-ebp -4961 c3/return -4962 -4963 mu-stmt-matches-primitive?: # stmt: (handle statement), primitive: (handle primitive) => result/eax: boolean -4964 # A mu stmt matches a primitive if the name matches, all the inout vars -4965 # match, and all the output vars match. -4966 # Vars match if types match and registers match. -4967 # In addition, a stmt output matches a primitive's output if types match -4968 # and the primitive has a wildcard register. -4969 # . prologue -4970 55/push-ebp -4971 89/<- %ebp 4/r32/esp -4972 # . save registers -4973 51/push-ecx -4974 52/push-edx -4975 53/push-ebx -4976 56/push-esi -4977 57/push-edi -4978 # ecx = stmt -4979 8b/-> *(ebp+8) 1/r32/ecx -4980 # edx = primitive -4981 8b/-> *(ebp+0xc) 2/r32/edx -4982 { -4983 $mu-stmt-matches-primitive?:check-name: -4984 # if (primitive->name != stmt->operation) return false -4985 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax -4986 3d/compare-eax-and 0/imm32 -4987 75/jump-if-!= break/disp8 -4988 b8/copy-to-eax 0/imm32 -4989 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4990 } -4991 $mu-stmt-matches-primitive?:check-inouts: -4992 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) -4993 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts -4994 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts -4995 { -4996 # if (curr == 0 && curr2 == 0) move on to check outputs -4997 { -4998 81 7/subop/compare %esi 0/imm32 -4999 75/jump-if-!= break/disp8 -5000 $mu-stmt-matches-primitive?:stmt-inout-is-null: -5001 { -5002 81 7/subop/compare %edi 0/imm32 -5003 75/jump-if-!= break/disp8 -5004 # -5005 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 -5006 } -5007 # return false -5008 b8/copy-to-eax 0/imm32/false -5009 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5010 } -5011 # if (curr2 == 0) return false -5012 { -5013 81 7/subop/compare %edi 0/imm32 -5014 75/jump-if-!= break/disp8 -5015 $mu-stmt-matches-primitive?:prim-inout-is-null: -5016 b8/copy-to-eax 0/imm32/false -5017 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5018 } -5019 # if (curr != curr2) return false -5020 { -5021 (operand-matches-primitive? *esi *edi) # => eax -5022 3d/compare-eax-and 0/imm32 -5023 75/jump-if-!= break/disp8 -5024 b8/copy-to-eax 0/imm32/false -5025 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5026 } -5027 # curr=curr->next -5028 8b/-> *(esi+4) 6/r32/esi # Operand-next -5029 # curr2=curr2->next -5030 8b/-> *(edi+4) 7/r32/edi # Operand-next -5031 eb/jump loop/disp8 -5032 } -5033 $mu-stmt-matches-primitive?:check-outputs: -5034 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) -5035 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs -5036 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs -5037 { -5038 # if (curr == 0) return (curr2 == 0) -5039 { -5040 $mu-stmt-matches-primitive?:check-output: -5041 81 7/subop/compare %esi 0/imm32 -5042 75/jump-if-!= break/disp8 -5043 { -5044 81 7/subop/compare %edi 0/imm32 -5045 75/jump-if-!= break/disp8 -5046 # return true -5047 b8/copy-to-eax 1/imm32 -5048 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5049 } -5050 # return false -5051 b8/copy-to-eax 0/imm32 -5052 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5053 } -5054 # if (curr2 == 0) return false -5055 { -5056 81 7/subop/compare %edi 0/imm32 -5057 75/jump-if-!= break/disp8 -5058 b8/copy-to-eax 0/imm32 -5059 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5060 } -5061 # if (curr != curr2) return false -5062 { -5063 (operand-matches-primitive? *esi *edi) # List-value List-value => eax -5064 3d/compare-eax-and 0/imm32 -5065 75/jump-if-!= break/disp8 -5066 b8/copy-to-eax 0/imm32 -5067 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5068 } -5069 # curr=curr->next -5070 8b/-> *(esi+4) 6/r32/esi # Operand-next -5071 # curr2=curr2->next -5072 8b/-> *(edi+4) 7/r32/edi # Operand-next -5073 eb/jump loop/disp8 -5074 } -5075 $mu-stmt-matches-primitive?:return-true: -5076 b8/copy-to-eax 1/imm32 -5077 $mu-stmt-matches-primitive?:end: -5078 # . restore registers -5079 5f/pop-to-edi -5080 5e/pop-to-esi -5081 5b/pop-to-ebx -5082 5a/pop-to-edx -5083 59/pop-to-ecx -5084 # . epilogue -5085 89/<- %esp 5/r32/ebp -5086 5d/pop-to-ebp -5087 c3/return -5088 -5089 operand-matches-primitive?: # var: (handle var), prim-var: (handle var) => result/eax: boolean -5090 # . prologue -5091 55/push-ebp -5092 89/<- %ebp 4/r32/esp -5093 # . save registers -5094 56/push-esi -5095 57/push-edi -5096 # esi = var -5097 8b/-> *(ebp+8) 6/r32/esi -5098 # edi = prim-var -5099 8b/-> *(ebp+0xc) 7/r32/edi -5100 # if (var->type != prim-var->type) return false -5101 (type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax -5102 3d/compare-eax-and 0/imm32 -5103 b8/copy-to-eax 0/imm32/false -5104 74/jump-if-= $operand-matches-primitive?:end/disp8 -5105 # return false if var->register doesn't match prim-var->register -5106 { -5107 # if addresses are equal, don't return here -5108 8b/-> *(esi+0x10) 0/r32/eax -5109 39/compare *(edi+0x10) 0/r32/eax -5110 74/jump-if-= break/disp8 -5111 # if either address is 0, return false -5112 3d/compare-eax-and 0/imm32 -5113 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -5114 81 7/subop/compare *(edi+0x10) 0/imm32 -5115 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -5116 # if prim-var->register is "*", return true -5117 (string-equal? *(edi+0x10) "*") # Var-register -5118 3d/compare-eax-and 0/imm32 -5119 b8/copy-to-eax 1/imm32/true -5120 75/jump-if-!= $operand-matches-primitive?:end/disp8 -5121 # if string contents don't match, return false -5122 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register -5123 3d/compare-eax-and 0/imm32 -5124 b8/copy-to-eax 0/imm32/false -5125 74/jump-if-= $operand-matches-primitive?:end/disp8 -5126 } -5127 # return true -5128 b8/copy-to-eax 1/imm32/true -5129 $operand-matches-primitive?:end: -5130 # . restore registers -5131 5f/pop-to-edi -5132 5e/pop-to-esi -5133 # . epilogue -5134 89/<- %esp 5/r32/ebp -5135 5d/pop-to-ebp -5136 c3/return -5137 -5138 type-equal?: # a: (handle tree type-id), b: (handle tree type-id) => result/eax: boolean -5139 # . prologue -5140 55/push-ebp -5141 89/<- %ebp 4/r32/esp -5142 # . save registers -5143 51/push-ecx -5144 52/push-edx -5145 # ecx = a -5146 8b/-> *(ebp+8) 1/r32/ecx -5147 # edx = b -5148 8b/-> *(ebp+0xc) 2/r32/edx -5149 # if (a == b) return true -5150 8b/-> %ecx 0/r32/eax # Var-type -5151 39/compare %edx 0/r32/eax # Var-type -5152 b8/copy-to-eax 1/imm32/true -5153 74/jump-if-= $type-equal?:end/disp8 -5154 # if (a < MAX_TYPE_ID) return false -5155 81 7/subop/compare %ecx 0x10000/imm32 -5156 b8/copy-to-eax 0/imm32/false -5157 72/jump-if-addr< $type-equal?:end/disp8 -5158 # if (b < MAX_TYPE_ID) return false -5159 81 7/subop/compare %edx 0x10000/imm32 -5160 b8/copy-to-eax 0/imm32/false -5161 72/jump-if-addr< $type-equal?:end/disp8 -5162 # if (!type-equal?(a->left, b->left)) return false -5163 (type-equal? *ecx *edx) # Tree-left, Tree-left => eax -5164 3d/compare-eax-and 0/imm32 -5165 74/jump-if-= $type-equal?:end/disp8 -5166 # return type-equal?(a->right, b->right) -5167 (type-equal? *(ecx+4) *(edx+4)) # Tree-right, Tree-right => eax -5168 $type-equal?:end: -5169 # . restore registers -5170 5a/pop-to-edx -5171 59/pop-to-ecx -5172 # . epilogue -5173 89/<- %esp 5/r32/ebp -5174 5d/pop-to-ebp -5175 c3/return -5176 -5177 test-emit-subx-statement-primitive: -5178 # Primitive operation on a variable on the stack. -5179 # increment foo -5180 # => -5181 # ff 0/subop/increment *(ebp-8) -5182 # -5183 # There's a variable on the var stack as follows: -5184 # name: 'foo' -5185 # type: int -5186 # stack-offset: -8 -5187 # -5188 # There's a primitive with this info: -5189 # name: 'increment' -5190 # inouts: int/mem -5191 # value: 'ff 0/subop/increment' -5192 # -5193 # There's nothing in functions. -5194 # -5195 # . prologue -5196 55/push-ebp -5197 89/<- %ebp 4/r32/esp -5198 # setup -5199 (clear-stream _test-output-stream) -5200 (clear-stream $_test-output-buffered-file->buffer) -5201 # var type/ecx: (handle tree type-id) = int -5202 68/push 0/imm32/right/null -5203 68/push 1/imm32/left/int -5204 89/<- %ecx 4/r32/esp -5205 # var var-foo/ecx: var -5206 68/push 0/imm32/no-register -5207 68/push -8/imm32/stack-offset -5208 68/push 1/imm32/block-depth -5209 51/push-ecx -5210 68/push "foo"/imm32 -5211 89/<- %ecx 4/r32/esp -5212 # var operand/ebx: (list var) -5213 68/push 0/imm32/next -5214 51/push-ecx/var-foo -5215 89/<- %ebx 4/r32/esp -5216 # var stmt/esi: statement -5217 68/push 0/imm32/next -5218 68/push 0/imm32/outputs -5219 53/push-ebx/operands -5220 68/push "increment"/imm32/operation -5221 68/push 1/imm32 -5222 89/<- %esi 4/r32/esp -5223 # var primitives/ebx: primitive -5224 68/push 0/imm32/next -5225 68/push 0/imm32/output-is-write-only -5226 68/push 0/imm32/no-imm32 -5227 68/push 0/imm32/no-r32 -5228 68/push 1/imm32/rm32-is-first-inout -5229 68/push "ff 0/subop/increment"/imm32/subx-name -5230 68/push 0/imm32/outputs -5231 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call -5232 68/push "increment"/imm32/name -5233 89/<- %ebx 4/r32/esp -5234 # convert -5235 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5236 (flush _test-output-buffered-file) -5237 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5243 # check output -5244 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") -5245 # . epilogue -5246 89/<- %esp 5/r32/ebp -5247 5d/pop-to-ebp -5248 c3/return -5249 -5250 test-emit-subx-statement-primitive-register: -5251 # Primitive operation on a variable in a register. -5252 # foo <- increment -5253 # => -5254 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5255 # -5256 # There's a variable on the var stack as follows: -5257 # name: 'foo' -5258 # type: int -5259 # register: 'eax' -5260 # -5261 # There's a primitive with this info: -5262 # name: 'increment' -5263 # out: int/reg -5264 # value: 'ff 0/subop/increment' -5265 # -5266 # There's nothing in functions. -5267 # -5268 # . prologue -5269 55/push-ebp -5270 89/<- %ebp 4/r32/esp -5271 # setup -5272 (clear-stream _test-output-stream) -5273 (clear-stream $_test-output-buffered-file->buffer) -5274 # var type/ecx: (handle tree type-id) = int -5275 68/push 0/imm32/right/null -5276 68/push 1/imm32/left/int -5277 89/<- %ecx 4/r32/esp -5278 # var var-foo/ecx: var in eax -5279 68/push "eax"/imm32/register -5280 68/push 0/imm32/no-stack-offset -5281 68/push 1/imm32/block-depth -5282 51/push-ecx -5283 68/push "foo"/imm32 -5284 89/<- %ecx 4/r32/esp -5285 # var operand/ebx: (list var) -5286 68/push 0/imm32/next -5287 51/push-ecx/var-foo -5288 89/<- %ebx 4/r32/esp -5289 # var stmt/esi: statement -5290 68/push 0/imm32/next -5291 53/push-ebx/outputs -5292 68/push 0/imm32/inouts -5293 68/push "increment"/imm32/operation -5294 68/push 1/imm32 -5295 89/<- %esi 4/r32/esp -5296 # var formal-var/ebx: var in any register -5297 68/push Any-register/imm32 -5298 68/push 0/imm32/no-stack-offset -5299 68/push 1/imm32/block-depth -5300 ff 6/subop/push *(ecx+4) # Var-type -5301 68/push "dummy"/imm32 -5302 89/<- %ebx 4/r32/esp -5303 # var operand/ebx: (list var) -5304 68/push 0/imm32/next -5305 53/push-ebx/formal-var -5306 89/<- %ebx 4/r32/esp -5307 # var primitives/ebx: primitive -5308 68/push 0/imm32/next -5309 68/push 0/imm32/output-is-write-only -5310 68/push 0/imm32/no-imm32 -5311 68/push 0/imm32/no-r32 -5312 68/push 3/imm32/rm32-in-first-output -5313 68/push "ff 0/subop/increment"/imm32/subx-name -5314 53/push-ebx/outputs -5315 68/push 0/imm32/inouts -5316 68/push "increment"/imm32/name -5317 89/<- %ebx 4/r32/esp -5318 # convert -5319 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5320 (flush _test-output-buffered-file) -5321 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5327 # check output -5328 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") -5329 # . epilogue -5330 89/<- %esp 5/r32/ebp -5331 5d/pop-to-ebp -5332 c3/return -5333 -5334 test-emit-subx-statement-select-primitive: -5335 # Select the right primitive between overloads. -5336 # foo <- increment -5337 # => -5338 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5339 # -5340 # There's a variable on the var stack as follows: -5341 # name: 'foo' -5342 # type: int -5343 # register: 'eax' -5344 # -5345 # There's two primitives, as follows: -5346 # - name: 'increment' -5347 # out: int/reg -5348 # value: 'ff 0/subop/increment' -5349 # - name: 'increment' -5350 # inout: int/mem -5351 # value: 'ff 0/subop/increment' -5352 # -5353 # There's nothing in functions. -5354 # -5355 # . prologue -5356 55/push-ebp -5357 89/<- %ebp 4/r32/esp -5358 # setup -5359 (clear-stream _test-output-stream) -5360 (clear-stream $_test-output-buffered-file->buffer) -5361 # var type/ecx: (handle tree type-id) = int -5362 68/push 0/imm32/right/null -5363 68/push 1/imm32/left/int -5364 89/<- %ecx 4/r32/esp -5365 # var var-foo/ecx: var in eax -5366 68/push "eax"/imm32/register -5367 68/push 0/imm32/no-stack-offset -5368 68/push 1/imm32/block-depth -5369 51/push-ecx -5370 68/push "foo"/imm32 -5371 89/<- %ecx 4/r32/esp -5372 # var real-outputs/edi: (list var) -5373 68/push 0/imm32/next -5374 51/push-ecx/var-foo -5375 89/<- %edi 4/r32/esp -5376 # var stmt/esi: statement -5377 68/push 0/imm32/next -5378 57/push-edi/outputs -5379 68/push 0/imm32/inouts -5380 68/push "increment"/imm32/operation -5381 68/push 1/imm32 -5382 89/<- %esi 4/r32/esp -5383 # var formal-var/ebx: var in any register -5384 68/push Any-register/imm32 -5385 68/push 0/imm32/no-stack-offset -5386 68/push 1/imm32/block-depth -5387 ff 6/subop/push *(ecx+4) # Var-type -5388 68/push "dummy"/imm32 -5389 89/<- %ebx 4/r32/esp -5390 # var formal-outputs/ebx: (list var) = {formal-var, 0} -5391 68/push 0/imm32/next -5392 53/push-ebx/formal-var -5393 89/<- %ebx 4/r32/esp -5394 # var primitive1/ebx: primitive -5395 68/push 0/imm32/next -5396 68/push 0/imm32/output-is-write-only -5397 68/push 0/imm32/no-imm32 -5398 68/push 0/imm32/no-r32 -5399 68/push 3/imm32/rm32-in-first-output -5400 68/push "ff 0/subop/increment"/imm32/subx-name -5401 53/push-ebx/outputs/formal-outputs -5402 68/push 0/imm32/inouts -5403 68/push "increment"/imm32/name -5404 89/<- %ebx 4/r32/esp -5405 # var primitives/ebx: primitive -5406 53/push-ebx/next -5407 68/push 0/imm32/output-is-write-only -5408 68/push 0/imm32/no-imm32 -5409 68/push 0/imm32/no-r32 -5410 68/push 1/imm32/rm32-is-first-inout -5411 68/push "ff 0/subop/increment"/imm32/subx-name -5412 68/push 0/imm32/outputs -5413 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -5414 68/push "increment"/imm32/name -5415 89/<- %ebx 4/r32/esp -5416 # convert -5417 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5418 (flush _test-output-buffered-file) -5419 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5425 # check output -5426 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") -5427 # . epilogue -5428 89/<- %esp 5/r32/ebp -5429 5d/pop-to-ebp -5430 c3/return -5431 -5432 test-emit-subx-statement-select-primitive-2: -5433 # Select the right primitive between overloads. -5434 # foo <- increment -5435 # => -5436 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5437 # -5438 # There's a variable on the var stack as follows: -5439 # name: 'foo' -5440 # type: int -5441 # register: 'eax' -5442 # -5443 # There's two primitives, as follows: -5444 # - name: 'increment' -5445 # out: int/reg -5446 # value: 'ff 0/subop/increment' -5447 # - name: 'increment' -5448 # inout: int/mem -5449 # value: 'ff 0/subop/increment' -5450 # -5451 # There's nothing in functions. -5452 # -5453 # . prologue -5454 55/push-ebp -5455 89/<- %ebp 4/r32/esp -5456 # setup -5457 (clear-stream _test-output-stream) -5458 (clear-stream $_test-output-buffered-file->buffer) -5459 # var type/ecx: (handle tree type-id) = int -5460 68/push 0/imm32/right/null -5461 68/push 1/imm32/left/int -5462 89/<- %ecx 4/r32/esp -5463 # var var-foo/ecx: var in eax -5464 68/push "eax"/imm32/register -5465 68/push 0/imm32/no-stack-offset -5466 68/push 1/imm32/block-depth -5467 51/push-ecx -5468 68/push "foo"/imm32 -5469 89/<- %ecx 4/r32/esp -5470 # var inouts/edi: (list var) +3656 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax: (handle list _type) +3657 # . prologue +3658 55/push-ebp +3659 89/<- %ebp 4/r32/esp +3660 # . save registers +3661 51/push-ecx +3662 # +3663 (allocate *(ebp+8) *List-size) # => eax +3664 8b/-> *(ebp+0xc) 1/r32/ecx +3665 89/<- *eax 1/r32/ecx # List-value +3666 # if (list == null) return result +3667 81 7/subop/compare *(ebp+0x10) 0/imm32 +3668 74/jump-if-= $new-list:end/disp8 +3669 # otherwise append +3670 # var curr/ecx = list +3671 8b/-> *(ebp+0x10) 1/r32/ecx +3672 # while (curr->next != null) curr = curr->next +3673 { +3674 81 7/subop/compare *(ecx+4) 0/imm32 # List-next +3675 74/jump-if-= break/disp8 +3676 # curr = curr->next +3677 8b/-> *(ecx+4) 1/r32/ecx +3678 eb/jump loop/disp8 +3679 } +3680 # curr->next = result +3681 89/<- *(ecx+4) 0/r32/eax +3682 # return list +3683 8b/-> *(ebp+0x10) 0/r32/eax +3684 $append-list:end: +3685 # . restore registers +3686 59/pop-to-ecx +3687 # . epilogue +3688 89/<- %esp 5/r32/ebp +3689 5d/pop-to-ebp +3690 c3/return +3691 +3692 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) +3693 # . prologue +3694 55/push-ebp +3695 89/<- %ebp 4/r32/esp +3696 # . save registers +3697 56/push-esi +3698 # esi = block +3699 8b/-> *(ebp+0xc) 6/r32/esi +3700 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements +3701 89/<- *(esi+4) 0/r32/eax # Block-statements +3702 $append-to-block:end: +3703 # . restore registers +3704 5e/pop-to-esi +3705 # . epilogue +3706 89/<- %esp 5/r32/ebp +3707 5d/pop-to-ebp +3708 c3/return +3709 +3710 ####################################################### +3711 # Type-checking +3712 ####################################################### +3713 +3714 check-mu-types: +3715 # . prologue +3716 55/push-ebp +3717 89/<- %ebp 4/r32/esp +3718 # +3719 $check-mu-types:end: +3720 # . epilogue +3721 89/<- %esp 5/r32/ebp +3722 5d/pop-to-ebp +3723 c3/return +3724 +3725 size-of: # n: (addr var) -> result/eax: int +3726 # . prologue +3727 55/push-ebp +3728 89/<- %ebp 4/r32/esp +3729 # hard-coded since we only support 'int' types for now +3730 b8/copy-to-eax 4/imm32 +3731 $size-of:end: +3732 # . epilogue +3733 89/<- %esp 5/r32/ebp +3734 5d/pop-to-ebp +3735 c3/return +3736 +3737 == data +3738 +3739 # not yet used, but it will be +3740 Type-size: # (stream int) +3741 0x18/imm32/write +3742 0/imm32/read +3743 0x100/imm32/length +3744 # data +3745 4/imm32 # literal +3746 4/imm32 # int +3747 4/imm32 # addr +3748 0/imm32 # array (logic elsewhere) +3749 8/imm32 # handle (fat pointer) +3750 4/imm32 # bool +3751 0/imm32 +3752 0/imm32 +3753 # 0x20 +3754 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3755 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3756 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3757 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3758 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3759 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3760 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3761 +3762 == code +3763 +3764 ####################################################### +3765 # Code-generation +3766 ####################################################### +3767 +3768 emit-subx: # out: (addr buffered-file) +3769 # . prologue +3770 55/push-ebp +3771 89/<- %ebp 4/r32/esp +3772 # . save registers +3773 50/push-eax +3774 51/push-ecx +3775 57/push-edi +3776 # edi = out +3777 8b/-> *(ebp+8) 7/r32/edi +3778 # var curr/ecx: (handle function) = *Program +3779 8b/-> *Program 1/r32/ecx +3780 { +3781 # if (curr == null) break +3782 81 7/subop/compare %ecx 0/imm32 +3783 0f 84/jump-if-= break/disp32 +3784 (emit-subx-function %edi %ecx) +3785 # curr = curr->next +3786 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +3787 e9/jump loop/disp32 +3788 } +3789 $emit-subx:end: +3790 # . restore registers +3791 5f/pop-to-edi +3792 59/pop-to-ecx +3793 58/pop-to-eax +3794 # . epilogue +3795 89/<- %esp 5/r32/ebp +3796 5d/pop-to-ebp +3797 c3/return +3798 +3799 emit-subx-function: # out: (addr buffered-file), f: (handle function) +3800 # . prologue +3801 55/push-ebp +3802 89/<- %ebp 4/r32/esp +3803 # . save registers +3804 50/push-eax +3805 51/push-ecx +3806 52/push-edx +3807 57/push-edi +3808 # edi = out +3809 8b/-> *(ebp+8) 7/r32/edi +3810 # ecx = f +3811 8b/-> *(ebp+0xc) 1/r32/ecx +3812 # var vars/edx: (stack (addr var) 256) +3813 81 5/subop/subtract %esp 0x400/imm32 +3814 68/push 0x400/imm32/length +3815 68/push 0/imm32/top +3816 89/<- %edx 4/r32/esp +3817 # +3818 (write-buffered %edi *ecx) +3819 (write-buffered %edi ":\n") +3820 (emit-subx-prologue %edi) +3821 (emit-subx-block %edi *(ecx+0x10) %edx) # Function-body +3822 (emit-subx-epilogue %edi) +3823 $emit-subx-function:end: +3824 # . reclaim locals +3825 81 0/subop/add %esp 408/imm32 +3826 # . restore registers +3827 5f/pop-to-edi +3828 5a/pop-to-edx +3829 59/pop-to-ecx +3830 58/pop-to-eax +3831 # . epilogue +3832 89/<- %esp 5/r32/ebp +3833 5d/pop-to-ebp +3834 c3/return +3835 +3836 emit-subx-block: # out: (addr buffered-file), block: (handle block), vars: (addr stack (handle var)) +3837 # . prologue +3838 55/push-ebp +3839 89/<- %ebp 4/r32/esp +3840 # . save registers +3841 50/push-eax +3842 56/push-esi +3843 # var stmts/esi: (handle list statement) = block->statements +3844 8b/-> *(ebp+0xc) 6/r32/esi +3845 8b/-> *(esi+4) 6/r32/esi # Block-statements +3846 # +3847 { +3848 $emit-subx-block:check-empty: +3849 81 7/subop/compare %esi 0/imm32 +3850 0f 84/jump-if-= break/disp32 +3851 (write-buffered *(ebp+8) "{\n") +3852 { +3853 $emit-subx-block:loop: +3854 81 7/subop/compare %esi 0/imm32 +3855 0f 84/jump-if-= break/disp32 +3856 # var curr/eax = stmts->value +3857 8b/-> *esi 0/r32/eax # List-value +3858 { +3859 $emit-subx-block:check-for-block: +3860 81 7/subop/compare *eax 0/imm32/block # Stmt-tag +3861 75/jump-if-!= break/disp8 +3862 $emit-subx-block:block: +3863 # TODO +3864 } +3865 { +3866 $emit-subx-block:check-for-stmt: +3867 81 7/subop/compare *eax 1/imm32/stmt1 # Stmt-tag +3868 75/jump-if-!= break/disp8 +3869 $emit-subx-block:stmt: +3870 (emit-subx-statement *(ebp+8) %eax Primitives *Program) +3871 } +3872 { +3873 $emit-subx-block:check-for-vardef: +3874 81 7/subop/compare *eax 2/imm32/vardef # Stmt-tag +3875 75/jump-if-!= break/disp8 +3876 $emit-subx-block:vardef: +3877 (emit-subx-var-def *(ebp+8) %eax) +3878 (push *(ebp+0x10) %eax) +3879 } +3880 { +3881 $emit-subx-block:check-for-regvardef: +3882 81 7/subop/compare *eax 3/imm32/regvardef # Stmt-tag +3883 75/jump-if-!= break/disp8 +3884 $emit-subx-block:regvardef: +3885 # TODO +3886 } +3887 { +3888 $emit-subx-block:check-for-named-block: +3889 81 7/subop/compare *eax 4/imm32/named-block # Stmt-tag +3890 75/jump-if-!= break/disp8 +3891 $emit-subx-block:named-block: +3892 # TODO +3893 } +3894 (write-buffered *(ebp+8) Newline) +3895 8b/-> *(esi+4) 6/r32/esi # List-next +3896 e9/jump loop/disp32 +3897 } +3898 # reclaim locals +3899 # TODO: support nested blocks; take block-ids into account +3900 { +3901 8b/-> *(ebp+0x10) 0/r32/eax) +3902 81 7/subop/compare *eax 0/imm32 # Stack-top +3903 74/jump-if-= break/disp8 +3904 (top %eax) # => eax +3905 (size-of %eax) # => eax +3906 01/add *Next-local-stack-offset 0/r32/eax +3907 (write-buffered *(ebp+8) "81 0/subop/add %esp ") +3908 (print-int32-buffered *(ebp+8) %eax) +3909 (write-buffered *(ebp+8) "/imm32\n") +3910 # +3911 (pop *(ebp+0x10)) +3912 e9/jump loop/disp32 +3913 } +3914 # +3915 (write-buffered *(ebp+8) "}\n") +3916 } +3917 $emit-subx-block:end: +3918 # . restore registers +3919 5e/pop-to-esi +3920 58/pop-to-eax +3921 # . epilogue +3922 89/<- %esp 5/r32/ebp +3923 5d/pop-to-ebp +3924 c3/return +3925 +3926 emit-subx-var-def: # out: (addr buffered-file), stmt: (handle statement) +3927 # . prologue +3928 55/push-ebp +3929 89/<- %ebp 4/r32/esp +3930 # . save registers +3931 # eax = stmt +3932 8b/-> *(ebp+0xc) 0/r32/eax +3933 # var n/eax: int = size-of(stmt->var) +3934 (size-of *(eax+4)) # Vardef-var => eax +3935 # while n > 0 +3936 { +3937 3d/compare-eax-with 0/imm32 +3938 7e/jump-if-<= break/disp8 +3939 (write-buffered *(ebp+8) "68/push 0/imm32") +3940 # n -= 4 +3941 2d/subtract-from-eax 4/imm32 +3942 # +3943 eb/jump loop/disp8 +3944 } +3945 $emit-subx-var-def:end: +3946 # . restore registers +3947 59/pop-to-ecx +3948 58/pop-to-eax +3949 # . epilogue +3950 89/<- %esp 5/r32/ebp +3951 5d/pop-to-ebp +3952 c3/return +3953 +3954 emit-subx-statement: # out: (addr buffered-file), stmt: (handle statement), primitives: (handle primitive), functions: (handle function) +3955 # . prologue +3956 55/push-ebp +3957 89/<- %ebp 4/r32/esp +3958 # . save registers +3959 50/push-eax +3960 51/push-ecx +3961 # if stmt matches a primitive, emit it +3962 { +3963 $emit-subx-statement:primitive: +3964 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax +3965 3d/compare-eax-and 0/imm32 +3966 74/jump-if-= break/disp8 +3967 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +3968 e9/jump $emit-subx-statement:end/disp32 +3969 } +3970 # else if stmt matches a function, emit a call to it +3971 { +3972 $emit-subx-statement:call: +3973 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax +3974 3d/compare-eax-and 0/imm32 +3975 74/jump-if-= break/disp8 +3976 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +3977 e9/jump $emit-subx-statement:end/disp32 +3978 } +3979 # else abort +3980 e9/jump $emit-subx-statement:abort/disp32 +3981 $emit-subx-statement:end: +3982 # . restore registers +3983 59/pop-to-ecx +3984 58/pop-to-eax +3985 # . epilogue +3986 89/<- %esp 5/r32/ebp +3987 5d/pop-to-ebp +3988 c3/return +3989 +3990 $emit-subx-statement:abort: +3991 # error("couldn't translate '" stmt "'\n") +3992 (write-buffered Stderr "couldn't translate '") +3993 #? (emit-string Stderr *(ebp+0xc)) # TODO +3994 (write-buffered Stderr "'\n") +3995 (flush Stderr) +3996 # . syscall(exit, 1) +3997 bb/copy-to-ebx 1/imm32 +3998 b8/copy-to-eax 1/imm32/exit +3999 cd/syscall 0x80/imm8 +4000 # never gets here +4001 +4002 # Primitives supported +4003 # For each operation, put variants with hard-coded registers before flexible ones. +4004 == data +4005 Primitives: +4006 # - increment/decrement +4007 _Primitive-inc-eax: +4008 # var/eax <- increment => 40/increment-eax +4009 "increment"/imm32/name +4010 0/imm32/no-inouts +4011 Single-int-var-in-eax/imm32/outputs +4012 "40/increment-eax"/imm32/subx-name +4013 0/imm32/no-rm32 +4014 0/imm32/no-r32 +4015 0/imm32/no-imm32 +4016 0/imm32/output-is-write-only +4017 _Primitive-inc-ecx/imm32/next +4018 _Primitive-inc-ecx: +4019 # var/ecx <- increment => 41/increment-ecx +4020 "increment"/imm32/name +4021 0/imm32/no-inouts +4022 Single-int-var-in-ecx/imm32/outputs +4023 "41/increment-ecx"/imm32/subx-name +4024 0/imm32/no-rm32 +4025 0/imm32/no-r32 +4026 0/imm32/no-imm32 +4027 0/imm32/output-is-write-only +4028 _Primitive-inc-edx/imm32/next +4029 _Primitive-inc-edx: +4030 # var/edx <- increment => 42/increment-edx +4031 "increment"/imm32/name +4032 0/imm32/no-inouts +4033 Single-int-var-in-edx/imm32/outputs +4034 "42/increment-edx"/imm32/subx-name +4035 0/imm32/no-rm32 +4036 0/imm32/no-r32 +4037 0/imm32/no-imm32 +4038 0/imm32/output-is-write-only +4039 _Primitive-inc-ebx/imm32/next +4040 _Primitive-inc-ebx: +4041 # var/ebx <- increment => 43/increment-ebx +4042 "increment"/imm32/name +4043 0/imm32/no-inouts +4044 Single-int-var-in-ebx/imm32/outputs +4045 "43/increment-ebx"/imm32/subx-name +4046 0/imm32/no-rm32 +4047 0/imm32/no-r32 +4048 0/imm32/no-imm32 +4049 0/imm32/output-is-write-only +4050 _Primitive-inc-esi/imm32/next +4051 _Primitive-inc-esi: +4052 # var/esi <- increment => 46/increment-esi +4053 "increment"/imm32/name +4054 0/imm32/no-inouts +4055 Single-int-var-in-esi/imm32/outputs +4056 "46/increment-esi"/imm32/subx-name +4057 0/imm32/no-rm32 +4058 0/imm32/no-r32 +4059 0/imm32/no-imm32 +4060 0/imm32/output-is-write-only +4061 _Primitive-inc-edi/imm32/next +4062 _Primitive-inc-edi: +4063 # var/edi <- increment => 47/increment-edi +4064 "increment"/imm32/name +4065 0/imm32/no-inouts +4066 Single-int-var-in-edi/imm32/outputs +4067 "47/increment-edi"/imm32/subx-name +4068 0/imm32/no-rm32 +4069 0/imm32/no-r32 +4070 0/imm32/no-imm32 +4071 0/imm32/output-is-write-only +4072 _Primitive-dec-eax/imm32/next +4073 _Primitive-dec-eax: +4074 # var/eax <- decrement => 48/decrement-eax +4075 "decrement"/imm32/name +4076 0/imm32/no-inouts +4077 Single-int-var-in-eax/imm32/outputs +4078 "48/decrement-eax"/imm32/subx-name +4079 0/imm32/no-rm32 +4080 0/imm32/no-r32 +4081 0/imm32/no-imm32 +4082 0/imm32/output-is-write-only +4083 _Primitive-dec-ecx/imm32/next +4084 _Primitive-dec-ecx: +4085 # var/ecx <- decrement => 49/decrement-ecx +4086 "decrement"/imm32/name +4087 0/imm32/no-inouts +4088 Single-int-var-in-ecx/imm32/outputs +4089 "49/decrement-ecx"/imm32/subx-name +4090 0/imm32/no-rm32 +4091 0/imm32/no-r32 +4092 0/imm32/no-imm32 +4093 0/imm32/output-is-write-only +4094 _Primitive-dec-edx/imm32/next +4095 _Primitive-dec-edx: +4096 # var/edx <- decrement => 4a/decrement-edx +4097 "decrement"/imm32/name +4098 0/imm32/no-inouts +4099 Single-int-var-in-edx/imm32/outputs +4100 "4a/decrement-edx"/imm32/subx-name +4101 0/imm32/no-rm32 +4102 0/imm32/no-r32 +4103 0/imm32/no-imm32 +4104 0/imm32/output-is-write-only +4105 _Primitive-dec-ebx/imm32/next +4106 _Primitive-dec-ebx: +4107 # var/ebx <- decrement => 4b/decrement-ebx +4108 "decrement"/imm32/name +4109 0/imm32/no-inouts +4110 Single-int-var-in-ebx/imm32/outputs +4111 "4b/decrement-ebx"/imm32/subx-name +4112 0/imm32/no-rm32 +4113 0/imm32/no-r32 +4114 0/imm32/no-imm32 +4115 0/imm32/output-is-write-only +4116 _Primitive-dec-esi/imm32/next +4117 _Primitive-dec-esi: +4118 # var/esi <- decrement => 4e/decrement-esi +4119 "decrement"/imm32/name +4120 0/imm32/no-inouts +4121 Single-int-var-in-esi/imm32/outputs +4122 "4e/decrement-esi"/imm32/subx-name +4123 0/imm32/no-rm32 +4124 0/imm32/no-r32 +4125 0/imm32/no-imm32 +4126 0/imm32/output-is-write-only +4127 _Primitive-dec-edi/imm32/next +4128 _Primitive-dec-edi: +4129 # var/edi <- decrement => 4f/decrement-edi +4130 "decrement"/imm32/name +4131 0/imm32/no-inouts +4132 Single-int-var-in-edi/imm32/outputs +4133 "4f/decrement-edi"/imm32/subx-name +4134 0/imm32/no-rm32 +4135 0/imm32/no-r32 +4136 0/imm32/no-imm32 +4137 0/imm32/output-is-write-only +4138 _Primitive-inc-mem/imm32/next +4139 _Primitive-inc-mem: +4140 # increment var => ff 0/subop/increment *(ebp+__) +4141 "increment"/imm32/name +4142 Single-int-var-on-stack/imm32/inouts +4143 0/imm32/no-outputs +4144 "ff 0/subop/increment"/imm32/subx-name +4145 1/imm32/rm32-is-first-inout +4146 0/imm32/no-r32 +4147 0/imm32/no-imm32 +4148 0/imm32/output-is-write-only +4149 _Primitive-inc-reg/imm32/next +4150 _Primitive-inc-reg: +4151 # var/reg <- increment => ff 0/subop/increment %__ +4152 "increment"/imm32/name +4153 0/imm32/no-inouts +4154 Single-int-var-in-some-register/imm32/outputs +4155 "ff 0/subop/increment"/imm32/subx-name +4156 3/imm32/rm32-is-first-output +4157 0/imm32/no-r32 +4158 0/imm32/no-imm32 +4159 0/imm32/output-is-write-only +4160 _Primitive-dec-mem/imm32/next +4161 _Primitive-dec-mem: +4162 # decrement var => ff 1/subop/decrement *(ebp+__) +4163 "decrement"/imm32/name +4164 Single-int-var-on-stack/imm32/inouts +4165 0/imm32/no-outputs +4166 "ff 1/subop/decrement"/imm32/subx-name +4167 1/imm32/rm32-is-first-inout +4168 0/imm32/no-r32 +4169 0/imm32/no-imm32 +4170 0/imm32/output-is-write-only +4171 _Primitive-dec-reg/imm32/next +4172 _Primitive-dec-reg: +4173 # var/reg <- decrement => ff 1/subop/decrement %__ +4174 "decrement"/imm32/name +4175 0/imm32/no-inouts +4176 Single-int-var-in-some-register/imm32/outputs +4177 "ff 1/subop/decrement"/imm32/subx-name +4178 3/imm32/rm32-is-first-output +4179 0/imm32/no-r32 +4180 0/imm32/no-imm32 +4181 0/imm32/output-is-write-only +4182 _Primitive-add-to-eax/imm32/next +4183 # - add +4184 _Primitive-add-to-eax: +4185 # var/eax <- add lit => 05/add-to-eax lit/imm32 +4186 "add"/imm32/name +4187 Single-lit-var/imm32/inouts +4188 Single-int-var-in-eax/imm32/outputs +4189 "05/add-to-eax"/imm32/subx-name +4190 0/imm32/no-rm32 +4191 0/imm32/no-r32 +4192 1/imm32/imm32-is-first-inout +4193 0/imm32/output-is-write-only +4194 _Primitive-add-reg-to-reg/imm32/next +4195 _Primitive-add-reg-to-reg: +4196 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 +4197 "add"/imm32/name +4198 Single-int-var-in-some-register/imm32/inouts +4199 Single-int-var-in-some-register/imm32/outputs +4200 "01/add-to"/imm32/subx-name +4201 3/imm32/rm32-is-first-output +4202 1/imm32/r32-is-first-inout +4203 0/imm32/no-imm32 +4204 0/imm32/output-is-write-only +4205 _Primitive-add-reg-to-mem/imm32/next +4206 _Primitive-add-reg-to-mem: +4207 # add-to var1 var2/reg => 01/add-to var1 var2/r32 +4208 "add-to"/imm32/name +4209 Int-var-and-second-int-var-in-some-register/imm32/inouts +4210 0/imm32/outputs +4211 "01/add-to"/imm32/subx-name +4212 1/imm32/rm32-is-first-inout +4213 2/imm32/r32-is-second-inout +4214 0/imm32/no-imm32 +4215 0/imm32/output-is-write-only +4216 _Primitive-add-mem-to-reg/imm32/next +4217 _Primitive-add-mem-to-reg: +4218 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 +4219 "add"/imm32/name +4220 Single-int-var-on-stack/imm32/inouts +4221 Single-int-var-in-some-register/imm32/outputs +4222 "03/add"/imm32/subx-name +4223 1/imm32/rm32-is-first-inout +4224 3/imm32/r32-is-first-output +4225 0/imm32/no-imm32 +4226 0/imm32/output-is-write-only +4227 _Primitive-add-lit-to-reg/imm32/next +4228 _Primitive-add-lit-to-reg: +4229 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 +4230 "add"/imm32/name +4231 Single-lit-var/imm32/inouts +4232 Single-int-var-in-some-register/imm32/outputs +4233 "81 0/subop/add"/imm32/subx-name +4234 3/imm32/rm32-is-first-output +4235 0/imm32/no-r32 +4236 1/imm32/imm32-is-first-inout +4237 0/imm32/output-is-write-only +4238 _Primitive-add-lit-to-mem/imm32/next +4239 _Primitive-add-lit-to-mem: +4240 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 +4241 "add-to"/imm32/name +4242 Int-var-and-literal/imm32/inouts +4243 0/imm32/outputs +4244 "81 0/subop/add"/imm32/subx-name +4245 1/imm32/rm32-is-first-inout +4246 0/imm32/no-r32 +4247 2/imm32/imm32-is-first-inout +4248 0/imm32/output-is-write-only +4249 _Primitive-subtract-from-eax/imm32/next +4250 # - subtract +4251 _Primitive-subtract-from-eax: +4252 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 +4253 "subtract"/imm32/name +4254 Single-lit-var/imm32/inouts +4255 Single-int-var-in-eax/imm32/outputs +4256 "2d/subtract-from-eax"/imm32/subx-name +4257 0/imm32/no-rm32 +4258 0/imm32/no-r32 +4259 1/imm32/imm32-is-first-inout +4260 0/imm32/output-is-write-only +4261 _Primitive-subtract-reg-from-reg/imm32/next +4262 _Primitive-subtract-reg-from-reg: +4263 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 +4264 "subtract"/imm32/name +4265 Single-int-var-in-some-register/imm32/inouts +4266 Single-int-var-in-some-register/imm32/outputs +4267 "29/subtract-from"/imm32/subx-name +4268 3/imm32/rm32-is-first-output +4269 1/imm32/r32-is-first-inout +4270 0/imm32/no-imm32 +4271 0/imm32/output-is-write-only +4272 _Primitive-subtract-reg-from-mem/imm32/next +4273 _Primitive-subtract-reg-from-mem: +4274 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 +4275 "subtract-from"/imm32/name +4276 Int-var-and-second-int-var-in-some-register/imm32/inouts +4277 0/imm32/outputs +4278 "29/subtract-from"/imm32/subx-name +4279 1/imm32/rm32-is-first-inout +4280 2/imm32/r32-is-second-inout +4281 0/imm32/no-imm32 +4282 0/imm32/output-is-write-only +4283 _Primitive-subtract-mem-from-reg/imm32/next +4284 _Primitive-subtract-mem-from-reg: +4285 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 +4286 "subtract"/imm32/name +4287 Single-int-var-on-stack/imm32/inouts +4288 Single-int-var-in-some-register/imm32/outputs +4289 "2b/subtract"/imm32/subx-name +4290 1/imm32/rm32-is-first-inout +4291 3/imm32/r32-is-first-output +4292 0/imm32/no-imm32 +4293 0/imm32/output-is-write-only +4294 _Primitive-subtract-lit-from-reg/imm32/next +4295 _Primitive-subtract-lit-from-reg: +4296 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 +4297 "subtract"/imm32/name +4298 Single-lit-var/imm32/inouts +4299 Single-int-var-in-some-register/imm32/outputs +4300 "81 5/subop/subtract"/imm32/subx-name +4301 3/imm32/rm32-is-first-output +4302 0/imm32/no-r32 +4303 1/imm32/imm32-is-first-inout +4304 0/imm32/output-is-write-only +4305 _Primitive-subtract-lit-from-mem/imm32/next +4306 _Primitive-subtract-lit-from-mem: +4307 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 +4308 "subtract-from"/imm32/name +4309 Int-var-and-literal/imm32/inouts +4310 0/imm32/outputs +4311 "81 5/subop/subtract"/imm32/subx-name +4312 1/imm32/rm32-is-first-inout +4313 0/imm32/no-r32 +4314 2/imm32/imm32-is-first-inout +4315 0/imm32/output-is-write-only +4316 _Primitive-and-with-eax/imm32/next +4317 # - and +4318 _Primitive-and-with-eax: +4319 # var/eax <- and lit => 25/and-with-eax lit/imm32 +4320 "and"/imm32/name +4321 Single-lit-var/imm32/inouts +4322 Single-int-var-in-eax/imm32/outputs +4323 "25/and-with-eax"/imm32/subx-name +4324 0/imm32/no-rm32 +4325 0/imm32/no-r32 +4326 1/imm32/imm32-is-first-inout +4327 0/imm32/output-is-write-only +4328 _Primitive-and-reg-with-reg/imm32/next +4329 _Primitive-and-reg-with-reg: +4330 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 +4331 "and"/imm32/name +4332 Single-int-var-in-some-register/imm32/inouts +4333 Single-int-var-in-some-register/imm32/outputs +4334 "21/and-with"/imm32/subx-name +4335 3/imm32/rm32-is-first-output +4336 1/imm32/r32-is-first-inout +4337 0/imm32/no-imm32 +4338 0/imm32/output-is-write-only +4339 _Primitive-and-reg-with-mem/imm32/next +4340 _Primitive-and-reg-with-mem: +4341 # and-with var1 var2/reg => 21/and-with var1 var2/r32 +4342 "and-with"/imm32/name +4343 Int-var-and-second-int-var-in-some-register/imm32/inouts +4344 0/imm32/outputs +4345 "21/and-with"/imm32/subx-name +4346 1/imm32/rm32-is-first-inout +4347 2/imm32/r32-is-second-inout +4348 0/imm32/no-imm32 +4349 0/imm32/output-is-write-only +4350 _Primitive-and-mem-with-reg/imm32/next +4351 _Primitive-and-mem-with-reg: +4352 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 +4353 "and"/imm32/name +4354 Single-int-var-on-stack/imm32/inouts +4355 Single-int-var-in-some-register/imm32/outputs +4356 "23/and"/imm32/subx-name +4357 1/imm32/rm32-is-first-inout +4358 3/imm32/r32-is-first-output +4359 0/imm32/no-imm32 +4360 0/imm32/output-is-write-only +4361 _Primitive-and-lit-with-reg/imm32/next +4362 _Primitive-and-lit-with-reg: +4363 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 +4364 "and"/imm32/name +4365 Single-lit-var/imm32/inouts +4366 Single-int-var-in-some-register/imm32/outputs +4367 "81 4/subop/and"/imm32/subx-name +4368 3/imm32/rm32-is-first-output +4369 0/imm32/no-r32 +4370 1/imm32/imm32-is-first-inout +4371 0/imm32/output-is-write-only +4372 _Primitive-and-lit-with-mem/imm32/next +4373 _Primitive-and-lit-with-mem: +4374 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 +4375 "and-with"/imm32/name +4376 Int-var-and-literal/imm32/inouts +4377 0/imm32/outputs +4378 "81 4/subop/and"/imm32/subx-name +4379 1/imm32/rm32-is-first-inout +4380 0/imm32/no-r32 +4381 2/imm32/imm32-is-first-inout +4382 0/imm32/output-is-write-only +4383 _Primitive-or-with-eax/imm32/next +4384 # - or +4385 _Primitive-or-with-eax: +4386 # var/eax <- or lit => 0d/or-with-eax lit/imm32 +4387 "or"/imm32/name +4388 Single-lit-var/imm32/inouts +4389 Single-int-var-in-eax/imm32/outputs +4390 "0d/or-with-eax"/imm32/subx-name +4391 0/imm32/no-rm32 +4392 0/imm32/no-r32 +4393 1/imm32/imm32-is-first-inout +4394 0/imm32/output-is-write-only +4395 _Primitive-or-reg-with-reg/imm32/next +4396 _Primitive-or-reg-with-reg: +4397 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 +4398 "or"/imm32/name +4399 Single-int-var-in-some-register/imm32/inouts +4400 Single-int-var-in-some-register/imm32/outputs +4401 "09/or-with"/imm32/subx-name +4402 3/imm32/rm32-is-first-output +4403 1/imm32/r32-is-first-inout +4404 0/imm32/no-imm32 +4405 0/imm32/output-is-write-only +4406 _Primitive-or-reg-with-mem/imm32/next +4407 _Primitive-or-reg-with-mem: +4408 # or-with var1 var2/reg => 09/or-with var1 var2/r32 +4409 "or-with"/imm32/name +4410 Int-var-and-second-int-var-in-some-register/imm32/inouts +4411 0/imm32/outputs +4412 "09/or-with"/imm32/subx-name +4413 1/imm32/rm32-is-first-inout +4414 2/imm32/r32-is-second-inout +4415 0/imm32/no-imm32 +4416 0/imm32/output-is-write-only +4417 _Primitive-or-mem-with-reg/imm32/next +4418 _Primitive-or-mem-with-reg: +4419 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 +4420 "or"/imm32/name +4421 Single-int-var-on-stack/imm32/inouts +4422 Single-int-var-in-some-register/imm32/outputs +4423 "0b/or"/imm32/subx-name +4424 1/imm32/rm32-is-first-inout +4425 3/imm32/r32-is-first-output +4426 0/imm32/no-imm32 +4427 0/imm32/output-is-write-only +4428 _Primitive-or-lit-with-reg/imm32/next +4429 _Primitive-or-lit-with-reg: +4430 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 +4431 "or"/imm32/name +4432 Single-lit-var/imm32/inouts +4433 Single-int-var-in-some-register/imm32/outputs +4434 "81 4/subop/or"/imm32/subx-name +4435 3/imm32/rm32-is-first-output +4436 0/imm32/no-r32 +4437 1/imm32/imm32-is-first-inout +4438 0/imm32/output-is-write-only +4439 _Primitive-or-lit-with-mem/imm32/next +4440 _Primitive-or-lit-with-mem: +4441 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 +4442 "or-with"/imm32/name +4443 Int-var-and-literal/imm32/inouts +4444 0/imm32/outputs +4445 "81 4/subop/or"/imm32/subx-name +4446 1/imm32/rm32-is-first-inout +4447 0/imm32/no-r32 +4448 2/imm32/imm32-is-first-inout +4449 0/imm32/output-is-write-only +4450 _Primitive-xor-with-eax/imm32/next +4451 # - xor +4452 _Primitive-xor-with-eax: +4453 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 +4454 "xor"/imm32/name +4455 Single-lit-var/imm32/inouts +4456 Single-int-var-in-eax/imm32/outputs +4457 "35/xor-with-eax"/imm32/subx-name +4458 0/imm32/no-rm32 +4459 0/imm32/no-r32 +4460 1/imm32/imm32-is-first-inout +4461 0/imm32/output-is-write-only +4462 _Primitive-xor-reg-with-reg/imm32/next +4463 _Primitive-xor-reg-with-reg: +4464 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 +4465 "xor"/imm32/name +4466 Single-int-var-in-some-register/imm32/inouts +4467 Single-int-var-in-some-register/imm32/outputs +4468 "31/xor-with"/imm32/subx-name +4469 3/imm32/rm32-is-first-output +4470 1/imm32/r32-is-first-inout +4471 0/imm32/no-imm32 +4472 0/imm32/output-is-write-only +4473 _Primitive-xor-reg-with-mem/imm32/next +4474 _Primitive-xor-reg-with-mem: +4475 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 +4476 "xor-with"/imm32/name +4477 Int-var-and-second-int-var-in-some-register/imm32/inouts +4478 0/imm32/outputs +4479 "31/xor-with"/imm32/subx-name +4480 1/imm32/rm32-is-first-inout +4481 2/imm32/r32-is-second-inout +4482 0/imm32/no-imm32 +4483 0/imm32/output-is-write-only +4484 _Primitive-xor-mem-with-reg/imm32/next +4485 _Primitive-xor-mem-with-reg: +4486 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 +4487 "xor"/imm32/name +4488 Single-int-var-on-stack/imm32/inouts +4489 Single-int-var-in-some-register/imm32/outputs +4490 "33/xor"/imm32/subx-name +4491 1/imm32/rm32-is-first-inout +4492 3/imm32/r32-is-first-output +4493 0/imm32/no-imm32 +4494 0/imm32/output-is-write-only +4495 _Primitive-xor-lit-with-reg/imm32/next +4496 _Primitive-xor-lit-with-reg: +4497 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 +4498 "xor"/imm32/name +4499 Single-lit-var/imm32/inouts +4500 Single-int-var-in-some-register/imm32/outputs +4501 "81 4/subop/xor"/imm32/subx-name +4502 3/imm32/rm32-is-first-output +4503 0/imm32/no-r32 +4504 1/imm32/imm32-is-first-inout +4505 0/imm32/output-is-write-only +4506 _Primitive-xor-lit-with-mem/imm32/next +4507 _Primitive-xor-lit-with-mem: +4508 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 +4509 "xor-with"/imm32/name +4510 Int-var-and-literal/imm32/inouts +4511 0/imm32/outputs +4512 "81 4/subop/xor"/imm32/subx-name +4513 1/imm32/rm32-is-first-inout +4514 0/imm32/no-r32 +4515 2/imm32/imm32-is-first-inout +4516 0/imm32/output-is-write-only +4517 _Primitive-copy-to-eax/imm32/next +4518 # - copy +4519 _Primitive-copy-to-eax: +4520 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 +4521 "copy"/imm32/name +4522 Single-lit-var/imm32/inouts +4523 Single-int-var-in-eax/imm32/outputs +4524 "b8/copy-to-eax"/imm32/subx-name +4525 0/imm32/no-rm32 +4526 0/imm32/no-r32 +4527 1/imm32/imm32-is-first-inout +4528 1/imm32/output-is-write-only +4529 _Primitive-copy-to-ecx/imm32/next +4530 _Primitive-copy-to-ecx: +4531 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 +4532 "copy"/imm32/name +4533 Single-lit-var/imm32/inouts +4534 Single-int-var-in-ecx/imm32/outputs +4535 "b9/copy-to-ecx"/imm32/subx-name +4536 0/imm32/no-rm32 +4537 0/imm32/no-r32 +4538 1/imm32/imm32-is-first-inout +4539 1/imm32/output-is-write-only +4540 _Primitive-copy-to-edx/imm32/next +4541 _Primitive-copy-to-edx: +4542 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 +4543 "copy"/imm32/name +4544 Single-lit-var/imm32/inouts +4545 Single-int-var-in-edx/imm32/outputs +4546 "ba/copy-to-edx"/imm32/subx-name +4547 0/imm32/no-rm32 +4548 0/imm32/no-r32 +4549 1/imm32/imm32-is-first-inout +4550 1/imm32/output-is-write-only +4551 _Primitive-copy-to-ebx/imm32/next +4552 _Primitive-copy-to-ebx: +4553 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 +4554 "copy"/imm32/name +4555 Single-lit-var/imm32/inouts +4556 Single-int-var-in-ebx/imm32/outputs +4557 "bb/copy-to-ebx"/imm32/subx-name +4558 0/imm32/no-rm32 +4559 0/imm32/no-r32 +4560 1/imm32/imm32-is-first-inout +4561 1/imm32/output-is-write-only +4562 _Primitive-copy-to-esi/imm32/next +4563 _Primitive-copy-to-esi: +4564 # var/esi <- copy lit => be/copy-to-esi lit/imm32 +4565 "copy"/imm32/name +4566 Single-lit-var/imm32/inouts +4567 Single-int-var-in-esi/imm32/outputs +4568 "be/copy-to-esi"/imm32/subx-name +4569 0/imm32/no-rm32 +4570 0/imm32/no-r32 +4571 1/imm32/imm32-is-first-inout +4572 1/imm32/output-is-write-only +4573 _Primitive-copy-to-edi/imm32/next +4574 _Primitive-copy-to-edi: +4575 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 +4576 "copy"/imm32/name +4577 Single-lit-var/imm32/inouts +4578 Single-int-var-in-edi/imm32/outputs +4579 "bf/copy-to-edi"/imm32/subx-name +4580 0/imm32/no-rm32 +4581 0/imm32/no-r32 +4582 1/imm32/imm32-is-first-inout +4583 1/imm32/output-is-write-only +4584 _Primitive-copy-reg-to-reg/imm32/next +4585 _Primitive-copy-reg-to-reg: +4586 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 +4587 "copy"/imm32/name +4588 Single-int-var-in-some-register/imm32/inouts +4589 Single-int-var-in-some-register/imm32/outputs +4590 "89/copy-to"/imm32/subx-name +4591 3/imm32/rm32-is-first-output +4592 1/imm32/r32-is-first-inout +4593 0/imm32/no-imm32 +4594 1/imm32/output-is-write-only +4595 _Primitive-copy-reg-to-mem/imm32/next +4596 _Primitive-copy-reg-to-mem: +4597 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 +4598 "copy-to"/imm32/name +4599 Int-var-and-second-int-var-in-some-register/imm32/inouts +4600 0/imm32/outputs +4601 "89/copy-to"/imm32/subx-name +4602 1/imm32/rm32-is-first-inout +4603 2/imm32/r32-is-second-inout +4604 0/imm32/no-imm32 +4605 1/imm32/output-is-write-only +4606 _Primitive-copy-mem-to-reg/imm32/next +4607 _Primitive-copy-mem-to-reg: +4608 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 +4609 "copy"/imm32/name +4610 Single-int-var-on-stack/imm32/inouts +4611 Single-int-var-in-some-register/imm32/outputs +4612 "8b/copy-from"/imm32/subx-name +4613 1/imm32/rm32-is-first-inout +4614 3/imm32/r32-is-first-output +4615 0/imm32/no-imm32 +4616 1/imm32/output-is-write-only +4617 _Primitive-copy-lit-to-reg/imm32/next +4618 _Primitive-copy-lit-to-reg: +4619 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 +4620 "copy"/imm32/name +4621 Single-lit-var/imm32/inouts +4622 Single-int-var-in-some-register/imm32/outputs +4623 "c7 0/subop/copy"/imm32/subx-name +4624 3/imm32/rm32-is-first-output +4625 0/imm32/no-r32 +4626 1/imm32/imm32-is-first-inout +4627 1/imm32/output-is-write-only +4628 _Primitive-copy-lit-to-mem/imm32/next +4629 _Primitive-copy-lit-to-mem: +4630 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 +4631 "copy-to"/imm32/name +4632 Int-var-and-literal/imm32/inouts +4633 0/imm32/outputs +4634 "c7 0/subop/copy"/imm32/subx-name +4635 1/imm32/rm32-is-first-inout +4636 0/imm32/no-r32 +4637 2/imm32/imm32-is-first-inout +4638 1/imm32/output-is-write-only +4639 0/imm32/next +4640 +4641 Single-int-var-on-stack: +4642 Int-var-on-stack/imm32 +4643 0/imm32/next +4644 +4645 Int-var-on-stack: +4646 "arg1"/imm32/name +4647 Type-int/imm32 +4648 1/imm32/some-block-depth +4649 1/imm32/some-stack-offset +4650 0/imm32/no-register +4651 +4652 Int-var-and-second-int-var-in-some-register: +4653 Int-var-on-stack/imm32 +4654 Single-int-var-in-some-register/imm32/next +4655 +4656 Int-var-and-literal: +4657 Int-var-on-stack/imm32 +4658 Single-lit-var/imm32/next +4659 +4660 Single-int-var-in-some-register: +4661 Int-var-in-some-register/imm32 +4662 0/imm32/next +4663 +4664 Int-var-in-some-register: +4665 "arg1"/imm32/name +4666 Type-int/imm32 +4667 1/imm32/some-block-depth +4668 0/imm32/no-stack-offset +4669 "*"/imm32/register +4670 +4671 Single-int-var-in-eax: +4672 Int-var-in-eax/imm32 +4673 0/imm32/next +4674 +4675 Int-var-in-eax: +4676 "arg1"/imm32/name +4677 Type-int/imm32 +4678 1/imm32/some-block-depth +4679 0/imm32/no-stack-offset +4680 "eax"/imm32/register +4681 +4682 Single-int-var-in-ecx: +4683 Int-var-in-ecx/imm32 +4684 0/imm32/next +4685 +4686 Int-var-in-ecx: +4687 "arg1"/imm32/name +4688 Type-int/imm32 +4689 1/imm32/some-block-depth +4690 0/imm32/no-stack-offset +4691 "ecx"/imm32/register +4692 +4693 Single-int-var-in-edx: +4694 Int-var-in-edx/imm32 +4695 0/imm32/next +4696 +4697 Int-var-in-edx: +4698 "arg1"/imm32/name +4699 Type-int/imm32 +4700 1/imm32/some-block-depth +4701 0/imm32/no-stack-offset +4702 "edx"/imm32/register +4703 +4704 Single-int-var-in-ebx: +4705 Int-var-in-ebx/imm32 +4706 0/imm32/next +4707 +4708 Int-var-in-ebx: +4709 "arg1"/imm32/name +4710 Type-int/imm32 +4711 1/imm32/some-block-depth +4712 0/imm32/no-stack-offset +4713 "ebx"/imm32/register +4714 +4715 Single-int-var-in-esi: +4716 Int-var-in-esi/imm32 +4717 0/imm32/next +4718 +4719 Int-var-in-esi: +4720 "arg1"/imm32/name +4721 Type-int/imm32 +4722 1/imm32/some-block-depth +4723 0/imm32/no-stack-offset +4724 "esi"/imm32/register +4725 +4726 Single-int-var-in-edi: +4727 Int-var-in-edi/imm32 +4728 0/imm32/next +4729 +4730 Int-var-in-edi: +4731 "arg1"/imm32/name +4732 Type-int/imm32 +4733 1/imm32/some-block-depth +4734 0/imm32/no-stack-offset +4735 "edi"/imm32/register +4736 +4737 Single-lit-var: +4738 Lit-var/imm32 +4739 0/imm32/next +4740 +4741 Lit-var: +4742 "literal"/imm32/name +4743 Type-literal/imm32 +4744 1/imm32/some-block-depth +4745 0/imm32/no-stack-offset +4746 0/imm32/no-register +4747 +4748 Type-int: +4749 1/imm32/left/int +4750 0/imm32/right/null +4751 +4752 Type-literal: +4753 0/imm32/left/literal +4754 0/imm32/right/null +4755 +4756 == code +4757 emit-subx-primitive: # out: (addr buffered-file), stmt: (handle statement), primitive: (handle function) +4758 # . prologue +4759 55/push-ebp +4760 89/<- %ebp 4/r32/esp +4761 # . save registers +4762 50/push-eax +4763 51/push-ecx +4764 # ecx = primitive +4765 8b/-> *(ebp+0x10) 1/r32/ecx +4766 # emit primitive name +4767 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name +4768 # emit rm32 if necessary +4769 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt +4770 # emit r32 if necessary +4771 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt +4772 # emit imm32 if necessary +4773 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt +4774 $emit-subx-primitive:end: +4775 # . restore registers +4776 59/pop-to-ecx +4777 58/pop-to-eax +4778 # . epilogue +4779 89/<- %esp 5/r32/ebp +4780 5d/pop-to-ebp +4781 c3/return +4782 +4783 emit-subx-rm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) +4784 # . prologue +4785 55/push-ebp +4786 89/<- %ebp 4/r32/esp +4787 # . save registers +4788 50/push-eax +4789 # if (l == 0) return +4790 81 7/subop/compare *(ebp+0xc) 0/imm32 +4791 74/jump-if-= $emit-subx-rm32:end/disp8 +4792 # +4793 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4794 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var +4795 $emit-subx-rm32:end: +4796 # . restore registers +4797 58/pop-to-eax +4798 # . epilogue +4799 89/<- %esp 5/r32/ebp +4800 5d/pop-to-ebp +4801 c3/return +4802 +4803 get-stmt-operand-from-arg-location: # stmt: (handle statement), l: arg-location -> var/eax: (handle variable) +4804 # . prologue +4805 55/push-ebp +4806 89/<- %ebp 4/r32/esp +4807 # . save registers +4808 51/push-ecx +4809 # eax = l +4810 8b/-> *(ebp+0xc) 0/r32/eax +4811 # ecx = stmt +4812 8b/-> *(ebp+8) 1/r32/ecx +4813 # if (l == 1) return stmt->inouts->var +4814 { +4815 3d/compare-eax-and 1/imm32 +4816 75/jump-if-!= break/disp8 +4817 $get-stmt-operand-from-arg-location:1: +4818 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +4819 8b/-> *eax 0/r32/eax # Operand-var +4820 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4821 } +4822 # if (l == 2) return stmt->inouts->next->var +4823 { +4824 3d/compare-eax-and 2/imm32 +4825 75/jump-if-!= break/disp8 +4826 $get-stmt-operand-from-arg-location:2: +4827 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +4828 8b/-> *(eax+4) 0/r32/eax # Operand-next +4829 8b/-> *eax 0/r32/eax # Operand-var +4830 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4831 } +4832 # if (l == 3) return stmt->outputs +4833 { +4834 3d/compare-eax-and 3/imm32 +4835 75/jump-if-!= break/disp8 +4836 $get-stmt-operand-from-arg-location:3: +4837 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs +4838 8b/-> *eax 0/r32/eax # Operand-var +4839 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4840 } +4841 # abort +4842 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 +4843 $get-stmt-operand-from-arg-location:end: +4844 # . restore registers +4845 59/pop-to-ecx +4846 # . epilogue +4847 89/<- %esp 5/r32/ebp +4848 5d/pop-to-ebp +4849 c3/return +4850 +4851 $get-stmt-operand-from-arg-location:abort: +4852 # error("invalid arg-location " eax) +4853 (write-buffered Stderr "invalid arg-location ") +4854 (print-int32-buffered Stderr %eax) +4855 (write-buffered Stderr Newline) +4856 (flush Stderr) +4857 # . syscall(exit, 1) +4858 bb/copy-to-ebx 1/imm32 +4859 b8/copy-to-eax 1/imm32/exit +4860 cd/syscall 0x80/imm8 +4861 # never gets here +4862 +4863 emit-subx-r32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) +4864 # . prologue +4865 55/push-ebp +4866 89/<- %ebp 4/r32/esp +4867 # . save registers +4868 50/push-eax +4869 51/push-ecx +4870 # if (location == 0) return +4871 81 7/subop/compare *(ebp+0xc) 0/imm32 +4872 0f 84/jump-if-= $emit-subx-r32:end/disp32 +4873 # +4874 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4875 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax: (addr register-index) +4876 (write-buffered *(ebp+8) Space) +4877 (print-int32-buffered *(ebp+8) *eax) +4878 (write-buffered *(ebp+8) "/r32") +4879 $emit-subx-r32:end: +4880 # . restore registers +4881 59/pop-to-ecx +4882 58/pop-to-eax +4883 # . epilogue +4884 89/<- %esp 5/r32/ebp +4885 5d/pop-to-ebp +4886 c3/return +4887 +4888 emit-subx-imm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) +4889 # . prologue +4890 55/push-ebp +4891 89/<- %ebp 4/r32/esp +4892 # . save registers +4893 50/push-eax +4894 51/push-ecx +4895 # if (location == 0) return +4896 81 7/subop/compare *(ebp+0xc) 0/imm32 +4897 74/jump-if-= $emit-subx-imm32:end/disp8 +4898 # +4899 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4900 (write-buffered *(ebp+8) Space) +4901 (write-buffered *(ebp+8) *eax) # Var-name +4902 (write-buffered *(ebp+8) "/imm32") +4903 $emit-subx-imm32:end: +4904 # . restore registers +4905 59/pop-to-ecx +4906 58/pop-to-eax +4907 # . epilogue +4908 89/<- %esp 5/r32/ebp +4909 5d/pop-to-ebp +4910 c3/return +4911 +4912 emit-subx-call: # out: (addr buffered-file), stmt: (handle statement), callee: (handle function) +4913 # . prologue +4914 55/push-ebp +4915 89/<- %ebp 4/r32/esp +4916 # . save registers +4917 50/push-eax +4918 51/push-ecx +4919 # +4920 (write-buffered *(ebp+8) "(") +4921 # - emit function name +4922 8b/-> *(ebp+0x10) 1/r32/ecx +4923 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name +4924 # - emit arguments +4925 # var curr/ecx: (handle list var) = stmt->inouts +4926 8b/-> *(ebp+0xc) 1/r32/ecx +4927 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts +4928 { +4929 # if (curr == null) break +4930 81 7/subop/compare %ecx 0/imm32 +4931 74/jump-if-= break/disp8 +4932 # +4933 (emit-subx-call-operand *(ebp+8) *ecx) +4934 # curr = curr->next +4935 8b/-> *(ecx+4) 1/r32/ecx +4936 eb/jump loop/disp8 +4937 } +4938 # +4939 (write-buffered *(ebp+8) ")") +4940 $emit-subx-call:end: +4941 # . restore registers +4942 59/pop-to-ecx +4943 58/pop-to-eax +4944 # . epilogue +4945 89/<- %esp 5/r32/ebp +4946 5d/pop-to-ebp +4947 c3/return +4948 +4949 emit-subx-call-operand: # out: (addr buffered-file), operand: (handle variable) +4950 # . prologue +4951 55/push-ebp +4952 89/<- %ebp 4/r32/esp +4953 # . save registers +4954 50/push-eax +4955 # eax = operand +4956 8b/-> *(ebp+0xc) 0/r32/eax +4957 # if (operand->register) emit "%__" +4958 { +4959 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +4960 74/jump-if-= break/disp8 +4961 $emit-subx-call-operand:register: +4962 (write-buffered *(ebp+8) " %") +4963 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +4964 e9/jump $emit-subx-call-operand:end/disp32 +4965 } +4966 # else if (operand->stack-offset) emit "*(ebp+__)" +4967 { +4968 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +4969 74/jump-if-= break/disp8 +4970 $emit-subx-call-operand:stack: +4971 (write-buffered *(ebp+8) Space) +4972 (write-buffered *(ebp+8) "*(ebp+") +4973 8b/-> *(ebp+0xc) 0/r32/eax +4974 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +4975 (write-buffered *(ebp+8) ")") +4976 e9/jump $emit-subx-call-operand:end/disp32 +4977 } +4978 # else if (operand->type == literal) emit "__" +4979 { +4980 50/push-eax +4981 8b/-> *(eax+4) 0/r32/eax # Var-type +4982 81 7/subop/compare *eax 0/imm32 # Tree-left +4983 58/pop-to-eax +4984 75/jump-if-!= break/disp8 +4985 $emit-subx-call-operand:literal: +4986 (write-buffered *(ebp+8) Space) +4987 (write-buffered *(ebp+8) *eax) +4988 } +4989 $emit-subx-call-operand:end: +4990 # . restore registers +4991 58/pop-to-eax +4992 # . epilogue +4993 89/<- %esp 5/r32/ebp +4994 5d/pop-to-ebp +4995 c3/return +4996 +4997 emit-subx-var-as-rm32: # out: (addr buffered-file), operand: (handle variable) +4998 # . prologue +4999 55/push-ebp +5000 89/<- %ebp 4/r32/esp +5001 # . save registers +5002 50/push-eax +5003 # eax = operand +5004 8b/-> *(ebp+0xc) 0/r32/eax +5005 # if (operand->register) emit "%__" +5006 { +5007 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +5008 74/jump-if-= break/disp8 +5009 $emit-subx-var-as-rm32:register: +5010 (write-buffered *(ebp+8) " %") +5011 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +5012 } +5013 # else if (operand->stack-offset) emit "*(ebp+__)" +5014 { +5015 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +5016 74/jump-if-= break/disp8 +5017 $emit-subx-var-as-rm32:stack: +5018 (write-buffered *(ebp+8) Space) +5019 (write-buffered *(ebp+8) "*(ebp+") +5020 8b/-> *(ebp+0xc) 0/r32/eax +5021 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +5022 (write-buffered *(ebp+8) ")") +5023 } +5024 $emit-subx-var-as-rm32:end: +5025 # . restore registers +5026 58/pop-to-eax +5027 # . epilogue +5028 89/<- %esp 5/r32/ebp +5029 5d/pop-to-ebp +5030 c3/return +5031 +5032 find-matching-function: # functions: (addr function), stmt: (handle statement) -> result/eax: (handle function) +5033 # . prologue +5034 55/push-ebp +5035 89/<- %ebp 4/r32/esp +5036 # . save registers +5037 51/push-ecx +5038 # var curr/ecx: (handle function) = functions +5039 8b/-> *(ebp+8) 1/r32/ecx +5040 { +5041 # if (curr == null) break +5042 81 7/subop/compare %ecx 0/imm32 +5043 74/jump-if-= break/disp8 +5044 # if match(stmt, curr) return curr +5045 { +5046 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax +5047 3d/compare-eax-and 0/imm32 +5048 74/jump-if-= break/disp8 +5049 89/<- %eax 1/r32/ecx +5050 eb/jump $find-matching-function:end/disp8 +5051 } +5052 # curr = curr->next +5053 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +5054 eb/jump loop/disp8 +5055 } +5056 # return null +5057 b8/copy-to-eax 0/imm32 +5058 $find-matching-function:end: +5059 # . restore registers +5060 59/pop-to-ecx +5061 # . epilogue +5062 89/<- %esp 5/r32/ebp +5063 5d/pop-to-ebp +5064 c3/return +5065 +5066 find-matching-primitive: # primitives: (handle primitive), stmt: (handle statement) -> result/eax: (handle primitive) +5067 # . prologue +5068 55/push-ebp +5069 89/<- %ebp 4/r32/esp +5070 # . save registers +5071 51/push-ecx +5072 # var curr/ecx: (handle primitive) = primitives +5073 8b/-> *(ebp+8) 1/r32/ecx +5074 { +5075 $find-matching-primitive:loop: +5076 # if (curr == null) break +5077 81 7/subop/compare %ecx 0/imm32 +5078 0f 84/jump-if-= break/disp32 +5079 #? (write-buffered Stderr "prim: ") +5080 #? (write-buffered Stderr *ecx) # Primitive-name +5081 #? (write-buffered Stderr " => ") +5082 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name +5083 #? (write-buffered Stderr Newline) +5084 #? (flush Stderr) +5085 # if match(curr, stmt) return curr +5086 { +5087 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax +5088 3d/compare-eax-and 0/imm32 +5089 74/jump-if-= break/disp8 +5090 89/<- %eax 1/r32/ecx +5091 eb/jump $find-matching-primitive:end/disp8 +5092 } +5093 $find-matching-primitive:next-primitive: +5094 # curr = curr->next +5095 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next +5096 e9/jump loop/disp32 +5097 } +5098 # return null +5099 b8/copy-to-eax 0/imm32 +5100 $find-matching-primitive:end: +5101 # . restore registers +5102 59/pop-to-ecx +5103 # . epilogue +5104 89/<- %esp 5/r32/ebp +5105 5d/pop-to-ebp +5106 c3/return +5107 +5108 mu-stmt-matches-function?: # stmt: (handle statement), function: (handle function) => result/eax: boolean +5109 # . prologue +5110 55/push-ebp +5111 89/<- %ebp 4/r32/esp +5112 # . save registers +5113 51/push-ecx +5114 # return function->name == stmt->operation +5115 8b/-> *(ebp+8) 1/r32/ecx +5116 8b/-> *(ebp+0xc) 0/r32/eax +5117 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax +5118 $mu-stmt-matches-function?:end: +5119 # . restore registers +5120 59/pop-to-ecx +5121 # . epilogue +5122 89/<- %esp 5/r32/ebp +5123 5d/pop-to-ebp +5124 c3/return +5125 +5126 mu-stmt-matches-primitive?: # stmt: (handle statement), primitive: (handle primitive) => result/eax: boolean +5127 # A mu stmt matches a primitive if the name matches, all the inout vars +5128 # match, and all the output vars match. +5129 # Vars match if types match and registers match. +5130 # In addition, a stmt output matches a primitive's output if types match +5131 # and the primitive has a wildcard register. +5132 # . prologue +5133 55/push-ebp +5134 89/<- %ebp 4/r32/esp +5135 # . save registers +5136 51/push-ecx +5137 52/push-edx +5138 53/push-ebx +5139 56/push-esi +5140 57/push-edi +5141 # ecx = stmt +5142 8b/-> *(ebp+8) 1/r32/ecx +5143 # edx = primitive +5144 8b/-> *(ebp+0xc) 2/r32/edx +5145 { +5146 $mu-stmt-matches-primitive?:check-name: +5147 # if (primitive->name != stmt->operation) return false +5148 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax +5149 3d/compare-eax-and 0/imm32 +5150 75/jump-if-!= break/disp8 +5151 b8/copy-to-eax 0/imm32 +5152 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5153 } +5154 $mu-stmt-matches-primitive?:check-inouts: +5155 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) +5156 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts +5157 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts +5158 { +5159 # if (curr == 0 && curr2 == 0) move on to check outputs +5160 { +5161 81 7/subop/compare %esi 0/imm32 +5162 75/jump-if-!= break/disp8 +5163 $mu-stmt-matches-primitive?:stmt-inout-is-null: +5164 { +5165 81 7/subop/compare %edi 0/imm32 +5166 75/jump-if-!= break/disp8 +5167 # +5168 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 +5169 } +5170 # return false +5171 b8/copy-to-eax 0/imm32/false +5172 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5173 } +5174 # if (curr2 == 0) return false +5175 { +5176 81 7/subop/compare %edi 0/imm32 +5177 75/jump-if-!= break/disp8 +5178 $mu-stmt-matches-primitive?:prim-inout-is-null: +5179 b8/copy-to-eax 0/imm32/false +5180 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5181 } +5182 # if (curr != curr2) return false +5183 { +5184 (operand-matches-primitive? *esi *edi) # => eax +5185 3d/compare-eax-and 0/imm32 +5186 75/jump-if-!= break/disp8 +5187 b8/copy-to-eax 0/imm32/false +5188 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5189 } +5190 # curr=curr->next +5191 8b/-> *(esi+4) 6/r32/esi # Operand-next +5192 # curr2=curr2->next +5193 8b/-> *(edi+4) 7/r32/edi # Operand-next +5194 eb/jump loop/disp8 +5195 } +5196 $mu-stmt-matches-primitive?:check-outputs: +5197 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) +5198 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs +5199 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs +5200 { +5201 # if (curr == 0) return (curr2 == 0) +5202 { +5203 $mu-stmt-matches-primitive?:check-output: +5204 81 7/subop/compare %esi 0/imm32 +5205 75/jump-if-!= break/disp8 +5206 { +5207 81 7/subop/compare %edi 0/imm32 +5208 75/jump-if-!= break/disp8 +5209 # return true +5210 b8/copy-to-eax 1/imm32 +5211 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5212 } +5213 # return false +5214 b8/copy-to-eax 0/imm32 +5215 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5216 } +5217 # if (curr2 == 0) return false +5218 { +5219 81 7/subop/compare %edi 0/imm32 +5220 75/jump-if-!= break/disp8 +5221 b8/copy-to-eax 0/imm32 +5222 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5223 } +5224 # if (curr != curr2) return false +5225 { +5226 (operand-matches-primitive? *esi *edi) # List-value List-value => eax +5227 3d/compare-eax-and 0/imm32 +5228 75/jump-if-!= break/disp8 +5229 b8/copy-to-eax 0/imm32 +5230 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5231 } +5232 # curr=curr->next +5233 8b/-> *(esi+4) 6/r32/esi # Operand-next +5234 # curr2=curr2->next +5235 8b/-> *(edi+4) 7/r32/edi # Operand-next +5236 eb/jump loop/disp8 +5237 } +5238 $mu-stmt-matches-primitive?:return-true: +5239 b8/copy-to-eax 1/imm32 +5240 $mu-stmt-matches-primitive?:end: +5241 # . restore registers +5242 5f/pop-to-edi +5243 5e/pop-to-esi +5244 5b/pop-to-ebx +5245 5a/pop-to-edx +5246 59/pop-to-ecx +5247 # . epilogue +5248 89/<- %esp 5/r32/ebp +5249 5d/pop-to-ebp +5250 c3/return +5251 +5252 operand-matches-primitive?: # var: (handle var), prim-var: (handle var) => result/eax: boolean +5253 # . prologue +5254 55/push-ebp +5255 89/<- %ebp 4/r32/esp +5256 # . save registers +5257 56/push-esi +5258 57/push-edi +5259 # esi = var +5260 8b/-> *(ebp+8) 6/r32/esi +5261 # edi = prim-var +5262 8b/-> *(ebp+0xc) 7/r32/edi +5263 # if (var->type != prim-var->type) return false +5264 (type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax +5265 3d/compare-eax-and 0/imm32 +5266 b8/copy-to-eax 0/imm32/false +5267 74/jump-if-= $operand-matches-primitive?:end/disp8 +5268 # return false if var->register doesn't match prim-var->register +5269 { +5270 # if addresses are equal, don't return here +5271 8b/-> *(esi+0x10) 0/r32/eax +5272 39/compare *(edi+0x10) 0/r32/eax +5273 74/jump-if-= break/disp8 +5274 # if either address is 0, return false +5275 3d/compare-eax-and 0/imm32 +5276 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +5277 81 7/subop/compare *(edi+0x10) 0/imm32 +5278 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +5279 # if prim-var->register is "*", return true +5280 (string-equal? *(edi+0x10) "*") # Var-register +5281 3d/compare-eax-and 0/imm32 +5282 b8/copy-to-eax 1/imm32/true +5283 75/jump-if-!= $operand-matches-primitive?:end/disp8 +5284 # if string contents don't match, return false +5285 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register +5286 3d/compare-eax-and 0/imm32 +5287 b8/copy-to-eax 0/imm32/false +5288 74/jump-if-= $operand-matches-primitive?:end/disp8 +5289 } +5290 # return true +5291 b8/copy-to-eax 1/imm32/true +5292 $operand-matches-primitive?:end: +5293 # . restore registers +5294 5f/pop-to-edi +5295 5e/pop-to-esi +5296 # . epilogue +5297 89/<- %esp 5/r32/ebp +5298 5d/pop-to-ebp +5299 c3/return +5300 +5301 type-equal?: # a: (handle tree type-id), b: (handle tree type-id) => result/eax: boolean +5302 # . prologue +5303 55/push-ebp +5304 89/<- %ebp 4/r32/esp +5305 # . save registers +5306 51/push-ecx +5307 52/push-edx +5308 # ecx = a +5309 8b/-> *(ebp+8) 1/r32/ecx +5310 # edx = b +5311 8b/-> *(ebp+0xc) 2/r32/edx +5312 # if (a == b) return true +5313 8b/-> %ecx 0/r32/eax # Var-type +5314 39/compare %edx 0/r32/eax # Var-type +5315 b8/copy-to-eax 1/imm32/true +5316 74/jump-if-= $type-equal?:end/disp8 +5317 # if (a < MAX_TYPE_ID) return false +5318 81 7/subop/compare %ecx 0x10000/imm32 +5319 b8/copy-to-eax 0/imm32/false +5320 72/jump-if-addr< $type-equal?:end/disp8 +5321 # if (b < MAX_TYPE_ID) return false +5322 81 7/subop/compare %edx 0x10000/imm32 +5323 b8/copy-to-eax 0/imm32/false +5324 72/jump-if-addr< $type-equal?:end/disp8 +5325 # if (!type-equal?(a->left, b->left)) return false +5326 (type-equal? *ecx *edx) # Tree-left, Tree-left => eax +5327 3d/compare-eax-and 0/imm32 +5328 74/jump-if-= $type-equal?:end/disp8 +5329 # return type-equal?(a->right, b->right) +5330 (type-equal? *(ecx+4) *(edx+4)) # Tree-right, Tree-right => eax +5331 $type-equal?:end: +5332 # . restore registers +5333 5a/pop-to-edx +5334 59/pop-to-ecx +5335 # . epilogue +5336 89/<- %esp 5/r32/ebp +5337 5d/pop-to-ebp +5338 c3/return +5339 +5340 test-emit-subx-statement-primitive: +5341 # Primitive operation on a variable on the stack. +5342 # increment foo +5343 # => +5344 # ff 0/subop/increment *(ebp-8) +5345 # +5346 # There's a variable on the var stack as follows: +5347 # name: 'foo' +5348 # type: int +5349 # stack-offset: -8 +5350 # +5351 # There's a primitive with this info: +5352 # name: 'increment' +5353 # inouts: int/mem +5354 # value: 'ff 0/subop/increment' +5355 # +5356 # There's nothing in functions. +5357 # +5358 # . prologue +5359 55/push-ebp +5360 89/<- %ebp 4/r32/esp +5361 # setup +5362 (clear-stream _test-output-stream) +5363 (clear-stream $_test-output-buffered-file->buffer) +5364 # var type/ecx: (handle tree type-id) = int +5365 68/push 0/imm32/right/null +5366 68/push 1/imm32/left/int +5367 89/<- %ecx 4/r32/esp +5368 # var var-foo/ecx: var +5369 68/push 0/imm32/no-register +5370 68/push -8/imm32/stack-offset +5371 68/push 1/imm32/block-depth +5372 51/push-ecx +5373 68/push "foo"/imm32 +5374 89/<- %ecx 4/r32/esp +5375 # var operand/ebx: (list var) +5376 68/push 0/imm32/next +5377 51/push-ecx/var-foo +5378 89/<- %ebx 4/r32/esp +5379 # var stmt/esi: statement +5380 68/push 0/imm32/next +5381 68/push 0/imm32/outputs +5382 53/push-ebx/operands +5383 68/push "increment"/imm32/operation +5384 68/push 1/imm32 +5385 89/<- %esi 4/r32/esp +5386 # var primitives/ebx: primitive +5387 68/push 0/imm32/next +5388 68/push 0/imm32/output-is-write-only +5389 68/push 0/imm32/no-imm32 +5390 68/push 0/imm32/no-r32 +5391 68/push 1/imm32/rm32-is-first-inout +5392 68/push "ff 0/subop/increment"/imm32/subx-name +5393 68/push 0/imm32/outputs +5394 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call +5395 68/push "increment"/imm32/name +5396 89/<- %ebx 4/r32/esp +5397 # convert +5398 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5399 (flush _test-output-buffered-file) +5400 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5406 # check output +5407 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") +5408 # . epilogue +5409 89/<- %esp 5/r32/ebp +5410 5d/pop-to-ebp +5411 c3/return +5412 +5413 test-emit-subx-statement-primitive-register: +5414 # Primitive operation on a variable in a register. +5415 # foo <- increment +5416 # => +5417 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5418 # +5419 # There's a variable on the var stack as follows: +5420 # name: 'foo' +5421 # type: int +5422 # register: 'eax' +5423 # +5424 # There's a primitive with this info: +5425 # name: 'increment' +5426 # out: int/reg +5427 # value: 'ff 0/subop/increment' +5428 # +5429 # There's nothing in functions. +5430 # +5431 # . prologue +5432 55/push-ebp +5433 89/<- %ebp 4/r32/esp +5434 # setup +5435 (clear-stream _test-output-stream) +5436 (clear-stream $_test-output-buffered-file->buffer) +5437 # var type/ecx: (handle tree type-id) = int +5438 68/push 0/imm32/right/null +5439 68/push 1/imm32/left/int +5440 89/<- %ecx 4/r32/esp +5441 # var var-foo/ecx: var in eax +5442 68/push "eax"/imm32/register +5443 68/push 0/imm32/no-stack-offset +5444 68/push 1/imm32/block-depth +5445 51/push-ecx +5446 68/push "foo"/imm32 +5447 89/<- %ecx 4/r32/esp +5448 # var operand/ebx: (list var) +5449 68/push 0/imm32/next +5450 51/push-ecx/var-foo +5451 89/<- %ebx 4/r32/esp +5452 # var stmt/esi: statement +5453 68/push 0/imm32/next +5454 53/push-ebx/outputs +5455 68/push 0/imm32/inouts +5456 68/push "increment"/imm32/operation +5457 68/push 1/imm32 +5458 89/<- %esi 4/r32/esp +5459 # var formal-var/ebx: var in any register +5460 68/push Any-register/imm32 +5461 68/push 0/imm32/no-stack-offset +5462 68/push 1/imm32/block-depth +5463 ff 6/subop/push *(ecx+4) # Var-type +5464 68/push "dummy"/imm32 +5465 89/<- %ebx 4/r32/esp +5466 # var operand/ebx: (list var) +5467 68/push 0/imm32/next +5468 53/push-ebx/formal-var +5469 89/<- %ebx 4/r32/esp +5470 # var primitives/ebx: primitive 5471 68/push 0/imm32/next -5472 51/push-ecx/var-foo -5473 89/<- %edi 4/r32/esp -5474 # var stmt/esi: statement -5475 68/push 0/imm32/next -5476 68/push 0/imm32/outputs -5477 57/push-edi/inouts -5478 68/push "increment"/imm32/operation -5479 68/push 1/imm32 -5480 89/<- %esi 4/r32/esp -5481 # var formal-var/ebx: var in any register -5482 68/push Any-register/imm32 -5483 68/push 0/imm32/no-stack-offset -5484 68/push 1/imm32/block-depth -5485 ff 6/subop/push *(ecx+4) # Var-type -5486 68/push "dummy"/imm32 -5487 89/<- %ebx 4/r32/esp -5488 # var operand/ebx: (list var) -5489 68/push 0/imm32/next -5490 53/push-ebx/formal-var -5491 89/<- %ebx 4/r32/esp -5492 # var primitive1/ebx: primitive -5493 68/push 0/imm32/next -5494 68/push 0/imm32/output-is-write-only -5495 68/push 0/imm32/no-imm32 -5496 68/push 0/imm32/no-r32 -5497 68/push 3/imm32/rm32-in-first-output -5498 68/push "ff 0/subop/increment"/imm32/subx-name -5499 53/push-ebx/outputs/formal-outputs -5500 68/push 0/imm32/inouts -5501 68/push "increment"/imm32/name -5502 89/<- %ebx 4/r32/esp -5503 # var primitives/ebx: primitive -5504 53/push-ebx/next -5505 68/push 0/imm32/output-is-write-only -5506 68/push 0/imm32/no-imm32 -5507 68/push 0/imm32/no-r32 -5508 68/push 1/imm32/rm32-is-first-inout -5509 68/push "ff 0/subop/increment"/imm32/subx-name -5510 68/push 0/imm32/outputs -5511 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -5512 68/push "increment"/imm32/name -5513 89/<- %ebx 4/r32/esp -5514 # convert -5515 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5516 (flush _test-output-buffered-file) -5517 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5523 # check output -5524 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") -5525 # . epilogue -5526 89/<- %esp 5/r32/ebp -5527 5d/pop-to-ebp -5528 c3/return -5529 -5530 test-increment-register: -5531 # Select the right primitive between overloads. -5532 # foo <- increment -5533 # => -5534 # 50/increment-eax -5535 # -5536 # There's a variable on the var stack as follows: -5537 # name: 'foo' -5538 # type: int -5539 # register: 'eax' -5540 # -5541 # Primitives are the global definitions. -5542 # -5543 # There are no functions defined. -5544 # -5545 # . prologue -5546 55/push-ebp -5547 89/<- %ebp 4/r32/esp -5548 # setup -5549 (clear-stream _test-output-stream) -5550 (clear-stream $_test-output-buffered-file->buffer) -5551 # var type/ecx: (handle tree type-id) = int -5552 68/push 0/imm32/right/null -5553 68/push 1/imm32/left/int -5554 89/<- %ecx 4/r32/esp -5555 # var var-foo/ecx: var in eax -5556 68/push "eax"/imm32/register -5557 68/push 0/imm32/no-stack-offset -5558 68/push 1/imm32/block-depth -5559 51/push-ecx -5560 68/push "foo"/imm32 -5561 89/<- %ecx 4/r32/esp -5562 # var real-outputs/edi: (list var) -5563 68/push 0/imm32/next -5564 51/push-ecx/var-foo -5565 89/<- %edi 4/r32/esp -5566 # var stmt/esi: statement -5567 68/push 0/imm32/next -5568 57/push-edi/outputs -5569 68/push 0/imm32/inouts -5570 68/push "increment"/imm32/operation -5571 68/push 1/imm32/regular-statement -5572 89/<- %esi 4/r32/esp -5573 # convert -5574 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5575 (flush _test-output-buffered-file) -5576 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5582 # check output -5583 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") -5584 # . epilogue -5585 89/<- %esp 5/r32/ebp -5586 5d/pop-to-ebp -5587 c3/return -5588 -5589 test-increment-var: -5590 # Select the right primitive between overloads. -5591 # foo <- increment -5592 # => -5593 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5594 # -5595 # There's a variable on the var stack as follows: -5596 # name: 'foo' -5597 # type: int -5598 # register: 'eax' -5599 # -5600 # Primitives are the global definitions. -5601 # -5602 # There are no functions defined. -5603 # -5604 # . prologue -5605 55/push-ebp -5606 89/<- %ebp 4/r32/esp -5607 # setup -5608 (clear-stream _test-output-stream) -5609 (clear-stream $_test-output-buffered-file->buffer) -5610 # var type/ecx: (handle tree type-id) = int -5611 68/push 0/imm32/right/null -5612 68/push 1/imm32/left/int -5613 89/<- %ecx 4/r32/esp -5614 # var var-foo/ecx: var in eax -5615 68/push "eax"/imm32/register -5616 68/push 0/imm32/no-stack-offset -5617 68/push 1/imm32/block-depth -5618 51/push-ecx -5619 68/push "foo"/imm32 -5620 89/<- %ecx 4/r32/esp -5621 # var inouts/edi: (list var) -5622 68/push 0/imm32/next -5623 51/push-ecx/var-foo -5624 89/<- %edi 4/r32/esp -5625 # var stmt/esi: statement -5626 68/push 0/imm32/next -5627 68/push 0/imm32/outputs -5628 57/push-edi/inouts -5629 68/push "increment"/imm32/operation -5630 68/push 1/imm32 -5631 89/<- %esi 4/r32/esp -5632 # convert -5633 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5634 (flush _test-output-buffered-file) -5635 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5641 # check output -5642 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") -5643 # . epilogue -5644 89/<- %esp 5/r32/ebp -5645 5d/pop-to-ebp -5646 c3/return -5647 -5648 test-add-reg-to-reg: -5649 # var1/reg <- add var2/reg -5650 # => -5651 # 01/add %var1 var2 -5652 # -5653 # . prologue -5654 55/push-ebp -5655 89/<- %ebp 4/r32/esp -5656 # setup -5657 (clear-stream _test-output-stream) -5658 (clear-stream $_test-output-buffered-file->buffer) -5659 # var type/ecx: (handle tree type-id) = int -5660 68/push 0/imm32/right/null -5661 68/push 1/imm32/left/int -5662 89/<- %ecx 4/r32/esp -5663 # var var-var1/ecx: var in eax -5664 68/push "eax"/imm32/register -5665 68/push 0/imm32/no-stack-offset -5666 68/push 1/imm32/block-depth -5667 51/push-ecx -5668 68/push "var1"/imm32 -5669 89/<- %ecx 4/r32/esp -5670 # var var-var2/edx: var in ecx -5671 68/push "ecx"/imm32/register -5672 68/push 0/imm32/no-stack-offset -5673 68/push 1/imm32/block-depth -5674 ff 6/subop/push *(ecx+4) # Var-type -5675 68/push "var2"/imm32 -5676 89/<- %edx 4/r32/esp -5677 # var inouts/esi: (list var2) -5678 68/push 0/imm32/next -5679 52/push-edx/var-var2 -5680 89/<- %esi 4/r32/esp -5681 # var outputs/edi: (list var1) -5682 68/push 0/imm32/next -5683 51/push-ecx/var-var1 -5684 89/<- %edi 4/r32/esp -5685 # var stmt/esi: statement -5686 68/push 0/imm32/next -5687 57/push-edi/outputs -5688 56/push-esi/inouts -5689 68/push "add"/imm32/operation -5690 68/push 1/imm32 -5691 89/<- %esi 4/r32/esp -5692 # convert -5693 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5694 (flush _test-output-buffered-file) -5695 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5701 # check output -5702 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") -5703 # . epilogue -5704 89/<- %esp 5/r32/ebp -5705 5d/pop-to-ebp -5706 c3/return -5707 -5708 test-add-reg-to-mem: -5709 # add-to var1 var2/reg -5710 # => -5711 # 01/add *(ebp+__) var2 -5712 # -5713 # . prologue -5714 55/push-ebp -5715 89/<- %ebp 4/r32/esp -5716 # setup -5717 (clear-stream _test-output-stream) -5718 (clear-stream $_test-output-buffered-file->buffer) -5719 # var type/ecx: (handle tree type-id) = int -5720 68/push 0/imm32/right/null -5721 68/push 1/imm32/left/int -5722 89/<- %ecx 4/r32/esp -5723 # var var-var1/ecx: var -5724 68/push 0/imm32/no-register -5725 68/push 8/imm32/stack-offset -5726 68/push 1/imm32/block-depth -5727 51/push-ecx -5728 68/push "var1"/imm32 -5729 89/<- %ecx 4/r32/esp -5730 # var var-var2/edx: var in ecx -5731 68/push "ecx"/imm32/register -5732 68/push 0/imm32/no-stack-offset -5733 68/push 1/imm32/block-depth -5734 ff 6/subop/push *(ecx+4) # Var-type -5735 68/push "var2"/imm32 -5736 89/<- %edx 4/r32/esp -5737 # var inouts/esi: (list var2) -5738 68/push 0/imm32/next -5739 52/push-edx/var-var2 -5740 89/<- %esi 4/r32/esp -5741 # var inouts = (list var1 var2) -5742 56/push-esi/next -5743 51/push-ecx/var-var1 -5744 89/<- %esi 4/r32/esp -5745 # var stmt/esi: statement -5746 68/push 0/imm32/next -5747 68/push 0/imm32/outputs -5748 56/push-esi/inouts -5749 68/push "add-to"/imm32/operation -5750 68/push 1/imm32 -5751 89/<- %esi 4/r32/esp -5752 # convert -5753 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5754 (flush _test-output-buffered-file) -5755 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5761 # check output -5762 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") -5763 # . epilogue -5764 89/<- %esp 5/r32/ebp -5765 5d/pop-to-ebp -5766 c3/return -5767 -5768 test-add-mem-to-reg: -5769 # var1/reg <- add var2 -5770 # => -5771 # 03/add *(ebp+__) var1 -5772 # -5773 # . prologue -5774 55/push-ebp -5775 89/<- %ebp 4/r32/esp -5776 # setup -5777 (clear-stream _test-output-stream) -5778 (clear-stream $_test-output-buffered-file->buffer) -5779 # var type/ecx: (handle tree type-id) = int -5780 68/push 0/imm32/right/null -5781 68/push 1/imm32/left/int -5782 89/<- %ecx 4/r32/esp -5783 # var var-var1/ecx: var in eax -5784 68/push "eax"/imm32/register -5785 68/push 0/imm32/no-stack-offset -5786 68/push 1/imm32/block-depth -5787 51/push-ecx -5788 68/push "var1"/imm32 -5789 89/<- %ecx 4/r32/esp -5790 # var var-var2/edx: var -5791 68/push 0/imm32/no-register -5792 68/push 8/imm32/stack-offset -5793 68/push 1/imm32/block-depth -5794 ff 6/subop/push *(ecx+4) # Var-type -5795 68/push "var2"/imm32 -5796 89/<- %edx 4/r32/esp -5797 # var inouts/esi: (list var2) -5798 68/push 0/imm32/next -5799 52/push-edx/var-var2 -5800 89/<- %esi 4/r32/esp -5801 # var outputs/edi: (list var1) -5802 68/push 0/imm32/next -5803 51/push-ecx/var-var1 -5804 89/<- %edi 4/r32/esp -5805 # var stmt/esi: statement -5806 68/push 0/imm32/next -5807 57/push-edi/outputs -5808 56/push-esi/inouts -5809 68/push "add"/imm32/operation -5810 68/push 1/imm32 -5811 89/<- %esi 4/r32/esp -5812 # convert -5813 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5814 (flush _test-output-buffered-file) -5815 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5821 # check output -5822 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") -5823 # . epilogue -5824 89/<- %esp 5/r32/ebp -5825 5d/pop-to-ebp -5826 c3/return -5827 -5828 test-add-literal-to-eax: -5829 # var1/eax <- add 0x34 -5830 # => -5831 # 05/add-to-eax 0x34/imm32 -5832 # -5833 # . prologue -5834 55/push-ebp -5835 89/<- %ebp 4/r32/esp -5836 # setup -5837 (clear-stream _test-output-stream) -5838 (clear-stream $_test-output-buffered-file->buffer) -5839 # var type/ecx: (handle tree type-id) = int -5840 68/push 0/imm32/right/null -5841 68/push 1/imm32/left/int -5842 89/<- %ecx 4/r32/esp -5843 # var var-var1/ecx: var in eax -5844 68/push "eax"/imm32/register -5845 68/push 0/imm32/no-stack-offset -5846 68/push 1/imm32/block-depth -5847 51/push-ecx -5848 68/push "var1"/imm32 -5849 89/<- %ecx 4/r32/esp -5850 # var type/edx: (handle tree type-id) = literal -5851 68/push 0/imm32/right/null -5852 68/push 0/imm32/left/literal -5853 89/<- %edx 4/r32/esp -5854 # var var-var2/edx: var literal -5855 68/push 0/imm32/no-register -5856 68/push 0/imm32/no-stack-offset -5857 68/push 1/imm32/block-depth -5858 52/push-edx -5859 68/push "0x34"/imm32 -5860 89/<- %edx 4/r32/esp -5861 # var inouts/esi: (list var2) -5862 68/push 0/imm32/next -5863 52/push-edx/var-var2 -5864 89/<- %esi 4/r32/esp -5865 # var outputs/edi: (list var1) -5866 68/push 0/imm32/next -5867 51/push-ecx/var-var1 -5868 89/<- %edi 4/r32/esp -5869 # var stmt/esi: statement -5870 68/push 0/imm32/next -5871 57/push-edi/outputs -5872 56/push-esi/inouts -5873 68/push "add"/imm32/operation -5874 68/push 1/imm32 -5875 89/<- %esi 4/r32/esp -5876 # convert -5877 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5878 (flush _test-output-buffered-file) -5879 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5885 # check output -5886 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") -5887 # . epilogue -5888 89/<- %esp 5/r32/ebp -5889 5d/pop-to-ebp -5890 c3/return -5891 -5892 test-add-literal-to-reg: -5893 # var1/ecx <- add 0x34 -5894 # => -5895 # 81 0/subop/add %ecx 0x34/imm32 -5896 # -5897 # . prologue -5898 55/push-ebp -5899 89/<- %ebp 4/r32/esp -5900 # setup -5901 (clear-stream _test-output-stream) -5902 (clear-stream $_test-output-buffered-file->buffer) -5903 # var type/ecx: (handle tree type-id) = int -5904 68/push 0/imm32/right/null -5905 68/push 1/imm32/left/int -5906 89/<- %ecx 4/r32/esp -5907 # var var-var1/ecx: var in ecx -5908 68/push "ecx"/imm32/register -5909 68/push 0/imm32/no-stack-offset -5910 68/push 1/imm32/block-depth -5911 51/push-ecx -5912 68/push "var1"/imm32 -5913 89/<- %ecx 4/r32/esp -5914 # var type/edx: (handle tree type-id) = literal -5915 68/push 0/imm32/right/null -5916 68/push 0/imm32/left/literal -5917 89/<- %edx 4/r32/esp -5918 # var var-var2/edx: var literal -5919 68/push 0/imm32/no-register -5920 68/push 0/imm32/no-stack-offset -5921 68/push 1/imm32/block-depth -5922 52/push-edx -5923 68/push "0x34"/imm32 -5924 89/<- %edx 4/r32/esp -5925 # var inouts/esi: (list var2) -5926 68/push 0/imm32/next -5927 52/push-edx/var-var2 -5928 89/<- %esi 4/r32/esp -5929 # var outputs/edi: (list var1) -5930 68/push 0/imm32/next -5931 51/push-ecx/var-var1 -5932 89/<- %edi 4/r32/esp -5933 # var stmt/esi: statement -5934 68/push 0/imm32/next -5935 57/push-edi/outputs -5936 56/push-esi/inouts -5937 68/push "add"/imm32/operation -5938 68/push 1/imm32 -5939 89/<- %esi 4/r32/esp -5940 # convert -5941 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5942 (flush _test-output-buffered-file) -5943 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5949 # check output -5950 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") -5951 # . epilogue -5952 89/<- %esp 5/r32/ebp -5953 5d/pop-to-ebp -5954 c3/return -5955 -5956 test-add-literal-to-mem: -5957 # add-to var1, 0x34 -5958 # => -5959 # 81 0/subop/add %eax 0x34/imm32 -5960 # -5961 # . prologue -5962 55/push-ebp -5963 89/<- %ebp 4/r32/esp -5964 # setup -5965 (clear-stream _test-output-stream) -5966 (clear-stream $_test-output-buffered-file->buffer) -5967 # var type/ecx: (handle tree type-id) = int -5968 68/push 0/imm32/right/null -5969 68/push 1/imm32/left/int -5970 89/<- %ecx 4/r32/esp -5971 # var var-var1/ecx: var -5972 68/push 0/imm32/no-register -5973 68/push 8/imm32/stack-offset -5974 68/push 1/imm32/block-depth -5975 51/push-ecx -5976 68/push "var1"/imm32 -5977 89/<- %ecx 4/r32/esp -5978 # var type/edx: (handle tree type-id) = literal -5979 68/push 0/imm32/right/null -5980 68/push 0/imm32/left/literal -5981 89/<- %edx 4/r32/esp -5982 # var var-var2/edx: var literal -5983 68/push 0/imm32/no-register -5984 68/push 0/imm32/no-stack-offset -5985 68/push 1/imm32/block-depth -5986 52/push-edx -5987 68/push "0x34"/imm32 -5988 89/<- %edx 4/r32/esp -5989 # var inouts/esi: (list var2) -5990 68/push 0/imm32/next -5991 52/push-edx/var-var2 -5992 89/<- %esi 4/r32/esp -5993 # var inouts = (list var1 inouts) -5994 56/push-esi/next -5995 51/push-ecx/var-var1 -5996 89/<- %esi 4/r32/esp -5997 # var stmt/esi: statement -5998 68/push 0/imm32/next -5999 68/push 0/imm32/outputs -6000 56/push-esi/inouts -6001 68/push "add-to"/imm32/operation -6002 68/push 1/imm32 -6003 89/<- %esi 4/r32/esp -6004 # convert -6005 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -6006 (flush _test-output-buffered-file) -6007 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -6013 # check output -6014 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") -6015 # . epilogue -6016 89/<- %esp 5/r32/ebp -6017 5d/pop-to-ebp -6018 c3/return -6019 -6020 test-emit-subx-statement-function-call: -6021 # Call a function on a variable on the stack. -6022 # f foo -6023 # => -6024 # (f2 *(ebp-8)) -6025 # (Changing the function name supports overloading in general, but here it -6026 # just serves to help disambiguate things.) -6027 # -6028 # There's a variable on the var stack as follows: -6029 # name: 'foo' -6030 # type: int -6031 # stack-offset: -8 -6032 # -6033 # There's nothing in primitives. -6034 # -6035 # There's a function with this info: -6036 # name: 'f' -6037 # inout: int/mem -6038 # value: 'f2' -6039 # -6040 # . prologue -6041 55/push-ebp -6042 89/<- %ebp 4/r32/esp -6043 # setup -6044 (clear-stream _test-output-stream) -6045 (clear-stream $_test-output-buffered-file->buffer) -6046 # var type/ecx: (handle tree type-id) = int -6047 68/push 0/imm32/right/null -6048 68/push 1/imm32/left/int -6049 89/<- %ecx 4/r32/esp -6050 # var var-foo/ecx: var -6051 68/push 0/imm32/no-register -6052 68/push -8/imm32/stack-offset -6053 68/push 0/imm32/block-depth -6054 51/push-ecx -6055 68/push "foo"/imm32 -6056 89/<- %ecx 4/r32/esp -6057 # var operands/esi: (list var) -6058 68/push 0/imm32/next -6059 51/push-ecx/var-foo -6060 89/<- %esi 4/r32/esp -6061 # var stmt/esi: statement -6062 68/push 0/imm32/next -6063 68/push 0/imm32/outputs -6064 56/push-esi/inouts -6065 68/push "f"/imm32/operation -6066 68/push 1/imm32 -6067 89/<- %esi 4/r32/esp -6068 # var functions/ebx: function -6069 68/push 0/imm32/next -6070 68/push 0/imm32/body -6071 68/push 0/imm32/outputs -6072 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -6073 68/push "f2"/imm32/subx-name -6074 68/push "f"/imm32/name -6075 89/<- %ebx 4/r32/esp -6076 # convert -6077 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -6078 (flush _test-output-buffered-file) -6079 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -6085 # check output -6086 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") -6087 # . epilogue -6088 89/<- %esp 5/r32/ebp -6089 5d/pop-to-ebp -6090 c3/return -6091 -6092 test-emit-subx-statement-function-call-with-literal-arg: -6093 # Call a function on a literal. -6094 # f 34 -6095 # => -6096 # (f2 34) -6097 # -6098 # . prologue -6099 55/push-ebp -6100 89/<- %ebp 4/r32/esp -6101 # setup -6102 (clear-stream _test-output-stream) -6103 (clear-stream $_test-output-buffered-file->buffer) -6104 # var type/ecx: (handle tree type-id) = literal -6105 68/push 0/imm32/right/null -6106 68/push 0/imm32/left/literal -6107 89/<- %ecx 4/r32/esp -6108 # var var-foo/ecx: var literal -6109 68/push 0/imm32/no-register -6110 68/push 0/imm32/no-stack-offset -6111 68/push 0/imm32/block-depth -6112 51/push-ecx -6113 68/push "34"/imm32 -6114 89/<- %ecx 4/r32/esp -6115 # var operands/esi: (list var) -6116 68/push 0/imm32/next -6117 51/push-ecx/var-foo -6118 89/<- %esi 4/r32/esp -6119 # var stmt/esi: statement -6120 68/push 0/imm32/next -6121 68/push 0/imm32/outputs -6122 56/push-esi/inouts -6123 68/push "f"/imm32/operation -6124 68/push 1/imm32 -6125 89/<- %esi 4/r32/esp -6126 # var functions/ebx: function -6127 68/push 0/imm32/next -6128 68/push 0/imm32/body -6129 68/push 0/imm32/outputs -6130 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -6131 68/push "f2"/imm32/subx-name -6132 68/push "f"/imm32/name -6133 89/<- %ebx 4/r32/esp -6134 # convert -6135 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -6136 (flush _test-output-buffered-file) -6137 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -6143 # check output -6144 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") -6145 # . epilogue -6146 89/<- %esp 5/r32/ebp -6147 5d/pop-to-ebp -6148 c3/return -6149 -6150 emit-subx-prologue: # out: (addr buffered-file) -6151 # . prologue -6152 55/push-ebp -6153 89/<- %ebp 4/r32/esp -6154 # -6155 (write-buffered *(ebp+8) "# . prologue\n") -6156 (write-buffered *(ebp+8) "55/push-ebp\n") -6157 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") -6158 $emit-subx-prologue:end: -6159 # . epilogue -6160 89/<- %esp 5/r32/ebp -6161 5d/pop-to-ebp -6162 c3/return -6163 -6164 emit-subx-epilogue: # out: (addr buffered-file) -6165 # . prologue -6166 55/push-ebp -6167 89/<- %ebp 4/r32/esp -6168 # -6169 (write-buffered *(ebp+8) "# . epilogue\n") -6170 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") -6171 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") -6172 (write-buffered *(ebp+8) "c3/return\n") -6173 $emit-subx-epilogue:end: -6174 # . epilogue -6175 89/<- %esp 5/r32/ebp -6176 5d/pop-to-ebp -6177 c3/return +5472 68/push 0/imm32/output-is-write-only +5473 68/push 0/imm32/no-imm32 +5474 68/push 0/imm32/no-r32 +5475 68/push 3/imm32/rm32-in-first-output +5476 68/push "ff 0/subop/increment"/imm32/subx-name +5477 53/push-ebx/outputs +5478 68/push 0/imm32/inouts +5479 68/push "increment"/imm32/name +5480 89/<- %ebx 4/r32/esp +5481 # convert +5482 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5483 (flush _test-output-buffered-file) +5484 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5490 # check output +5491 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") +5492 # . epilogue +5493 89/<- %esp 5/r32/ebp +5494 5d/pop-to-ebp +5495 c3/return +5496 +5497 test-emit-subx-statement-select-primitive: +5498 # Select the right primitive between overloads. +5499 # foo <- increment +5500 # => +5501 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5502 # +5503 # There's a variable on the var stack as follows: +5504 # name: 'foo' +5505 # type: int +5506 # register: 'eax' +5507 # +5508 # There's two primitives, as follows: +5509 # - name: 'increment' +5510 # out: int/reg +5511 # value: 'ff 0/subop/increment' +5512 # - name: 'increment' +5513 # inout: int/mem +5514 # value: 'ff 0/subop/increment' +5515 # +5516 # There's nothing in functions. +5517 # +5518 # . prologue +5519 55/push-ebp +5520 89/<- %ebp 4/r32/esp +5521 # setup +5522 (clear-stream _test-output-stream) +5523 (clear-stream $_test-output-buffered-file->buffer) +5524 # var type/ecx: (handle tree type-id) = int +5525 68/push 0/imm32/right/null +5526 68/push 1/imm32/left/int +5527 89/<- %ecx 4/r32/esp +5528 # var var-foo/ecx: var in eax +5529 68/push "eax"/imm32/register +5530 68/push 0/imm32/no-stack-offset +5531 68/push 1/imm32/block-depth +5532 51/push-ecx +5533 68/push "foo"/imm32 +5534 89/<- %ecx 4/r32/esp +5535 # var real-outputs/edi: (list var) +5536 68/push 0/imm32/next +5537 51/push-ecx/var-foo +5538 89/<- %edi 4/r32/esp +5539 # var stmt/esi: statement +5540 68/push 0/imm32/next +5541 57/push-edi/outputs +5542 68/push 0/imm32/inouts +5543 68/push "increment"/imm32/operation +5544 68/push 1/imm32 +5545 89/<- %esi 4/r32/esp +5546 # var formal-var/ebx: var in any register +5547 68/push Any-register/imm32 +5548 68/push 0/imm32/no-stack-offset +5549 68/push 1/imm32/block-depth +5550 ff 6/subop/push *(ecx+4) # Var-type +5551 68/push "dummy"/imm32 +5552 89/<- %ebx 4/r32/esp +5553 # var formal-outputs/ebx: (list var) = {formal-var, 0} +5554 68/push 0/imm32/next +5555 53/push-ebx/formal-var +5556 89/<- %ebx 4/r32/esp +5557 # var primitive1/ebx: primitive +5558 68/push 0/imm32/next +5559 68/push 0/imm32/output-is-write-only +5560 68/push 0/imm32/no-imm32 +5561 68/push 0/imm32/no-r32 +5562 68/push 3/imm32/rm32-in-first-output +5563 68/push "ff 0/subop/increment"/imm32/subx-name +5564 53/push-ebx/outputs/formal-outputs +5565 68/push 0/imm32/inouts +5566 68/push "increment"/imm32/name +5567 89/<- %ebx 4/r32/esp +5568 # var primitives/ebx: primitive +5569 53/push-ebx/next +5570 68/push 0/imm32/output-is-write-only +5571 68/push 0/imm32/no-imm32 +5572 68/push 0/imm32/no-r32 +5573 68/push 1/imm32/rm32-is-first-inout +5574 68/push "ff 0/subop/increment"/imm32/subx-name +5575 68/push 0/imm32/outputs +5576 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +5577 68/push "increment"/imm32/name +5578 89/<- %ebx 4/r32/esp +5579 # convert +5580 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5581 (flush _test-output-buffered-file) +5582 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5588 # check output +5589 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") +5590 # . epilogue +5591 89/<- %esp 5/r32/ebp +5592 5d/pop-to-ebp +5593 c3/return +5594 +5595 test-emit-subx-statement-select-primitive-2: +5596 # Select the right primitive between overloads. +5597 # foo <- increment +5598 # => +5599 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5600 # +5601 # There's a variable on the var stack as follows: +5602 # name: 'foo' +5603 # type: int +5604 # register: 'eax' +5605 # +5606 # There's two primitives, as follows: +5607 # - name: 'increment' +5608 # out: int/reg +5609 # value: 'ff 0/subop/increment' +5610 # - name: 'increment' +5611 # inout: int/mem +5612 # value: 'ff 0/subop/increment' +5613 # +5614 # There's nothing in functions. +5615 # +5616 # . prologue +5617 55/push-ebp +5618 89/<- %ebp 4/r32/esp +5619 # setup +5620 (clear-stream _test-output-stream) +5621 (clear-stream $_test-output-buffered-file->buffer) +5622 # var type/ecx: (handle tree type-id) = int +5623 68/push 0/imm32/right/null +5624 68/push 1/imm32/left/int +5625 89/<- %ecx 4/r32/esp +5626 # var var-foo/ecx: var in eax +5627 68/push "eax"/imm32/register +5628 68/push 0/imm32/no-stack-offset +5629 68/push 1/imm32/block-depth +5630 51/push-ecx +5631 68/push "foo"/imm32 +5632 89/<- %ecx 4/r32/esp +5633 # var inouts/edi: (list var) +5634 68/push 0/imm32/next +5635 51/push-ecx/var-foo +5636 89/<- %edi 4/r32/esp +5637 # var stmt/esi: statement +5638 68/push 0/imm32/next +5639 68/push 0/imm32/outputs +5640 57/push-edi/inouts +5641 68/push "increment"/imm32/operation +5642 68/push 1/imm32 +5643 89/<- %esi 4/r32/esp +5644 # var formal-var/ebx: var in any register +5645 68/push Any-register/imm32 +5646 68/push 0/imm32/no-stack-offset +5647 68/push 1/imm32/block-depth +5648 ff 6/subop/push *(ecx+4) # Var-type +5649 68/push "dummy"/imm32 +5650 89/<- %ebx 4/r32/esp +5651 # var operand/ebx: (list var) +5652 68/push 0/imm32/next +5653 53/push-ebx/formal-var +5654 89/<- %ebx 4/r32/esp +5655 # var primitive1/ebx: primitive +5656 68/push 0/imm32/next +5657 68/push 0/imm32/output-is-write-only +5658 68/push 0/imm32/no-imm32 +5659 68/push 0/imm32/no-r32 +5660 68/push 3/imm32/rm32-in-first-output +5661 68/push "ff 0/subop/increment"/imm32/subx-name +5662 53/push-ebx/outputs/formal-outputs +5663 68/push 0/imm32/inouts +5664 68/push "increment"/imm32/name +5665 89/<- %ebx 4/r32/esp +5666 # var primitives/ebx: primitive +5667 53/push-ebx/next +5668 68/push 0/imm32/output-is-write-only +5669 68/push 0/imm32/no-imm32 +5670 68/push 0/imm32/no-r32 +5671 68/push 1/imm32/rm32-is-first-inout +5672 68/push "ff 0/subop/increment"/imm32/subx-name +5673 68/push 0/imm32/outputs +5674 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +5675 68/push "increment"/imm32/name +5676 89/<- %ebx 4/r32/esp +5677 # convert +5678 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5679 (flush _test-output-buffered-file) +5680 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5686 # check output +5687 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") +5688 # . epilogue +5689 89/<- %esp 5/r32/ebp +5690 5d/pop-to-ebp +5691 c3/return +5692 +5693 test-increment-register: +5694 # Select the right primitive between overloads. +5695 # foo <- increment +5696 # => +5697 # 50/increment-eax +5698 # +5699 # There's a variable on the var stack as follows: +5700 # name: 'foo' +5701 # type: int +5702 # register: 'eax' +5703 # +5704 # Primitives are the global definitions. +5705 # +5706 # There are no functions defined. +5707 # +5708 # . prologue +5709 55/push-ebp +5710 89/<- %ebp 4/r32/esp +5711 # setup +5712 (clear-stream _test-output-stream) +5713 (clear-stream $_test-output-buffered-file->buffer) +5714 # var type/ecx: (handle tree type-id) = int +5715 68/push 0/imm32/right/null +5716 68/push 1/imm32/left/int +5717 89/<- %ecx 4/r32/esp +5718 # var var-foo/ecx: var in eax +5719 68/push "eax"/imm32/register +5720 68/push 0/imm32/no-stack-offset +5721 68/push 1/imm32/block-depth +5722 51/push-ecx +5723 68/push "foo"/imm32 +5724 89/<- %ecx 4/r32/esp +5725 # var real-outputs/edi: (list var) +5726 68/push 0/imm32/next +5727 51/push-ecx/var-foo +5728 89/<- %edi 4/r32/esp +5729 # var stmt/esi: statement +5730 68/push 0/imm32/next +5731 57/push-edi/outputs +5732 68/push 0/imm32/inouts +5733 68/push "increment"/imm32/operation +5734 68/push 1/imm32/regular-statement +5735 89/<- %esi 4/r32/esp +5736 # convert +5737 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5738 (flush _test-output-buffered-file) +5739 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5745 # check output +5746 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") +5747 # . epilogue +5748 89/<- %esp 5/r32/ebp +5749 5d/pop-to-ebp +5750 c3/return +5751 +5752 test-increment-var: +5753 # Select the right primitive between overloads. +5754 # foo <- increment +5755 # => +5756 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5757 # +5758 # There's a variable on the var stack as follows: +5759 # name: 'foo' +5760 # type: int +5761 # register: 'eax' +5762 # +5763 # Primitives are the global definitions. +5764 # +5765 # There are no functions defined. +5766 # +5767 # . prologue +5768 55/push-ebp +5769 89/<- %ebp 4/r32/esp +5770 # setup +5771 (clear-stream _test-output-stream) +5772 (clear-stream $_test-output-buffered-file->buffer) +5773 # var type/ecx: (handle tree type-id) = int +5774 68/push 0/imm32/right/null +5775 68/push 1/imm32/left/int +5776 89/<- %ecx 4/r32/esp +5777 # var var-foo/ecx: var in eax +5778 68/push "eax"/imm32/register +5779 68/push 0/imm32/no-stack-offset +5780 68/push 1/imm32/block-depth +5781 51/push-ecx +5782 68/push "foo"/imm32 +5783 89/<- %ecx 4/r32/esp +5784 # var inouts/edi: (list var) +5785 68/push 0/imm32/next +5786 51/push-ecx/var-foo +5787 89/<- %edi 4/r32/esp +5788 # var stmt/esi: statement +5789 68/push 0/imm32/next +5790 68/push 0/imm32/outputs +5791 57/push-edi/inouts +5792 68/push "increment"/imm32/operation +5793 68/push 1/imm32 +5794 89/<- %esi 4/r32/esp +5795 # convert +5796 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5797 (flush _test-output-buffered-file) +5798 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5804 # check output +5805 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") +5806 # . epilogue +5807 89/<- %esp 5/r32/ebp +5808 5d/pop-to-ebp +5809 c3/return +5810 +5811 test-add-reg-to-reg: +5812 # var1/reg <- add var2/reg +5813 # => +5814 # 01/add %var1 var2 +5815 # +5816 # . prologue +5817 55/push-ebp +5818 89/<- %ebp 4/r32/esp +5819 # setup +5820 (clear-stream _test-output-stream) +5821 (clear-stream $_test-output-buffered-file->buffer) +5822 # var type/ecx: (handle tree type-id) = int +5823 68/push 0/imm32/right/null +5824 68/push 1/imm32/left/int +5825 89/<- %ecx 4/r32/esp +5826 # var var-var1/ecx: var in eax +5827 68/push "eax"/imm32/register +5828 68/push 0/imm32/no-stack-offset +5829 68/push 1/imm32/block-depth +5830 51/push-ecx +5831 68/push "var1"/imm32 +5832 89/<- %ecx 4/r32/esp +5833 # var var-var2/edx: var in ecx +5834 68/push "ecx"/imm32/register +5835 68/push 0/imm32/no-stack-offset +5836 68/push 1/imm32/block-depth +5837 ff 6/subop/push *(ecx+4) # Var-type +5838 68/push "var2"/imm32 +5839 89/<- %edx 4/r32/esp +5840 # var inouts/esi: (list var2) +5841 68/push 0/imm32/next +5842 52/push-edx/var-var2 +5843 89/<- %esi 4/r32/esp +5844 # var outputs/edi: (list var1) +5845 68/push 0/imm32/next +5846 51/push-ecx/var-var1 +5847 89/<- %edi 4/r32/esp +5848 # var stmt/esi: statement +5849 68/push 0/imm32/next +5850 57/push-edi/outputs +5851 56/push-esi/inouts +5852 68/push "add"/imm32/operation +5853 68/push 1/imm32 +5854 89/<- %esi 4/r32/esp +5855 # convert +5856 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5857 (flush _test-output-buffered-file) +5858 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5864 # check output +5865 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") +5866 # . epilogue +5867 89/<- %esp 5/r32/ebp +5868 5d/pop-to-ebp +5869 c3/return +5870 +5871 test-add-reg-to-mem: +5872 # add-to var1 var2/reg +5873 # => +5874 # 01/add *(ebp+__) var2 +5875 # +5876 # . prologue +5877 55/push-ebp +5878 89/<- %ebp 4/r32/esp +5879 # setup +5880 (clear-stream _test-output-stream) +5881 (clear-stream $_test-output-buffered-file->buffer) +5882 # var type/ecx: (handle tree type-id) = int +5883 68/push 0/imm32/right/null +5884 68/push 1/imm32/left/int +5885 89/<- %ecx 4/r32/esp +5886 # var var-var1/ecx: var +5887 68/push 0/imm32/no-register +5888 68/push 8/imm32/stack-offset +5889 68/push 1/imm32/block-depth +5890 51/push-ecx +5891 68/push "var1"/imm32 +5892 89/<- %ecx 4/r32/esp +5893 # var var-var2/edx: var in ecx +5894 68/push "ecx"/imm32/register +5895 68/push 0/imm32/no-stack-offset +5896 68/push 1/imm32/block-depth +5897 ff 6/subop/push *(ecx+4) # Var-type +5898 68/push "var2"/imm32 +5899 89/<- %edx 4/r32/esp +5900 # var inouts/esi: (list var2) +5901 68/push 0/imm32/next +5902 52/push-edx/var-var2 +5903 89/<- %esi 4/r32/esp +5904 # var inouts = (list var1 var2) +5905 56/push-esi/next +5906 51/push-ecx/var-var1 +5907 89/<- %esi 4/r32/esp +5908 # var stmt/esi: statement +5909 68/push 0/imm32/next +5910 68/push 0/imm32/outputs +5911 56/push-esi/inouts +5912 68/push "add-to"/imm32/operation +5913 68/push 1/imm32 +5914 89/<- %esi 4/r32/esp +5915 # convert +5916 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5917 (flush _test-output-buffered-file) +5918 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5924 # check output +5925 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") +5926 # . epilogue +5927 89/<- %esp 5/r32/ebp +5928 5d/pop-to-ebp +5929 c3/return +5930 +5931 test-add-mem-to-reg: +5932 # var1/reg <- add var2 +5933 # => +5934 # 03/add *(ebp+__) var1 +5935 # +5936 # . prologue +5937 55/push-ebp +5938 89/<- %ebp 4/r32/esp +5939 # setup +5940 (clear-stream _test-output-stream) +5941 (clear-stream $_test-output-buffered-file->buffer) +5942 # var type/ecx: (handle tree type-id) = int +5943 68/push 0/imm32/right/null +5944 68/push 1/imm32/left/int +5945 89/<- %ecx 4/r32/esp +5946 # var var-var1/ecx: var in eax +5947 68/push "eax"/imm32/register +5948 68/push 0/imm32/no-stack-offset +5949 68/push 1/imm32/block-depth +5950 51/push-ecx +5951 68/push "var1"/imm32 +5952 89/<- %ecx 4/r32/esp +5953 # var var-var2/edx: var +5954 68/push 0/imm32/no-register +5955 68/push 8/imm32/stack-offset +5956 68/push 1/imm32/block-depth +5957 ff 6/subop/push *(ecx+4) # Var-type +5958 68/push "var2"/imm32 +5959 89/<- %edx 4/r32/esp +5960 # var inouts/esi: (list var2) +5961 68/push 0/imm32/next +5962 52/push-edx/var-var2 +5963 89/<- %esi 4/r32/esp +5964 # var outputs/edi: (list var1) +5965 68/push 0/imm32/next +5966 51/push-ecx/var-var1 +5967 89/<- %edi 4/r32/esp +5968 # var stmt/esi: statement +5969 68/push 0/imm32/next +5970 57/push-edi/outputs +5971 56/push-esi/inouts +5972 68/push "add"/imm32/operation +5973 68/push 1/imm32 +5974 89/<- %esi 4/r32/esp +5975 # convert +5976 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5977 (flush _test-output-buffered-file) +5978 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5984 # check output +5985 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") +5986 # . epilogue +5987 89/<- %esp 5/r32/ebp +5988 5d/pop-to-ebp +5989 c3/return +5990 +5991 test-add-literal-to-eax: +5992 # var1/eax <- add 0x34 +5993 # => +5994 # 05/add-to-eax 0x34/imm32 +5995 # +5996 # . prologue +5997 55/push-ebp +5998 89/<- %ebp 4/r32/esp +5999 # setup +6000 (clear-stream _test-output-stream) +6001 (clear-stream $_test-output-buffered-file->buffer) +6002 # var type/ecx: (handle tree type-id) = int +6003 68/push 0/imm32/right/null +6004 68/push 1/imm32/left/int +6005 89/<- %ecx 4/r32/esp +6006 # var var-var1/ecx: var in eax +6007 68/push "eax"/imm32/register +6008 68/push 0/imm32/no-stack-offset +6009 68/push 1/imm32/block-depth +6010 51/push-ecx +6011 68/push "var1"/imm32 +6012 89/<- %ecx 4/r32/esp +6013 # var type/edx: (handle tree type-id) = literal +6014 68/push 0/imm32/right/null +6015 68/push 0/imm32/left/literal +6016 89/<- %edx 4/r32/esp +6017 # var var-var2/edx: var literal +6018 68/push 0/imm32/no-register +6019 68/push 0/imm32/no-stack-offset +6020 68/push 1/imm32/block-depth +6021 52/push-edx +6022 68/push "0x34"/imm32 +6023 89/<- %edx 4/r32/esp +6024 # var inouts/esi: (list var2) +6025 68/push 0/imm32/next +6026 52/push-edx/var-var2 +6027 89/<- %esi 4/r32/esp +6028 # var outputs/edi: (list var1) +6029 68/push 0/imm32/next +6030 51/push-ecx/var-var1 +6031 89/<- %edi 4/r32/esp +6032 # var stmt/esi: statement +6033 68/push 0/imm32/next +6034 57/push-edi/outputs +6035 56/push-esi/inouts +6036 68/push "add"/imm32/operation +6037 68/push 1/imm32 +6038 89/<- %esi 4/r32/esp +6039 # convert +6040 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +6041 (flush _test-output-buffered-file) +6042 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6048 # check output +6049 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") +6050 # . epilogue +6051 89/<- %esp 5/r32/ebp +6052 5d/pop-to-ebp +6053 c3/return +6054 +6055 test-add-literal-to-reg: +6056 # var1/ecx <- add 0x34 +6057 # => +6058 # 81 0/subop/add %ecx 0x34/imm32 +6059 # +6060 # . prologue +6061 55/push-ebp +6062 89/<- %ebp 4/r32/esp +6063 # setup +6064 (clear-stream _test-output-stream) +6065 (clear-stream $_test-output-buffered-file->buffer) +6066 # var type/ecx: (handle tree type-id) = int +6067 68/push 0/imm32/right/null +6068 68/push 1/imm32/left/int +6069 89/<- %ecx 4/r32/esp +6070 # var var-var1/ecx: var in ecx +6071 68/push "ecx"/imm32/register +6072 68/push 0/imm32/no-stack-offset +6073 68/push 1/imm32/block-depth +6074 51/push-ecx +6075 68/push "var1"/imm32 +6076 89/<- %ecx 4/r32/esp +6077 # var type/edx: (handle tree type-id) = literal +6078 68/push 0/imm32/right/null +6079 68/push 0/imm32/left/literal +6080 89/<- %edx 4/r32/esp +6081 # var var-var2/edx: var literal +6082 68/push 0/imm32/no-register +6083 68/push 0/imm32/no-stack-offset +6084 68/push 1/imm32/block-depth +6085 52/push-edx +6086 68/push "0x34"/imm32 +6087 89/<- %edx 4/r32/esp +6088 # var inouts/esi: (list var2) +6089 68/push 0/imm32/next +6090 52/push-edx/var-var2 +6091 89/<- %esi 4/r32/esp +6092 # var outputs/edi: (list var1) +6093 68/push 0/imm32/next +6094 51/push-ecx/var-var1 +6095 89/<- %edi 4/r32/esp +6096 # var stmt/esi: statement +6097 68/push 0/imm32/next +6098 57/push-edi/outputs +6099 56/push-esi/inouts +6100 68/push "add"/imm32/operation +6101 68/push 1/imm32 +6102 89/<- %esi 4/r32/esp +6103 # convert +6104 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +6105 (flush _test-output-buffered-file) +6106 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6112 # check output +6113 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") +6114 # . epilogue +6115 89/<- %esp 5/r32/ebp +6116 5d/pop-to-ebp +6117 c3/return +6118 +6119 test-add-literal-to-mem: +6120 # add-to var1, 0x34 +6121 # => +6122 # 81 0/subop/add %eax 0x34/imm32 +6123 # +6124 # . prologue +6125 55/push-ebp +6126 89/<- %ebp 4/r32/esp +6127 # setup +6128 (clear-stream _test-output-stream) +6129 (clear-stream $_test-output-buffered-file->buffer) +6130 # var type/ecx: (handle tree type-id) = int +6131 68/push 0/imm32/right/null +6132 68/push 1/imm32/left/int +6133 89/<- %ecx 4/r32/esp +6134 # var var-var1/ecx: var +6135 68/push 0/imm32/no-register +6136 68/push 8/imm32/stack-offset +6137 68/push 1/imm32/block-depth +6138 51/push-ecx +6139 68/push "var1"/imm32 +6140 89/<- %ecx 4/r32/esp +6141 # var type/edx: (handle tree type-id) = literal +6142 68/push 0/imm32/right/null +6143 68/push 0/imm32/left/literal +6144 89/<- %edx 4/r32/esp +6145 # var var-var2/edx: var literal +6146 68/push 0/imm32/no-register +6147 68/push 0/imm32/no-stack-offset +6148 68/push 1/imm32/block-depth +6149 52/push-edx +6150 68/push "0x34"/imm32 +6151 89/<- %edx 4/r32/esp +6152 # var inouts/esi: (list var2) +6153 68/push 0/imm32/next +6154 52/push-edx/var-var2 +6155 89/<- %esi 4/r32/esp +6156 # var inouts = (list var1 inouts) +6157 56/push-esi/next +6158 51/push-ecx/var-var1 +6159 89/<- %esi 4/r32/esp +6160 # var stmt/esi: statement +6161 68/push 0/imm32/next +6162 68/push 0/imm32/outputs +6163 56/push-esi/inouts +6164 68/push "add-to"/imm32/operation +6165 68/push 1/imm32 +6166 89/<- %esi 4/r32/esp +6167 # convert +6168 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +6169 (flush _test-output-buffered-file) +6170 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6176 # check output +6177 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") +6178 # . epilogue +6179 89/<- %esp 5/r32/ebp +6180 5d/pop-to-ebp +6181 c3/return +6182 +6183 test-emit-subx-statement-function-call: +6184 # Call a function on a variable on the stack. +6185 # f foo +6186 # => +6187 # (f2 *(ebp-8)) +6188 # (Changing the function name supports overloading in general, but here it +6189 # just serves to help disambiguate things.) +6190 # +6191 # There's a variable on the var stack as follows: +6192 # name: 'foo' +6193 # type: int +6194 # stack-offset: -8 +6195 # +6196 # There's nothing in primitives. +6197 # +6198 # There's a function with this info: +6199 # name: 'f' +6200 # inout: int/mem +6201 # value: 'f2' +6202 # +6203 # . prologue +6204 55/push-ebp +6205 89/<- %ebp 4/r32/esp +6206 # setup +6207 (clear-stream _test-output-stream) +6208 (clear-stream $_test-output-buffered-file->buffer) +6209 # var type/ecx: (handle tree type-id) = int +6210 68/push 0/imm32/right/null +6211 68/push 1/imm32/left/int +6212 89/<- %ecx 4/r32/esp +6213 # var var-foo/ecx: var +6214 68/push 0/imm32/no-register +6215 68/push -8/imm32/stack-offset +6216 68/push 0/imm32/block-depth +6217 51/push-ecx +6218 68/push "foo"/imm32 +6219 89/<- %ecx 4/r32/esp +6220 # var operands/esi: (list var) +6221 68/push 0/imm32/next +6222 51/push-ecx/var-foo +6223 89/<- %esi 4/r32/esp +6224 # var stmt/esi: statement +6225 68/push 0/imm32/next +6226 68/push 0/imm32/outputs +6227 56/push-esi/inouts +6228 68/push "f"/imm32/operation +6229 68/push 1/imm32 +6230 89/<- %esi 4/r32/esp +6231 # var functions/ebx: function +6232 68/push 0/imm32/next +6233 68/push 0/imm32/body +6234 68/push 0/imm32/outputs +6235 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +6236 68/push "f2"/imm32/subx-name +6237 68/push "f"/imm32/name +6238 89/<- %ebx 4/r32/esp +6239 # convert +6240 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +6241 (flush _test-output-buffered-file) +6242 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6248 # check output +6249 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") +6250 # . epilogue +6251 89/<- %esp 5/r32/ebp +6252 5d/pop-to-ebp +6253 c3/return +6254 +6255 test-emit-subx-statement-function-call-with-literal-arg: +6256 # Call a function on a literal. +6257 # f 34 +6258 # => +6259 # (f2 34) +6260 # +6261 # . prologue +6262 55/push-ebp +6263 89/<- %ebp 4/r32/esp +6264 # setup +6265 (clear-stream _test-output-stream) +6266 (clear-stream $_test-output-buffered-file->buffer) +6267 # var type/ecx: (handle tree type-id) = literal +6268 68/push 0/imm32/right/null +6269 68/push 0/imm32/left/literal +6270 89/<- %ecx 4/r32/esp +6271 # var var-foo/ecx: var literal +6272 68/push 0/imm32/no-register +6273 68/push 0/imm32/no-stack-offset +6274 68/push 0/imm32/block-depth +6275 51/push-ecx +6276 68/push "34"/imm32 +6277 89/<- %ecx 4/r32/esp +6278 # var operands/esi: (list var) +6279 68/push 0/imm32/next +6280 51/push-ecx/var-foo +6281 89/<- %esi 4/r32/esp +6282 # var stmt/esi: statement +6283 68/push 0/imm32/next +6284 68/push 0/imm32/outputs +6285 56/push-esi/inouts +6286 68/push "f"/imm32/operation +6287 68/push 1/imm32 +6288 89/<- %esi 4/r32/esp +6289 # var functions/ebx: function +6290 68/push 0/imm32/next +6291 68/push 0/imm32/body +6292 68/push 0/imm32/outputs +6293 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +6294 68/push "f2"/imm32/subx-name +6295 68/push "f"/imm32/name +6296 89/<- %ebx 4/r32/esp +6297 # convert +6298 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +6299 (flush _test-output-buffered-file) +6300 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6306 # check output +6307 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") +6308 # . epilogue +6309 89/<- %esp 5/r32/ebp +6310 5d/pop-to-ebp +6311 c3/return +6312 +6313 emit-subx-prologue: # out: (addr buffered-file) +6314 # . prologue +6315 55/push-ebp +6316 89/<- %ebp 4/r32/esp +6317 # +6318 (write-buffered *(ebp+8) "# . prologue\n") +6319 (write-buffered *(ebp+8) "55/push-ebp\n") +6320 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") +6321 $emit-subx-prologue:end: +6322 # . epilogue +6323 89/<- %esp 5/r32/ebp +6324 5d/pop-to-ebp +6325 c3/return +6326 +6327 emit-subx-epilogue: # out: (addr buffered-file) +6328 # . prologue +6329 55/push-ebp +6330 89/<- %ebp 4/r32/esp +6331 # +6332 (write-buffered *(ebp+8) "# . epilogue\n") +6333 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") +6334 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") +6335 (write-buffered *(ebp+8) "c3/return\n") +6336 $emit-subx-epilogue:end: +6337 # . epilogue +6338 89/<- %esp 5/r32/ebp +6339 5d/pop-to-ebp +6340 c3/return -- cgit 1.4.1-2-gfad0