From f4408d76c5bb12fa7f8ef77bb39b36b7a3a1263e Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Tue, 28 Jan 2020 21:41:24 -0800 Subject: 5944 --- html/apps/mu.subx.html | 10750 ++++++++++++++++++++++++----------------------- 1 file changed, 5461 insertions(+), 5289 deletions(-) (limited to 'html') diff --git a/html/apps/mu.subx.html b/html/apps/mu.subx.html index 157d4050..a8fe1412 100644 --- a/html/apps/mu.subx.html +++ b/html/apps/mu.subx.html @@ -370,9 +370,9 @@ if ('onhashchange' in window) { 308 Regvardef-outputs: # (handle list var) # will have exactly one element 309 0xc/imm32 310 - 311 Named-block-name: + 311 Named-block-statements: # (handle list statement) 312 4/imm32 - 313 Named-block-statements: # (handle list statement) + 313 Named-block-name: # (handle array byte) 314 8/imm32 315 316 Stmt-size: # (addr int) @@ -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 @@ -1005,8 +1005,8 @@ if ('onhashchange' in window) { 988 (clear-stream $_test-output-buffered-file->buffer) 989 # 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") + 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) @@ -1062,8 +1062,8 @@ if ('onhashchange' in window) { 1050 (clear-stream $_test-output-buffered-file->buffer) 1051 # 1052 (write _test-input-stream "fn foo {\n") -1053 (write _test-input-stream "var x/ecx: int <- copy 3\n") -1054 (write _test-input-stream "x <- increment\n") +1053 (write _test-input-stream " var x/ecx: int <- copy 3\n") +1054 (write _test-input-stream " x <- increment\n") 1055 (write _test-input-stream "}\n") 1056 # convert 1057 (convert-mu _test-input-buffered-file _test-output-buffered-file) @@ -1089,4656 +1089,4656 @@ if ('onhashchange' in window) { 1082 5d/pop-to-ebp 1083 c3/return 1084 -1085 ####################################################### -1086 # Parsing -1087 ####################################################### -1088 -1089 parse-mu: # in: (addr buffered-file) -1090 # pseudocode -1091 # var curr-function: (addr (handle function)) = Program -1092 # var line: (stream byte 512) -1093 # var word-slice: slice -1094 # while true # line loop -1095 # clear-stream(line) -1096 # read-line-buffered(in, line) -1097 # if (line->write == 0) break # end of file -1098 # word-slice = next-mu-token(line) -1099 # if slice-empty?(word-slice) # end of line -1100 # continue -1101 # else if slice-starts-with?(word-slice, "#") # comment -1102 # continue # end of line -1103 # else if slice-equal(word-slice, "fn") -1104 # var new-function: (handle function) = allocate(function) -1105 # var vars: (stack (addr var) 256) -1106 # populate-mu-function-header(in, new-function, vars) -1107 # populate-mu-function-body(in, new-function, vars) -1108 # assert(vars->top == 0) -1109 # *curr-function = new-function -1110 # curr-function = &new-function->next -1111 # else -1112 # abort() -1113 # -1114 # . prologue -1115 55/push-ebp -1116 89/<- %ebp 4/r32/esp -1117 # . save registers -1118 50/push-eax -1119 51/push-ecx -1120 52/push-edx -1121 53/push-ebx -1122 57/push-edi -1123 # var line/ecx: (stream byte 512) -1124 81 5/subop/subtract %esp 0x200/imm32 -1125 68/push 0x200/imm32/length -1126 68/push 0/imm32/read -1127 68/push 0/imm32/write -1128 89/<- %ecx 4/r32/esp -1129 # var word-slice/edx: slice -1130 68/push 0/imm32/end -1131 68/push 0/imm32/start -1132 89/<- %edx 4/r32/esp -1133 # var curr-function/edi: (addr (handle function)) = Program -1134 bf/copy-to-edi Program/imm32 -1135 # var vars/ebx: (stack (addr var) 256) -1136 81 5/subop/subtract %esp 0x400/imm32 -1137 68/push 0x400/imm32/length -1138 68/push 0/imm32/top -1139 89/<- %ebx 4/r32/esp -1140 { -1141 $parse-mu:line-loop: -1142 (clear-stream %ecx) -1143 (read-line-buffered *(ebp+8) %ecx) -1144 # if (line->write == 0) break -1145 81 7/subop/compare *ecx 0/imm32 -1146 0f 84/jump-if-= break/disp32 -1147 +-- 6 lines: #? # dump line --------------------------------------------------------------------------------------------------------------------------- -1153 (next-mu-token %ecx %edx) -1154 # if slice-empty?(word-slice) continue -1155 (slice-empty? %edx) -1156 3d/compare-eax-and 0/imm32 -1157 0f 85/jump-if-!= loop/disp32 -1158 # if (*word-slice->start == "#") continue -1159 # . eax = *word-slice->start -1160 8b/-> *edx 0/r32/eax -1161 8a/copy-byte *eax 0/r32/AL -1162 81 4/subop/and %eax 0xff/imm32 -1163 # . if (eax == '#') continue -1164 3d/compare-eax-and 0x23/imm32/hash -1165 0f 84/jump-if-= loop/disp32 -1166 # if (slice-equal?(word-slice, "fn")) parse a function -1167 { -1168 $parse-mu:fn: -1169 (slice-equal? %edx "fn") -1170 3d/compare-eax-and 0/imm32 -1171 0f 84/jump-if-= break/disp32 -1172 # var new-function/eax: (handle function) = populate-mu-function(in, new-function, vars) -1173 (allocate Heap *Function-size) # => eax -1174 (zero-out %eax *Function-size) -1175 (clear-stack %ebx) -1176 (populate-mu-function-header %ecx %eax %ebx) -1177 (populate-mu-function-body *(ebp+8) %eax %ebx) -1178 # *curr-function = new-function -1179 89/<- *edi 0/r32/eax -1180 # curr-function = &new-function->next -1181 8d/address-> *(eax+0x14) 7/r32/edi # Function-next -1182 e9/jump $parse-mu:line-loop/disp32 -1183 } -1184 # otherwise abort -1185 e9/jump $parse-mu:error1/disp32 -1186 } # end line loop -1187 $parse-mu:end: -1188 # . reclaim locals -1189 81 0/subop/add %esp 0x630/imm32 -1190 # . restore registers -1191 5f/pop-to-edi -1192 5b/pop-to-ebx -1193 5a/pop-to-edx -1194 59/pop-to-ecx -1195 58/pop-to-eax -1196 # . epilogue -1197 89/<- %esp 5/r32/ebp -1198 5d/pop-to-ebp -1199 c3/return -1200 -1201 $parse-mu:error1: -1202 # error("unexpected top-level command: " word-slice "\n") -1203 (write-buffered Stderr "unexpected top-level command: ") -1204 (write-slice-buffered Stderr %edx) -1205 (write-buffered Stderr "\n") -1206 (flush Stderr) -1207 # . syscall(exit, 1) -1208 bb/copy-to-ebx 1/imm32 -1209 b8/copy-to-eax 1/imm32/exit -1210 cd/syscall 0x80/imm8 -1211 # never gets here -1212 -1213 $parse-mu:error2: -1214 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") -1215 (print-int32-buffered Stderr *ebx) -1216 (write-buffered Stderr " vars not reclaimed after fn '") -1217 (write-slice-buffered Stderr *eax) # Function-name -1218 (write-buffered Stderr "'\n") -1219 (flush Stderr) -1220 # . syscall(exit, 1) -1221 bb/copy-to-ebx 1/imm32 -1222 b8/copy-to-eax 1/imm32/exit -1223 cd/syscall 0x80/imm8 -1224 # never gets here -1225 -1226 # scenarios considered: -1227 # ✗ fn foo # no block -1228 # ✓ fn foo { -1229 # ✗ fn foo { { -1230 # ✗ fn foo { } -1231 # ✗ fn foo { } { -1232 # ✗ fn foo x { -1233 # ✗ fn foo x: { -1234 # ✓ fn foo x: int { -1235 # ✓ fn foo x: int { -1236 # ✓ fn foo x: int -> y/eax: int { -1237 populate-mu-function-header: # first-line: (addr stream byte), out: (handle function), vars: (addr stack (handle var)) -1238 # pseudocode: -1239 # var name: slice -1240 # next-word(first-line, name) -1241 # assert(name not in '{' '}' '->') -1242 # out->name = slice-to-string(name) -1243 # var next-offset: int = 8 -1244 # ## inouts -1245 # while true -1246 # ## name -1247 # name = next-word(first-line) -1248 # if (name == '{') goto done -1249 # if (name == '->') break -1250 # assert(name != '}') -1251 # var v: (handle var) = parse-var-with-type(name, first-line) -1252 # assert(v->register == null) -1253 # v->stack-offset = next-offset -1254 # next-offset += size-of(v) -1255 # out->inouts = append(out->inouts, v) -1256 # push(vars, v) -1257 # ## outputs -1258 # while true -1259 # ## name -1260 # name = next-word(first-line) -1261 # assert(name not in '{' '}' '->') -1262 # var v: (handle var) = parse-var-with-type(name, first-line) -1263 # assert(v->register != null) -1264 # out->outputs = append(out->outputs, v) -1265 # done: -1266 # -1267 # . prologue -1268 55/push-ebp -1269 89/<- %ebp 4/r32/esp -1270 # . save registers -1271 50/push-eax -1272 51/push-ecx -1273 52/push-edx -1274 53/push-ebx -1275 57/push-edi -1276 # edi = out -1277 8b/-> *(ebp+0xc) 7/r32/edi -1278 # var word-slice/ecx: slice -1279 68/push 0/imm32/end -1280 68/push 0/imm32/start -1281 89/<- %ecx 4/r32/esp -1282 # var next-offset/edx = 8 -1283 ba/copy-to-edx 8/imm32 -1284 # read function name -1285 (next-word *(ebp+8) %ecx) -1286 # error checking -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 # if (word-slice == '->') abort -1292 (slice-equal? %ecx "->") # => eax -1293 3d/compare-eax-and 0/imm32 -1294 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1295 # if (word-slice == '}') abort -1296 (slice-equal? %ecx "}") # => eax -1297 3d/compare-eax-and 0/imm32 -1298 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1299 # save function name -1300 (slice-to-string Heap %ecx) # => eax -1301 89/<- *edi 0/r32/eax # Function-name -1302 # initialize default subx-name as well -1303 89/<- *(edi+4) 0/r32/eax # Function-subx-name -1304 # save function inouts -1305 { -1306 $populate-mu-function-header:check-for-inout: -1307 (next-word *(ebp+8) %ecx) -1308 # if (word-slice == '{') goto done -1309 (slice-equal? %ecx "{") # => eax -1310 3d/compare-eax-and 0/imm32 -1311 0f 85/jump-if-!= $populate-mu-function-header:done/disp32 -1312 # if (word-slice == '->') break -1313 (slice-equal? %ecx "->") # => eax -1314 3d/compare-eax-and 0/imm32 -1315 0f 85/jump-if-!= break/disp32 -1316 # if (word-slice == '}') abort -1317 (slice-equal? %ecx "}") # => eax -1318 3d/compare-eax-and 0/imm32 -1319 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1320 # var v/ebx: (handle var) = parse-var-with-type(word-slice, first-line) -1321 (parse-var-with-type %ecx *(ebp+8)) # => eax -1322 89/<- %ebx 0/r32/eax -1323 # assert(v->register == null) -1324 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register -1325 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 -1326 # v->stack-offset = next-offset -1327 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset -1328 # next-offset += size-of(v) -1329 (size-of %ebx) # => eax -1330 01/add %edx 0/r32/eax -1331 # -1332 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax -1333 89/<- *(edi+8) 0/r32/eax # Function-inouts -1334 (push *(ebp+0x10) %ebx) -1335 # -1336 e9/jump loop/disp32 -1337 } -1338 # save function outputs -1339 { -1340 $parse-var-with-type:check-for-out: -1341 (next-word *(ebp+8) %ecx) -1342 # if (word-slice == '{') break -1343 (slice-equal? %ecx "{") # => eax -1344 3d/compare-eax-and 0/imm32 -1345 0f 85/jump-if-!= break/disp32 -1346 # if (word-slice == '->') abort -1347 (slice-equal? %ecx "->") # => eax -1348 3d/compare-eax-and 0/imm32 -1349 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1350 # if (word-slice == '}') abort -1351 (slice-equal? %ecx "}") # => eax -1352 3d/compare-eax-and 0/imm32 -1353 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1354 # -1355 (parse-var-with-type %ecx *(ebp+8)) # => eax -1356 89/<- %ebx 0/r32/eax -1357 # assert(var->register != null) -1358 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register -1359 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 -1360 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax -1361 89/<- *(edi+0xc) 0/r32/eax # Function-outputs -1362 e9/jump loop/disp32 -1363 } -1364 $populate-mu-function-header:done: -1365 (check-no-tokens-left *(ebp+8)) -1366 $populate-mu-function-header:end: -1367 # . reclaim locals -1368 81 0/subop/add %esp 8/imm32 -1369 # . restore registers -1370 5f/pop-to-edi -1371 5b/pop-to-ebx -1372 5a/pop-to-edx -1373 59/pop-to-ecx -1374 58/pop-to-eax -1375 # . epilogue -1376 89/<- %esp 5/r32/ebp -1377 5d/pop-to-ebp -1378 c3/return -1379 -1380 $populate-mu-function-header:error1: -1381 # error("function header not in form 'fn <name> {'") -1382 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") -1383 (flush Stderr) -1384 (rewind-stream *(ebp+8)) -1385 (write-stream 2 *(ebp+8)) -1386 (write-buffered Stderr "'\n") -1387 (flush Stderr) -1388 # . syscall(exit, 1) -1389 bb/copy-to-ebx 1/imm32 -1390 b8/copy-to-eax 1/imm32/exit -1391 cd/syscall 0x80/imm8 -1392 # never gets here -1393 -1394 $populate-mu-function-header:error2: -1395 # error("function input '" var "' cannot be in a register") -1396 (write-buffered Stderr "function input '") -1397 (write-buffered Stderr *ebx) # Var-name -1398 (write-buffered Stderr "' cannot be in a register") -1399 (flush Stderr) -1400 # . syscall(exit, 1) -1401 bb/copy-to-ebx 1/imm32 -1402 b8/copy-to-eax 1/imm32/exit -1403 cd/syscall 0x80/imm8 -1404 # never gets here -1405 -1406 $populate-mu-function-header:error3: -1407 # error("function input '" var "' must be in a register") -1408 (write-buffered Stderr "function input '") -1409 (write-buffered Stderr *eax) # Var-name -1410 (write-buffered Stderr " must be in a register'") -1411 (flush Stderr) -1412 (rewind-stream *(ebp+8)) -1413 (write-stream 2 *(ebp+8)) -1414 (write-buffered Stderr "'\n") -1415 (flush Stderr) -1416 # . syscall(exit, 1) -1417 bb/copy-to-ebx 1/imm32 -1418 b8/copy-to-eax 1/imm32/exit -1419 cd/syscall 0x80/imm8 -1420 # never gets here -1421 -1422 test-function-header-with-arg: -1423 # 'foo n : int {' -1424 # . prologue -1425 55/push-ebp -1426 89/<- %ebp 4/r32/esp -1427 # setup -1428 (clear-stream _test-input-stream) -1429 (write _test-input-stream "foo n : int {\n") -1430 # var result/ecx: function -1431 2b/subtract-> *Function-size 4/r32/esp -1432 89/<- %ecx 4/r32/esp -1433 (zero-out %ecx *Function-size) -1434 # var vars/ebx: (stack (addr var) 16) -1435 81 5/subop/subtract %esp 0x10/imm32 -1436 68/push 0x10/imm32/length -1437 68/push 0/imm32/top -1438 89/<- %ebx 4/r32/esp -1439 # convert -1440 (populate-mu-function-header _test-input-stream %ecx %ebx) -1441 # check result -1442 (check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name -1443 # edx: (handle list var) = result->inouts -1444 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1445 # ebx: (handle var) = result->inouts->value -1446 8b/-> *edx 3/r32/ebx # List-value -1447 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name -1448 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1449 (check-ints-equal *ebx 1 "F - test-function-header-with-arg/inout:0/type:0") # Tree-left -1450 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-arg/inout:0/type:1") # Tree-right -1451 # . epilogue -1452 89/<- %esp 5/r32/ebp -1453 5d/pop-to-ebp -1454 c3/return -1455 -1456 test-function-header-with-multiple-args: -1457 # 'fn foo a: int, b: int, c: int {' -1458 # . prologue -1459 55/push-ebp -1460 89/<- %ebp 4/r32/esp -1461 # setup -1462 (clear-stream _test-input-stream) -1463 (write _test-input-stream "foo a: int, b: int c: int {\n") -1464 # result/ecx: (handle function) -1465 2b/subtract-> *Function-size 4/r32/esp -1466 89/<- %ecx 4/r32/esp -1467 (zero-out %ecx *Function-size) -1468 # var vars/ebx: (stack (addr var) 16) -1469 81 5/subop/subtract %esp 0x10/imm32 -1470 68/push 0x10/imm32/length -1471 68/push 0/imm32/top -1472 89/<- %ebx 4/r32/esp -1473 # convert -1474 (populate-mu-function-header _test-input-stream %ecx %ebx) -1475 # check result -1476 (check-strings-equal *ecx "foo") # Function-name -1477 # edx: (handle list var) = result->inouts -1478 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1479 $test-function-header-with-multiple-args:inout0: -1480 # ebx: (handle var) = result->inouts->value -1481 8b/-> *edx 3/r32/ebx # List-value -1482 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name -1483 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1484 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Tree-left -1485 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-right -1486 # edx = result->inouts->next -1487 8b/-> *(edx+4) 2/r32/edx # List-next -1488 $test-function-header-with-multiple-args:inout1: -1489 # ebx = result->inouts->next->value -1490 8b/-> *edx 3/r32/ebx # List-value -1491 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name -1492 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1493 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Tree-left -1494 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-right -1495 # edx = result->inouts->next->next -1496 8b/-> *(edx+4) 2/r32/edx # List-next -1497 $test-function-header-with-multiple-args:inout2: -1498 # ebx = result->inouts->next->next->value -1499 8b/-> *edx 3/r32/ebx # List-value -1500 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name -1501 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1502 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Tree-left -1503 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-right -1504 # . epilogue -1505 89/<- %esp 5/r32/ebp -1506 5d/pop-to-ebp -1507 c3/return -1508 -1509 test-function-with-multiple-args-and-outputs: -1510 # fn foo a: int, b: int, c: int -> x: int, y: int { -1511 # . prologue -1512 55/push-ebp -1513 89/<- %ebp 4/r32/esp -1514 # setup -1515 (clear-stream _test-input-stream) -1516 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n") -1517 # result/ecx: (handle function) -1518 2b/subtract-> *Function-size 4/r32/esp -1519 89/<- %ecx 4/r32/esp -1520 (zero-out %ecx *Function-size) -1521 # var vars/ebx: (stack (addr var) 16) -1522 81 5/subop/subtract %esp 0x10/imm32 -1523 68/push 0x10/imm32/length -1524 68/push 0/imm32/top -1525 89/<- %ebx 4/r32/esp -1526 # convert -1527 (populate-mu-function-header _test-input-stream %ecx %ebx) -1528 # check result -1529 (check-strings-equal *ecx "foo") # Function-name -1530 # edx: (handle list var) = result->inouts -1531 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1532 # ebx: (handle var) = result->inouts->value -1533 8b/-> *edx 3/r32/ebx # List-value -1534 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") # Var-name -1535 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1536 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Tree-left -1537 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-right -1538 # edx = result->inouts->next -1539 8b/-> *(edx+4) 2/r32/edx # List-next -1540 # ebx = result->inouts->next->value -1541 8b/-> *edx 3/r32/ebx # List-value -1542 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") # Var-name -1543 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1544 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Tree-left -1545 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-right -1546 # edx = result->inouts->next->next -1547 8b/-> *(edx+4) 2/r32/edx # List-next -1548 # ebx = result->inouts->next->next->value -1549 8b/-> *edx 3/r32/ebx # List-value -1550 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") # Var-name -1551 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1552 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Tree-left -1553 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-right -1554 # edx: (handle list var) = result->outputs -1555 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs -1556 # ebx: (handle var) = result->outputs->value -1557 8b/-> *edx 3/r32/ebx # List-value -1558 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") # Var-name -1559 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register -1560 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1561 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-left -1562 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-right -1563 # edx = result->outputs->next -1564 8b/-> *(edx+4) 2/r32/edx # List-next -1565 # ebx = result->outputs->next->value -1566 8b/-> *edx 3/r32/ebx # List-value -1567 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") # Var-name -1568 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register -1569 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1570 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-left -1571 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-right -1572 # . epilogue -1573 89/<- %esp 5/r32/ebp -1574 5d/pop-to-ebp -1575 c3/return -1576 -1577 # format for variables with types -1578 # x: int -1579 # x: int -1580 # x: int, -1581 # ignores at most one trailing colon or comma -1582 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte) -> result/eax: (handle var) -1583 # pseudocode: -1584 # var v: (handle var) = allocate(Heap, Var-size) -1585 # var s: slice -1586 # next-token-from-slice(name->start, name->end, '/', s) -1587 # var end: (addr byte) = s->end -1588 # if (slice-ends-with(s, ":")) -1589 # decrement s->end -1590 # if (slice-ends-with(s, ",")) -1591 # decrement s->end -1592 # v->name = slice-to-string(s) -1593 # ## register -1594 # next-token-from-slice(end, name->end, '/', s) -1595 # if (slice-ends-with(s, ":")) -1596 # decrement s->end -1597 # if (slice-ends-with(s, ",")) -1598 # decrement s->end -1599 # if (!slice-empty?(s)) -1600 # v->register = slice-to-string(s) -1601 # ## type -1602 # var type: (handle tree type-id) = parse-type(first-line) -1603 # v->type = type -1604 # return v -1605 # -1606 # . prologue -1607 55/push-ebp -1608 89/<- %ebp 4/r32/esp -1609 # . save registers -1610 51/push-ecx -1611 52/push-edx -1612 53/push-ebx -1613 56/push-esi -1614 57/push-edi -1615 # var result/edi: (handle var) = allocate(Heap, Var-size) -1616 (allocate Heap *Var-size) # => eax -1617 (zero-out %eax *Var-size) -1618 89/<- %edi 0/r32/eax -1619 # esi = name -1620 8b/-> *(ebp+8) 6/r32/esi -1621 # var s/ecx: slice -1622 68/push 0/imm32/end -1623 68/push 0/imm32/start -1624 89/<- %ecx 4/r32/esp -1625 $parse-var-with-type:save-name: -1626 # save v->name -1627 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' -1628 # . end/edx = s->end -1629 8b/-> *(ecx+4) 2/r32/edx -1630 # . if s ends with ':', decrement s->end -1631 { -1632 8b/-> *(ecx+4) 0/r32/eax -1633 48/decrement-eax -1634 8a/copy-byte *eax 3/r32/BL -1635 81 4/subop/and %ebx 0xff/imm32 -1636 81 7/subop/compare %ebx 0x3a/imm32/colon -1637 75/jump-if-!= break/disp8 -1638 89/<- *(ecx+4) 0/r32/eax -1639 } -1640 # . if s ends with ',', decrement s->end -1641 { -1642 8b/-> *(ecx+4) 0/r32/eax -1643 48/decrement-eax -1644 8a/copy-byte *eax 3/r32/BL -1645 81 4/subop/and %ebx 0xff/imm32 -1646 81 7/subop/compare %ebx 0x2c/imm32/comma -1647 75/jump-if-!= break/disp8 -1648 89/<- *(ecx+4) 0/r32/eax -1649 } -1650 $parse-var-with-type:write-name: -1651 (slice-to-string Heap %ecx) # => eax -1652 89/<- *edi 0/r32/eax # Var-name -1653 # save v->register -1654 $parse-var-with-type:save-register: -1655 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' -1656 # . if s ends with ':', decrement s->end -1657 { -1658 8b/-> *(ecx+4) 0/r32/eax -1659 48/decrement-eax -1660 8a/copy-byte *eax 3/r32/BL -1661 81 4/subop/and %ebx 0xff/imm32 -1662 81 7/subop/compare %ebx 0x3a/imm32/colon -1663 75/jump-if-!= break/disp8 -1664 89/<- *(ecx+4) 0/r32/eax -1665 } -1666 # . if s ends with ',', decrement s->end -1667 { -1668 8b/-> *(ecx+4) 0/r32/eax -1669 48/decrement-eax -1670 8a/copy-byte *eax 3/r32/BL -1671 81 4/subop/and %ebx 0xff/imm32 -1672 81 7/subop/compare %ebx 0x2c/imm32/comma -1673 75/jump-if-!= break/disp8 -1674 89/<- *(ecx+4) 0/r32/eax -1675 } -1676 # if (!slice-empty?(s)) v->register = slice-to-string(s) -1677 { -1678 $parse-var-with-type:write-register: -1679 # HACK: s->end can be less than s->start with all the decrements above -1680 # That's probably a sign we have the wrong algorithm for this function. -1681 8b/-> *ecx 0/r32/eax -1682 39/compare 0/r32/eax *(ecx+4) -1683 76/jump-if-<= break/disp8 -1684 (slice-to-string Heap %ecx) -1685 89/<- *(edi+0x10) 0/r32/eax # Var-register -1686 } -1687 $parse-var-with-type:save-type: -1688 (parse-type Heap *(ebp+0xc)) # => eax -1689 89/<- *(edi+4) 0/r32/eax # Var-type -1690 $parse-var-with-type:end: -1691 # return result -1692 89/<- %eax 7/r32/edi -1693 # . reclaim locals -1694 81 0/subop/add %esp 8/imm32 -1695 # . restore registers -1696 5f/pop-to-edi -1697 5e/pop-to-esi -1698 5b/pop-to-ebx -1699 5a/pop-to-edx -1700 59/pop-to-ecx -1701 # . epilogue -1702 89/<- %esp 5/r32/ebp -1703 5d/pop-to-ebp -1704 c3/return -1705 -1706 $parse-var-with-type:abort: -1707 # error("function header not in form 'fn <name> {'") -1708 (write-buffered Stderr "var should have form 'name: type' in '") -1709 (flush Stderr) -1710 (rewind-stream *(ebp+0xc)) -1711 (write-stream 2 *(ebp+0xc)) -1712 (write-buffered Stderr "'\n") -1713 (flush Stderr) -1714 # . syscall(exit, 1) -1715 bb/copy-to-ebx 1/imm32 -1716 b8/copy-to-eax 1/imm32/exit -1717 cd/syscall 0x80/imm8 -1718 # never gets here -1719 -1720 parse-type: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) -1721 # pseudocode: -1722 # var s: slice = next-mu-token(in) -1723 # assert s != "" -1724 # assert s != "->" -1725 # assert s != "{" -1726 # assert s != "}" -1727 # if s == ")" -1728 # return 0 -1729 # result = allocate(Tree) -1730 # zero-out(result, *Tree-size) -1731 # if s != "(" -1732 # result->left = pos-slice(Type-id, s) -1733 # return -1734 # result->left = parse-type(ad, in) -1735 # result->right = parse-type-tree(ad, in) -1736 # -1737 # . prologue -1738 55/push-ebp -1739 89/<- %ebp 4/r32/esp -1740 # . save registers -1741 51/push-ecx -1742 52/push-edx -1743 # var s/ecx: slice -1744 68/push 0/imm32 -1745 68/push 0/imm32 -1746 89/<- %ecx 4/r32/esp -1747 # s = next-mu-token(in) -1748 (next-mu-token *(ebp+0xc) %ecx) -1749 #? (write-buffered Stderr "tok: ") -1750 #? (write-slice-buffered Stderr %ecx) -1751 #? (write-buffered Stderr "$\n") -1752 #? (flush Stderr) -1753 # assert s != "" -1754 (slice-equal? %ecx "") -1755 3d/compare-eax-and 0/imm32 -1756 0f 85/jump-if-!= $parse-type:abort/disp32 -1757 # assert s != "{" -1758 (slice-equal? %ecx "{") -1759 3d/compare-eax-and 0/imm32 -1760 0f 85/jump-if-!= $parse-type:abort/disp32 -1761 # assert s != "}" -1762 (slice-equal? %ecx "}") -1763 3d/compare-eax-and 0/imm32 -1764 0f 85/jump-if-!= $parse-type:abort/disp32 -1765 # assert s != "->" -1766 (slice-equal? %ecx "->") -1767 3d/compare-eax-and 0/imm32 -1768 0f 85/jump-if-!= $parse-type:abort/disp32 -1769 # if (s == ")") return 0 -1770 (slice-equal? %ecx ")") -1771 3d/compare-eax-and 0/imm32 -1772 b8/copy-to-eax 0/imm32 -1773 0f 85/jump-if-!= $parse-type:end/disp32 -1774 # var result/edx: (handle tree type-id) -1775 (allocate *(ebp+8) *Tree-size) # => eax -1776 (zero-out %eax *Tree-size) -1777 89/<- %edx 0/r32/eax -1778 { -1779 # if (s != "(") break -1780 (slice-equal? %ecx "(") -1781 3d/compare-eax-and 0/imm32 -1782 75/jump-if-!= break/disp8 -1783 # result->left = pos-slice(Type-id, s) -1784 (pos-slice Type-id %ecx) -1785 #? (write-buffered Stderr "=> {") -1786 #? (print-int32-buffered Stderr %eax) -1787 #? (write-buffered Stderr ", 0}\n") -1788 #? (flush Stderr) -1789 89/<- *edx 0/r32/eax # Tree-left -1790 e9/jump $parse-type:return-edx/disp32 +1085 test-convert-function-with-local-var-in-block: +1086 # empty function decl => function prologue and epilogue +1087 # fn foo { +1088 # { +1089 # var x: int +1090 # increment x +1091 # } +1092 # } +1093 # => +1094 # foo: +1095 # # . prologue +1096 # 55/push-ebp +1097 # 89/<- %ebp 4/r32/esp +1098 # { +1099 # { +1100 # 68/push 0/imm32 +1101 # ff 0/subop/increment *(ebp-4) +1102 # 81 0/subop/add %esp 4/imm32 +1103 # } +1104 # } +1105 # # . epilogue +1106 # 89/<- %esp 5/r32/ebp +1107 # 5d/pop-to-ebp +1108 # c3/return +1109 # . prologue +1110 55/push-ebp +1111 89/<- %ebp 4/r32/esp +1112 # setup +1113 (clear-stream _test-input-stream) +1114 (clear-stream $_test-input-buffered-file->buffer) +1115 (clear-stream _test-output-stream) +1116 (clear-stream $_test-output-buffered-file->buffer) +1117 # +1118 (write _test-input-stream "fn foo {\n") +1119 (write _test-input-stream " {\n") +1120 (write _test-input-stream " var x: int\n") +1121 (write _test-input-stream " increment x\n") +1122 (write _test-input-stream " }\n") +1123 (write _test-input-stream "}\n") +1124 # convert +1125 (convert-mu _test-input-buffered-file _test-output-buffered-file) +1126 (flush _test-output-buffered-file) +1127 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +1133 # check output +1134 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-block/0") +1135 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-with-local-var-in-block/1") +1136 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-with-local-var-in-block/2") +1137 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-block/3") +1138 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-with-local-var-in-block/4") +1139 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-with-local-var-in-block/5") +1140 (check-next-stream-line-equal _test-output-stream "68/push 0/imm32" "F - test-convert-function-with-local-var-in-block/6") +1141 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-local-var-in-block/7") +1142 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-local-var-in-block/8") +1143 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-with-local-var-in-block/9") +1144 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-with-local-var-in-block/10") +1145 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-with-local-var-in-block/11") +1146 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-block/12") +1147 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-block/13") +1148 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-with-local-var-in-block/14") +1149 # . epilogue +1150 89/<- %esp 5/r32/ebp +1151 5d/pop-to-ebp +1152 c3/return +1153 +1154 test-convert-function-with-local-var-in-named-block: +1155 # empty function decl => function prologue and epilogue +1156 # fn foo { +1157 # foo: { +1158 # var x: int +1159 # increment x +1160 # } +1161 # } +1162 # => +1163 # foo: +1164 # # . prologue +1165 # 55/push-ebp +1166 # 89/<- %ebp 4/r32/esp +1167 # { +1168 # { +1169 # foo:loop: +1170 # 68/push 0/imm32 +1171 # ff 0/subop/increment *(ebp-4) +1172 # 81 0/subop/add %esp 4/imm32 +1173 # } +1174 # foo:break: +1175 # } +1176 # # . epilogue +1177 # 89/<- %esp 5/r32/ebp +1178 # 5d/pop-to-ebp +1179 # c3/return +1180 # . prologue +1181 55/push-ebp +1182 89/<- %ebp 4/r32/esp +1183 # setup +1184 (clear-stream _test-input-stream) +1185 (clear-stream $_test-input-buffered-file->buffer) +1186 (clear-stream _test-output-stream) +1187 (clear-stream $_test-output-buffered-file->buffer) +1188 # +1189 (write _test-input-stream "fn foo {\n") +1190 (write _test-input-stream " foo: {\n") +1191 (write _test-input-stream " var x: int\n") +1192 (write _test-input-stream " increment x\n") +1193 (write _test-input-stream " }\n") +1194 (write _test-input-stream "}\n") +1195 # convert +1196 (convert-mu _test-input-buffered-file _test-output-buffered-file) +1197 (flush _test-output-buffered-file) +1198 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +1204 # check output +1205 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-local-var-in-named-block/0") +1206 (check-next-stream-line-equal _test-output-stream "# . prologue" "F - test-convert-function-with-local-var-in-named-block/1") +1207 (check-next-stream-line-equal _test-output-stream "55/push-ebp" "F - test-convert-function-with-local-var-in-named-block/2") +1208 (check-next-stream-line-equal _test-output-stream "89/<- %ebp 4/r32/esp" "F - test-convert-function-with-local-var-in-named-block/3") +1209 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-with-local-var-in-named-block/4") +1210 (check-next-stream-line-equal _test-output-stream "{" "F - test-convert-function-with-local-var-in-named-block/5") +1211 (check-next-stream-line-equal _test-output-stream "foo:loop:" "F - test-convert-function-with-local-var-in-named-block/6") +1212 (check-next-stream-line-equal _test-output-stream "68/push 0/imm32" "F - test-convert-function-with-local-var-in-named-block/7") +1213 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffffc)" "F - test-convert-function-with-local-var-in-named-block/8") +1214 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-local-var-in-named-block/9") +1215 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-with-local-var-in-named-block/10") +1216 (check-next-stream-line-equal _test-output-stream "foo:break:" "F - test-convert-function-with-local-var-in-named-block/11") +1217 (check-next-stream-line-equal _test-output-stream "}" "F - test-convert-function-with-local-var-in-named-block/12") +1218 (check-next-stream-line-equal _test-output-stream "# . epilogue" "F - test-convert-function-with-local-var-in-named-block/13") +1219 (check-next-stream-line-equal _test-output-stream "89/<- %esp 5/r32/ebp" "F - test-convert-function-with-local-var-in-named-block/14") +1220 (check-next-stream-line-equal _test-output-stream "5d/pop-to-ebp" "F - test-convert-function-with-local-var-in-named-block/15") +1221 (check-next-stream-line-equal _test-output-stream "c3/return" "F - test-convert-function-with-local-var-in-named-block/16") +1222 # . epilogue +1223 89/<- %esp 5/r32/ebp +1224 5d/pop-to-ebp +1225 c3/return +1226 +1227 ####################################################### +1228 # Parsing +1229 ####################################################### +1230 +1231 parse-mu: # in: (addr buffered-file) +1232 # pseudocode +1233 # var curr-function: (addr (handle function)) = Program +1234 # var line: (stream byte 512) +1235 # var word-slice: slice +1236 # while true # line loop +1237 # clear-stream(line) +1238 # read-line-buffered(in, line) +1239 # if (line->write == 0) break # end of file +1240 # word-slice = next-mu-token(line) +1241 # if slice-empty?(word-slice) # end of line +1242 # continue +1243 # else if slice-starts-with?(word-slice, "#") # comment +1244 # continue # end of line +1245 # else if slice-equal(word-slice, "fn") +1246 # var new-function: (handle function) = allocate(function) +1247 # var vars: (stack (addr var) 256) +1248 # populate-mu-function-header(in, new-function, vars) +1249 # populate-mu-function-body(in, new-function, vars) +1250 # assert(vars->top == 0) +1251 # *curr-function = new-function +1252 # curr-function = &new-function->next +1253 # else +1254 # abort() +1255 # +1256 # . prologue +1257 55/push-ebp +1258 89/<- %ebp 4/r32/esp +1259 # . save registers +1260 50/push-eax +1261 51/push-ecx +1262 52/push-edx +1263 53/push-ebx +1264 57/push-edi +1265 # var line/ecx: (stream byte 512) +1266 81 5/subop/subtract %esp 0x200/imm32 +1267 68/push 0x200/imm32/length +1268 68/push 0/imm32/read +1269 68/push 0/imm32/write +1270 89/<- %ecx 4/r32/esp +1271 # var word-slice/edx: slice +1272 68/push 0/imm32/end +1273 68/push 0/imm32/start +1274 89/<- %edx 4/r32/esp +1275 # var curr-function/edi: (addr (handle function)) = Program +1276 bf/copy-to-edi Program/imm32 +1277 # var vars/ebx: (stack (addr var) 256) +1278 81 5/subop/subtract %esp 0x400/imm32 +1279 68/push 0x400/imm32/length +1280 68/push 0/imm32/top +1281 89/<- %ebx 4/r32/esp +1282 { +1283 $parse-mu:line-loop: +1284 (clear-stream %ecx) +1285 (read-line-buffered *(ebp+8) %ecx) +1286 # if (line->write == 0) break +1287 81 7/subop/compare *ecx 0/imm32 +1288 0f 84/jump-if-= break/disp32 +1289 +-- 6 lines: #? # dump line --------------------------------------------------------------------------------------------------------------------------- +1295 (next-mu-token %ecx %edx) +1296 # if slice-empty?(word-slice) continue +1297 (slice-empty? %edx) +1298 3d/compare-eax-and 0/imm32 +1299 0f 85/jump-if-!= loop/disp32 +1300 # if (*word-slice->start == "#") continue +1301 # . eax = *word-slice->start +1302 8b/-> *edx 0/r32/eax +1303 8a/copy-byte *eax 0/r32/AL +1304 81 4/subop/and %eax 0xff/imm32 +1305 # . if (eax == '#') continue +1306 3d/compare-eax-and 0x23/imm32/hash +1307 0f 84/jump-if-= loop/disp32 +1308 # if (slice-equal?(word-slice, "fn")) parse a function +1309 { +1310 $parse-mu:fn: +1311 (slice-equal? %edx "fn") +1312 3d/compare-eax-and 0/imm32 +1313 0f 84/jump-if-= break/disp32 +1314 # var new-function/eax: (handle function) = populate-mu-function(in, new-function, vars) +1315 (allocate Heap *Function-size) # => eax +1316 (zero-out %eax *Function-size) +1317 (clear-stack %ebx) +1318 (populate-mu-function-header %ecx %eax %ebx) +1319 (populate-mu-function-body *(ebp+8) %eax %ebx) +1320 # *curr-function = new-function +1321 89/<- *edi 0/r32/eax +1322 # curr-function = &new-function->next +1323 8d/address-> *(eax+0x14) 7/r32/edi # Function-next +1324 e9/jump $parse-mu:line-loop/disp32 +1325 } +1326 # otherwise abort +1327 e9/jump $parse-mu:error1/disp32 +1328 } # end line loop +1329 $parse-mu:end: +1330 # . reclaim locals +1331 81 0/subop/add %esp 0x630/imm32 +1332 # . restore registers +1333 5f/pop-to-edi +1334 5b/pop-to-ebx +1335 5a/pop-to-edx +1336 59/pop-to-ecx +1337 58/pop-to-eax +1338 # . epilogue +1339 89/<- %esp 5/r32/ebp +1340 5d/pop-to-ebp +1341 c3/return +1342 +1343 $parse-mu:error1: +1344 # error("unexpected top-level command: " word-slice "\n") +1345 (write-buffered Stderr "unexpected top-level command: ") +1346 (write-slice-buffered Stderr %edx) +1347 (write-buffered Stderr "\n") +1348 (flush Stderr) +1349 # . syscall(exit, 1) +1350 bb/copy-to-ebx 1/imm32 +1351 b8/copy-to-eax 1/imm32/exit +1352 cd/syscall 0x80/imm8 +1353 # never gets here +1354 +1355 $parse-mu:error2: +1356 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") +1357 (print-int32-buffered Stderr *ebx) +1358 (write-buffered Stderr " vars not reclaimed after fn '") +1359 (write-slice-buffered Stderr *eax) # Function-name +1360 (write-buffered Stderr "'\n") +1361 (flush Stderr) +1362 # . syscall(exit, 1) +1363 bb/copy-to-ebx 1/imm32 +1364 b8/copy-to-eax 1/imm32/exit +1365 cd/syscall 0x80/imm8 +1366 # never gets here +1367 +1368 # scenarios considered: +1369 # ✗ fn foo # no block +1370 # ✓ fn foo { +1371 # ✗ fn foo { { +1372 # ✗ fn foo { } +1373 # ✗ fn foo { } { +1374 # ✗ fn foo x { +1375 # ✗ fn foo x: { +1376 # ✓ fn foo x: int { +1377 # ✓ fn foo x: int { +1378 # ✓ fn foo x: int -> y/eax: int { +1379 populate-mu-function-header: # first-line: (addr stream byte), out: (handle function), vars: (addr stack (handle var)) +1380 # pseudocode: +1381 # var name: slice +1382 # next-word(first-line, name) +1383 # assert(name not in '{' '}' '->') +1384 # out->name = slice-to-string(name) +1385 # var next-offset: int = 8 +1386 # ## inouts +1387 # while true +1388 # ## name +1389 # name = next-word(first-line) +1390 # if (name == '{') goto done +1391 # if (name == '->') break +1392 # assert(name != '}') +1393 # var v: (handle var) = parse-var-with-type(name, first-line) +1394 # assert(v->register == null) +1395 # v->stack-offset = next-offset +1396 # next-offset += size-of(v) +1397 # out->inouts = append(out->inouts, v) +1398 # push(vars, v) +1399 # ## outputs +1400 # while true +1401 # ## name +1402 # name = next-word(first-line) +1403 # assert(name not in '{' '}' '->') +1404 # var v: (handle var) = parse-var-with-type(name, first-line) +1405 # assert(v->register != null) +1406 # out->outputs = append(out->outputs, v) +1407 # done: +1408 # +1409 # . prologue +1410 55/push-ebp +1411 89/<- %ebp 4/r32/esp +1412 # . save registers +1413 50/push-eax +1414 51/push-ecx +1415 52/push-edx +1416 53/push-ebx +1417 57/push-edi +1418 # edi = out +1419 8b/-> *(ebp+0xc) 7/r32/edi +1420 # var word-slice/ecx: slice +1421 68/push 0/imm32/end +1422 68/push 0/imm32/start +1423 89/<- %ecx 4/r32/esp +1424 # var next-offset/edx = 8 +1425 ba/copy-to-edx 8/imm32 +1426 # read function name +1427 (next-word *(ebp+8) %ecx) +1428 # error checking +1429 # if (word-slice == '{') abort +1430 (slice-equal? %ecx "{") # => eax +1431 3d/compare-eax-and 0/imm32 +1432 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1433 # if (word-slice == '->') abort +1434 (slice-equal? %ecx "->") # => eax +1435 3d/compare-eax-and 0/imm32 +1436 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1437 # if (word-slice == '}') abort +1438 (slice-equal? %ecx "}") # => eax +1439 3d/compare-eax-and 0/imm32 +1440 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1441 # save function name +1442 (slice-to-string Heap %ecx) # => eax +1443 89/<- *edi 0/r32/eax # Function-name +1444 # initialize default subx-name as well +1445 89/<- *(edi+4) 0/r32/eax # Function-subx-name +1446 # save function inouts +1447 { +1448 $populate-mu-function-header:check-for-inout: +1449 (next-word *(ebp+8) %ecx) +1450 # if (word-slice == '{') goto done +1451 (slice-equal? %ecx "{") # => eax +1452 3d/compare-eax-and 0/imm32 +1453 0f 85/jump-if-!= $populate-mu-function-header:done/disp32 +1454 # if (word-slice == '->') break +1455 (slice-equal? %ecx "->") # => eax +1456 3d/compare-eax-and 0/imm32 +1457 0f 85/jump-if-!= break/disp32 +1458 # if (word-slice == '}') abort +1459 (slice-equal? %ecx "}") # => eax +1460 3d/compare-eax-and 0/imm32 +1461 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1462 # var v/ebx: (handle var) = parse-var-with-type(word-slice, first-line) +1463 (parse-var-with-type %ecx *(ebp+8)) # => eax +1464 89/<- %ebx 0/r32/eax +1465 # assert(v->register == null) +1466 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +1467 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 +1468 # v->stack-offset = next-offset +1469 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset +1470 # next-offset += size-of(v) +1471 (size-of %ebx) # => eax +1472 01/add %edx 0/r32/eax +1473 # +1474 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax +1475 89/<- *(edi+8) 0/r32/eax # Function-inouts +1476 (push *(ebp+0x10) %ebx) +1477 # +1478 e9/jump loop/disp32 +1479 } +1480 # save function outputs +1481 { +1482 $parse-var-with-type:check-for-out: +1483 (next-word *(ebp+8) %ecx) +1484 # if (word-slice == '{') break +1485 (slice-equal? %ecx "{") # => eax +1486 3d/compare-eax-and 0/imm32 +1487 0f 85/jump-if-!= break/disp32 +1488 # if (word-slice == '->') abort +1489 (slice-equal? %ecx "->") # => eax +1490 3d/compare-eax-and 0/imm32 +1491 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1492 # if (word-slice == '}') abort +1493 (slice-equal? %ecx "}") # => eax +1494 3d/compare-eax-and 0/imm32 +1495 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1496 # +1497 (parse-var-with-type %ecx *(ebp+8)) # => eax +1498 89/<- %ebx 0/r32/eax +1499 # assert(var->register != null) +1500 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +1501 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 +1502 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax +1503 89/<- *(edi+0xc) 0/r32/eax # Function-outputs +1504 e9/jump loop/disp32 +1505 } +1506 $populate-mu-function-header:done: +1507 (check-no-tokens-left *(ebp+8)) +1508 $populate-mu-function-header:end: +1509 # . reclaim locals +1510 81 0/subop/add %esp 8/imm32 +1511 # . restore registers +1512 5f/pop-to-edi +1513 5b/pop-to-ebx +1514 5a/pop-to-edx +1515 59/pop-to-ecx +1516 58/pop-to-eax +1517 # . epilogue +1518 89/<- %esp 5/r32/ebp +1519 5d/pop-to-ebp +1520 c3/return +1521 +1522 $populate-mu-function-header:error1: +1523 # error("function header not in form 'fn <name> {'") +1524 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") +1525 (flush Stderr) +1526 (rewind-stream *(ebp+8)) +1527 (write-stream 2 *(ebp+8)) +1528 (write-buffered Stderr "'\n") +1529 (flush Stderr) +1530 # . syscall(exit, 1) +1531 bb/copy-to-ebx 1/imm32 +1532 b8/copy-to-eax 1/imm32/exit +1533 cd/syscall 0x80/imm8 +1534 # never gets here +1535 +1536 $populate-mu-function-header:error2: +1537 # error("function input '" var "' cannot be in a register") +1538 (write-buffered Stderr "function input '") +1539 (write-buffered Stderr *ebx) # Var-name +1540 (write-buffered Stderr "' cannot be in a register") +1541 (flush Stderr) +1542 # . syscall(exit, 1) +1543 bb/copy-to-ebx 1/imm32 +1544 b8/copy-to-eax 1/imm32/exit +1545 cd/syscall 0x80/imm8 +1546 # never gets here +1547 +1548 $populate-mu-function-header:error3: +1549 # error("function input '" var "' must be in a register") +1550 (write-buffered Stderr "function input '") +1551 (write-buffered Stderr *eax) # Var-name +1552 (write-buffered Stderr " must be in a register'") +1553 (flush Stderr) +1554 (rewind-stream *(ebp+8)) +1555 (write-stream 2 *(ebp+8)) +1556 (write-buffered Stderr "'\n") +1557 (flush Stderr) +1558 # . syscall(exit, 1) +1559 bb/copy-to-ebx 1/imm32 +1560 b8/copy-to-eax 1/imm32/exit +1561 cd/syscall 0x80/imm8 +1562 # never gets here +1563 +1564 test-function-header-with-arg: +1565 # 'foo n : int {' +1566 # . prologue +1567 55/push-ebp +1568 89/<- %ebp 4/r32/esp +1569 # setup +1570 (clear-stream _test-input-stream) +1571 (write _test-input-stream "foo n : int {\n") +1572 # var result/ecx: function +1573 2b/subtract-> *Function-size 4/r32/esp +1574 89/<- %ecx 4/r32/esp +1575 (zero-out %ecx *Function-size) +1576 # var vars/ebx: (stack (addr var) 16) +1577 81 5/subop/subtract %esp 0x10/imm32 +1578 68/push 0x10/imm32/length +1579 68/push 0/imm32/top +1580 89/<- %ebx 4/r32/esp +1581 # convert +1582 (populate-mu-function-header _test-input-stream %ecx %ebx) +1583 # check result +1584 (check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name +1585 # edx: (handle list var) = result->inouts +1586 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1587 # ebx: (handle var) = result->inouts->value +1588 8b/-> *edx 3/r32/ebx # List-value +1589 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name +1590 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1591 (check-ints-equal *ebx 1 "F - test-function-header-with-arg/inout:0/type:0") # Tree-left +1592 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-arg/inout:0/type:1") # Tree-right +1593 # . epilogue +1594 89/<- %esp 5/r32/ebp +1595 5d/pop-to-ebp +1596 c3/return +1597 +1598 test-function-header-with-multiple-args: +1599 # 'fn foo a: int, b: int, c: int {' +1600 # . prologue +1601 55/push-ebp +1602 89/<- %ebp 4/r32/esp +1603 # setup +1604 (clear-stream _test-input-stream) +1605 (write _test-input-stream "foo a: int, b: int c: int {\n") +1606 # result/ecx: (handle function) +1607 2b/subtract-> *Function-size 4/r32/esp +1608 89/<- %ecx 4/r32/esp +1609 (zero-out %ecx *Function-size) +1610 # var vars/ebx: (stack (addr var) 16) +1611 81 5/subop/subtract %esp 0x10/imm32 +1612 68/push 0x10/imm32/length +1613 68/push 0/imm32/top +1614 89/<- %ebx 4/r32/esp +1615 # convert +1616 (populate-mu-function-header _test-input-stream %ecx %ebx) +1617 # check result +1618 (check-strings-equal *ecx "foo") # Function-name +1619 # edx: (handle list var) = result->inouts +1620 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1621 $test-function-header-with-multiple-args:inout0: +1622 # ebx: (handle var) = result->inouts->value +1623 8b/-> *edx 3/r32/ebx # List-value +1624 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name +1625 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1626 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Tree-left +1627 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-right +1628 # edx = result->inouts->next +1629 8b/-> *(edx+4) 2/r32/edx # List-next +1630 $test-function-header-with-multiple-args:inout1: +1631 # ebx = result->inouts->next->value +1632 8b/-> *edx 3/r32/ebx # List-value +1633 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name +1634 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1635 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Tree-left +1636 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-right +1637 # edx = result->inouts->next->next +1638 8b/-> *(edx+4) 2/r32/edx # List-next +1639 $test-function-header-with-multiple-args:inout2: +1640 # ebx = result->inouts->next->next->value +1641 8b/-> *edx 3/r32/ebx # List-value +1642 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name +1643 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1644 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Tree-left +1645 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-right +1646 # . epilogue +1647 89/<- %esp 5/r32/ebp +1648 5d/pop-to-ebp +1649 c3/return +1650 +1651 test-function-with-multiple-args-and-outputs: +1652 # fn foo a: int, b: int, c: int -> x: int, y: int { +1653 # . prologue +1654 55/push-ebp +1655 89/<- %ebp 4/r32/esp +1656 # setup +1657 (clear-stream _test-input-stream) +1658 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n") +1659 # result/ecx: (handle function) +1660 2b/subtract-> *Function-size 4/r32/esp +1661 89/<- %ecx 4/r32/esp +1662 (zero-out %ecx *Function-size) +1663 # var vars/ebx: (stack (addr var) 16) +1664 81 5/subop/subtract %esp 0x10/imm32 +1665 68/push 0x10/imm32/length +1666 68/push 0/imm32/top +1667 89/<- %ebx 4/r32/esp +1668 # convert +1669 (populate-mu-function-header _test-input-stream %ecx %ebx) +1670 # check result +1671 (check-strings-equal *ecx "foo") # Function-name +1672 # edx: (handle list var) = result->inouts +1673 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1674 # ebx: (handle var) = result->inouts->value +1675 8b/-> *edx 3/r32/ebx # List-value +1676 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") # Var-name +1677 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1678 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Tree-left +1679 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-right +1680 # edx = result->inouts->next +1681 8b/-> *(edx+4) 2/r32/edx # List-next +1682 # ebx = result->inouts->next->value +1683 8b/-> *edx 3/r32/ebx # List-value +1684 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") # Var-name +1685 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1686 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Tree-left +1687 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-right +1688 # edx = result->inouts->next->next +1689 8b/-> *(edx+4) 2/r32/edx # List-next +1690 # ebx = result->inouts->next->next->value +1691 8b/-> *edx 3/r32/ebx # List-value +1692 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") # Var-name +1693 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1694 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Tree-left +1695 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-right +1696 # edx: (handle list var) = result->outputs +1697 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs +1698 # ebx: (handle var) = result->outputs->value +1699 8b/-> *edx 3/r32/ebx # List-value +1700 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") # Var-name +1701 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register +1702 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1703 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-left +1704 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-right +1705 # edx = result->outputs->next +1706 8b/-> *(edx+4) 2/r32/edx # List-next +1707 # ebx = result->outputs->next->value +1708 8b/-> *edx 3/r32/ebx # List-value +1709 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") # Var-name +1710 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register +1711 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1712 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-left +1713 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-right +1714 # . epilogue +1715 89/<- %esp 5/r32/ebp +1716 5d/pop-to-ebp +1717 c3/return +1718 +1719 # format for variables with types +1720 # x: int +1721 # x: int +1722 # x: int, +1723 # ignores at most one trailing colon or comma +1724 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte) -> result/eax: (handle var) +1725 # pseudocode: +1726 # var v: (handle var) = allocate(Heap, Var-size) +1727 # var s: slice +1728 # next-token-from-slice(name->start, name->end, '/', s) +1729 # var end: (addr byte) = s->end +1730 # if (slice-ends-with(s, ":")) +1731 # decrement s->end +1732 # if (slice-ends-with(s, ",")) +1733 # decrement s->end +1734 # v->name = slice-to-string(s) +1735 # ## register +1736 # next-token-from-slice(end, name->end, '/', s) +1737 # if (slice-ends-with(s, ":")) +1738 # decrement s->end +1739 # if (slice-ends-with(s, ",")) +1740 # decrement s->end +1741 # if (!slice-empty?(s)) +1742 # v->register = slice-to-string(s) +1743 # ## type +1744 # var type: (handle tree type-id) = parse-type(first-line) +1745 # v->type = type +1746 # return v +1747 # +1748 # . prologue +1749 55/push-ebp +1750 89/<- %ebp 4/r32/esp +1751 # . save registers +1752 51/push-ecx +1753 52/push-edx +1754 53/push-ebx +1755 56/push-esi +1756 57/push-edi +1757 # var result/edi: (handle var) = allocate(Heap, Var-size) +1758 (allocate Heap *Var-size) # => eax +1759 (zero-out %eax *Var-size) +1760 89/<- %edi 0/r32/eax +1761 # esi = name +1762 8b/-> *(ebp+8) 6/r32/esi +1763 # var s/ecx: slice +1764 68/push 0/imm32/end +1765 68/push 0/imm32/start +1766 89/<- %ecx 4/r32/esp +1767 $parse-var-with-type:save-name: +1768 # save v->name +1769 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' +1770 # . end/edx = s->end +1771 8b/-> *(ecx+4) 2/r32/edx +1772 # . if s ends with ':', decrement s->end +1773 { +1774 8b/-> *(ecx+4) 0/r32/eax +1775 48/decrement-eax +1776 8a/copy-byte *eax 3/r32/BL +1777 81 4/subop/and %ebx 0xff/imm32 +1778 81 7/subop/compare %ebx 0x3a/imm32/colon +1779 75/jump-if-!= break/disp8 +1780 89/<- *(ecx+4) 0/r32/eax +1781 } +1782 # . if s ends with ',', decrement s->end +1783 { +1784 8b/-> *(ecx+4) 0/r32/eax +1785 48/decrement-eax +1786 8a/copy-byte *eax 3/r32/BL +1787 81 4/subop/and %ebx 0xff/imm32 +1788 81 7/subop/compare %ebx 0x2c/imm32/comma +1789 75/jump-if-!= break/disp8 +1790 89/<- *(ecx+4) 0/r32/eax 1791 } -1792 # otherwise s == "(" -1793 # result->left = parse-type(ad, in) -1794 (parse-type *(ebp+8) *(ebp+0xc)) -1795 #? (write-buffered Stderr "=> {") -1796 #? (print-int32-buffered Stderr %eax) -1797 89/<- *edx 0/r32/eax # Tree-left -1798 # result->right = parse-type-tree(ad, in) -1799 (parse-type-tree *(ebp+8) *(ebp+0xc)) -1800 #? (write-buffered Stderr Space) -1801 #? (print-int32-buffered Stderr %eax) -1802 #? (write-buffered Stderr "}\n") -1803 #? (flush Stderr) -1804 89/<- *(edx+4) 0/r32/eax # Tree-right -1805 $parse-type:return-edx: -1806 89/<- %eax 2/r32/edx -1807 $parse-type:end: -1808 # . reclaim locals -1809 81 0/subop/add %esp 8/imm32 -1810 # . restore registers -1811 5a/pop-to-edx -1812 59/pop-to-ecx -1813 # . epilogue -1814 89/<- %esp 5/r32/ebp -1815 5d/pop-to-ebp -1816 c3/return -1817 -1818 $parse-type:abort: -1819 # error("unexpected token when parsing type: '" s "'\n") -1820 (write-buffered Stderr "unexpected token when parsing type: '") -1821 (write-slice-buffered Stderr %ecx) -1822 (write-buffered Stderr "'\n") -1823 (flush Stderr) -1824 # . syscall(exit, 1) -1825 bb/copy-to-ebx 1/imm32 -1826 b8/copy-to-eax 1/imm32/exit -1827 cd/syscall 0x80/imm8 -1828 # never gets here -1829 -1830 parse-type-tree: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) -1831 # pseudocode: -1832 # var tmp: (handle tree type-id) = parse-type(ad, in) -1833 # if tmp == 0 -1834 # return 0 -1835 # result = allocate(Tree) -1836 # zero-out(result, *Tree-size) -1837 # result->left = tmp -1838 # result->right = parse-type-tree(ad, in) -1839 # -1840 # . prologue -1841 55/push-ebp -1842 89/<- %ebp 4/r32/esp -1843 # . save registers -1844 51/push-ecx -1845 52/push-edx -1846 # var tmp/eax: (handle tree type-id) = parse-type(ad, in) -1847 (parse-type *(ebp+8) *(ebp+0xc)) -1848 # if (tmp == 0) return tmp -1849 3d/compare-eax-and 0/imm32 -1850 74/jump-if-= $parse-type-tree:end/disp8 -1851 # var tmp2/ecx = tmp -1852 89/<- %ecx 0/r32/eax -1853 # var result/edx: (handle tree type-id) -1854 (allocate *(ebp+8) *Tree-size) # => eax -1855 (zero-out %eax *Tree-size) -1856 89/<- %edx 0/r32/eax -1857 # result->left = tmp2 -1858 89/<- *edx 1/r32/ecx # Tree-left -1859 # result->right = parse-type-tree(ad, in) -1860 (parse-type-tree *(ebp+8) *(ebp+0xc)) -1861 89/<- *(edx+4) 0/r32/eax # Tree-right -1862 $parse-type-tree:return-edx: -1863 89/<- %eax 2/r32/edx -1864 $parse-type-tree:end: -1865 # . restore registers -1866 5a/pop-to-edx -1867 59/pop-to-ecx -1868 # . epilogue -1869 89/<- %esp 5/r32/ebp -1870 5d/pop-to-ebp -1871 c3/return -1872 -1873 next-mu-token: # in: (addr stream byte), out: (addr slice) -1874 # pseudocode: -1875 # start: -1876 # skip-chars-matching-whitespace(in) -1877 # if in->read >= in->write # end of in -1878 # out = {0, 0} -1879 # return -1880 # out->start = &in->data[in->read] -1881 # var curr-byte/eax: byte = in->data[in->read] -1882 # if curr->byte == ':' # comment token -1883 # ++in->read -1884 # goto start -1885 # if curr->byte == ',' # comment token -1886 # ++in->read -1887 # goto start -1888 # if curr-byte == '#' # comment -1889 # in->read = in->write # skip to end of in -1890 # goto done -1891 # if curr-byte == '"' # string literal -1892 # skip-string(in) -1893 # goto done # no metadata -1894 # if curr-byte == '(' -1895 # ++in->read -1896 # goto done -1897 # if curr-byte == ')' -1898 # ++in->read -1899 # goto done -1900 # # read a word -1901 # while true -1902 # if in->read >= in->write -1903 # break -1904 # curr-byte = in->data[in->read] -1905 # if curr-byte == ' ' -1906 # break -1907 # if curr-byte == '\r' -1908 # break -1909 # if curr-byte == '\n' -1910 # break -1911 # if curr-byte == '(' -1912 # break -1913 # if curr-byte == ')' -1914 # break -1915 # if curr-byte == ':' -1916 # break -1917 # if curr-byte == ',' -1918 # break -1919 # ++in->read -1920 # done: -1921 # out->end = &in->data[in->read] -1922 # # hack: skip a few trailing delimiters, because we don't always use -1923 # # this correct tokenizer in later tokens -1924 # while true -1925 # if in->read >= in->write -1926 # break -1927 # curr-byte = in->data[in->read] -1928 # if curr-byte == ':' -1929 # ++in->read -1930 # else if curr-byte == ',' -1931 # ++in->read -1932 # else -1933 # break -1934 # -1935 # . prologue -1936 55/push-ebp -1937 89/<- %ebp 4/r32/esp -1938 # . save registers -1939 50/push-eax -1940 51/push-ecx -1941 56/push-esi -1942 57/push-edi -1943 # esi = in -1944 8b/-> *(ebp+8) 6/r32/esi -1945 # edi = out -1946 8b/-> *(ebp+0xc) 7/r32/edi -1947 $next-mu-token:start: -1948 (skip-chars-matching-whitespace %esi) -1949 $next-mu-token:check0: -1950 # if (in->read >= in->write) return out = {0, 0} -1951 # . ecx = in->read -1952 8b/-> *(esi+4) 1/r32/ecx -1953 # . if (ecx >= in->write) return out = {0, 0} -1954 3b/compare 1/r32/ecx *esi -1955 c7 0/subop/copy *edi 0/imm32 -1956 c7 0/subop/copy *(edi+4) 0/imm32 -1957 0f 8d/jump-if->= $next-mu-token:end/disp32 -1958 # out->start = &in->data[in->read] -1959 8d/copy-address *(esi+ecx+0xc) 0/r32/eax -1960 89/<- *edi 0/r32/eax -1961 # var curr-byte/eax: byte = in->data[in->read] -1962 31/xor %eax 0/r32/eax -1963 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL -1964 { -1965 $next-mu-token:check-for-colon: -1966 # if (curr-byte != ':') break -1967 3d/compare-eax-and 0x3a/imm32/colon -1968 75/jump-if-!= break/disp8 -1969 # ++in->read -1970 ff 0/subop/increment *(esi+4) -1971 # restart -1972 e9/jump $next-mu-token:start/disp32 -1973 } -1974 { -1975 $next-mu-token:check-for-comma: -1976 # if (curr-byte != ',') break -1977 3d/compare-eax-and 0x2c/imm32/comma -1978 75/jump-if-!= break/disp8 -1979 # ++in->read -1980 ff 0/subop/increment *(esi+4) -1981 # restart -1982 e9/jump $next-mu-token:start/disp32 -1983 } -1984 { -1985 $next-mu-token:check-for-comment: -1986 # if (curr-byte != '#') break -1987 3d/compare-eax-and 0x23/imm32/pound -1988 75/jump-if-!= break/disp8 -1989 # in->read = in->write # skip rest of in -1990 8b/-> *esi 0/r32/eax -1991 89/<- *(esi+4) 0/r32/eax -1992 # return -1993 e9/jump $next-mu-token:done/disp32 -1994 } -1995 { -1996 $next-mu-token:check-for-string-literal: -1997 # if (curr-byte != '"') break -1998 3d/compare-eax-and 0x22/imm32/dquote -1999 75/jump-if-!= break/disp8 -2000 (skip-string %esi) -2001 # return -2002 e9/jump $next-mu-token:done/disp32 -2003 } -2004 { -2005 $next-mu-token:check-for-open-paren: -2006 # if (curr-byte != '(') break -2007 3d/compare-eax-and 0x28/imm32/open-paren -2008 75/jump-if-!= break/disp8 -2009 # ++in->read -2010 ff 0/subop/increment *(esi+4) -2011 # return -2012 e9/jump $next-mu-token:done/disp32 -2013 } -2014 { -2015 $next-mu-token:check-for-close-paren: -2016 # if (curr-byte != ')') break -2017 3d/compare-eax-and 0x29/imm32/close-paren -2018 75/jump-if-!= break/disp8 -2019 # ++in->read -2020 ff 0/subop/increment *(esi+4) -2021 # return -2022 e9/jump $next-mu-token:done/disp32 -2023 } -2024 { -2025 $next-mu-token:regular-word-without-metadata: -2026 # if (in->read >= in->write) break -2027 # . ecx = in->read -2028 8b/-> *(esi+4) 1/r32/ecx -2029 # . if (ecx >= in->write) break -2030 3b/compare *esi 1/r32/ecx -2031 7d/jump-if->= break/disp8 -2032 # var c/eax: byte = in->data[in->read] -2033 31/xor %eax 0/r32/eax -2034 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL -2035 # if (c == ' ') break -2036 3d/compare-eax-and 0x20/imm32/space -2037 74/jump-if-= break/disp8 -2038 # if (c == '\r') break -2039 3d/compare-eax-and 0xd/imm32/carriage-return -2040 74/jump-if-= break/disp8 -2041 # if (c == '\n') break -2042 3d/compare-eax-and 0xa/imm32/newline -2043 74/jump-if-= break/disp8 -2044 # if (c == '(') break -2045 3d/compare-eax-and 0x28/imm32/open-paren -2046 0f 84/jump-if-= break/disp32 -2047 # if (c == ')') break -2048 3d/compare-eax-and 0x29/imm32/close-paren -2049 0f 84/jump-if-= break/disp32 -2050 # if (c == ':') break -2051 3d/compare-eax-and 0x3a/imm32/colon -2052 0f 84/jump-if-= break/disp32 -2053 # if (c == ',') break -2054 3d/compare-eax-and 0x2c/imm32/comma -2055 0f 84/jump-if-= break/disp32 -2056 # ++in->read -2057 ff 0/subop/increment *(esi+4) -2058 # -2059 e9/jump loop/disp32 -2060 } -2061 $next-mu-token:done: -2062 # out->end = &in->data[in->read] -2063 8b/-> *(esi+4) 1/r32/ecx -2064 8d/copy-address *(esi+ecx+0xc) 0/r32/eax -2065 89/<- *(edi+4) 0/r32/eax -2066 { -2067 $next-mu-token:skip-trailing-delimiters: -2068 # if (in->read >= in->write) break -2069 # . ecx = in->read -2070 8b/-> *(esi+4) 1/r32/ecx -2071 # . if (ecx >= in->write) break -2072 3b/compare *esi 1/r32/ecx -2073 7d/jump-if->= break/disp8 -2074 # var c/eax: byte = in->data[in->read] -2075 31/xor %eax 0/r32/eax -2076 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL -2077 # if (c == ':') ++in->read and loop -2078 { -2079 3d/compare-eax-and 0x3a/imm32/colon -2080 75/jump-if-!= break/disp8 -2081 # ++in->read -2082 ff 0/subop/increment *(esi+4) -2083 # -2084 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 -2085 } -2086 # if (c == ',') ++in->read and loop -2087 { -2088 3d/compare-eax-and 0x2c/imm32/comma -2089 75/jump-if-!= break/disp8 -2090 # ++in->read -2091 ff 0/subop/increment *(esi+4) -2092 # -2093 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 -2094 } -2095 # else break -2096 } -2097 $next-mu-token:end: -2098 # . restore registers -2099 5f/pop-to-edi -2100 5e/pop-to-esi -2101 59/pop-to-ecx -2102 58/pop-to-eax -2103 # . epilogue -2104 89/<- %esp 5/r32/ebp -2105 5d/pop-to-ebp -2106 c3/return -2107 -2108 # return the index in an array of strings matching 's' -2109 # index is denominated in elements, not bytes -2110 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int -2111 # . prologue -2112 55/push-ebp -2113 89/<- %ebp 4/r32/esp -2114 # . save registers -2115 51/push-ecx -2116 52/push-edx -2117 53/push-ebx -2118 56/push-esi -2119 #? (write-buffered Stderr "pos-slice: ") -2120 #? (write-slice-buffered Stderr *(ebp+0xc)) -2121 #? (write-buffered Stderr "\n") -2122 #? (flush Stderr) -2123 # esi = arr -2124 8b/-> *(ebp+8) 6/r32/esi -2125 # var index/ecx: int = 0 -2126 b9/copy-to-ecx 0/imm32 -2127 # var curr/edx: (addr (addr array byte)) = arr->data -2128 8d/copy-address *(esi+0xc) 2/r32/edx -2129 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] -2130 8b/-> *esi 3/r32/ebx -2131 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx -2132 { -2133 #? (write-buffered Stderr " ") -2134 #? (print-int32-buffered Stderr %ecx) -2135 #? (write-buffered Stderr "\n") -2136 #? (flush Stderr) -2137 # if (curr >= max) return -1 -2138 39/compare %edx 3/r32/ebx -2139 b8/copy-to-eax -1/imm32 -2140 73/jump-if-addr>= $pos-slice:end/disp8 -2141 # if (slice-equal?(s, *curr)) break -2142 (slice-equal? *(ebp+0xc) *edx) # => eax -2143 3d/compare-eax-and 0/imm32 -2144 75/jump-if-!= break/disp8 -2145 # ++index -2146 41/increment-ecx -2147 # curr += 4 -2148 81 0/subop/add %edx 4/imm32 -2149 # -2150 eb/jump loop/disp8 -2151 } -2152 # return index -2153 89/<- %eax 1/r32/ecx -2154 $pos-slice:end: -2155 #? (write-buffered Stderr "=> ") -2156 #? (print-int32-buffered Stderr %eax) -2157 #? (write-buffered Stderr "\n") -2158 # . restore registers -2159 5e/pop-to-esi -2160 5b/pop-to-ebx -2161 5a/pop-to-edx -2162 59/pop-to-ecx -2163 # . epilogue -2164 89/<- %esp 5/r32/ebp -2165 5d/pop-to-ebp -2166 c3/return -2167 -2168 == data -2169 -2170 Type-id: # (stream (address array byte)) -2171 0x18/imm32/write -2172 0/imm32/read -2173 0x100/imm32/length -2174 # data -2175 "literal"/imm32 # 0 -2176 "int"/imm32 # 1 -2177 "addr"/imm32 # 2 -2178 "array"/imm32 # 3 -2179 "handle"/imm32 # 4 -2180 "bool"/imm32 # 5 -2181 0/imm32 -2182 0/imm32 -2183 # 0x20 -2184 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2185 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2186 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2187 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2188 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2189 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2190 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2191 -2192 == code -2193 -2194 test-parse-var-with-type: -2195 # . prologue -2196 55/push-ebp -2197 89/<- %ebp 4/r32/esp -2198 # (eax..ecx) = "x:" -2199 b8/copy-to-eax "x:"/imm32 -2200 8b/-> *eax 1/r32/ecx -2201 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2202 05/add-to-eax 4/imm32 -2203 # var slice/ecx: slice = {eax, ecx} -2204 51/push-ecx -2205 50/push-eax -2206 89/<- %ecx 4/r32/esp -2207 # _test-input-stream contains "int" -2208 (clear-stream _test-input-stream) -2209 (write _test-input-stream "int") -2210 # -2211 (parse-var-with-type %ecx _test-input-stream) -2212 8b/-> *eax 2/r32/edx # Var-name -2213 (check-strings-equal %edx "x" "F - test-var-with-type/name") -2214 8b/-> *(eax+4) 2/r32/edx # Var-type -2215 (check-ints-equal *edx 1 "F - test-var-with-type/type") -2216 (check-ints-equal *(edx+4) 0 "F - test-var-with-type/type") -2217 # . epilogue -2218 89/<- %esp 5/r32/ebp -2219 5d/pop-to-ebp -2220 c3/return -2221 -2222 test-parse-var-with-type-and-register: -2223 # . prologue -2224 55/push-ebp -2225 89/<- %ebp 4/r32/esp -2226 # (eax..ecx) = "x/eax" -2227 b8/copy-to-eax "x/eax"/imm32 -2228 8b/-> *eax 1/r32/ecx -2229 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2230 05/add-to-eax 4/imm32 -2231 # var slice/ecx: slice = {eax, ecx} -2232 51/push-ecx -2233 50/push-eax -2234 89/<- %ecx 4/r32/esp -2235 # _test-input-stream contains ": int" -2236 (clear-stream _test-input-stream) -2237 (write _test-input-stream ": int") -2238 # -2239 (parse-var-with-type %ecx _test-input-stream) -2240 8b/-> *eax 2/r32/edx # Var-name -2241 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") -2242 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2243 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") -2244 8b/-> *(eax+4) 2/r32/edx # Var-type -2245 (check-ints-equal *edx 1 "F - test-var-with-type-and-register/type") -2246 (check-ints-equal *(edx+4) 0 "F - test-var-with-type-and-register/type") -2247 # . epilogue -2248 89/<- %esp 5/r32/ebp -2249 5d/pop-to-ebp -2250 c3/return -2251 -2252 test-parse-var-with-trailing-characters: +1792 $parse-var-with-type:write-name: +1793 (slice-to-string Heap %ecx) # => eax +1794 89/<- *edi 0/r32/eax # Var-name +1795 # save v->register +1796 $parse-var-with-type:save-register: +1797 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' +1798 # . if s ends with ':', decrement s->end +1799 { +1800 8b/-> *(ecx+4) 0/r32/eax +1801 48/decrement-eax +1802 8a/copy-byte *eax 3/r32/BL +1803 81 4/subop/and %ebx 0xff/imm32 +1804 81 7/subop/compare %ebx 0x3a/imm32/colon +1805 75/jump-if-!= break/disp8 +1806 89/<- *(ecx+4) 0/r32/eax +1807 } +1808 # . if s ends with ',', decrement s->end +1809 { +1810 8b/-> *(ecx+4) 0/r32/eax +1811 48/decrement-eax +1812 8a/copy-byte *eax 3/r32/BL +1813 81 4/subop/and %ebx 0xff/imm32 +1814 81 7/subop/compare %ebx 0x2c/imm32/comma +1815 75/jump-if-!= break/disp8 +1816 89/<- *(ecx+4) 0/r32/eax +1817 } +1818 # if (!slice-empty?(s)) v->register = slice-to-string(s) +1819 { +1820 $parse-var-with-type:write-register: +1821 # HACK: s->end can be less than s->start with all the decrements above +1822 # That's probably a sign we have the wrong algorithm for this function. +1823 8b/-> *ecx 0/r32/eax +1824 39/compare 0/r32/eax *(ecx+4) +1825 76/jump-if-<= break/disp8 +1826 (slice-to-string Heap %ecx) +1827 89/<- *(edi+0x10) 0/r32/eax # Var-register +1828 } +1829 $parse-var-with-type:save-type: +1830 (parse-type Heap *(ebp+0xc)) # => eax +1831 89/<- *(edi+4) 0/r32/eax # Var-type +1832 $parse-var-with-type:end: +1833 # return result +1834 89/<- %eax 7/r32/edi +1835 # . reclaim locals +1836 81 0/subop/add %esp 8/imm32 +1837 # . restore registers +1838 5f/pop-to-edi +1839 5e/pop-to-esi +1840 5b/pop-to-ebx +1841 5a/pop-to-edx +1842 59/pop-to-ecx +1843 # . epilogue +1844 89/<- %esp 5/r32/ebp +1845 5d/pop-to-ebp +1846 c3/return +1847 +1848 $parse-var-with-type:abort: +1849 # error("function header not in form 'fn <name> {'") +1850 (write-buffered Stderr "var should have form 'name: type' in '") +1851 (flush Stderr) +1852 (rewind-stream *(ebp+0xc)) +1853 (write-stream 2 *(ebp+0xc)) +1854 (write-buffered Stderr "'\n") +1855 (flush Stderr) +1856 # . syscall(exit, 1) +1857 bb/copy-to-ebx 1/imm32 +1858 b8/copy-to-eax 1/imm32/exit +1859 cd/syscall 0x80/imm8 +1860 # never gets here +1861 +1862 parse-type: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) +1863 # pseudocode: +1864 # var s: slice = next-mu-token(in) +1865 # assert s != "" +1866 # assert s != "->" +1867 # assert s != "{" +1868 # assert s != "}" +1869 # if s == ")" +1870 # return 0 +1871 # result = allocate(Tree) +1872 # zero-out(result, *Tree-size) +1873 # if s != "(" +1874 # result->left = pos-slice(Type-id, s) +1875 # return +1876 # result->left = parse-type(ad, in) +1877 # result->right = parse-type-tree(ad, in) +1878 # +1879 # . prologue +1880 55/push-ebp +1881 89/<- %ebp 4/r32/esp +1882 # . save registers +1883 51/push-ecx +1884 52/push-edx +1885 # var s/ecx: slice +1886 68/push 0/imm32 +1887 68/push 0/imm32 +1888 89/<- %ecx 4/r32/esp +1889 # s = next-mu-token(in) +1890 (next-mu-token *(ebp+0xc) %ecx) +1891 #? (write-buffered Stderr "tok: ") +1892 #? (write-slice-buffered Stderr %ecx) +1893 #? (write-buffered Stderr "$\n") +1894 #? (flush Stderr) +1895 # assert s != "" +1896 (slice-equal? %ecx "") +1897 3d/compare-eax-and 0/imm32 +1898 0f 85/jump-if-!= $parse-type:abort/disp32 +1899 # assert s != "{" +1900 (slice-equal? %ecx "{") +1901 3d/compare-eax-and 0/imm32 +1902 0f 85/jump-if-!= $parse-type:abort/disp32 +1903 # assert s != "}" +1904 (slice-equal? %ecx "}") +1905 3d/compare-eax-and 0/imm32 +1906 0f 85/jump-if-!= $parse-type:abort/disp32 +1907 # assert s != "->" +1908 (slice-equal? %ecx "->") +1909 3d/compare-eax-and 0/imm32 +1910 0f 85/jump-if-!= $parse-type:abort/disp32 +1911 # if (s == ")") return 0 +1912 (slice-equal? %ecx ")") +1913 3d/compare-eax-and 0/imm32 +1914 b8/copy-to-eax 0/imm32 +1915 0f 85/jump-if-!= $parse-type:end/disp32 +1916 # var result/edx: (handle tree type-id) +1917 (allocate *(ebp+8) *Tree-size) # => eax +1918 (zero-out %eax *Tree-size) +1919 89/<- %edx 0/r32/eax +1920 { +1921 # if (s != "(") break +1922 (slice-equal? %ecx "(") +1923 3d/compare-eax-and 0/imm32 +1924 75/jump-if-!= break/disp8 +1925 # result->left = pos-slice(Type-id, s) +1926 (pos-slice Type-id %ecx) +1927 #? (write-buffered Stderr "=> {") +1928 #? (print-int32-buffered Stderr %eax) +1929 #? (write-buffered Stderr ", 0}\n") +1930 #? (flush Stderr) +1931 89/<- *edx 0/r32/eax # Tree-left +1932 e9/jump $parse-type:return-edx/disp32 +1933 } +1934 # otherwise s == "(" +1935 # result->left = parse-type(ad, in) +1936 (parse-type *(ebp+8) *(ebp+0xc)) +1937 #? (write-buffered Stderr "=> {") +1938 #? (print-int32-buffered Stderr %eax) +1939 89/<- *edx 0/r32/eax # Tree-left +1940 # result->right = parse-type-tree(ad, in) +1941 (parse-type-tree *(ebp+8) *(ebp+0xc)) +1942 #? (write-buffered Stderr Space) +1943 #? (print-int32-buffered Stderr %eax) +1944 #? (write-buffered Stderr "}\n") +1945 #? (flush Stderr) +1946 89/<- *(edx+4) 0/r32/eax # Tree-right +1947 $parse-type:return-edx: +1948 89/<- %eax 2/r32/edx +1949 $parse-type:end: +1950 # . reclaim locals +1951 81 0/subop/add %esp 8/imm32 +1952 # . restore registers +1953 5a/pop-to-edx +1954 59/pop-to-ecx +1955 # . epilogue +1956 89/<- %esp 5/r32/ebp +1957 5d/pop-to-ebp +1958 c3/return +1959 +1960 $parse-type:abort: +1961 # error("unexpected token when parsing type: '" s "'\n") +1962 (write-buffered Stderr "unexpected token when parsing type: '") +1963 (write-slice-buffered Stderr %ecx) +1964 (write-buffered Stderr "'\n") +1965 (flush Stderr) +1966 # . syscall(exit, 1) +1967 bb/copy-to-ebx 1/imm32 +1968 b8/copy-to-eax 1/imm32/exit +1969 cd/syscall 0x80/imm8 +1970 # never gets here +1971 +1972 parse-type-tree: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) +1973 # pseudocode: +1974 # var tmp: (handle tree type-id) = parse-type(ad, in) +1975 # if tmp == 0 +1976 # return 0 +1977 # result = allocate(Tree) +1978 # zero-out(result, *Tree-size) +1979 # result->left = tmp +1980 # result->right = parse-type-tree(ad, in) +1981 # +1982 # . prologue +1983 55/push-ebp +1984 89/<- %ebp 4/r32/esp +1985 # . save registers +1986 51/push-ecx +1987 52/push-edx +1988 # var tmp/eax: (handle tree type-id) = parse-type(ad, in) +1989 (parse-type *(ebp+8) *(ebp+0xc)) +1990 # if (tmp == 0) return tmp +1991 3d/compare-eax-and 0/imm32 +1992 74/jump-if-= $parse-type-tree:end/disp8 +1993 # var tmp2/ecx = tmp +1994 89/<- %ecx 0/r32/eax +1995 # var result/edx: (handle tree type-id) +1996 (allocate *(ebp+8) *Tree-size) # => eax +1997 (zero-out %eax *Tree-size) +1998 89/<- %edx 0/r32/eax +1999 # result->left = tmp2 +2000 89/<- *edx 1/r32/ecx # Tree-left +2001 # result->right = parse-type-tree(ad, in) +2002 (parse-type-tree *(ebp+8) *(ebp+0xc)) +2003 89/<- *(edx+4) 0/r32/eax # Tree-right +2004 $parse-type-tree:return-edx: +2005 89/<- %eax 2/r32/edx +2006 $parse-type-tree:end: +2007 # . restore registers +2008 5a/pop-to-edx +2009 59/pop-to-ecx +2010 # . epilogue +2011 89/<- %esp 5/r32/ebp +2012 5d/pop-to-ebp +2013 c3/return +2014 +2015 next-mu-token: # in: (addr stream byte), out: (addr slice) +2016 # pseudocode: +2017 # start: +2018 # skip-chars-matching-whitespace(in) +2019 # if in->read >= in->write # end of in +2020 # out = {0, 0} +2021 # return +2022 # out->start = &in->data[in->read] +2023 # var curr-byte/eax: byte = in->data[in->read] +2024 # if curr->byte == ':' # comment token +2025 # ++in->read +2026 # goto start +2027 # if curr->byte == ',' # comment token +2028 # ++in->read +2029 # goto start +2030 # if curr-byte == '#' # comment +2031 # in->read = in->write # skip to end of in +2032 # goto done +2033 # if curr-byte == '"' # string literal +2034 # skip-string(in) +2035 # goto done # no metadata +2036 # if curr-byte == '(' +2037 # ++in->read +2038 # goto done +2039 # if curr-byte == ')' +2040 # ++in->read +2041 # goto done +2042 # # read a word +2043 # while true +2044 # if in->read >= in->write +2045 # break +2046 # curr-byte = in->data[in->read] +2047 # if curr-byte == ' ' +2048 # break +2049 # if curr-byte == '\r' +2050 # break +2051 # if curr-byte == '\n' +2052 # break +2053 # if curr-byte == '(' +2054 # break +2055 # if curr-byte == ')' +2056 # break +2057 # if curr-byte == ':' +2058 # break +2059 # if curr-byte == ',' +2060 # break +2061 # ++in->read +2062 # done: +2063 # out->end = &in->data[in->read] +2064 # # hack: skip a few trailing delimiters, because we don't always use +2065 # # this correct tokenizer in later tokens +2066 # while true +2067 # if in->read >= in->write +2068 # break +2069 # curr-byte = in->data[in->read] +2070 # if curr-byte == ':' +2071 # ++in->read +2072 # else if curr-byte == ',' +2073 # ++in->read +2074 # else +2075 # break +2076 # +2077 # . prologue +2078 55/push-ebp +2079 89/<- %ebp 4/r32/esp +2080 # . save registers +2081 50/push-eax +2082 51/push-ecx +2083 56/push-esi +2084 57/push-edi +2085 # esi = in +2086 8b/-> *(ebp+8) 6/r32/esi +2087 # edi = out +2088 8b/-> *(ebp+0xc) 7/r32/edi +2089 $next-mu-token:start: +2090 (skip-chars-matching-whitespace %esi) +2091 $next-mu-token:check0: +2092 # if (in->read >= in->write) return out = {0, 0} +2093 # . ecx = in->read +2094 8b/-> *(esi+4) 1/r32/ecx +2095 # . if (ecx >= in->write) return out = {0, 0} +2096 3b/compare 1/r32/ecx *esi +2097 c7 0/subop/copy *edi 0/imm32 +2098 c7 0/subop/copy *(edi+4) 0/imm32 +2099 0f 8d/jump-if->= $next-mu-token:end/disp32 +2100 # out->start = &in->data[in->read] +2101 8d/copy-address *(esi+ecx+0xc) 0/r32/eax +2102 89/<- *edi 0/r32/eax +2103 # var curr-byte/eax: byte = in->data[in->read] +2104 31/xor %eax 0/r32/eax +2105 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +2106 { +2107 $next-mu-token:check-for-colon: +2108 # if (curr-byte != ':') break +2109 3d/compare-eax-and 0x3a/imm32/colon +2110 75/jump-if-!= break/disp8 +2111 # ++in->read +2112 ff 0/subop/increment *(esi+4) +2113 # restart +2114 e9/jump $next-mu-token:start/disp32 +2115 } +2116 { +2117 $next-mu-token:check-for-comma: +2118 # if (curr-byte != ',') break +2119 3d/compare-eax-and 0x2c/imm32/comma +2120 75/jump-if-!= break/disp8 +2121 # ++in->read +2122 ff 0/subop/increment *(esi+4) +2123 # restart +2124 e9/jump $next-mu-token:start/disp32 +2125 } +2126 { +2127 $next-mu-token:check-for-comment: +2128 # if (curr-byte != '#') break +2129 3d/compare-eax-and 0x23/imm32/pound +2130 75/jump-if-!= break/disp8 +2131 # in->read = in->write # skip rest of in +2132 8b/-> *esi 0/r32/eax +2133 89/<- *(esi+4) 0/r32/eax +2134 # return +2135 e9/jump $next-mu-token:done/disp32 +2136 } +2137 { +2138 $next-mu-token:check-for-string-literal: +2139 # if (curr-byte != '"') break +2140 3d/compare-eax-and 0x22/imm32/dquote +2141 75/jump-if-!= break/disp8 +2142 (skip-string %esi) +2143 # return +2144 e9/jump $next-mu-token:done/disp32 +2145 } +2146 { +2147 $next-mu-token:check-for-open-paren: +2148 # if (curr-byte != '(') break +2149 3d/compare-eax-and 0x28/imm32/open-paren +2150 75/jump-if-!= break/disp8 +2151 # ++in->read +2152 ff 0/subop/increment *(esi+4) +2153 # return +2154 e9/jump $next-mu-token:done/disp32 +2155 } +2156 { +2157 $next-mu-token:check-for-close-paren: +2158 # if (curr-byte != ')') break +2159 3d/compare-eax-and 0x29/imm32/close-paren +2160 75/jump-if-!= break/disp8 +2161 # ++in->read +2162 ff 0/subop/increment *(esi+4) +2163 # return +2164 e9/jump $next-mu-token:done/disp32 +2165 } +2166 { +2167 $next-mu-token:regular-word-without-metadata: +2168 # if (in->read >= in->write) break +2169 # . ecx = in->read +2170 8b/-> *(esi+4) 1/r32/ecx +2171 # . if (ecx >= in->write) break +2172 3b/compare *esi 1/r32/ecx +2173 7d/jump-if->= break/disp8 +2174 # var c/eax: byte = in->data[in->read] +2175 31/xor %eax 0/r32/eax +2176 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +2177 # if (c == ' ') break +2178 3d/compare-eax-and 0x20/imm32/space +2179 74/jump-if-= break/disp8 +2180 # if (c == '\r') break +2181 3d/compare-eax-and 0xd/imm32/carriage-return +2182 74/jump-if-= break/disp8 +2183 # if (c == '\n') break +2184 3d/compare-eax-and 0xa/imm32/newline +2185 74/jump-if-= break/disp8 +2186 # if (c == '(') break +2187 3d/compare-eax-and 0x28/imm32/open-paren +2188 0f 84/jump-if-= break/disp32 +2189 # if (c == ')') break +2190 3d/compare-eax-and 0x29/imm32/close-paren +2191 0f 84/jump-if-= break/disp32 +2192 # if (c == ':') break +2193 3d/compare-eax-and 0x3a/imm32/colon +2194 0f 84/jump-if-= break/disp32 +2195 # if (c == ',') break +2196 3d/compare-eax-and 0x2c/imm32/comma +2197 0f 84/jump-if-= break/disp32 +2198 # ++in->read +2199 ff 0/subop/increment *(esi+4) +2200 # +2201 e9/jump loop/disp32 +2202 } +2203 $next-mu-token:done: +2204 # out->end = &in->data[in->read] +2205 8b/-> *(esi+4) 1/r32/ecx +2206 8d/copy-address *(esi+ecx+0xc) 0/r32/eax +2207 89/<- *(edi+4) 0/r32/eax +2208 { +2209 $next-mu-token:skip-trailing-delimiters: +2210 # if (in->read >= in->write) break +2211 # . ecx = in->read +2212 8b/-> *(esi+4) 1/r32/ecx +2213 # . if (ecx >= in->write) break +2214 3b/compare *esi 1/r32/ecx +2215 7d/jump-if->= break/disp8 +2216 # var c/eax: byte = in->data[in->read] +2217 31/xor %eax 0/r32/eax +2218 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +2219 # if (c == ':') ++in->read and loop +2220 { +2221 3d/compare-eax-and 0x3a/imm32/colon +2222 75/jump-if-!= break/disp8 +2223 # ++in->read +2224 ff 0/subop/increment *(esi+4) +2225 # +2226 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 +2227 } +2228 # if (c == ',') ++in->read and loop +2229 { +2230 3d/compare-eax-and 0x2c/imm32/comma +2231 75/jump-if-!= break/disp8 +2232 # ++in->read +2233 ff 0/subop/increment *(esi+4) +2234 # +2235 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 +2236 } +2237 # else break +2238 } +2239 $next-mu-token:end: +2240 # . restore registers +2241 5f/pop-to-edi +2242 5e/pop-to-esi +2243 59/pop-to-ecx +2244 58/pop-to-eax +2245 # . epilogue +2246 89/<- %esp 5/r32/ebp +2247 5d/pop-to-ebp +2248 c3/return +2249 +2250 # return the index in an array of strings matching 's' +2251 # index is denominated in elements, not bytes +2252 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int 2253 # . prologue 2254 55/push-ebp 2255 89/<- %ebp 4/r32/esp -2256 # (eax..ecx) = "x:" -2257 b8/copy-to-eax "x:"/imm32 -2258 8b/-> *eax 1/r32/ecx -2259 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2260 05/add-to-eax 4/imm32 -2261 # var slice/ecx: slice = {eax, ecx} -2262 51/push-ecx -2263 50/push-eax -2264 89/<- %ecx 4/r32/esp -2265 # _test-input-stream contains "int," -2266 (clear-stream _test-input-stream) -2267 (write _test-input-stream "int,") -2268 # -2269 (parse-var-with-type %ecx _test-input-stream) -2270 8b/-> *eax 2/r32/edx # Var-name -2271 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") -2272 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2273 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") -2274 8b/-> *(eax+4) 2/r32/edx # Var-type -2275 (check-ints-equal *edx 1 "F - test-var-with-trailing-characters/type") -2276 (check-ints-equal *(edx+4) 0 "F - test-var-with-trailing-characters/type") -2277 # . epilogue -2278 89/<- %esp 5/r32/ebp -2279 5d/pop-to-ebp -2280 c3/return -2281 -2282 test-parse-var-with-register-and-trailing-characters: -2283 # . prologue -2284 55/push-ebp -2285 89/<- %ebp 4/r32/esp -2286 # (eax..ecx) = "x/eax:" -2287 b8/copy-to-eax "x/eax:"/imm32 -2288 8b/-> *eax 1/r32/ecx -2289 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2290 05/add-to-eax 4/imm32 -2291 # var slice/ecx: slice = {eax, ecx} -2292 51/push-ecx -2293 50/push-eax -2294 89/<- %ecx 4/r32/esp -2295 # _test-input-stream contains "int," -2296 (clear-stream _test-input-stream) -2297 (write _test-input-stream "int,") -2298 # -2299 (parse-var-with-type %ecx _test-input-stream) -2300 8b/-> *eax 2/r32/edx # Var-name -2301 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") -2302 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2303 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") -2304 8b/-> *(eax+4) 2/r32/edx # Var-type -2305 (check-ints-equal *edx 1 "F - test-var-with-register-and-trailing-characters/type") -2306 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") -2307 # . epilogue -2308 89/<- %esp 5/r32/ebp -2309 5d/pop-to-ebp -2310 c3/return +2256 # . save registers +2257 51/push-ecx +2258 52/push-edx +2259 53/push-ebx +2260 56/push-esi +2261 #? (write-buffered Stderr "pos-slice: ") +2262 #? (write-slice-buffered Stderr *(ebp+0xc)) +2263 #? (write-buffered Stderr "\n") +2264 #? (flush Stderr) +2265 # esi = arr +2266 8b/-> *(ebp+8) 6/r32/esi +2267 # var index/ecx: int = 0 +2268 b9/copy-to-ecx 0/imm32 +2269 # var curr/edx: (addr (addr array byte)) = arr->data +2270 8d/copy-address *(esi+0xc) 2/r32/edx +2271 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] +2272 8b/-> *esi 3/r32/ebx +2273 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx +2274 { +2275 #? (write-buffered Stderr " ") +2276 #? (print-int32-buffered Stderr %ecx) +2277 #? (write-buffered Stderr "\n") +2278 #? (flush Stderr) +2279 # if (curr >= max) return -1 +2280 39/compare %edx 3/r32/ebx +2281 b8/copy-to-eax -1/imm32 +2282 73/jump-if-addr>= $pos-slice:end/disp8 +2283 # if (slice-equal?(s, *curr)) break +2284 (slice-equal? *(ebp+0xc) *edx) # => eax +2285 3d/compare-eax-and 0/imm32 +2286 75/jump-if-!= break/disp8 +2287 # ++index +2288 41/increment-ecx +2289 # curr += 4 +2290 81 0/subop/add %edx 4/imm32 +2291 # +2292 eb/jump loop/disp8 +2293 } +2294 # return index +2295 89/<- %eax 1/r32/ecx +2296 $pos-slice:end: +2297 #? (write-buffered Stderr "=> ") +2298 #? (print-int32-buffered Stderr %eax) +2299 #? (write-buffered Stderr "\n") +2300 # . restore registers +2301 5e/pop-to-esi +2302 5b/pop-to-ebx +2303 5a/pop-to-edx +2304 59/pop-to-ecx +2305 # . epilogue +2306 89/<- %esp 5/r32/ebp +2307 5d/pop-to-ebp +2308 c3/return +2309 +2310 == data 2311 -2312 test-parse-var-with-compound-type: -2313 # . prologue -2314 55/push-ebp -2315 89/<- %ebp 4/r32/esp -2316 # (eax..ecx) = "x:" -2317 b8/copy-to-eax "x:"/imm32 -2318 8b/-> *eax 1/r32/ecx -2319 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2320 05/add-to-eax 4/imm32 -2321 # var slice/ecx: slice = {eax, ecx} -2322 51/push-ecx -2323 50/push-eax -2324 89/<- %ecx 4/r32/esp -2325 # _test-input-stream contains "(addr int)" -2326 (clear-stream _test-input-stream) -2327 (write _test-input-stream "(addr int)") -2328 # -2329 (parse-var-with-type %ecx _test-input-stream) -2330 8b/-> *eax 2/r32/edx # Var-name -2331 (check-strings-equal %edx "x" "F - test-var-with-compound-type/name") -2332 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2333 (check-ints-equal %edx 0 "F - test-var-with-compound-type/register") -2334 # var type/edx: (handle tree type-id) = var->type -2335 8b/-> *(eax+4) 2/r32/edx # Var-type -2336 # type->left == atom(addr) -2337 8b/-> *edx 0/r32/eax # Atom-value -2338 (check-ints-equal *eax 2 "F - test-var-with-compound-type/type:0") # Tree-left -2339 # type->right->left == atom(int) -2340 8b/-> *(edx+4) 2/r32/edx # Tree-right -2341 8b/-> *edx 0/r32/eax # Tree-left -2342 (check-ints-equal *eax 1 "F - test-var-with-compound-type/type:1") # Atom-value -2343 # type->right->right == null -2344 (check-ints-equal *(edx+4) 0 "F - test-var-with-compound-type/type:2") # Tree-right -2345 # . epilogue -2346 89/<- %esp 5/r32/ebp -2347 5d/pop-to-ebp -2348 c3/return -2349 -2350 # identifier starts with a letter or '$' or '_' -2351 # no constraints at the moment on later letters -2352 # all we really want to do so far is exclude '{', '}' and '->' -2353 is-identifier?: # in: (addr slice) -> result/eax: boolean -2354 # . prologue -2355 55/push-ebp -2356 89/<- %ebp 4/r32/esp -2357 # if (slice-empty?(in)) return false -2358 (slice-empty? *(ebp+8)) # => eax -2359 3d/compare-eax-and 0/imm32 -2360 75/jump-if-!= $is-identifier?:false/disp8 -2361 # var c/eax: byte = *in->start -2362 8b/-> *(ebp+8) 0/r32/eax -2363 8b/-> *eax 0/r32/eax -2364 8a/copy-byte *eax 0/r32/AL -2365 81 4/subop/and %eax 0xff/imm32 -2366 # if (c == '$') return true -2367 3d/compare-eax-and 0x24/imm32/$ -2368 74/jump-if-= $is-identifier?:true/disp8 -2369 # if (c == '_') return true -2370 3d/compare-eax-and 0x5f/imm32/_ -2371 74/jump-if-= $is-identifier?:true/disp8 -2372 # drop case -2373 25/and-eax-with 0x5f/imm32 -2374 # if (c < 'A') return false -2375 3d/compare-eax-and 0x41/imm32/A -2376 7c/jump-if-< $is-identifier?:false/disp8 -2377 # if (c > 'Z') return false -2378 3d/compare-eax-and 0x5a/imm32/Z -2379 7f/jump-if-> $is-identifier?:false/disp8 -2380 # otherwise return true -2381 $is-identifier?:true: -2382 b8/copy-to-eax 1/imm32/true -2383 eb/jump $is-identifier?:end/disp8 -2384 $is-identifier?:false: -2385 b8/copy-to-eax 0/imm32/false -2386 $is-identifier?:end: -2387 # . epilogue -2388 89/<- %esp 5/r32/ebp -2389 5d/pop-to-ebp -2390 c3/return -2391 -2392 test-is-identifier-dollar: -2393 # . prologue -2394 55/push-ebp -2395 89/<- %ebp 4/r32/esp -2396 # (eax..ecx) = "$a" -2397 b8/copy-to-eax "$a"/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-dollar") -2408 # . epilogue -2409 89/<- %esp 5/r32/ebp -2410 5d/pop-to-ebp -2411 c3/return -2412 -2413 test-is-identifier-underscore: -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-underscore") -2429 # . epilogue -2430 89/<- %esp 5/r32/ebp -2431 5d/pop-to-ebp -2432 c3/return -2433 -2434 test-is-identifier-a: -2435 # . prologue -2436 55/push-ebp -2437 89/<- %ebp 4/r32/esp -2438 # (eax..ecx) = "a$" -2439 b8/copy-to-eax "a$"/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-a") -2450 # . epilogue -2451 89/<- %esp 5/r32/ebp -2452 5d/pop-to-ebp -2453 c3/return -2454 -2455 test-is-identifier-z: -2456 # . prologue -2457 55/push-ebp -2458 89/<- %ebp 4/r32/esp -2459 # (eax..ecx) = "z$" -2460 b8/copy-to-eax "z$"/imm32 -2461 8b/-> *eax 1/r32/ecx -2462 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2463 05/add-to-eax 4/imm32 -2464 # var slice/ecx: slice = {eax, ecx} -2465 51/push-ecx -2466 50/push-eax -2467 89/<- %ecx 4/r32/esp -2468 # -2469 (is-identifier? %ecx) -2470 (check-ints-equal %eax 1 "F - test-is-identifier-z") -2471 # . epilogue -2472 89/<- %esp 5/r32/ebp -2473 5d/pop-to-ebp -2474 c3/return -2475 -2476 test-is-identifier-A: -2477 # . prologue -2478 55/push-ebp -2479 89/<- %ebp 4/r32/esp -2480 # (eax..ecx) = "A$" -2481 b8/copy-to-eax "A$"/imm32 -2482 8b/-> *eax 1/r32/ecx -2483 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2484 05/add-to-eax 4/imm32 -2485 # var slice/ecx: slice = {eax, ecx} -2486 51/push-ecx -2487 50/push-eax -2488 89/<- %ecx 4/r32/esp -2489 # -2490 (is-identifier? %ecx) -2491 (check-ints-equal %eax 1 "F - test-is-identifier-A") -2492 # . epilogue -2493 89/<- %esp 5/r32/ebp -2494 5d/pop-to-ebp -2495 c3/return -2496 -2497 test-is-identifier-Z: -2498 # . prologue -2499 55/push-ebp -2500 89/<- %ebp 4/r32/esp -2501 # (eax..ecx) = "Z$" -2502 b8/copy-to-eax "Z$"/imm32 -2503 8b/-> *eax 1/r32/ecx -2504 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2505 05/add-to-eax 4/imm32 -2506 # var slice/ecx: slice = {eax, ecx} -2507 51/push-ecx -2508 50/push-eax -2509 89/<- %ecx 4/r32/esp -2510 # -2511 (is-identifier? %ecx) -2512 (check-ints-equal %eax 1 "F - test-is-identifier-Z") -2513 # . epilogue -2514 89/<- %esp 5/r32/ebp -2515 5d/pop-to-ebp -2516 c3/return -2517 -2518 test-is-identifier-@: -2519 # character before 'A' is invalid -2520 # . prologue -2521 55/push-ebp -2522 89/<- %ebp 4/r32/esp -2523 # (eax..ecx) = "@a" -2524 b8/copy-to-eax "@a"/imm32 -2525 8b/-> *eax 1/r32/ecx -2526 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2527 05/add-to-eax 4/imm32 -2528 # var slice/ecx: slice = {eax, ecx} -2529 51/push-ecx -2530 50/push-eax -2531 89/<- %ecx 4/r32/esp -2532 # -2533 (is-identifier? %ecx) -2534 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2535 # . epilogue -2536 89/<- %esp 5/r32/ebp -2537 5d/pop-to-ebp -2538 c3/return -2539 -2540 test-is-identifier-square-bracket: -2541 # character after 'Z' is invalid -2542 # . prologue -2543 55/push-ebp -2544 89/<- %ebp 4/r32/esp -2545 # (eax..ecx) = "[a" -2546 b8/copy-to-eax "[a"/imm32 -2547 8b/-> *eax 1/r32/ecx -2548 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2549 05/add-to-eax 4/imm32 -2550 # var slice/ecx: slice = {eax, ecx} -2551 51/push-ecx -2552 50/push-eax -2553 89/<- %ecx 4/r32/esp -2554 # -2555 (is-identifier? %ecx) -2556 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2557 # . epilogue -2558 89/<- %esp 5/r32/ebp -2559 5d/pop-to-ebp -2560 c3/return -2561 -2562 test-is-identifier-backtick: -2563 # character before 'a' is invalid -2564 # . prologue -2565 55/push-ebp -2566 89/<- %ebp 4/r32/esp -2567 # (eax..ecx) = "`a" -2568 b8/copy-to-eax "`a"/imm32 -2569 8b/-> *eax 1/r32/ecx -2570 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2571 05/add-to-eax 4/imm32 -2572 # var slice/ecx: slice = {eax, ecx} -2573 51/push-ecx -2574 50/push-eax -2575 89/<- %ecx 4/r32/esp -2576 # -2577 (is-identifier? %ecx) -2578 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") -2579 # . epilogue -2580 89/<- %esp 5/r32/ebp -2581 5d/pop-to-ebp -2582 c3/return -2583 -2584 test-is-identifier-curly-brace-open: -2585 # character after 'z' is invalid; also used for blocks -2586 # . prologue -2587 55/push-ebp -2588 89/<- %ebp 4/r32/esp -2589 # (eax..ecx) = "{a" -2590 b8/copy-to-eax "{a"/imm32 -2591 8b/-> *eax 1/r32/ecx -2592 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2593 05/add-to-eax 4/imm32 -2594 # var slice/ecx: slice = {eax, ecx} -2595 51/push-ecx -2596 50/push-eax -2597 89/<- %ecx 4/r32/esp -2598 # -2599 (is-identifier? %ecx) -2600 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") -2601 # . epilogue -2602 89/<- %esp 5/r32/ebp -2603 5d/pop-to-ebp -2604 c3/return -2605 -2606 test-is-identifier-curly-brace-close: -2607 # . prologue -2608 55/push-ebp -2609 89/<- %ebp 4/r32/esp -2610 # (eax..ecx) = "}a" -2611 b8/copy-to-eax "}a"/imm32 -2612 8b/-> *eax 1/r32/ecx -2613 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2614 05/add-to-eax 4/imm32 -2615 # var slice/ecx: slice = {eax, ecx} -2616 51/push-ecx -2617 50/push-eax -2618 89/<- %ecx 4/r32/esp -2619 # -2620 (is-identifier? %ecx) -2621 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") -2622 # . epilogue -2623 89/<- %esp 5/r32/ebp -2624 5d/pop-to-ebp -2625 c3/return -2626 -2627 test-is-identifier-hyphen: -2628 # disallow leading '-' since '->' has special meaning -2629 # . prologue -2630 55/push-ebp -2631 89/<- %ebp 4/r32/esp -2632 # (eax..ecx) = "-a" -2633 b8/copy-to-eax "-a"/imm32 -2634 8b/-> *eax 1/r32/ecx -2635 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2636 05/add-to-eax 4/imm32 -2637 # var slice/ecx: slice = {eax, ecx} -2638 51/push-ecx -2639 50/push-eax -2640 89/<- %ecx 4/r32/esp -2641 # -2642 (is-identifier? %ecx) -2643 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") -2644 # . epilogue -2645 89/<- %esp 5/r32/ebp -2646 5d/pop-to-ebp -2647 c3/return -2648 -2649 populate-mu-function-body: # in: (addr buffered-file), out: (handle function), vars: (addr stack (handle var)) -2650 # . prologue -2651 55/push-ebp -2652 89/<- %ebp 4/r32/esp -2653 # . save registers -2654 50/push-eax -2655 56/push-esi -2656 57/push-edi -2657 # esi = in -2658 8b/-> *(ebp+8) 6/r32/esi -2659 # edi = out -2660 8b/-> *(ebp+0xc) 7/r32/edi -2661 # initialize some global state -2662 c7 0/subop/copy *Curr-block-depth 0/imm32 -2663 c7 0/subop/copy *Next-local-stack-offset -4/imm32 -2664 # var eax: (handle block) = parse-mu-block(in, vars) -2665 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax -2666 # out->body = eax -2667 89/<- *(edi+0x10) 0/r32/eax # Function-body -2668 $populate-mu-function-body:end: -2669 # . restore registers -2670 5f/pop-to-edi -2671 5e/pop-to-esi -2672 58/pop-to-eax -2673 # . epilogue -2674 89/<- %esp 5/r32/ebp -2675 5d/pop-to-ebp -2676 c3/return -2677 -2678 == data -2679 -2680 # Global state when parsing a function -2681 Curr-block-depth: # (addr int) -2682 0/imm32 -2683 Next-local-stack-offset: # (addr int) -2684 -4/imm32 -2685 -2686 == code -2687 -2688 # parses a block, assuming that the leading '{' has already been read by the caller -2689 parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle block) -2690 # pseudocode: -2691 # var line: (stream byte 512) -2692 # var word-slice: slice -2693 # result/eax = allocate(Heap, Stmt-size) -2694 # result->tag = 0/Block -2695 # while true # line loop -2696 # clear-stream(line) -2697 # read-line-buffered(in, line) -2698 # if (line->write == 0) break # end of file -2699 # word-slice = next-word(line) -2700 # if slice-empty?(word-slice) # end of line -2701 # continue -2702 # else if slice-starts-with?(word-slice, "#") -2703 # continue -2704 # else if slice-equal?(word-slice, "{") -2705 # assert(no-tokens-in(line)) -2706 # block = parse-mu-block(in, vars, fn) -2707 # append-to-block(result, block) -2708 # else if slice-equal?(word-slice, "}") -2709 # break -2710 # else if slice-ends-with?(word-slice, ":") -2711 # named-block = parse-mu-named-block(word-slice, line, in, vars, fn) -2712 # append-to-block(result, named-block) -2713 # else if slice-equal?(word-slice, "var") -2714 # var-def = parse-mu-var-def(line, vars) -2715 # append-to-block(result, var-def) -2716 # else -2717 # stmt = parse-mu-stmt(line, vars, fn) -2718 # append-to-block(result, stmt) -2719 # TODO: reclaim locals -2720 # return result -2721 # -2722 # . prologue -2723 55/push-ebp -2724 89/<- %ebp 4/r32/esp -2725 # . save registers -2726 51/push-ecx -2727 52/push-edx -2728 53/push-ebx -2729 57/push-edi -2730 # var line/ecx: (stream byte 512) -2731 81 5/subop/subtract %esp 0x200/imm32 -2732 68/push 0x200/imm32/length -2733 68/push 0/imm32/read -2734 68/push 0/imm32/write -2735 89/<- %ecx 4/r32/esp -2736 # var word-slice/edx: slice -2737 68/push 0/imm32/end -2738 68/push 0/imm32/start -2739 89/<- %edx 4/r32/esp -2740 # edi = result -2741 (allocate Heap *Stmt-size) # => eax -2742 (zero-out %eax *Stmt-size) -2743 89/<- %edi 0/r32/eax -2744 { # line loop -2745 $parse-mu-block:line-loop: -2746 # line = read-line-buffered(in) -2747 (clear-stream %ecx) -2748 (read-line-buffered *(ebp+8) %ecx) -2749 #? (write-buffered Stderr "line: ") -2750 #? (write-stream-data Stderr %ecx) -2751 #? (write-buffered Stderr Newline) -2752 #? (flush Stderr) -2753 # if (line->write == 0) break -2754 81 7/subop/compare *ecx 0/imm32 -2755 0f 84/jump-if-= break/disp32 -2756 # word-slice = next-word(line) -2757 (next-word %ecx %edx) -2758 #? (write-buffered Stderr "word: ") -2759 #? (write-slice-buffered Stderr %edx) -2760 #? (write-buffered Stderr Newline) -2761 #? (flush Stderr) -2762 # if slice-empty?(word-slice) continue -2763 (slice-empty? %edx) -2764 3d/compare-eax-and 0/imm32 -2765 0f 85/jump-if-!= loop/disp32 -2766 # if (slice-starts-with?(word-slice, '#') continue -2767 # . eax = *word-slice->start -2768 8b/-> *edx 0/r32/eax -2769 8a/copy-byte *eax 0/r32/AL -2770 81 4/subop/and %eax 0xff/imm32 -2771 # . if (eax == '#') continue -2772 3d/compare-eax-and 0x23/imm32/hash -2773 0f 84/jump-if-= loop/disp32 -2774 # if slice-equal?(word-slice, "{") -2775 { -2776 $parse-mu-block:check-for-block: -2777 (slice-equal? %edx "{") -2778 3d/compare-eax-and 0/imm32 -2779 74/jump-if-= break/disp8 -2780 (check-no-tokens-left %ecx) -2781 # parse new block and append -2782 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -2783 (append-to-block Heap %edi %eax) -2784 e9/jump $parse-mu-block:line-loop/disp32 -2785 } -2786 # if slice-equal?(word-slice, "}") break -2787 $parse-mu-block:check-for-end: -2788 (slice-equal? %edx "}") -2789 3d/compare-eax-and 0/imm32 -2790 0f 85/jump-if-!= break/disp32 -2791 # if slice-ends-with?(word-slice, ":") parse named block and append -2792 { -2793 $parse-mu-block:check-for-named-block: -2794 # . eax = *word-slice->end -2795 8b/-> *(edx+4) 0/r32/eax -2796 8a/copy-byte *eax 0/r32/AL -2797 81 4/subop/and %eax 0xff/imm32 -2798 # . if (eax != ':') break -2799 3d/compare-eax-and 0x23/imm32/hash -2800 0f 85/jump-if-!= break/disp32 -2801 # -2802 (parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -2803 (append-to-block Heap %edi %eax) -2804 e9/jump $parse-mu-block:line-loop/disp32 -2805 } -2806 # if slice-equal?(word-slice, "var") -2807 { -2808 $parse-mu-block:check-for-var: -2809 (slice-equal? %edx "var") -2810 3d/compare-eax-and 0/imm32 -2811 74/jump-if-= break/disp8 -2812 # -2813 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax -2814 (append-to-block Heap %edi %eax) -2815 e9/jump $parse-mu-block:line-loop/disp32 -2816 } -2817 $parse-mu-block:regular-stmt: -2818 # otherwise -2819 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -2820 (append-to-block Heap %edi %eax) -2821 e9/jump loop/disp32 -2822 } # end line loop -2823 # return result -2824 89/<- %eax 7/r32/edi -2825 $parse-mu-block:end: -2826 # . reclaim locals -2827 81 0/subop/add %esp 0x214/imm32 -2828 # . restore registers -2829 5f/pop-to-edi -2830 5b/pop-to-ebx -2831 5a/pop-to-edx -2832 59/pop-to-ecx -2833 # . epilogue -2834 89/<- %esp 5/r32/ebp -2835 5d/pop-to-ebp -2836 c3/return -2837 -2838 $parse-mu-block:abort: -2839 # error("'{' or '}' should be on its own line, but got '") -2840 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2841 (rewind-stream %ecx) -2842 (write-stream 2 %ecx) -2843 (write-buffered Stderr "'\n") -2844 (flush Stderr) -2845 # . syscall(exit, 1) -2846 bb/copy-to-ebx 1/imm32 -2847 b8/copy-to-eax 1/imm32/exit -2848 cd/syscall 0x80/imm8 -2849 # never gets here -2850 -2851 check-no-tokens-left: # line: (addr stream byte) -2852 # . prologue -2853 55/push-ebp -2854 89/<- %ebp 4/r32/esp -2855 # . save registers -2856 50/push-eax -2857 51/push-ecx -2858 # var s/ecx: slice -2859 68/push 0/imm32/end -2860 68/push 0/imm32/start -2861 89/<- %ecx 4/r32/esp -2862 # -2863 (next-word *(ebp+8) %ecx) -2864 # if slice-empty?(s) return -2865 (slice-empty? %ecx) -2866 3d/compare-eax-and 0/imm32 -2867 75/jump-if-!= $check-no-tokens-left:end/disp8 -2868 # if (slice-starts-with?(s, '#') return -2869 # . eax = *s->start -2870 8b/-> *edx 0/r32/eax -2871 8a/copy-byte *eax 0/r32/AL -2872 81 4/subop/and %eax 0xff/imm32 -2873 # . if (eax == '#') continue -2874 3d/compare-eax-and 0x23/imm32/hash -2875 74/jump-if-= $check-no-tokens-left:end/disp8 -2876 # abort -2877 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2878 (rewind-stream %ecx) -2879 (write-stream 2 %ecx) -2880 (write-buffered Stderr "'\n") -2881 (flush Stderr) -2882 # . syscall(exit, 1) -2883 bb/copy-to-ebx 1/imm32 -2884 b8/copy-to-eax 1/imm32/exit -2885 cd/syscall 0x80/imm8 -2886 # never gets here -2887 $check-no-tokens-left:end: -2888 # . reclaim locals -2889 81 0/subop/add %esp 8/imm32 -2890 # . restore registers -2891 59/pop-to-ecx -2892 58/pop-to-eax -2893 # . epilogue -2894 89/<- %esp 5/r32/ebp -2895 5d/pop-to-ebp -2896 c3/return -2897 -2898 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) -2899 # pseudocode: -2900 # var line: (stream byte 512) -2901 # var word-slice: slice -2902 # result/eax = allocate(Heap, Stmt-size) -2903 # result->tag = 4/Named-block -2904 # result->name = name -2905 # assert(next-word(first-line) == "{") -2906 # assert(no-tokens-in(first-line)) -2907 # while true # line loop -2908 # clear-stream(line) -2909 # read-line-buffered(in, line) -2910 # if (line->write == 0) break # end of file -2911 # word-slice = next-word(line) -2912 # if slice-empty?(word-slice) # end of line -2913 # break -2914 # else if slice-equal?(word-slice, "{") -2915 # block = parse-mu-block(in, vars) -2916 # append-to-block(result, block) -2917 # else if slice-equal?(word-slice, "}") -2918 # break -2919 # else if slice-ends-with?(word-slice, ":") -2920 # named-block = parse-mu-named-block(word-slice, in, vars) -2921 # append-to-block(result, named-block) -2922 # else if slice-equal?(word-slice, "var") -2923 # var-def = parse-mu-var-def(line, vars) -2924 # append-to-block(result, var-def) -2925 # else -2926 # stmt = parse-mu-stmt(line, vars, fn) -2927 # append-to-block(result, stmt) -2928 # return result -2929 # -2930 # . prologue -2931 55/push-ebp -2932 89/<- %ebp 4/r32/esp -2933 # . save registers -2934 $parse-mu-named-block:end: -2935 # . reclaim locals -2936 # . restore registers -2937 # . epilogue -2938 89/<- %esp 5/r32/ebp -2939 5d/pop-to-ebp -2940 c3/return -2941 -2942 parse-mu-var-def: # line: (addr stream byte), vars: (addr stack (handle var)) -> result/eax: (handle stmt) -2943 # . prologue -2944 55/push-ebp -2945 89/<- %ebp 4/r32/esp -2946 # . save registers -2947 51/push-ecx -2948 52/push-edx -2949 # var word-slice/ecx: slice -2950 68/push 0/imm32/end -2951 68/push 0/imm32/start -2952 89/<- %ecx 4/r32/esp -2953 # var v/edx: (handle var) = parse-var-with-type(line) -2954 (next-word *(ebp+8) %ecx) -2955 (parse-var-with-type %ecx *(ebp+8)) # => eax -2956 89/<- %edx 0/r32/eax -2957 # v->stack-offset = *Next-local-stack-offset -2958 8b/-> *Next-local-stack-offset 0/r32/eax -2959 89/<- *(edx+0xc) 0/r32/eax # Var-stack-offset -2960 # *Next-local-stack-offset -= size-of(v) -2961 (size-of %edx) -2962 29/subtract-from *Next-local-stack-offset 0/r32/eax -2963 # -2964 (push *(ebp+0xc) %edx) -2965 # either v has no register and there's no more to this line -2966 8b/-> *(edx+0x10) 0/r32/eax # Var-register -2967 3d/compare-eax-and 0/imm32 -2968 { -2969 75/jump-if-!= break/disp8 -2970 # TODO: ensure that there's nothing else on this line -2971 (new-vardef Heap %edx) # => eax -2972 eb/jump $parse-mu-var-def:end/disp8 -2973 } -2974 # or v has a register and there's more to this line -2975 { -2976 74/jump-if-= break/disp8 -2977 # ensure that the next word is '<-' -2978 (next-word *(ebp+8) %ecx) -2979 (slice-equal? %ecx "<-") # => eax -2980 3d/compare-eax-and 0/imm32 -2981 74/jump-if-= $parse-mu-var-def:abort/disp8 -2982 # -2983 (new-regvardef Heap %edx) # => eax -2984 (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc)) -2985 } -2986 $parse-mu-var-def:end: -2987 # . reclaim locals -2988 81 0/subop/add %esp 8/imm32 -2989 # . restore registers -2990 5a/pop-to-edx -2991 59/pop-to-ecx -2992 # . epilogue -2993 89/<- %esp 5/r32/ebp -2994 5d/pop-to-ebp -2995 c3/return -2996 -2997 $parse-mu-var-def:abort: -2998 (rewind-stream *(ebp+8)) -2999 # error("register variable requires a valid instruction to initialize but got '" line "'\n") -3000 (write-buffered Stderr "register variable requires a valid instruction to initialize but got '") -3001 (flush Stderr) -3002 (write-stream 2 *(ebp+8)) -3003 (write-buffered Stderr "'\n") -3004 (flush Stderr) -3005 # . syscall(exit, 1) -3006 bb/copy-to-ebx 1/imm32 -3007 b8/copy-to-eax 1/imm32/exit -3008 cd/syscall 0x80/imm8 -3009 # never gets here -3010 -3011 test-parse-mu-var-def: -3012 # 'var n: int' -3013 # . prologue -3014 55/push-ebp -3015 89/<- %ebp 4/r32/esp -3016 # setup -3017 (clear-stream _test-input-stream) -3018 (write _test-input-stream "n: int\n") # caller has consumed the 'var' -3019 # var vars/ecx: (stack (addr var) 4) -3020 81 5/subop/subtract %esp 0x10/imm32 -3021 68/push 0x10/imm32/length -3022 68/push 0/imm32/top -3023 89/<- %ecx 4/r32/esp -3024 (clear-stack %ecx) -3025 # convert -3026 (parse-mu-var-def _test-input-stream %ecx) # => eax -3027 # check result -3028 (check-ints-equal *eax 2 "F - test-parse-mu-var-def/tag") # Stmt-tag is vardef -3029 8b/-> *(eax+4) 0/r32/eax # Vardef-var -3030 (check-strings-equal *eax "n" "F - test-parse-mu-var-def/var-name") # Var-name -3031 (check-ints-equal *(eax+0x10) 0 "F - test-parse-mu-var-def/var-register") # Var-register -3032 # TODO: ensure stack-offset is -4 -3033 # TODO: ensure block-depth is 1 -3034 # ensure type is int -3035 8b/-> *(eax+4) 0/r32/eax # Var-type -3036 (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0") # Tree-left -3037 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-var-def/var-type:0") # Tree-right +2312 Type-id: # (stream (address array byte)) +2313 0x18/imm32/write +2314 0/imm32/read +2315 0x100/imm32/length +2316 # data +2317 "literal"/imm32 # 0 +2318 "int"/imm32 # 1 +2319 "addr"/imm32 # 2 +2320 "array"/imm32 # 3 +2321 "handle"/imm32 # 4 +2322 "bool"/imm32 # 5 +2323 0/imm32 +2324 0/imm32 +2325 # 0x20 +2326 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2327 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2328 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2329 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2330 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2331 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2332 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2333 +2334 == code +2335 +2336 test-parse-var-with-type: +2337 # . prologue +2338 55/push-ebp +2339 89/<- %ebp 4/r32/esp +2340 # (eax..ecx) = "x:" +2341 b8/copy-to-eax "x:"/imm32 +2342 8b/-> *eax 1/r32/ecx +2343 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2344 05/add-to-eax 4/imm32 +2345 # var slice/ecx: slice = {eax, ecx} +2346 51/push-ecx +2347 50/push-eax +2348 89/<- %ecx 4/r32/esp +2349 # _test-input-stream contains "int" +2350 (clear-stream _test-input-stream) +2351 (write _test-input-stream "int") +2352 # +2353 (parse-var-with-type %ecx _test-input-stream) +2354 8b/-> *eax 2/r32/edx # Var-name +2355 (check-strings-equal %edx "x" "F - test-var-with-type/name") +2356 8b/-> *(eax+4) 2/r32/edx # Var-type +2357 (check-ints-equal *edx 1 "F - test-var-with-type/type") +2358 (check-ints-equal *(edx+4) 0 "F - test-var-with-type/type") +2359 # . epilogue +2360 89/<- %esp 5/r32/ebp +2361 5d/pop-to-ebp +2362 c3/return +2363 +2364 test-parse-var-with-type-and-register: +2365 # . prologue +2366 55/push-ebp +2367 89/<- %ebp 4/r32/esp +2368 # (eax..ecx) = "x/eax" +2369 b8/copy-to-eax "x/eax"/imm32 +2370 8b/-> *eax 1/r32/ecx +2371 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2372 05/add-to-eax 4/imm32 +2373 # var slice/ecx: slice = {eax, ecx} +2374 51/push-ecx +2375 50/push-eax +2376 89/<- %ecx 4/r32/esp +2377 # _test-input-stream contains ": int" +2378 (clear-stream _test-input-stream) +2379 (write _test-input-stream ": int") +2380 # +2381 (parse-var-with-type %ecx _test-input-stream) +2382 8b/-> *eax 2/r32/edx # Var-name +2383 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") +2384 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2385 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") +2386 8b/-> *(eax+4) 2/r32/edx # Var-type +2387 (check-ints-equal *edx 1 "F - test-var-with-type-and-register/type") +2388 (check-ints-equal *(edx+4) 0 "F - test-var-with-type-and-register/type") +2389 # . epilogue +2390 89/<- %esp 5/r32/ebp +2391 5d/pop-to-ebp +2392 c3/return +2393 +2394 test-parse-var-with-trailing-characters: +2395 # . prologue +2396 55/push-ebp +2397 89/<- %ebp 4/r32/esp +2398 # (eax..ecx) = "x:" +2399 b8/copy-to-eax "x:"/imm32 +2400 8b/-> *eax 1/r32/ecx +2401 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2402 05/add-to-eax 4/imm32 +2403 # var slice/ecx: slice = {eax, ecx} +2404 51/push-ecx +2405 50/push-eax +2406 89/<- %ecx 4/r32/esp +2407 # _test-input-stream contains "int," +2408 (clear-stream _test-input-stream) +2409 (write _test-input-stream "int,") +2410 # +2411 (parse-var-with-type %ecx _test-input-stream) +2412 8b/-> *eax 2/r32/edx # Var-name +2413 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") +2414 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2415 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") +2416 8b/-> *(eax+4) 2/r32/edx # Var-type +2417 (check-ints-equal *edx 1 "F - test-var-with-trailing-characters/type") +2418 (check-ints-equal *(edx+4) 0 "F - test-var-with-trailing-characters/type") +2419 # . epilogue +2420 89/<- %esp 5/r32/ebp +2421 5d/pop-to-ebp +2422 c3/return +2423 +2424 test-parse-var-with-register-and-trailing-characters: +2425 # . prologue +2426 55/push-ebp +2427 89/<- %ebp 4/r32/esp +2428 # (eax..ecx) = "x/eax:" +2429 b8/copy-to-eax "x/eax:"/imm32 +2430 8b/-> *eax 1/r32/ecx +2431 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2432 05/add-to-eax 4/imm32 +2433 # var slice/ecx: slice = {eax, ecx} +2434 51/push-ecx +2435 50/push-eax +2436 89/<- %ecx 4/r32/esp +2437 # _test-input-stream contains "int," +2438 (clear-stream _test-input-stream) +2439 (write _test-input-stream "int,") +2440 # +2441 (parse-var-with-type %ecx _test-input-stream) +2442 8b/-> *eax 2/r32/edx # Var-name +2443 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") +2444 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2445 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") +2446 8b/-> *(eax+4) 2/r32/edx # Var-type +2447 (check-ints-equal *edx 1 "F - test-var-with-register-and-trailing-characters/type") +2448 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") +2449 # . epilogue +2450 89/<- %esp 5/r32/ebp +2451 5d/pop-to-ebp +2452 c3/return +2453 +2454 test-parse-var-with-compound-type: +2455 # . prologue +2456 55/push-ebp +2457 89/<- %ebp 4/r32/esp +2458 # (eax..ecx) = "x:" +2459 b8/copy-to-eax "x:"/imm32 +2460 8b/-> *eax 1/r32/ecx +2461 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2462 05/add-to-eax 4/imm32 +2463 # var slice/ecx: slice = {eax, ecx} +2464 51/push-ecx +2465 50/push-eax +2466 89/<- %ecx 4/r32/esp +2467 # _test-input-stream contains "(addr int)" +2468 (clear-stream _test-input-stream) +2469 (write _test-input-stream "(addr int)") +2470 # +2471 (parse-var-with-type %ecx _test-input-stream) +2472 8b/-> *eax 2/r32/edx # Var-name +2473 (check-strings-equal %edx "x" "F - test-var-with-compound-type/name") +2474 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2475 (check-ints-equal %edx 0 "F - test-var-with-compound-type/register") +2476 # var type/edx: (handle tree type-id) = var->type +2477 8b/-> *(eax+4) 2/r32/edx # Var-type +2478 # type->left == atom(addr) +2479 8b/-> *edx 0/r32/eax # Atom-value +2480 (check-ints-equal *eax 2 "F - test-var-with-compound-type/type:0") # Tree-left +2481 # type->right->left == atom(int) +2482 8b/-> *(edx+4) 2/r32/edx # Tree-right +2483 8b/-> *edx 0/r32/eax # Tree-left +2484 (check-ints-equal *eax 1 "F - test-var-with-compound-type/type:1") # Atom-value +2485 # type->right->right == null +2486 (check-ints-equal *(edx+4) 0 "F - test-var-with-compound-type/type:2") # Tree-right +2487 # . epilogue +2488 89/<- %esp 5/r32/ebp +2489 5d/pop-to-ebp +2490 c3/return +2491 +2492 # identifier starts with a letter or '$' or '_' +2493 # no constraints at the moment on later letters +2494 # all we really want to do so far is exclude '{', '}' and '->' +2495 is-identifier?: # in: (addr slice) -> result/eax: boolean +2496 # . prologue +2497 55/push-ebp +2498 89/<- %ebp 4/r32/esp +2499 # if (slice-empty?(in)) return false +2500 (slice-empty? *(ebp+8)) # => eax +2501 3d/compare-eax-and 0/imm32 +2502 75/jump-if-!= $is-identifier?:false/disp8 +2503 # var c/eax: byte = *in->start +2504 8b/-> *(ebp+8) 0/r32/eax +2505 8b/-> *eax 0/r32/eax +2506 8a/copy-byte *eax 0/r32/AL +2507 81 4/subop/and %eax 0xff/imm32 +2508 # if (c == '$') return true +2509 3d/compare-eax-and 0x24/imm32/$ +2510 74/jump-if-= $is-identifier?:true/disp8 +2511 # if (c == '_') return true +2512 3d/compare-eax-and 0x5f/imm32/_ +2513 74/jump-if-= $is-identifier?:true/disp8 +2514 # drop case +2515 25/and-eax-with 0x5f/imm32 +2516 # if (c < 'A') return false +2517 3d/compare-eax-and 0x41/imm32/A +2518 7c/jump-if-< $is-identifier?:false/disp8 +2519 # if (c > 'Z') return false +2520 3d/compare-eax-and 0x5a/imm32/Z +2521 7f/jump-if-> $is-identifier?:false/disp8 +2522 # otherwise return true +2523 $is-identifier?:true: +2524 b8/copy-to-eax 1/imm32/true +2525 eb/jump $is-identifier?:end/disp8 +2526 $is-identifier?:false: +2527 b8/copy-to-eax 0/imm32/false +2528 $is-identifier?:end: +2529 # . epilogue +2530 89/<- %esp 5/r32/ebp +2531 5d/pop-to-ebp +2532 c3/return +2533 +2534 test-is-identifier-dollar: +2535 # . prologue +2536 55/push-ebp +2537 89/<- %ebp 4/r32/esp +2538 # (eax..ecx) = "$a" +2539 b8/copy-to-eax "$a"/imm32 +2540 8b/-> *eax 1/r32/ecx +2541 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2542 05/add-to-eax 4/imm32 +2543 # var slice/ecx: slice = {eax, ecx} +2544 51/push-ecx +2545 50/push-eax +2546 89/<- %ecx 4/r32/esp +2547 # +2548 (is-identifier? %ecx) +2549 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") +2550 # . epilogue +2551 89/<- %esp 5/r32/ebp +2552 5d/pop-to-ebp +2553 c3/return +2554 +2555 test-is-identifier-underscore: +2556 # . prologue +2557 55/push-ebp +2558 89/<- %ebp 4/r32/esp +2559 # (eax..ecx) = "_a" +2560 b8/copy-to-eax "_a"/imm32 +2561 8b/-> *eax 1/r32/ecx +2562 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2563 05/add-to-eax 4/imm32 +2564 # var slice/ecx: slice = {eax, ecx} +2565 51/push-ecx +2566 50/push-eax +2567 89/<- %ecx 4/r32/esp +2568 # +2569 (is-identifier? %ecx) +2570 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") +2571 # . epilogue +2572 89/<- %esp 5/r32/ebp +2573 5d/pop-to-ebp +2574 c3/return +2575 +2576 test-is-identifier-a: +2577 # . prologue +2578 55/push-ebp +2579 89/<- %ebp 4/r32/esp +2580 # (eax..ecx) = "a$" +2581 b8/copy-to-eax "a$"/imm32 +2582 8b/-> *eax 1/r32/ecx +2583 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2584 05/add-to-eax 4/imm32 +2585 # var slice/ecx: slice = {eax, ecx} +2586 51/push-ecx +2587 50/push-eax +2588 89/<- %ecx 4/r32/esp +2589 # +2590 (is-identifier? %ecx) +2591 (check-ints-equal %eax 1 "F - test-is-identifier-a") +2592 # . epilogue +2593 89/<- %esp 5/r32/ebp +2594 5d/pop-to-ebp +2595 c3/return +2596 +2597 test-is-identifier-z: +2598 # . prologue +2599 55/push-ebp +2600 89/<- %ebp 4/r32/esp +2601 # (eax..ecx) = "z$" +2602 b8/copy-to-eax "z$"/imm32 +2603 8b/-> *eax 1/r32/ecx +2604 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2605 05/add-to-eax 4/imm32 +2606 # var slice/ecx: slice = {eax, ecx} +2607 51/push-ecx +2608 50/push-eax +2609 89/<- %ecx 4/r32/esp +2610 # +2611 (is-identifier? %ecx) +2612 (check-ints-equal %eax 1 "F - test-is-identifier-z") +2613 # . epilogue +2614 89/<- %esp 5/r32/ebp +2615 5d/pop-to-ebp +2616 c3/return +2617 +2618 test-is-identifier-A: +2619 # . prologue +2620 55/push-ebp +2621 89/<- %ebp 4/r32/esp +2622 # (eax..ecx) = "A$" +2623 b8/copy-to-eax "A$"/imm32 +2624 8b/-> *eax 1/r32/ecx +2625 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2626 05/add-to-eax 4/imm32 +2627 # var slice/ecx: slice = {eax, ecx} +2628 51/push-ecx +2629 50/push-eax +2630 89/<- %ecx 4/r32/esp +2631 # +2632 (is-identifier? %ecx) +2633 (check-ints-equal %eax 1 "F - test-is-identifier-A") +2634 # . epilogue +2635 89/<- %esp 5/r32/ebp +2636 5d/pop-to-ebp +2637 c3/return +2638 +2639 test-is-identifier-Z: +2640 # . prologue +2641 55/push-ebp +2642 89/<- %ebp 4/r32/esp +2643 # (eax..ecx) = "Z$" +2644 b8/copy-to-eax "Z$"/imm32 +2645 8b/-> *eax 1/r32/ecx +2646 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2647 05/add-to-eax 4/imm32 +2648 # var slice/ecx: slice = {eax, ecx} +2649 51/push-ecx +2650 50/push-eax +2651 89/<- %ecx 4/r32/esp +2652 # +2653 (is-identifier? %ecx) +2654 (check-ints-equal %eax 1 "F - test-is-identifier-Z") +2655 # . epilogue +2656 89/<- %esp 5/r32/ebp +2657 5d/pop-to-ebp +2658 c3/return +2659 +2660 test-is-identifier-@: +2661 # character before 'A' is invalid +2662 # . prologue +2663 55/push-ebp +2664 89/<- %ebp 4/r32/esp +2665 # (eax..ecx) = "@a" +2666 b8/copy-to-eax "@a"/imm32 +2667 8b/-> *eax 1/r32/ecx +2668 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2669 05/add-to-eax 4/imm32 +2670 # var slice/ecx: slice = {eax, ecx} +2671 51/push-ecx +2672 50/push-eax +2673 89/<- %ecx 4/r32/esp +2674 # +2675 (is-identifier? %ecx) +2676 (check-ints-equal %eax 0 "F - test-is-identifier-@") +2677 # . epilogue +2678 89/<- %esp 5/r32/ebp +2679 5d/pop-to-ebp +2680 c3/return +2681 +2682 test-is-identifier-square-bracket: +2683 # character after 'Z' is invalid +2684 # . prologue +2685 55/push-ebp +2686 89/<- %ebp 4/r32/esp +2687 # (eax..ecx) = "[a" +2688 b8/copy-to-eax "[a"/imm32 +2689 8b/-> *eax 1/r32/ecx +2690 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2691 05/add-to-eax 4/imm32 +2692 # var slice/ecx: slice = {eax, ecx} +2693 51/push-ecx +2694 50/push-eax +2695 89/<- %ecx 4/r32/esp +2696 # +2697 (is-identifier? %ecx) +2698 (check-ints-equal %eax 0 "F - test-is-identifier-@") +2699 # . epilogue +2700 89/<- %esp 5/r32/ebp +2701 5d/pop-to-ebp +2702 c3/return +2703 +2704 test-is-identifier-backtick: +2705 # character before 'a' is invalid +2706 # . prologue +2707 55/push-ebp +2708 89/<- %ebp 4/r32/esp +2709 # (eax..ecx) = "`a" +2710 b8/copy-to-eax "`a"/imm32 +2711 8b/-> *eax 1/r32/ecx +2712 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2713 05/add-to-eax 4/imm32 +2714 # var slice/ecx: slice = {eax, ecx} +2715 51/push-ecx +2716 50/push-eax +2717 89/<- %ecx 4/r32/esp +2718 # +2719 (is-identifier? %ecx) +2720 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") +2721 # . epilogue +2722 89/<- %esp 5/r32/ebp +2723 5d/pop-to-ebp +2724 c3/return +2725 +2726 test-is-identifier-curly-brace-open: +2727 # character after 'z' is invalid; also used for blocks +2728 # . prologue +2729 55/push-ebp +2730 89/<- %ebp 4/r32/esp +2731 # (eax..ecx) = "{a" +2732 b8/copy-to-eax "{a"/imm32 +2733 8b/-> *eax 1/r32/ecx +2734 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2735 05/add-to-eax 4/imm32 +2736 # var slice/ecx: slice = {eax, ecx} +2737 51/push-ecx +2738 50/push-eax +2739 89/<- %ecx 4/r32/esp +2740 # +2741 (is-identifier? %ecx) +2742 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") +2743 # . epilogue +2744 89/<- %esp 5/r32/ebp +2745 5d/pop-to-ebp +2746 c3/return +2747 +2748 test-is-identifier-curly-brace-close: +2749 # . prologue +2750 55/push-ebp +2751 89/<- %ebp 4/r32/esp +2752 # (eax..ecx) = "}a" +2753 b8/copy-to-eax "}a"/imm32 +2754 8b/-> *eax 1/r32/ecx +2755 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2756 05/add-to-eax 4/imm32 +2757 # var slice/ecx: slice = {eax, ecx} +2758 51/push-ecx +2759 50/push-eax +2760 89/<- %ecx 4/r32/esp +2761 # +2762 (is-identifier? %ecx) +2763 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") +2764 # . epilogue +2765 89/<- %esp 5/r32/ebp +2766 5d/pop-to-ebp +2767 c3/return +2768 +2769 test-is-identifier-hyphen: +2770 # disallow leading '-' since '->' has special meaning +2771 # . prologue +2772 55/push-ebp +2773 89/<- %ebp 4/r32/esp +2774 # (eax..ecx) = "-a" +2775 b8/copy-to-eax "-a"/imm32 +2776 8b/-> *eax 1/r32/ecx +2777 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2778 05/add-to-eax 4/imm32 +2779 # var slice/ecx: slice = {eax, ecx} +2780 51/push-ecx +2781 50/push-eax +2782 89/<- %ecx 4/r32/esp +2783 # +2784 (is-identifier? %ecx) +2785 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") +2786 # . epilogue +2787 89/<- %esp 5/r32/ebp +2788 5d/pop-to-ebp +2789 c3/return +2790 +2791 populate-mu-function-body: # in: (addr buffered-file), out: (handle function), vars: (addr stack (handle var)) +2792 # . prologue +2793 55/push-ebp +2794 89/<- %ebp 4/r32/esp +2795 # . save registers +2796 50/push-eax +2797 56/push-esi +2798 57/push-edi +2799 # esi = in +2800 8b/-> *(ebp+8) 6/r32/esi +2801 # edi = out +2802 8b/-> *(ebp+0xc) 7/r32/edi +2803 # initialize some global state +2804 c7 0/subop/copy *Curr-block-depth 0/imm32 +2805 c7 0/subop/copy *Next-local-stack-offset -4/imm32 +2806 # var eax: (handle block) = parse-mu-block(in, vars) +2807 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax +2808 # out->body = eax +2809 89/<- *(edi+0x10) 0/r32/eax # Function-body +2810 $populate-mu-function-body:end: +2811 # . restore registers +2812 5f/pop-to-edi +2813 5e/pop-to-esi +2814 58/pop-to-eax +2815 # . epilogue +2816 89/<- %esp 5/r32/ebp +2817 5d/pop-to-ebp +2818 c3/return +2819 +2820 == data +2821 +2822 # Global state when parsing a function +2823 Curr-block-depth: # (addr int) +2824 0/imm32 +2825 Next-local-stack-offset: # (addr int) +2826 -4/imm32 +2827 +2828 == code +2829 +2830 # parses a block, assuming that the leading '{' has already been read by the caller +2831 parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle block) +2832 # pseudocode: +2833 # var line: (stream byte 512) +2834 # var word-slice: slice +2835 # result/eax = allocate(Heap, Stmt-size) +2836 # result->tag = 0/Block +2837 # while true # line loop +2838 # clear-stream(line) +2839 # read-line-buffered(in, line) +2840 # if (line->write == 0) break # end of file +2841 # word-slice = next-word(line) +2842 # if slice-empty?(word-slice) # end of line +2843 # continue +2844 # else if slice-starts-with?(word-slice, "#") +2845 # continue +2846 # else if slice-equal?(word-slice, "{") +2847 # assert(no-tokens-in(line)) +2848 # block = parse-mu-block(in, vars, fn) +2849 # append-to-block(result, block) +2850 # else if slice-equal?(word-slice, "}") +2851 # break +2852 # else if slice-ends-with?(word-slice, ":") +2853 # # TODO: check the rest of line +2854 # named-block = parse-mu-named-block(word-slice, in, vars, fn) +2855 # append-to-block(result, named-block) +2856 # else if slice-equal?(word-slice, "var") +2857 # var-def = parse-mu-var-def(line, vars) +2858 # append-to-block(result, var-def) +2859 # else +2860 # stmt = parse-mu-stmt(line, vars, fn) +2861 # append-to-block(result, stmt) +2862 # return result +2863 # +2864 # . prologue +2865 55/push-ebp +2866 89/<- %ebp 4/r32/esp +2867 # . save registers +2868 51/push-ecx +2869 52/push-edx +2870 53/push-ebx +2871 57/push-edi +2872 # var line/ecx: (stream byte 512) +2873 81 5/subop/subtract %esp 0x200/imm32 +2874 68/push 0x200/imm32/length +2875 68/push 0/imm32/read +2876 68/push 0/imm32/write +2877 89/<- %ecx 4/r32/esp +2878 # var word-slice/edx: slice +2879 68/push 0/imm32/end +2880 68/push 0/imm32/start +2881 89/<- %edx 4/r32/esp +2882 # edi = result +2883 (allocate Heap *Stmt-size) # => eax +2884 (zero-out %eax *Stmt-size) +2885 89/<- %edi 0/r32/eax +2886 # result->tag is implicitly block (0) +2887 { # line loop +2888 $parse-mu-block:line-loop: +2889 # line = read-line-buffered(in) +2890 (clear-stream %ecx) +2891 (read-line-buffered *(ebp+8) %ecx) +2892 #? (write-buffered Stderr "line: ") +2893 #? (write-stream-data Stderr %ecx) +2894 #? (write-buffered Stderr Newline) +2895 #? (flush Stderr) +2896 # if (line->write == 0) break +2897 81 7/subop/compare *ecx 0/imm32 +2898 0f 84/jump-if-= break/disp32 +2899 # word-slice = next-word(line) +2900 (next-word %ecx %edx) +2901 #? (write-buffered Stderr "word: ") +2902 #? (write-slice-buffered Stderr %edx) +2903 #? (write-buffered Stderr Newline) +2904 #? (flush Stderr) +2905 # if slice-empty?(word-slice) continue +2906 (slice-empty? %edx) +2907 3d/compare-eax-and 0/imm32 +2908 0f 85/jump-if-!= loop/disp32 +2909 # if (slice-starts-with?(word-slice, '#') continue +2910 # . eax = *word-slice->start +2911 8b/-> *edx 0/r32/eax +2912 8a/copy-byte *eax 0/r32/AL +2913 81 4/subop/and %eax 0xff/imm32 +2914 # . if (eax == '#') continue +2915 3d/compare-eax-and 0x23/imm32/hash +2916 0f 84/jump-if-= loop/disp32 +2917 # if slice-equal?(word-slice, "{") +2918 { +2919 $parse-mu-block:check-for-block: +2920 (slice-equal? %edx "{") +2921 3d/compare-eax-and 0/imm32 +2922 74/jump-if-= break/disp8 +2923 (check-no-tokens-left %ecx) +2924 # parse new block and append +2925 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2926 (append-to-block Heap %edi %eax) +2927 e9/jump $parse-mu-block:line-loop/disp32 +2928 } +2929 # if slice-equal?(word-slice, "}") break +2930 $parse-mu-block:check-for-end: +2931 (slice-equal? %edx "}") +2932 3d/compare-eax-and 0/imm32 +2933 0f 85/jump-if-!= break/disp32 +2934 # if slice-ends-with?(word-slice, ":") parse named block and append +2935 { +2936 $parse-mu-block:check-for-named-block: +2937 # . eax = *(word-slice->end-1) +2938 8b/-> *(edx+4) 0/r32/eax +2939 48/decrement-eax +2940 8a/copy-byte *eax 0/r32/AL +2941 81 4/subop/and %eax 0xff/imm32 +2942 # . if (eax != ':') break +2943 3d/compare-eax-and 0x3a/imm32/colon +2944 0f 85/jump-if-!= break/disp32 +2945 # +2946 # TODO: error-check the rest of 'line' +2947 (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2948 (append-to-block Heap %edi %eax) +2949 e9/jump $parse-mu-block:line-loop/disp32 +2950 } +2951 # if slice-equal?(word-slice, "var") +2952 { +2953 $parse-mu-block:check-for-var: +2954 (slice-equal? %edx "var") +2955 3d/compare-eax-and 0/imm32 +2956 74/jump-if-= break/disp8 +2957 # +2958 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax +2959 (append-to-block Heap %edi %eax) +2960 e9/jump $parse-mu-block:line-loop/disp32 +2961 } +2962 $parse-mu-block:regular-stmt: +2963 # otherwise +2964 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +2965 (append-to-block Heap %edi %eax) +2966 e9/jump loop/disp32 +2967 } # end line loop +2968 # return result +2969 89/<- %eax 7/r32/edi +2970 $parse-mu-block:end: +2971 # . reclaim locals +2972 81 0/subop/add %esp 0x214/imm32 +2973 # . restore registers +2974 5f/pop-to-edi +2975 5b/pop-to-ebx +2976 5a/pop-to-edx +2977 59/pop-to-ecx +2978 # . epilogue +2979 89/<- %esp 5/r32/ebp +2980 5d/pop-to-ebp +2981 c3/return +2982 +2983 $parse-mu-block:abort: +2984 # error("'{' or '}' should be on its own line, but got '") +2985 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +2986 (rewind-stream %ecx) +2987 (write-stream 2 %ecx) +2988 (write-buffered Stderr "'\n") +2989 (flush Stderr) +2990 # . syscall(exit, 1) +2991 bb/copy-to-ebx 1/imm32 +2992 b8/copy-to-eax 1/imm32/exit +2993 cd/syscall 0x80/imm8 +2994 # never gets here +2995 +2996 check-no-tokens-left: # line: (addr stream byte) +2997 # . prologue +2998 55/push-ebp +2999 89/<- %ebp 4/r32/esp +3000 # . save registers +3001 50/push-eax +3002 51/push-ecx +3003 # var s/ecx: slice +3004 68/push 0/imm32/end +3005 68/push 0/imm32/start +3006 89/<- %ecx 4/r32/esp +3007 # +3008 (next-word *(ebp+8) %ecx) +3009 # if slice-empty?(s) return +3010 (slice-empty? %ecx) +3011 3d/compare-eax-and 0/imm32 +3012 75/jump-if-!= $check-no-tokens-left:end/disp8 +3013 # if (slice-starts-with?(s, '#') return +3014 # . eax = *s->start +3015 8b/-> *edx 0/r32/eax +3016 8a/copy-byte *eax 0/r32/AL +3017 81 4/subop/and %eax 0xff/imm32 +3018 # . if (eax == '#') continue +3019 3d/compare-eax-and 0x23/imm32/hash +3020 74/jump-if-= $check-no-tokens-left:end/disp8 +3021 # abort +3022 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +3023 (rewind-stream %ecx) +3024 (write-stream 2 %ecx) +3025 (write-buffered Stderr "'\n") +3026 (flush Stderr) +3027 # . syscall(exit, 1) +3028 bb/copy-to-ebx 1/imm32 +3029 b8/copy-to-eax 1/imm32/exit +3030 cd/syscall 0x80/imm8 +3031 # never gets here +3032 $check-no-tokens-left:end: +3033 # . reclaim locals +3034 81 0/subop/add %esp 8/imm32 +3035 # . restore registers +3036 59/pop-to-ecx +3037 58/pop-to-eax 3038 # . epilogue 3039 89/<- %esp 5/r32/ebp 3040 5d/pop-to-ebp 3041 c3/return 3042 -3043 test-parse-mu-reg-var-def: -3044 # 'var n/eax: int <- copy 0' -3045 # . prologue -3046 55/push-ebp -3047 89/<- %ebp 4/r32/esp -3048 # setup -3049 (clear-stream _test-input-stream) -3050 (write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var' -3051 # var vars/ecx: (stack (addr var) 4) -3052 81 5/subop/subtract %esp 0x10/imm32 -3053 68/push 0x10/imm32/length -3054 68/push 0/imm32/top -3055 89/<- %ecx 4/r32/esp -3056 (clear-stack %ecx) -3057 # convert -3058 (parse-mu-var-def _test-input-stream %ecx) # => eax -3059 # check result -3060 (check-ints-equal *eax 3 "F - test-parse-mu-reg-var-def/tag") # Stmt-tag is regvardef -3061 8b/-> *(eax+0xc) 0/r32/eax # Regvardef-outputs -3062 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/single-output") # List-next -3063 8b/-> *eax 0/r32/eax # List-value -3064 (check-strings-equal *eax "n" "F - test-parse-mu-reg-var-def/output-name") # Var-name -3065 (check-strings-equal *(eax+0x10) "eax" "F - test-parse-mu-reg-var-def/output-register") # Var-register -3066 # TODO: ensure stack-offset is -4 -3067 # TODO: ensure block-depth is 1 -3068 # ensure type is int -3069 8b/-> *(eax+4) 0/r32/eax # Var-type -3070 (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-left -3071 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-right -3072 # . epilogue -3073 89/<- %esp 5/r32/ebp -3074 5d/pop-to-ebp -3075 c3/return -3076 -3077 parse-mu-stmt: # line: (addr stream byte), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) -3078 # pseudocode: -3079 # var name: slice -3080 # result = allocate(Heap, Stmt-size) -3081 # if stmt-has-outputs?(line) -3082 # while true -3083 # name = next-mu-token(line) -3084 # if (name == '<-') break -3085 # assert(is-identifier?(name)) -3086 # var v: (handle var) = lookup-or-define-var(name, vars, fn) # regular stmts may define vars in fn outputs -3087 # result->outputs = append(result->outputs, v) -3088 # add-operation-and-inputs-to-stmt(result, line, vars) -3089 # -3090 # . prologue -3091 55/push-ebp -3092 89/<- %ebp 4/r32/esp -3093 # . save registers -3094 51/push-ecx -3095 57/push-edi -3096 # var name/ecx: slice -3097 68/push 0/imm32/end -3098 68/push 0/imm32/start -3099 89/<- %ecx 4/r32/esp -3100 # result/edi: (handle stmt) -3101 (allocate Heap *Stmt-size) # => eax -3102 (zero-out %eax *Stmt-size) -3103 89/<- %edi 0/r32/eax -3104 # result->tag = 1/stmt -3105 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag -3106 { -3107 (stmt-has-outputs? *(ebp+8)) -3108 3d/compare-eax-and 0/imm32 -3109 0f 84/jump-if-= break/disp32 -3110 { -3111 $parse-mu-stmt:read-outputs: -3112 # name = next-mu-token(line) -3113 (next-mu-token *(ebp+8) %ecx) -3114 # if slice-empty?(word-slice) break -3115 (slice-empty? %ecx) -3116 3d/compare-eax-and 0/imm32 -3117 0f 85/jump-if-!= break/disp32 -3118 # if (name == "<-") break -3119 (slice-equal? %ecx "<-") -3120 3d/compare-eax-and 0/imm32 -3121 75/jump-if-!= break/disp8 -3122 # assert(is-identifier?(name)) -3123 (is-identifier? %ecx) -3124 3d/compare-eax-and 0/imm32 -3125 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 -3126 # -3127 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -3128 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax -3129 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs -3130 e9/jump loop/disp32 -3131 } -3132 } -3133 (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc)) -3134 $parse-mu-stmt:end: -3135 # return result -3136 89/<- %eax 7/r32/edi -3137 # . reclaim locals -3138 81 0/subop/add %esp 8/imm32 -3139 # . restore registers -3140 5f/pop-to-edi -3141 59/pop-to-ecx -3142 # . epilogue -3143 89/<- %esp 5/r32/ebp -3144 5d/pop-to-ebp -3145 c3/return -3146 -3147 $parse-mu-stmt:abort: -3148 # error("invalid identifier '" name "'\n") -3149 (write-buffered Stderr "invalid identifier '") -3150 (write-slice-buffered Stderr %ecx) -3151 (write-buffered Stderr "'\n") -3152 (flush Stderr) -3153 # . syscall(exit, 1) -3154 bb/copy-to-ebx 1/imm32 -3155 b8/copy-to-eax 1/imm32/exit -3156 cd/syscall 0x80/imm8 -3157 # never gets here -3158 -3159 add-operation-and-inputs-to-stmt: # stmt: (handle stmt), line: (addr stream byte) -3160 # pseudocode: -3161 # stmt->name = slice-to-string(next-mu-token(line)) -3162 # while true -3163 # name = next-mu-token(line) -3164 # v = lookup-var-or-literal(name) -3165 # stmt->inouts = append(stmt->inouts, v) -3166 # -3167 # . prologue -3168 55/push-ebp -3169 89/<- %ebp 4/r32/esp -3170 # . save registers -3171 50/push-eax -3172 51/push-ecx -3173 57/push-edi -3174 # edi = stmt -3175 8b/-> *(ebp+8) 7/r32/edi -3176 # var name/ecx: slice -3177 68/push 0/imm32/end -3178 68/push 0/imm32/start -3179 89/<- %ecx 4/r32/esp -3180 $add-operation-and-inputs-to-stmt:read-operation: -3181 (next-mu-token *(ebp+0xc) %ecx) -3182 (slice-to-string Heap %ecx) # => eax -3183 89/<- *(edi+4) 0/r32/eax # Stmt1-operation or Regvardef-operation -3184 { -3185 $add-operation-and-inputs-to-stmt:read-inouts: -3186 # name = next-mu-token(line) -3187 (next-mu-token *(ebp+0xc) %ecx) -3188 # if slice-empty?(word-slice) break -3189 (slice-empty? %ecx) # => eax -3190 3d/compare-eax-and 0/imm32 -3191 0f 85/jump-if-!= break/disp32 -3192 # if (name == "<-") abort -3193 (slice-equal? %ecx "<-") -3194 3d/compare-eax-and 0/imm32 -3195 0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32 -3196 # -3197 (lookup-var-or-literal %ecx *(ebp+0x10)) # => eax -3198 (append-list Heap %eax *(edi+8)) # Stmt1-inouts or Regvardef-inouts => eax -3199 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts -3200 e9/jump loop/disp32 -3201 } -3202 $add-operation-and-inputs-to-stmt:end: -3203 # . reclaim locals -3204 81 0/subop/add %esp 8/imm32 -3205 # . restore registers -3206 5f/pop-to-edi -3207 59/pop-to-ecx -3208 58/pop-to-eax -3209 # . epilogue -3210 89/<- %esp 5/r32/ebp -3211 5d/pop-to-ebp -3212 c3/return -3213 -3214 $add-operation-and-inputs-to-stmt:abort: -3215 # error("invalid statement '" line "'\n") -3216 (rewind-stream *(ebp+8)) -3217 (write-buffered Stderr "invalid identifier '") -3218 (flush Stderr) -3219 (write-stream 2 *(ebp+8)) -3220 (write-buffered Stderr "'\n") -3221 (flush Stderr) -3222 # . syscall(exit, 1) -3223 bb/copy-to-ebx 1/imm32 -3224 b8/copy-to-eax 1/imm32/exit -3225 cd/syscall 0x80/imm8 -3226 # never gets here -3227 -3228 stmt-has-outputs?: # line: (addr stream byte) -> result/eax: boolean -3229 # . prologue -3230 55/push-ebp -3231 89/<- %ebp 4/r32/esp -3232 # . save registers -3233 51/push-ecx -3234 # var word-slice/ecx: slice -3235 68/push 0/imm32/end -3236 68/push 0/imm32/start -3237 89/<- %ecx 4/r32/esp -3238 # result = false -3239 b8/copy-to-eax 0/imm32/false -3240 (rewind-stream *(ebp+8)) -3241 { -3242 (next-mu-token *(ebp+8) %ecx) -3243 # if slice-empty?(word-slice) break -3244 (slice-empty? %ecx) -3245 3d/compare-eax-and 0/imm32 -3246 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -3247 0f 85/jump-if-!= break/disp32 -3248 # if slice-starts-with?(word-slice, '#') break -3249 # . eax = *word-slice->start -3250 8b/-> *ecx 0/r32/eax -3251 8a/copy-byte *eax 0/r32/AL -3252 81 4/subop/and %eax 0xff/imm32 -3253 # . if (eax == '#') break -3254 3d/compare-eax-and 0x23/imm32/hash -3255 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -3256 0f 84/jump-if-= break/disp32 -3257 # if slice-equal?(word-slice, '<-') return true -3258 (slice-equal? %ecx "<-") -3259 3d/compare-eax-and 0/imm32 -3260 74/jump-if-= loop/disp8 -3261 b8/copy-to-eax 1/imm32/true +3043 parse-mu-named-block: # name: (addr slice), in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) +3044 # pseudocode: +3045 # result = parse-mu-block(in, vars, fn) +3046 # result->tag = named-block +3047 # result->name = slice-to-string(name) +3048 # return result +3049 # +3050 # . prologue +3051 55/push-ebp +3052 89/<- %ebp 4/r32/esp +3053 # . save registers +3054 51/push-ecx +3055 # var s/ecx: (addr array byte) = slice-to-string(name) +3056 (slice-to-string Heap *(ebp+8)) # => eax +3057 89/<- %ecx 0/r32/eax +3058 # +3059 (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) # => eax +3060 # result->tag = named-block +3061 c7 0/subop/copy *eax 4/imm32/named-block # Stmt-tag +3062 # result->name = slice-to-string(name) +3063 89/<- *(eax+8) 1/r32/ecx # Named-block-name +3064 $parse-mu-named-block:end: +3065 # . restore registers +3066 59/pop-to-ecx +3067 # . epilogue +3068 89/<- %esp 5/r32/ebp +3069 5d/pop-to-ebp +3070 c3/return +3071 +3072 parse-mu-var-def: # line: (addr stream byte), vars: (addr stack (handle var)) -> result/eax: (handle stmt) +3073 # . prologue +3074 55/push-ebp +3075 89/<- %ebp 4/r32/esp +3076 # . save registers +3077 51/push-ecx +3078 52/push-edx +3079 # var word-slice/ecx: slice +3080 68/push 0/imm32/end +3081 68/push 0/imm32/start +3082 89/<- %ecx 4/r32/esp +3083 # var v/edx: (handle var) = parse-var-with-type(line) +3084 (next-word *(ebp+8) %ecx) +3085 (parse-var-with-type %ecx *(ebp+8)) # => eax +3086 89/<- %edx 0/r32/eax +3087 # v->stack-offset = *Next-local-stack-offset +3088 8b/-> *Next-local-stack-offset 0/r32/eax +3089 89/<- *(edx+0xc) 0/r32/eax # Var-stack-offset +3090 # *Next-local-stack-offset -= size-of(v) +3091 (size-of %edx) +3092 29/subtract-from *Next-local-stack-offset 0/r32/eax +3093 # +3094 (push *(ebp+0xc) %edx) +3095 # either v has no register and there's no more to this line +3096 8b/-> *(edx+0x10) 0/r32/eax # Var-register +3097 3d/compare-eax-and 0/imm32 +3098 { +3099 75/jump-if-!= break/disp8 +3100 # TODO: ensure that there's nothing else on this line +3101 (new-vardef Heap %edx) # => eax +3102 eb/jump $parse-mu-var-def:end/disp8 +3103 } +3104 # or v has a register and there's more to this line +3105 { +3106 74/jump-if-= break/disp8 +3107 # ensure that the next word is '<-' +3108 (next-word *(ebp+8) %ecx) +3109 (slice-equal? %ecx "<-") # => eax +3110 3d/compare-eax-and 0/imm32 +3111 74/jump-if-= $parse-mu-var-def:abort/disp8 +3112 # +3113 (new-regvardef Heap %edx) # => eax +3114 (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc)) +3115 } +3116 $parse-mu-var-def:end: +3117 # . reclaim locals +3118 81 0/subop/add %esp 8/imm32 +3119 # . restore registers +3120 5a/pop-to-edx +3121 59/pop-to-ecx +3122 # . epilogue +3123 89/<- %esp 5/r32/ebp +3124 5d/pop-to-ebp +3125 c3/return +3126 +3127 $parse-mu-var-def:abort: +3128 (rewind-stream *(ebp+8)) +3129 # error("register variable requires a valid instruction to initialize but got '" line "'\n") +3130 (write-buffered Stderr "register variable requires a valid instruction to initialize but got '") +3131 (flush Stderr) +3132 (write-stream 2 *(ebp+8)) +3133 (write-buffered Stderr "'\n") +3134 (flush Stderr) +3135 # . syscall(exit, 1) +3136 bb/copy-to-ebx 1/imm32 +3137 b8/copy-to-eax 1/imm32/exit +3138 cd/syscall 0x80/imm8 +3139 # never gets here +3140 +3141 test-parse-mu-var-def: +3142 # 'var n: int' +3143 # . prologue +3144 55/push-ebp +3145 89/<- %ebp 4/r32/esp +3146 # setup +3147 (clear-stream _test-input-stream) +3148 (write _test-input-stream "n: int\n") # caller has consumed the 'var' +3149 # var vars/ecx: (stack (addr var) 4) +3150 81 5/subop/subtract %esp 0x10/imm32 +3151 68/push 0x10/imm32/length +3152 68/push 0/imm32/top +3153 89/<- %ecx 4/r32/esp +3154 (clear-stack %ecx) +3155 # convert +3156 (parse-mu-var-def _test-input-stream %ecx) # => eax +3157 # check result +3158 (check-ints-equal *eax 2 "F - test-parse-mu-var-def/tag") # Stmt-tag is vardef +3159 8b/-> *(eax+4) 0/r32/eax # Vardef-var +3160 (check-strings-equal *eax "n" "F - test-parse-mu-var-def/var-name") # Var-name +3161 (check-ints-equal *(eax+0x10) 0 "F - test-parse-mu-var-def/var-register") # Var-register +3162 # TODO: ensure stack-offset is -4 +3163 # TODO: ensure block-depth is 1 +3164 # ensure type is int +3165 8b/-> *(eax+4) 0/r32/eax # Var-type +3166 (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0") # Tree-left +3167 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-var-def/var-type:0") # Tree-right +3168 # . epilogue +3169 89/<- %esp 5/r32/ebp +3170 5d/pop-to-ebp +3171 c3/return +3172 +3173 test-parse-mu-reg-var-def: +3174 # 'var n/eax: int <- copy 0' +3175 # . prologue +3176 55/push-ebp +3177 89/<- %ebp 4/r32/esp +3178 # setup +3179 (clear-stream _test-input-stream) +3180 (write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var' +3181 # var vars/ecx: (stack (addr var) 4) +3182 81 5/subop/subtract %esp 0x10/imm32 +3183 68/push 0x10/imm32/length +3184 68/push 0/imm32/top +3185 89/<- %ecx 4/r32/esp +3186 (clear-stack %ecx) +3187 # convert +3188 (parse-mu-var-def _test-input-stream %ecx) # => eax +3189 # check result +3190 (check-ints-equal *eax 3 "F - test-parse-mu-reg-var-def/tag") # Stmt-tag is regvardef +3191 8b/-> *(eax+0xc) 0/r32/eax # Regvardef-outputs +3192 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/single-output") # List-next +3193 8b/-> *eax 0/r32/eax # List-value +3194 (check-strings-equal *eax "n" "F - test-parse-mu-reg-var-def/output-name") # Var-name +3195 (check-strings-equal *(eax+0x10) "eax" "F - test-parse-mu-reg-var-def/output-register") # Var-register +3196 # TODO: ensure stack-offset is -4 +3197 # TODO: ensure block-depth is 1 +3198 # ensure type is int +3199 8b/-> *(eax+4) 0/r32/eax # Var-type +3200 (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-left +3201 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-right +3202 # . epilogue +3203 89/<- %esp 5/r32/ebp +3204 5d/pop-to-ebp +3205 c3/return +3206 +3207 parse-mu-stmt: # line: (addr stream byte), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) +3208 # pseudocode: +3209 # var name: slice +3210 # result = allocate(Heap, Stmt-size) +3211 # if stmt-has-outputs?(line) +3212 # while true +3213 # name = next-mu-token(line) +3214 # if (name == '<-') break +3215 # assert(is-identifier?(name)) +3216 # var v: (handle var) = lookup-or-define-var(name, vars, fn) # regular stmts may define vars in fn outputs +3217 # result->outputs = append(result->outputs, v) +3218 # add-operation-and-inputs-to-stmt(result, line, vars) +3219 # +3220 # . prologue +3221 55/push-ebp +3222 89/<- %ebp 4/r32/esp +3223 # . save registers +3224 51/push-ecx +3225 57/push-edi +3226 # var name/ecx: slice +3227 68/push 0/imm32/end +3228 68/push 0/imm32/start +3229 89/<- %ecx 4/r32/esp +3230 # result/edi: (handle stmt) +3231 (allocate Heap *Stmt-size) # => eax +3232 (zero-out %eax *Stmt-size) +3233 89/<- %edi 0/r32/eax +3234 # result->tag = 1/stmt +3235 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag +3236 { +3237 (stmt-has-outputs? *(ebp+8)) +3238 3d/compare-eax-and 0/imm32 +3239 0f 84/jump-if-= break/disp32 +3240 { +3241 $parse-mu-stmt:read-outputs: +3242 # name = next-mu-token(line) +3243 (next-mu-token *(ebp+8) %ecx) +3244 # if slice-empty?(word-slice) break +3245 (slice-empty? %ecx) +3246 3d/compare-eax-and 0/imm32 +3247 0f 85/jump-if-!= break/disp32 +3248 # if (name == "<-") break +3249 (slice-equal? %ecx "<-") +3250 3d/compare-eax-and 0/imm32 +3251 75/jump-if-!= break/disp8 +3252 # assert(is-identifier?(name)) +3253 (is-identifier? %ecx) +3254 3d/compare-eax-and 0/imm32 +3255 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 +3256 # +3257 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +3258 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax +3259 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs +3260 e9/jump loop/disp32 +3261 } 3262 } -3263 $stmt-has-outputs:end: -3264 (rewind-stream *(ebp+8)) -3265 # . reclaim locals -3266 81 0/subop/add %esp 8/imm32 -3267 # . restore registers -3268 59/pop-to-ecx -3269 # . epilogue -3270 89/<- %esp 5/r32/ebp -3271 5d/pop-to-ebp -3272 c3/return -3273 -3274 # if 'name' starts with a digit, create a new literal var for it -3275 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found -3276 lookup-var-or-literal: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) -3277 # . prologue -3278 55/push-ebp -3279 89/<- %ebp 4/r32/esp -3280 # . save registers -3281 51/push-ecx -3282 56/push-esi -3283 # esi = name -3284 8b/-> *(ebp+8) 6/r32/esi -3285 # if slice-empty?(name) abort -3286 (slice-empty? %esi) # => eax -3287 3d/compare-eax-and 0/imm32 -3288 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 -3289 # var ecx: byte = *name->start -3290 8b/-> *esi 1/r32/ecx -3291 8a/copy-byte *ecx 1/r32/CL -3292 81 4/subop/and %ecx 0xff/imm32 -3293 # if is-decimal-digit?(*name->start) return new var(name) -3294 (is-decimal-digit? %ecx) # => eax -3295 81 7/subop/compare %eax 0/imm32 -3296 { -3297 74/jump-if-= break/disp8 -3298 (new-literal-integer Heap %esi) # => eax -3299 } -3300 # otherwise return lookup-var(name, vars) -3301 { -3302 75/jump-if-!= break/disp8 -3303 (lookup-var %esi *(ebp+0xc)) # => eax -3304 } -3305 $lookup-var-or-literal:end: -3306 # . restore registers -3307 5e/pop-to-esi -3308 59/pop-to-ecx -3309 # . epilogue -3310 89/<- %esp 5/r32/ebp -3311 5d/pop-to-ebp -3312 c3/return -3313 -3314 $lookup-var-or-literal:abort: -3315 (write-buffered Stderr "empty variable!") -3316 (flush Stderr) -3317 # . syscall(exit, 1) -3318 bb/copy-to-ebx 1/imm32 -3319 b8/copy-to-eax 1/imm32/exit -3320 cd/syscall 0x80/imm8 -3321 # never gets here -3322 -3323 # return first 'name' from the top (back) of 'vars' and abort if not found -3324 lookup-var: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) -3325 # . prologue -3326 55/push-ebp -3327 89/<- %ebp 4/r32/esp -3328 # var target/eax: (handle array byte) = slice-to-string(name) -3329 (slice-to-string Heap *(ebp+8)) # => eax -3330 # -3331 (lookup-var-helper %eax *(ebp+0xc)) # => eax -3332 # if (result == 0) abort -3333 3d/compare-eax-and 0/imm32 -3334 74/jump-if-= $lookup-var:abort/disp8 -3335 $lookup-var:end: -3336 # . epilogue -3337 89/<- %esp 5/r32/ebp -3338 5d/pop-to-ebp -3339 c3/return -3340 -3341 $lookup-var:abort: -3342 (write-buffered Stderr "unknown variable '") -3343 (write-slice-buffered Stderr *(ebp+8)) -3344 (write-buffered Stderr "'\n") -3345 (flush Stderr) -3346 # . syscall(exit, 1) -3347 bb/copy-to-ebx 1/imm32 -3348 b8/copy-to-eax 1/imm32/exit -3349 cd/syscall 0x80/imm8 -3350 # never gets here -3351 -3352 # return first 'name' from the top (back) of 'vars', and 0/null if not found -3353 lookup-var-helper: # name: (addr array byte), vars: (addr stack (handle var)) -> result/eax: (handle var) -3354 # pseudocode: -3355 # var curr: (addr handle var) = &vars->data[vars->top - 4] -3356 # var min = vars->data -3357 # while curr >= min -3358 # var v: (handle var) = *curr -3359 # if v->name == name -3360 # return v -3361 # return 0 -3362 # -3363 # . prologue -3364 55/push-ebp -3365 89/<- %ebp 4/r32/esp -3366 # . save registers -3367 52/push-edx -3368 53/push-ebx -3369 56/push-esi -3370 # esi = vars -3371 8b/-> *(ebp+0xc) 6/r32/esi -3372 # ebx = vars->top -3373 8b/-> *esi 3/r32/ebx -3374 # if (vars->top > vars->length) abort -3375 3b/compare 0/r32/eax *(esi+4) -3376 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 -3377 # var min/edx: (addr handle var) = vars->data -3378 8d/copy-address *(esi+8) 2/r32/edx -3379 # var curr/ebx: (addr handle var) = &vars->data[vars->top - 4] -3380 81 5/subop/subtract %ebx 4/imm32 -3381 8d/copy-address *(esi+ebx+8) 3/r32/ebx -3382 { -3383 # if (curr < min) return 0 -3384 39/compare %ebx 2/r32/edx -3385 b8/copy-to-eax 0/imm32 -3386 0f 82/jump-if-addr< break/disp32 -3387 # var v/eax: (handle var) = *curr -3388 8b/-> *ebx 0/r32/eax -3389 # if (v->name == name) return v -3390 (string-equal? *eax *(ebp+8)) # Var-name -3391 3d/compare-eax-and 0/imm32 -3392 8b/-> *ebx 0/r32/eax -3393 75/jump-if-!= break/disp8 -3394 # curr -= 4 -3395 81 5/subop/subtract %ebx 4/imm32 -3396 e9/jump loop/disp32 -3397 } -3398 $lookup-var-helper:end: -3399 # . restore registers -3400 5e/pop-to-esi -3401 5b/pop-to-ebx -3402 5a/pop-to-edx -3403 # . epilogue -3404 89/<- %esp 5/r32/ebp -3405 5d/pop-to-ebp -3406 c3/return -3407 -3408 $lookup-var-helper:error1: -3409 (write-buffered Stderr "malformed stack when looking up '") -3410 (write-slice-buffered Stderr *(ebp+8)) -3411 (write-buffered Stderr "'\n") -3412 (flush Stderr) -3413 # . syscall(exit, 1) -3414 bb/copy-to-ebx 1/imm32 -3415 b8/copy-to-eax 1/imm32/exit -3416 cd/syscall 0x80/imm8 -3417 # never gets here -3418 -3419 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found -3420 lookup-or-define-var: # name: (addr slice), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle var) -3421 # . prologue -3422 55/push-ebp -3423 89/<- %ebp 4/r32/esp -3424 # . save registers -3425 51/push-ecx -3426 # var target/ecx: (handle array byte) = slice-to-string(name) -3427 (slice-to-string Heap *(ebp+8)) # => eax -3428 89/<- %ecx 0/r32/eax -3429 # -3430 (lookup-var-helper %ecx *(ebp+0xc)) # => eax +3263 (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc)) +3264 $parse-mu-stmt:end: +3265 # return result +3266 89/<- %eax 7/r32/edi +3267 # . reclaim locals +3268 81 0/subop/add %esp 8/imm32 +3269 # . restore registers +3270 5f/pop-to-edi +3271 59/pop-to-ecx +3272 # . epilogue +3273 89/<- %esp 5/r32/ebp +3274 5d/pop-to-ebp +3275 c3/return +3276 +3277 $parse-mu-stmt:abort: +3278 # error("invalid identifier '" name "'\n") +3279 (write-buffered Stderr "invalid identifier '") +3280 (write-slice-buffered Stderr %ecx) +3281 (write-buffered Stderr "'\n") +3282 (flush Stderr) +3283 # . syscall(exit, 1) +3284 bb/copy-to-ebx 1/imm32 +3285 b8/copy-to-eax 1/imm32/exit +3286 cd/syscall 0x80/imm8 +3287 # never gets here +3288 +3289 add-operation-and-inputs-to-stmt: # stmt: (handle stmt), line: (addr stream byte) +3290 # pseudocode: +3291 # stmt->name = slice-to-string(next-mu-token(line)) +3292 # while true +3293 # name = next-mu-token(line) +3294 # v = lookup-var-or-literal(name) +3295 # stmt->inouts = append(stmt->inouts, v) +3296 # +3297 # . prologue +3298 55/push-ebp +3299 89/<- %ebp 4/r32/esp +3300 # . save registers +3301 50/push-eax +3302 51/push-ecx +3303 57/push-edi +3304 # edi = stmt +3305 8b/-> *(ebp+8) 7/r32/edi +3306 # var name/ecx: slice +3307 68/push 0/imm32/end +3308 68/push 0/imm32/start +3309 89/<- %ecx 4/r32/esp +3310 $add-operation-and-inputs-to-stmt:read-operation: +3311 (next-mu-token *(ebp+0xc) %ecx) +3312 (slice-to-string Heap %ecx) # => eax +3313 89/<- *(edi+4) 0/r32/eax # Stmt1-operation or Regvardef-operation +3314 { +3315 $add-operation-and-inputs-to-stmt:read-inouts: +3316 # name = next-mu-token(line) +3317 (next-mu-token *(ebp+0xc) %ecx) +3318 # if slice-empty?(word-slice) break +3319 (slice-empty? %ecx) # => eax +3320 3d/compare-eax-and 0/imm32 +3321 0f 85/jump-if-!= break/disp32 +3322 # if (name == "<-") abort +3323 (slice-equal? %ecx "<-") +3324 3d/compare-eax-and 0/imm32 +3325 0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32 +3326 # +3327 (lookup-var-or-literal %ecx *(ebp+0x10)) # => eax +3328 (append-list Heap %eax *(edi+8)) # Stmt1-inouts or Regvardef-inouts => eax +3329 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts +3330 e9/jump loop/disp32 +3331 } +3332 $add-operation-and-inputs-to-stmt:end: +3333 # . reclaim locals +3334 81 0/subop/add %esp 8/imm32 +3335 # . restore registers +3336 5f/pop-to-edi +3337 59/pop-to-ecx +3338 58/pop-to-eax +3339 # . epilogue +3340 89/<- %esp 5/r32/ebp +3341 5d/pop-to-ebp +3342 c3/return +3343 +3344 $add-operation-and-inputs-to-stmt:abort: +3345 # error("invalid statement '" line "'\n") +3346 (rewind-stream *(ebp+8)) +3347 (write-buffered Stderr "invalid identifier '") +3348 (flush Stderr) +3349 (write-stream 2 *(ebp+8)) +3350 (write-buffered Stderr "'\n") +3351 (flush Stderr) +3352 # . syscall(exit, 1) +3353 bb/copy-to-ebx 1/imm32 +3354 b8/copy-to-eax 1/imm32/exit +3355 cd/syscall 0x80/imm8 +3356 # never gets here +3357 +3358 stmt-has-outputs?: # line: (addr stream byte) -> result/eax: boolean +3359 # . prologue +3360 55/push-ebp +3361 89/<- %ebp 4/r32/esp +3362 # . save registers +3363 51/push-ecx +3364 # var word-slice/ecx: slice +3365 68/push 0/imm32/end +3366 68/push 0/imm32/start +3367 89/<- %ecx 4/r32/esp +3368 # result = false +3369 b8/copy-to-eax 0/imm32/false +3370 (rewind-stream *(ebp+8)) +3371 { +3372 (next-mu-token *(ebp+8) %ecx) +3373 # if slice-empty?(word-slice) break +3374 (slice-empty? %ecx) +3375 3d/compare-eax-and 0/imm32 +3376 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +3377 0f 85/jump-if-!= break/disp32 +3378 # if slice-starts-with?(word-slice, '#') break +3379 # . eax = *word-slice->start +3380 8b/-> *ecx 0/r32/eax +3381 8a/copy-byte *eax 0/r32/AL +3382 81 4/subop/and %eax 0xff/imm32 +3383 # . if (eax == '#') break +3384 3d/compare-eax-and 0x23/imm32/hash +3385 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +3386 0f 84/jump-if-= break/disp32 +3387 # if slice-equal?(word-slice, '<-') return true +3388 (slice-equal? %ecx "<-") +3389 3d/compare-eax-and 0/imm32 +3390 74/jump-if-= loop/disp8 +3391 b8/copy-to-eax 1/imm32/true +3392 } +3393 $stmt-has-outputs:end: +3394 (rewind-stream *(ebp+8)) +3395 # . reclaim locals +3396 81 0/subop/add %esp 8/imm32 +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 # if 'name' starts with a digit, create a new literal var for it +3405 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found +3406 lookup-var-or-literal: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) +3407 # . prologue +3408 55/push-ebp +3409 89/<- %ebp 4/r32/esp +3410 # . save registers +3411 51/push-ecx +3412 56/push-esi +3413 # esi = name +3414 8b/-> *(ebp+8) 6/r32/esi +3415 # if slice-empty?(name) abort +3416 (slice-empty? %esi) # => eax +3417 3d/compare-eax-and 0/imm32 +3418 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 +3419 # var ecx: byte = *name->start +3420 8b/-> *esi 1/r32/ecx +3421 8a/copy-byte *ecx 1/r32/CL +3422 81 4/subop/and %ecx 0xff/imm32 +3423 # if is-decimal-digit?(*name->start) return new var(name) +3424 (is-decimal-digit? %ecx) # => eax +3425 81 7/subop/compare %eax 0/imm32 +3426 { +3427 74/jump-if-= break/disp8 +3428 (new-literal-integer Heap %esi) # => eax +3429 } +3430 # otherwise return lookup-var(name, vars) 3431 { -3432 # if (result != 0) return -3433 3d/compare-eax-and 0/imm32 -3434 75/jump-if-!= break/disp8 -3435 # if name is one of fn's outputs, return it -3436 { -3437 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax -3438 3d/compare-eax-and 0/imm32 -3439 # otherwise abort -3440 0f 84/jump-if-!= $lookup-var:abort/disp32 -3441 } -3442 } -3443 $lookup-or-define-var:end: -3444 # . restore registers -3445 59/pop-to-ecx -3446 # . epilogue -3447 89/<- %esp 5/r32/ebp -3448 5d/pop-to-ebp -3449 c3/return -3450 -3451 find-in-function-outputs: # fn: (handle function), name: (handle array byte) => result/eax: (handle var) -3452 # . prologue -3453 55/push-ebp -3454 89/<- %ebp 4/r32/esp -3455 # . save registers -3456 51/push-ecx -3457 # var curr/ecx: (handle list var) = fn->outputs -3458 8b/-> *(ebp+8) 1/r32/ecx -3459 8b/-> *(ecx+0xc) 1/r32/ecx -3460 # while curr != null -3461 { -3462 81 7/subop/compare %ecx 0/imm32 -3463 74/jump-if-= break/disp8 -3464 # var v: (handle var) = *curr -3465 8b/-> *ecx 0/r32/eax # List-value -3466 # if (curr->name == name) return curr -3467 50/push-eax -3468 (string-equal? *eax *(ebp+0xc)) -3469 3d/compare-eax-and 0/imm32 -3470 58/pop-to-eax -3471 75/jump-if-!= $find-in-function-outputs:end/disp8 -3472 # curr = curr->next -3473 8b/-> *(ecx+4) 1/r32/ecx # List-next -3474 eb/jump loop/disp8 -3475 } -3476 b8/copy-to-eax 0/imm32 -3477 $find-in-function-outputs: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 test-parse-mu-stmt: -3486 # 'increment n' -3487 # . prologue -3488 55/push-ebp -3489 89/<- %ebp 4/r32/esp -3490 # setup -3491 (clear-stream _test-input-stream) -3492 (write _test-input-stream "increment n\n") -3493 # var vars/ecx: (stack (addr var) 4) -3494 81 5/subop/subtract %esp 0x10/imm32 -3495 68/push 0x10/imm32/length -3496 68/push 0/imm32/top -3497 89/<- %ecx 4/r32/esp -3498 (clear-stack %ecx) -3499 # var v/edx: var -3500 81 5/subop/subtract %esp 0x14/imm32 # Var-size -3501 89/<- %edx 4/r32/esp -3502 (zero-out %edx 0x14) -3503 # v->name = "n" -3504 c7 0/subop/copy *edx "n"/imm32 # Var-name -3505 # -3506 (push %ecx %edx) -3507 # convert -3508 (parse-mu-stmt _test-input-stream %ecx) # => eax -3509 # check result -3510 (check-ints-equal *eax 1 "F - test-parse-mu-stmt/tag") # Stmt-tag is Stmt1 -3511 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation -3512 # edx: (handle list var) = result->inouts -3513 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts -3514 # ebx: (handle var) = result->inouts->value -3515 8b/-> *edx 3/r32/ebx # List-value -3516 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name -3517 # . epilogue -3518 89/<- %esp 5/r32/ebp -3519 5d/pop-to-ebp -3520 c3/return -3521 -3522 test-parse-mu-stmt-with-comma: -3523 # 'increment n' -3524 # . prologue -3525 55/push-ebp -3526 89/<- %ebp 4/r32/esp -3527 # setup -3528 (clear-stream _test-input-stream) -3529 (write _test-input-stream "copy-to n, 3\n") -3530 # var vars/ecx: (stack (addr var) 4) -3531 81 5/subop/subtract %esp 0x10/imm32 -3532 68/push 0x10/imm32/length -3533 68/push 0/imm32/top -3534 89/<- %ecx 4/r32/esp -3535 (clear-stack %ecx) -3536 # var v/edx: var -3537 81 5/subop/subtract %esp 0x14/imm32 # Var-size -3538 89/<- %edx 4/r32/esp -3539 (zero-out %edx 0x14) -3540 # v->name = "n" -3541 c7 0/subop/copy *edx "n"/imm32 # Var-name -3542 # -3543 (push %ecx %edx) -3544 # convert -3545 (parse-mu-stmt _test-input-stream %ecx) # => eax -3546 # check result -3547 (check-ints-equal *eax 1 "F - test-parse-mu-stmt-with-comma/tag") # Stmt-tag is Stmt1 -3548 (check-strings-equal *(eax+4) "copy-to" "F - test-parse-mu-stmt-with-comma/name") # Stmt1-operation -3549 # edx: (handle list var) = result->inouts -3550 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts -3551 # ebx: (handle var) = result->inouts->value -3552 8b/-> *edx 3/r32/ebx # List-value -3553 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt-with-comma/inout:0") # Var-name -3554 # . epilogue -3555 89/<- %esp 5/r32/ebp -3556 5d/pop-to-ebp -3557 c3/return -3558 -3559 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) -3560 # . prologue -3561 55/push-ebp -3562 89/<- %ebp 4/r32/esp -3563 # . save registers -3564 51/push-ecx -3565 # -3566 (allocate *(ebp+8) *Function-size) # => eax -3567 8b/-> *(ebp+0xc) 1/r32/ecx -3568 89/<- *eax 1/r32/ecx # Function-name -3569 8b/-> *(ebp+0x10) 1/r32/ecx -3570 89/<- *(eax+4) 1/r32/ecx # Function-subx-name -3571 8b/-> *(ebp+0x14) 1/r32/ecx -3572 89/<- *(eax+8) 1/r32/ecx # Function-inouts -3573 8b/-> *(ebp+0x18) 1/r32/ecx -3574 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs -3575 8b/-> *(ebp+0x1c) 1/r32/ecx -3576 89/<- *(eax+0x10) 1/r32/ecx # Function-body -3577 8b/-> *(ebp+0x20) 1/r32/ecx -3578 89/<- *(eax+0x14) 1/r32/ecx # Function-next -3579 $new-function:end: -3580 # . restore registers -3581 59/pop-to-ecx -3582 # . epilogue -3583 89/<- %esp 5/r32/ebp -3584 5d/pop-to-ebp -3585 c3/return -3586 -3587 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) -3588 # . prologue -3589 55/push-ebp -3590 89/<- %ebp 4/r32/esp -3591 # . save registers -3592 51/push-ecx -3593 # -3594 (allocate *(ebp+8) *Var-size) # => eax -3595 8b/-> *(ebp+0xc) 1/r32/ecx -3596 89/<- *eax 1/r32/ecx # Var-name -3597 8b/-> *(ebp+0x10) 1/r32/ecx -3598 89/<- *(eax+4) 1/r32/ecx # Var-type -3599 8b/-> *(ebp+0x14) 1/r32/ecx -3600 89/<- *(eax+8) 1/r32/ecx # Var-block -3601 8b/-> *(ebp+0x18) 1/r32/ecx -3602 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset -3603 8b/-> *(ebp+0x1c) 1/r32/ecx -3604 89/<- *(eax+0x10) 1/r32/ecx # Var-register -3605 $new-var:end: -3606 # . restore registers -3607 59/pop-to-ecx -3608 # . epilogue -3609 89/<- %esp 5/r32/ebp -3610 5d/pop-to-ebp -3611 c3/return -3612 -3613 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) -3614 # . prologue -3615 55/push-ebp -3616 89/<- %ebp 4/r32/esp -3617 # . save registers -3618 51/push-ecx -3619 # if (!is-hex-int?(name)) abort -3620 (is-hex-int? *(ebp+0xc)) # => eax -3621 3d/compare-eax-and 0/imm32 -3622 0f 84/jump-if-= $new-literal-integer:abort/disp32 -3623 # var s/ecx: (addr array byte) -3624 (slice-to-string Heap *(ebp+0xc)) # => eax -3625 89/<- %ecx 0/r32/eax -3626 # -3627 (allocate *(ebp+8) *Var-size) # => eax -3628 89/<- *eax 1/r32/ecx # Var-name -3629 89/<- %ecx 0/r32/eax -3630 (allocate *(ebp+8) *Tree-size) # => eax -3631 89/<- *(ecx+4) 0/r32/eax # Var-type -3632 89/<- %eax 1/r32/ecx -3633 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block -3634 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset -3635 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register -3636 $new-literal-integer:end: -3637 # . restore registers -3638 59/pop-to-ecx -3639 # . epilogue -3640 89/<- %esp 5/r32/ebp -3641 5d/pop-to-ebp -3642 c3/return -3643 -3644 $new-literal-integer:abort: -3645 (write-buffered Stderr "variable cannot begin with a digit '") -3646 (write-slice-buffered Stderr *(ebp+0xc)) -3647 (write-buffered Stderr "'\n") -3648 (flush Stderr) -3649 # . syscall(exit, 1) -3650 bb/copy-to-ebx 1/imm32 -3651 b8/copy-to-eax 1/imm32/exit -3652 cd/syscall 0x80/imm8 -3653 # never gets here -3654 -3655 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) -3656 # . prologue -3657 55/push-ebp -3658 89/<- %ebp 4/r32/esp -3659 # . save registers -3660 51/push-ecx -3661 # -3662 (allocate *(ebp+8) *Stmt-size) # => eax -3663 (zero-out %eax *Stmt-size) -3664 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag -3665 8b/-> *(ebp+0xc) 1/r32/ecx -3666 89/<- *(eax+4) 1/r32/ecx # Block-statements -3667 $new-block:end: -3668 # . restore registers -3669 59/pop-to-ecx -3670 # . epilogue -3671 89/<- %esp 5/r32/ebp -3672 5d/pop-to-ebp -3673 c3/return -3674 -3675 new-vardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) -3676 # . prologue -3677 55/push-ebp -3678 89/<- %ebp 4/r32/esp -3679 # . save registers -3680 51/push-ecx -3681 # -3682 (allocate *(ebp+8) *Stmt-size) # => eax -3683 (zero-out %eax *Stmt-size) -3684 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag -3685 # result->var = var -3686 8b/-> *(ebp+0xc) 1/r32/ecx -3687 89/<- *(eax+4) 1/r32/ecx # Vardef-var -3688 $new-vardef:end: -3689 # . restore registers -3690 59/pop-to-ecx -3691 # . epilogue -3692 89/<- %esp 5/r32/ebp -3693 5d/pop-to-ebp -3694 c3/return -3695 -3696 new-regvardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) -3697 # . prologue -3698 55/push-ebp -3699 89/<- %ebp 4/r32/esp -3700 # . save registers -3701 51/push-ecx -3702 57/push-edi -3703 # ecx = var -3704 8b/-> *(ebp+0xc) 1/r32/ecx -3705 # edi = result -3706 (allocate *(ebp+8) *Stmt-size) # => eax -3707 89/<- %edi 0/r32/eax -3708 (zero-out %edi *Stmt-size) -3709 # set tag -3710 c7 0/subop/copy *edi 3/imm32/tag/var-in-register # Stmt-tag -3711 # set output -3712 (append-list Heap %ecx *(edi+0xc)) # Regvardef-outputs => eax -3713 89/<- *(edi+0xc) 0/r32/eax # Regvardef-outputs -3714 $new-regvardef:end: -3715 89/<- %eax 7/r32/edi -3716 # . restore registers -3717 5f/pop-to-edi -3718 59/pop-to-ecx -3719 # . epilogue -3720 89/<- %esp 5/r32/ebp -3721 5d/pop-to-ebp -3722 c3/return -3723 -3724 new-named-block: # ad: (addr allocation-descriptor), name: (addr array byte), data: (handle list statement) -> result/eax: (handle statement) -3725 # . prologue -3726 55/push-ebp -3727 89/<- %ebp 4/r32/esp -3728 # . save registers -3729 51/push-ecx -3730 # -3731 (allocate *(ebp+8) *Stmt-size) # => eax -3732 (zero-out %eax *Stmt-size) -3733 c7 0/subop/copy *eax 4/imm32/tag/named-block -3734 8b/-> *(ebp+0xc) 1/r32/ecx -3735 89/<- *(eax+4) 1/r32/ecx # Named-block-name -3736 8b/-> *(ebp+0x10) 1/r32/ecx -3737 89/<- *(eax+8) 1/r32/ecx # Named-block-statements -3738 $new-named-block:end: -3739 # . restore registers -3740 59/pop-to-ecx -3741 # . epilogue -3742 89/<- %esp 5/r32/ebp -3743 5d/pop-to-ebp -3744 c3/return -3745 -3746 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax: (handle list _type) -3747 # . prologue -3748 55/push-ebp -3749 89/<- %ebp 4/r32/esp -3750 # . save registers -3751 51/push-ecx -3752 # -3753 (allocate *(ebp+8) *List-size) # => eax -3754 8b/-> *(ebp+0xc) 1/r32/ecx -3755 89/<- *eax 1/r32/ecx # List-value -3756 8b/-> *(ebp+0x10) 1/r32/ecx -3757 89/<- *(eax+4) 1/r32/ecx # List-next -3758 $new-list:end: -3759 # . restore registers -3760 59/pop-to-ecx -3761 # . epilogue -3762 89/<- %esp 5/r32/ebp -3763 5d/pop-to-ebp -3764 c3/return -3765 -3766 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax: (handle list _type) -3767 # . prologue -3768 55/push-ebp -3769 89/<- %ebp 4/r32/esp -3770 # . save registers -3771 51/push-ecx -3772 # -3773 (allocate *(ebp+8) *List-size) # => eax -3774 8b/-> *(ebp+0xc) 1/r32/ecx -3775 89/<- *eax 1/r32/ecx # List-value -3776 # if (list == null) return result -3777 81 7/subop/compare *(ebp+0x10) 0/imm32 -3778 74/jump-if-= $new-list:end/disp8 -3779 # otherwise append -3780 # var curr/ecx = list -3781 8b/-> *(ebp+0x10) 1/r32/ecx -3782 # while (curr->next != null) curr = curr->next -3783 { -3784 81 7/subop/compare *(ecx+4) 0/imm32 # List-next -3785 74/jump-if-= break/disp8 -3786 # curr = curr->next -3787 8b/-> *(ecx+4) 1/r32/ecx -3788 eb/jump loop/disp8 -3789 } -3790 # curr->next = result -3791 89/<- *(ecx+4) 0/r32/eax -3792 # return list -3793 8b/-> *(ebp+0x10) 0/r32/eax -3794 $append-list:end: -3795 # . restore registers -3796 59/pop-to-ecx -3797 # . epilogue -3798 89/<- %esp 5/r32/ebp -3799 5d/pop-to-ebp -3800 c3/return -3801 -3802 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) -3803 # . prologue -3804 55/push-ebp -3805 89/<- %ebp 4/r32/esp -3806 # . save registers -3807 56/push-esi -3808 # esi = block -3809 8b/-> *(ebp+0xc) 6/r32/esi -3810 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements -3811 89/<- *(esi+4) 0/r32/eax # Block-statements -3812 $append-to-block:end: -3813 # . restore registers -3814 5e/pop-to-esi -3815 # . epilogue -3816 89/<- %esp 5/r32/ebp -3817 5d/pop-to-ebp -3818 c3/return -3819 -3820 ####################################################### -3821 # Type-checking -3822 ####################################################### -3823 -3824 check-mu-types: -3825 # . prologue -3826 55/push-ebp -3827 89/<- %ebp 4/r32/esp -3828 # -3829 $check-mu-types:end: -3830 # . epilogue -3831 89/<- %esp 5/r32/ebp -3832 5d/pop-to-ebp -3833 c3/return -3834 -3835 size-of: # n: (addr var) -> result/eax: int -3836 # . prologue -3837 55/push-ebp -3838 89/<- %ebp 4/r32/esp -3839 # hard-coded since we only support 'int' types for now -3840 b8/copy-to-eax 4/imm32 -3841 $size-of:end: -3842 # . epilogue -3843 89/<- %esp 5/r32/ebp -3844 5d/pop-to-ebp -3845 c3/return -3846 -3847 == data -3848 -3849 # not yet used, but it will be -3850 Type-size: # (stream int) -3851 0x18/imm32/write -3852 0/imm32/read -3853 0x100/imm32/length -3854 # data -3855 4/imm32 # literal -3856 4/imm32 # int -3857 4/imm32 # addr -3858 0/imm32 # array (logic elsewhere) -3859 8/imm32 # handle (fat pointer) -3860 4/imm32 # bool -3861 0/imm32 -3862 0/imm32 -3863 # 0x20 -3864 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -3865 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -3866 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -3867 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -3868 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -3869 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -3870 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -3871 -3872 == code -3873 -3874 ####################################################### -3875 # Code-generation -3876 ####################################################### -3877 -3878 emit-subx: # out: (addr buffered-file) -3879 # . prologue -3880 55/push-ebp -3881 89/<- %ebp 4/r32/esp -3882 # . save registers -3883 50/push-eax -3884 51/push-ecx -3885 57/push-edi -3886 # edi = out -3887 8b/-> *(ebp+8) 7/r32/edi -3888 # var curr/ecx: (handle function) = *Program -3889 8b/-> *Program 1/r32/ecx -3890 { -3891 # if (curr == null) break -3892 81 7/subop/compare %ecx 0/imm32 -3893 0f 84/jump-if-= break/disp32 -3894 (emit-subx-function %edi %ecx) -3895 # curr = curr->next -3896 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -3897 e9/jump loop/disp32 -3898 } -3899 $emit-subx:end: -3900 # . restore registers -3901 5f/pop-to-edi -3902 59/pop-to-ecx -3903 58/pop-to-eax -3904 # . epilogue -3905 89/<- %esp 5/r32/ebp -3906 5d/pop-to-ebp -3907 c3/return -3908 -3909 emit-subx-function: # out: (addr buffered-file), f: (handle function) -3910 # . prologue -3911 55/push-ebp -3912 89/<- %ebp 4/r32/esp -3913 # . save registers -3914 50/push-eax -3915 51/push-ecx -3916 52/push-edx -3917 57/push-edi -3918 # edi = out -3919 8b/-> *(ebp+8) 7/r32/edi -3920 # ecx = f -3921 8b/-> *(ebp+0xc) 1/r32/ecx -3922 # var vars/edx: (stack (addr var) 256) -3923 81 5/subop/subtract %esp 0x400/imm32 -3924 68/push 0x400/imm32/length -3925 68/push 0/imm32/top -3926 89/<- %edx 4/r32/esp -3927 # -3928 (write-buffered %edi *ecx) -3929 (write-buffered %edi ":\n") -3930 (emit-subx-prologue %edi) -3931 (emit-subx-block %edi *(ecx+0x10) %edx) # Function-body -3932 (emit-subx-epilogue %edi) -3933 $emit-subx-function:end: -3934 # . reclaim locals -3935 81 0/subop/add %esp 408/imm32 -3936 # . restore registers -3937 5f/pop-to-edi -3938 5a/pop-to-edx -3939 59/pop-to-ecx -3940 58/pop-to-eax -3941 # . epilogue -3942 89/<- %esp 5/r32/ebp -3943 5d/pop-to-ebp -3944 c3/return -3945 -3946 emit-subx-block: # out: (addr buffered-file), block: (handle block), vars: (addr stack (handle var)) -3947 # . prologue -3948 55/push-ebp -3949 89/<- %ebp 4/r32/esp -3950 # . save registers -3951 50/push-eax -3952 51/push-ecx -3953 56/push-esi -3954 # var stmts/esi: (handle list statement) = block->statements -3955 8b/-> *(ebp+0xc) 6/r32/esi -3956 8b/-> *(esi+4) 6/r32/esi # Block-statements -3957 # -3958 { -3959 $emit-subx-block:check-empty: -3960 81 7/subop/compare %esi 0/imm32 -3961 0f 84/jump-if-= break/disp32 -3962 (write-buffered *(ebp+8) "{\n") -3963 { -3964 $emit-subx-block:loop: -3965 81 7/subop/compare %esi 0/imm32 -3966 0f 84/jump-if-= break/disp32 -3967 # var curr-stmt/ecx = stmts->value -3968 8b/-> *esi 1/r32/ecx # List-value -3969 { -3970 $emit-subx-block:check-for-block: -3971 81 7/subop/compare *ecx 0/imm32/block # Stmt-tag -3972 75/jump-if-!= break/disp8 -3973 $emit-subx-block:block: -3974 # TODO -3975 } -3976 { -3977 $emit-subx-block:check-for-stmt: -3978 81 7/subop/compare *ecx 1/imm32/stmt1 # Stmt-tag -3979 75/jump-if-!= break/disp8 -3980 $emit-subx-block:stmt: -3981 (emit-subx-statement *(ebp+8) %ecx Primitives *Program) -3982 } -3983 { -3984 $emit-subx-block:check-for-vardef: -3985 81 7/subop/compare *ecx 2/imm32/vardef # Stmt-tag -3986 75/jump-if-!= break/disp8 -3987 $emit-subx-block:vardef: -3988 (emit-subx-var-def *(ebp+8) %ecx) -3989 (push *(ebp+0x10) *(ecx+4)) # Vardef-var -3990 } -3991 { -3992 $emit-subx-block:check-for-regvardef: -3993 81 7/subop/compare *ecx 3/imm32/regvardef # Stmt-tag -3994 0f 85/jump-if-!= break/disp32 -3995 $emit-subx-block:regvardef: -3996 # TODO: ensure that there's exactly one output -3997 # var output/eax: (handle var) = curr-stmt->outputs->value -3998 8b/-> *(ecx+0xc) 0/r32/eax -3999 8b/-> *eax 0/r32/eax -4000 # ensure that output is in a register -4001 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -4002 0f 84/jump-if-equal $emit-subx-block:abort-regvardef-without-register/disp32 -4003 # emit spill -4004 (write-buffered *(ebp+8) "ff 6/subop/push %") -4005 (write-buffered *(ebp+8) *(eax+0x10)) -4006 (write-buffered *(ebp+8) Newline) -4007 # register variable definition -4008 (push *(ebp+0x10) %eax) -4009 # emit the instruction as usual -4010 (emit-subx-statement *(ebp+8) %ecx Primitives *Program) -4011 } -4012 { -4013 $emit-subx-block:check-for-named-block: -4014 81 7/subop/compare *ecx 4/imm32/named-block # Stmt-tag -4015 75/jump-if-!= break/disp8 -4016 $emit-subx-block:named-block: -4017 # TODO -4018 } -4019 (write-buffered *(ebp+8) Newline) -4020 8b/-> *(esi+4) 6/r32/esi # List-next -4021 e9/jump loop/disp32 -4022 } -4023 # reclaim locals -4024 # TODO: support nested blocks; take block-ids into account -4025 { -4026 $emit-subx-block:reclaim-loop: -4027 8b/-> *(ebp+0x10) 0/r32/eax -4028 81 7/subop/compare *eax 0/imm32 # Stack-top -4029 0f 84/jump-if-= break/disp32 -4030 # var v/ecx : (handle var) = top(vars) -4031 (top %eax) # => eax -4032 89/<- %ecx 0/r32/eax -4033 # if v is in a register -4034 81 7/subop/compare *(ecx+0x10) 0/imm32 # Var-register -4035 { -4036 74/jump-if-= break/disp8 -4037 $emit-subx-block:reclaim-var-in-register: -4038 (write-buffered *(ebp+8) "8f 0/subop/pop %") -4039 (write-buffered *(ebp+8) *(ecx+0x10)) -4040 (write-buffered *(ebp+8) Newline) -4041 } -4042 # if v is on the stack -4043 { -4044 75/jump-if-!= break/disp8 -4045 $emit-subx-block:reclaim-var-on-stack: -4046 (size-of %ecx) # => eax -4047 01/add *Next-local-stack-offset 0/r32/eax -4048 (write-buffered *(ebp+8) "81 0/subop/add %esp ") -4049 (print-int32-buffered *(ebp+8) %eax) -4050 (write-buffered *(ebp+8) "/imm32\n") -4051 } -4052 # -4053 (pop *(ebp+0x10)) -4054 e9/jump loop/disp32 -4055 } -4056 # -4057 (write-buffered *(ebp+8) "}\n") -4058 } -4059 $emit-subx-block:end: -4060 # . restore registers -4061 5e/pop-to-esi -4062 59/pop-to-ecx -4063 58/pop-to-eax -4064 # . epilogue -4065 89/<- %esp 5/r32/ebp -4066 5d/pop-to-ebp -4067 c3/return -4068 -4069 $emit-subx-block:abort-regvardef-without-register: -4070 # error("var '" var->name "' initialized from an instruction must live in a register\n") -4071 (write-buffered Stderr "var '") -4072 (write-buffered Stderr *eax) # Var-name -4073 (write-buffered Stderr "' initialized from an instruction must live in a register\n") -4074 (flush Stderr) -4075 # . syscall(exit, 1) -4076 bb/copy-to-ebx 1/imm32 -4077 b8/copy-to-eax 1/imm32/exit -4078 cd/syscall 0x80/imm8 -4079 # never gets here -4080 -4081 emit-subx-var-def: # out: (addr buffered-file), stmt: (handle statement) -4082 # . prologue -4083 55/push-ebp -4084 89/<- %ebp 4/r32/esp -4085 # . save registers -4086 50/push-eax -4087 51/push-ecx -4088 # eax = stmt -4089 8b/-> *(ebp+0xc) 0/r32/eax -4090 # var n/eax: int = size-of(stmt->var) -4091 (size-of *(eax+4)) # Vardef-var => eax -4092 # while n > 0 -4093 { -4094 3d/compare-eax-with 0/imm32 -4095 7e/jump-if-<= break/disp8 -4096 (write-buffered *(ebp+8) "68/push 0/imm32") -4097 # n -= 4 -4098 2d/subtract-from-eax 4/imm32 -4099 # -4100 eb/jump loop/disp8 -4101 } -4102 $emit-subx-var-def:end: -4103 # . restore registers -4104 59/pop-to-ecx -4105 58/pop-to-eax -4106 # . epilogue -4107 89/<- %esp 5/r32/ebp -4108 5d/pop-to-ebp -4109 c3/return -4110 -4111 emit-subx-statement: # out: (addr buffered-file), stmt: (handle statement), primitives: (handle primitive), functions: (handle function) -4112 # . prologue -4113 55/push-ebp -4114 89/<- %ebp 4/r32/esp -4115 # . save registers -4116 50/push-eax -4117 51/push-ecx -4118 # if stmt matches a primitive, emit it -4119 { -4120 $emit-subx-statement:primitive: -4121 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax -4122 3d/compare-eax-and 0/imm32 -4123 74/jump-if-= break/disp8 -4124 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -4125 e9/jump $emit-subx-statement:end/disp32 -4126 } -4127 # else if stmt matches a function, emit a call to it -4128 { -4129 $emit-subx-statement:call: -4130 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax -4131 3d/compare-eax-and 0/imm32 -4132 74/jump-if-= break/disp8 -4133 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -4134 e9/jump $emit-subx-statement:end/disp32 -4135 } -4136 # else abort -4137 e9/jump $emit-subx-statement:abort/disp32 -4138 $emit-subx-statement:end: -4139 # . restore registers -4140 59/pop-to-ecx -4141 58/pop-to-eax -4142 # . epilogue -4143 89/<- %esp 5/r32/ebp -4144 5d/pop-to-ebp -4145 c3/return -4146 -4147 $emit-subx-statement:abort: -4148 # error("couldn't translate '" stmt "'\n") -4149 (write-buffered Stderr "couldn't translate '") -4150 #? (emit-string Stderr *(ebp+0xc)) # TODO -4151 (write-buffered Stderr "'\n") -4152 (flush Stderr) -4153 # . syscall(exit, 1) -4154 bb/copy-to-ebx 1/imm32 -4155 b8/copy-to-eax 1/imm32/exit -4156 cd/syscall 0x80/imm8 -4157 # never gets here -4158 -4159 # Primitives supported -4160 # For each operation, put variants with hard-coded registers before flexible ones. -4161 == data -4162 Primitives: -4163 # - increment/decrement -4164 _Primitive-inc-eax: -4165 # var/eax <- increment => 40/increment-eax -4166 "increment"/imm32/name -4167 0/imm32/no-inouts -4168 Single-int-var-in-eax/imm32/outputs -4169 "40/increment-eax"/imm32/subx-name -4170 0/imm32/no-rm32 -4171 0/imm32/no-r32 -4172 0/imm32/no-imm32 -4173 0/imm32/output-is-write-only -4174 _Primitive-inc-ecx/imm32/next -4175 _Primitive-inc-ecx: -4176 # var/ecx <- increment => 41/increment-ecx -4177 "increment"/imm32/name -4178 0/imm32/no-inouts -4179 Single-int-var-in-ecx/imm32/outputs -4180 "41/increment-ecx"/imm32/subx-name -4181 0/imm32/no-rm32 -4182 0/imm32/no-r32 -4183 0/imm32/no-imm32 -4184 0/imm32/output-is-write-only -4185 _Primitive-inc-edx/imm32/next -4186 _Primitive-inc-edx: -4187 # var/edx <- increment => 42/increment-edx -4188 "increment"/imm32/name -4189 0/imm32/no-inouts -4190 Single-int-var-in-edx/imm32/outputs -4191 "42/increment-edx"/imm32/subx-name -4192 0/imm32/no-rm32 -4193 0/imm32/no-r32 -4194 0/imm32/no-imm32 -4195 0/imm32/output-is-write-only -4196 _Primitive-inc-ebx/imm32/next -4197 _Primitive-inc-ebx: -4198 # var/ebx <- increment => 43/increment-ebx -4199 "increment"/imm32/name -4200 0/imm32/no-inouts -4201 Single-int-var-in-ebx/imm32/outputs -4202 "43/increment-ebx"/imm32/subx-name -4203 0/imm32/no-rm32 -4204 0/imm32/no-r32 -4205 0/imm32/no-imm32 -4206 0/imm32/output-is-write-only -4207 _Primitive-inc-esi/imm32/next -4208 _Primitive-inc-esi: -4209 # var/esi <- increment => 46/increment-esi -4210 "increment"/imm32/name -4211 0/imm32/no-inouts -4212 Single-int-var-in-esi/imm32/outputs -4213 "46/increment-esi"/imm32/subx-name -4214 0/imm32/no-rm32 -4215 0/imm32/no-r32 -4216 0/imm32/no-imm32 -4217 0/imm32/output-is-write-only -4218 _Primitive-inc-edi/imm32/next -4219 _Primitive-inc-edi: -4220 # var/edi <- increment => 47/increment-edi -4221 "increment"/imm32/name -4222 0/imm32/no-inouts -4223 Single-int-var-in-edi/imm32/outputs -4224 "47/increment-edi"/imm32/subx-name -4225 0/imm32/no-rm32 -4226 0/imm32/no-r32 -4227 0/imm32/no-imm32 -4228 0/imm32/output-is-write-only -4229 _Primitive-dec-eax/imm32/next -4230 _Primitive-dec-eax: -4231 # var/eax <- decrement => 48/decrement-eax -4232 "decrement"/imm32/name -4233 0/imm32/no-inouts -4234 Single-int-var-in-eax/imm32/outputs -4235 "48/decrement-eax"/imm32/subx-name -4236 0/imm32/no-rm32 -4237 0/imm32/no-r32 -4238 0/imm32/no-imm32 -4239 0/imm32/output-is-write-only -4240 _Primitive-dec-ecx/imm32/next -4241 _Primitive-dec-ecx: -4242 # var/ecx <- decrement => 49/decrement-ecx -4243 "decrement"/imm32/name -4244 0/imm32/no-inouts -4245 Single-int-var-in-ecx/imm32/outputs -4246 "49/decrement-ecx"/imm32/subx-name -4247 0/imm32/no-rm32 -4248 0/imm32/no-r32 -4249 0/imm32/no-imm32 -4250 0/imm32/output-is-write-only -4251 _Primitive-dec-edx/imm32/next -4252 _Primitive-dec-edx: -4253 # var/edx <- decrement => 4a/decrement-edx -4254 "decrement"/imm32/name -4255 0/imm32/no-inouts -4256 Single-int-var-in-edx/imm32/outputs -4257 "4a/decrement-edx"/imm32/subx-name -4258 0/imm32/no-rm32 -4259 0/imm32/no-r32 -4260 0/imm32/no-imm32 -4261 0/imm32/output-is-write-only -4262 _Primitive-dec-ebx/imm32/next -4263 _Primitive-dec-ebx: -4264 # var/ebx <- decrement => 4b/decrement-ebx -4265 "decrement"/imm32/name -4266 0/imm32/no-inouts -4267 Single-int-var-in-ebx/imm32/outputs -4268 "4b/decrement-ebx"/imm32/subx-name -4269 0/imm32/no-rm32 -4270 0/imm32/no-r32 -4271 0/imm32/no-imm32 -4272 0/imm32/output-is-write-only -4273 _Primitive-dec-esi/imm32/next -4274 _Primitive-dec-esi: -4275 # var/esi <- decrement => 4e/decrement-esi -4276 "decrement"/imm32/name -4277 0/imm32/no-inouts -4278 Single-int-var-in-esi/imm32/outputs -4279 "4e/decrement-esi"/imm32/subx-name -4280 0/imm32/no-rm32 -4281 0/imm32/no-r32 -4282 0/imm32/no-imm32 -4283 0/imm32/output-is-write-only -4284 _Primitive-dec-edi/imm32/next -4285 _Primitive-dec-edi: -4286 # var/edi <- decrement => 4f/decrement-edi -4287 "decrement"/imm32/name -4288 0/imm32/no-inouts -4289 Single-int-var-in-edi/imm32/outputs -4290 "4f/decrement-edi"/imm32/subx-name -4291 0/imm32/no-rm32 -4292 0/imm32/no-r32 -4293 0/imm32/no-imm32 -4294 0/imm32/output-is-write-only -4295 _Primitive-inc-mem/imm32/next -4296 _Primitive-inc-mem: -4297 # increment var => ff 0/subop/increment *(ebp+__) -4298 "increment"/imm32/name -4299 Single-int-var-on-stack/imm32/inouts -4300 0/imm32/no-outputs -4301 "ff 0/subop/increment"/imm32/subx-name -4302 1/imm32/rm32-is-first-inout -4303 0/imm32/no-r32 -4304 0/imm32/no-imm32 -4305 0/imm32/output-is-write-only -4306 _Primitive-inc-reg/imm32/next -4307 _Primitive-inc-reg: -4308 # var/reg <- increment => ff 0/subop/increment %__ -4309 "increment"/imm32/name -4310 0/imm32/no-inouts -4311 Single-int-var-in-some-register/imm32/outputs -4312 "ff 0/subop/increment"/imm32/subx-name -4313 3/imm32/rm32-is-first-output -4314 0/imm32/no-r32 -4315 0/imm32/no-imm32 -4316 0/imm32/output-is-write-only -4317 _Primitive-dec-mem/imm32/next -4318 _Primitive-dec-mem: -4319 # decrement var => ff 1/subop/decrement *(ebp+__) -4320 "decrement"/imm32/name -4321 Single-int-var-on-stack/imm32/inouts -4322 0/imm32/no-outputs -4323 "ff 1/subop/decrement"/imm32/subx-name -4324 1/imm32/rm32-is-first-inout -4325 0/imm32/no-r32 -4326 0/imm32/no-imm32 -4327 0/imm32/output-is-write-only -4328 _Primitive-dec-reg/imm32/next -4329 _Primitive-dec-reg: -4330 # var/reg <- decrement => ff 1/subop/decrement %__ -4331 "decrement"/imm32/name -4332 0/imm32/no-inouts -4333 Single-int-var-in-some-register/imm32/outputs -4334 "ff 1/subop/decrement"/imm32/subx-name -4335 3/imm32/rm32-is-first-output -4336 0/imm32/no-r32 -4337 0/imm32/no-imm32 -4338 0/imm32/output-is-write-only -4339 _Primitive-add-to-eax/imm32/next -4340 # - add -4341 _Primitive-add-to-eax: -4342 # var/eax <- add lit => 05/add-to-eax lit/imm32 -4343 "add"/imm32/name -4344 Single-lit-var/imm32/inouts -4345 Single-int-var-in-eax/imm32/outputs -4346 "05/add-to-eax"/imm32/subx-name -4347 0/imm32/no-rm32 -4348 0/imm32/no-r32 -4349 1/imm32/imm32-is-first-inout -4350 0/imm32/output-is-write-only -4351 _Primitive-add-reg-to-reg/imm32/next -4352 _Primitive-add-reg-to-reg: -4353 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 -4354 "add"/imm32/name -4355 Single-int-var-in-some-register/imm32/inouts -4356 Single-int-var-in-some-register/imm32/outputs -4357 "01/add-to"/imm32/subx-name -4358 3/imm32/rm32-is-first-output -4359 1/imm32/r32-is-first-inout -4360 0/imm32/no-imm32 -4361 0/imm32/output-is-write-only -4362 _Primitive-add-reg-to-mem/imm32/next -4363 _Primitive-add-reg-to-mem: -4364 # add-to var1 var2/reg => 01/add-to var1 var2/r32 -4365 "add-to"/imm32/name -4366 Int-var-and-second-int-var-in-some-register/imm32/inouts -4367 0/imm32/outputs -4368 "01/add-to"/imm32/subx-name -4369 1/imm32/rm32-is-first-inout -4370 2/imm32/r32-is-second-inout -4371 0/imm32/no-imm32 -4372 0/imm32/output-is-write-only -4373 _Primitive-add-mem-to-reg/imm32/next -4374 _Primitive-add-mem-to-reg: -4375 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 -4376 "add"/imm32/name -4377 Single-int-var-on-stack/imm32/inouts -4378 Single-int-var-in-some-register/imm32/outputs -4379 "03/add"/imm32/subx-name -4380 1/imm32/rm32-is-first-inout -4381 3/imm32/r32-is-first-output -4382 0/imm32/no-imm32 -4383 0/imm32/output-is-write-only -4384 _Primitive-add-lit-to-reg/imm32/next -4385 _Primitive-add-lit-to-reg: -4386 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 -4387 "add"/imm32/name -4388 Single-lit-var/imm32/inouts -4389 Single-int-var-in-some-register/imm32/outputs -4390 "81 0/subop/add"/imm32/subx-name -4391 3/imm32/rm32-is-first-output -4392 0/imm32/no-r32 -4393 1/imm32/imm32-is-first-inout -4394 0/imm32/output-is-write-only -4395 _Primitive-add-lit-to-mem/imm32/next -4396 _Primitive-add-lit-to-mem: -4397 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 -4398 "add-to"/imm32/name -4399 Int-var-and-literal/imm32/inouts -4400 0/imm32/outputs -4401 "81 0/subop/add"/imm32/subx-name -4402 1/imm32/rm32-is-first-inout -4403 0/imm32/no-r32 -4404 2/imm32/imm32-is-first-inout -4405 0/imm32/output-is-write-only -4406 _Primitive-subtract-from-eax/imm32/next -4407 # - subtract -4408 _Primitive-subtract-from-eax: -4409 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 -4410 "subtract"/imm32/name -4411 Single-lit-var/imm32/inouts -4412 Single-int-var-in-eax/imm32/outputs -4413 "2d/subtract-from-eax"/imm32/subx-name -4414 0/imm32/no-rm32 -4415 0/imm32/no-r32 -4416 1/imm32/imm32-is-first-inout -4417 0/imm32/output-is-write-only -4418 _Primitive-subtract-reg-from-reg/imm32/next -4419 _Primitive-subtract-reg-from-reg: -4420 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 -4421 "subtract"/imm32/name -4422 Single-int-var-in-some-register/imm32/inouts -4423 Single-int-var-in-some-register/imm32/outputs -4424 "29/subtract-from"/imm32/subx-name -4425 3/imm32/rm32-is-first-output -4426 1/imm32/r32-is-first-inout -4427 0/imm32/no-imm32 -4428 0/imm32/output-is-write-only -4429 _Primitive-subtract-reg-from-mem/imm32/next -4430 _Primitive-subtract-reg-from-mem: -4431 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 -4432 "subtract-from"/imm32/name -4433 Int-var-and-second-int-var-in-some-register/imm32/inouts -4434 0/imm32/outputs -4435 "29/subtract-from"/imm32/subx-name -4436 1/imm32/rm32-is-first-inout -4437 2/imm32/r32-is-second-inout -4438 0/imm32/no-imm32 -4439 0/imm32/output-is-write-only -4440 _Primitive-subtract-mem-from-reg/imm32/next -4441 _Primitive-subtract-mem-from-reg: -4442 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 -4443 "subtract"/imm32/name -4444 Single-int-var-on-stack/imm32/inouts -4445 Single-int-var-in-some-register/imm32/outputs -4446 "2b/subtract"/imm32/subx-name -4447 1/imm32/rm32-is-first-inout -4448 3/imm32/r32-is-first-output -4449 0/imm32/no-imm32 -4450 0/imm32/output-is-write-only -4451 _Primitive-subtract-lit-from-reg/imm32/next -4452 _Primitive-subtract-lit-from-reg: -4453 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 -4454 "subtract"/imm32/name -4455 Single-lit-var/imm32/inouts -4456 Single-int-var-in-some-register/imm32/outputs -4457 "81 5/subop/subtract"/imm32/subx-name -4458 3/imm32/rm32-is-first-output -4459 0/imm32/no-r32 -4460 1/imm32/imm32-is-first-inout -4461 0/imm32/output-is-write-only -4462 _Primitive-subtract-lit-from-mem/imm32/next -4463 _Primitive-subtract-lit-from-mem: -4464 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 -4465 "subtract-from"/imm32/name -4466 Int-var-and-literal/imm32/inouts -4467 0/imm32/outputs -4468 "81 5/subop/subtract"/imm32/subx-name -4469 1/imm32/rm32-is-first-inout -4470 0/imm32/no-r32 -4471 2/imm32/imm32-is-first-inout -4472 0/imm32/output-is-write-only -4473 _Primitive-and-with-eax/imm32/next -4474 # - and -4475 _Primitive-and-with-eax: -4476 # var/eax <- and lit => 25/and-with-eax lit/imm32 -4477 "and"/imm32/name -4478 Single-lit-var/imm32/inouts -4479 Single-int-var-in-eax/imm32/outputs -4480 "25/and-with-eax"/imm32/subx-name -4481 0/imm32/no-rm32 -4482 0/imm32/no-r32 -4483 1/imm32/imm32-is-first-inout -4484 0/imm32/output-is-write-only -4485 _Primitive-and-reg-with-reg/imm32/next -4486 _Primitive-and-reg-with-reg: -4487 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 -4488 "and"/imm32/name -4489 Single-int-var-in-some-register/imm32/inouts -4490 Single-int-var-in-some-register/imm32/outputs -4491 "21/and-with"/imm32/subx-name -4492 3/imm32/rm32-is-first-output -4493 1/imm32/r32-is-first-inout -4494 0/imm32/no-imm32 -4495 0/imm32/output-is-write-only -4496 _Primitive-and-reg-with-mem/imm32/next -4497 _Primitive-and-reg-with-mem: -4498 # and-with var1 var2/reg => 21/and-with var1 var2/r32 -4499 "and-with"/imm32/name -4500 Int-var-and-second-int-var-in-some-register/imm32/inouts -4501 0/imm32/outputs -4502 "21/and-with"/imm32/subx-name -4503 1/imm32/rm32-is-first-inout -4504 2/imm32/r32-is-second-inout -4505 0/imm32/no-imm32 -4506 0/imm32/output-is-write-only -4507 _Primitive-and-mem-with-reg/imm32/next -4508 _Primitive-and-mem-with-reg: -4509 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 -4510 "and"/imm32/name -4511 Single-int-var-on-stack/imm32/inouts -4512 Single-int-var-in-some-register/imm32/outputs -4513 "23/and"/imm32/subx-name -4514 1/imm32/rm32-is-first-inout -4515 3/imm32/r32-is-first-output -4516 0/imm32/no-imm32 -4517 0/imm32/output-is-write-only -4518 _Primitive-and-lit-with-reg/imm32/next -4519 _Primitive-and-lit-with-reg: -4520 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 -4521 "and"/imm32/name -4522 Single-lit-var/imm32/inouts -4523 Single-int-var-in-some-register/imm32/outputs -4524 "81 4/subop/and"/imm32/subx-name -4525 3/imm32/rm32-is-first-output -4526 0/imm32/no-r32 -4527 1/imm32/imm32-is-first-inout -4528 0/imm32/output-is-write-only -4529 _Primitive-and-lit-with-mem/imm32/next -4530 _Primitive-and-lit-with-mem: -4531 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 -4532 "and-with"/imm32/name -4533 Int-var-and-literal/imm32/inouts -4534 0/imm32/outputs -4535 "81 4/subop/and"/imm32/subx-name -4536 1/imm32/rm32-is-first-inout -4537 0/imm32/no-r32 -4538 2/imm32/imm32-is-first-inout -4539 0/imm32/output-is-write-only -4540 _Primitive-or-with-eax/imm32/next -4541 # - or -4542 _Primitive-or-with-eax: -4543 # var/eax <- or lit => 0d/or-with-eax lit/imm32 -4544 "or"/imm32/name -4545 Single-lit-var/imm32/inouts -4546 Single-int-var-in-eax/imm32/outputs -4547 "0d/or-with-eax"/imm32/subx-name -4548 0/imm32/no-rm32 -4549 0/imm32/no-r32 -4550 1/imm32/imm32-is-first-inout -4551 0/imm32/output-is-write-only -4552 _Primitive-or-reg-with-reg/imm32/next -4553 _Primitive-or-reg-with-reg: -4554 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 -4555 "or"/imm32/name -4556 Single-int-var-in-some-register/imm32/inouts -4557 Single-int-var-in-some-register/imm32/outputs -4558 "09/or-with"/imm32/subx-name -4559 3/imm32/rm32-is-first-output -4560 1/imm32/r32-is-first-inout -4561 0/imm32/no-imm32 -4562 0/imm32/output-is-write-only -4563 _Primitive-or-reg-with-mem/imm32/next -4564 _Primitive-or-reg-with-mem: -4565 # or-with var1 var2/reg => 09/or-with var1 var2/r32 -4566 "or-with"/imm32/name -4567 Int-var-and-second-int-var-in-some-register/imm32/inouts -4568 0/imm32/outputs -4569 "09/or-with"/imm32/subx-name -4570 1/imm32/rm32-is-first-inout -4571 2/imm32/r32-is-second-inout -4572 0/imm32/no-imm32 -4573 0/imm32/output-is-write-only -4574 _Primitive-or-mem-with-reg/imm32/next -4575 _Primitive-or-mem-with-reg: -4576 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 -4577 "or"/imm32/name -4578 Single-int-var-on-stack/imm32/inouts -4579 Single-int-var-in-some-register/imm32/outputs -4580 "0b/or"/imm32/subx-name -4581 1/imm32/rm32-is-first-inout -4582 3/imm32/r32-is-first-output -4583 0/imm32/no-imm32 -4584 0/imm32/output-is-write-only -4585 _Primitive-or-lit-with-reg/imm32/next -4586 _Primitive-or-lit-with-reg: -4587 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 -4588 "or"/imm32/name -4589 Single-lit-var/imm32/inouts -4590 Single-int-var-in-some-register/imm32/outputs -4591 "81 4/subop/or"/imm32/subx-name -4592 3/imm32/rm32-is-first-output -4593 0/imm32/no-r32 -4594 1/imm32/imm32-is-first-inout -4595 0/imm32/output-is-write-only -4596 _Primitive-or-lit-with-mem/imm32/next -4597 _Primitive-or-lit-with-mem: -4598 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 -4599 "or-with"/imm32/name -4600 Int-var-and-literal/imm32/inouts -4601 0/imm32/outputs -4602 "81 4/subop/or"/imm32/subx-name -4603 1/imm32/rm32-is-first-inout -4604 0/imm32/no-r32 -4605 2/imm32/imm32-is-first-inout -4606 0/imm32/output-is-write-only -4607 _Primitive-xor-with-eax/imm32/next -4608 # - xor -4609 _Primitive-xor-with-eax: -4610 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 -4611 "xor"/imm32/name -4612 Single-lit-var/imm32/inouts -4613 Single-int-var-in-eax/imm32/outputs -4614 "35/xor-with-eax"/imm32/subx-name -4615 0/imm32/no-rm32 -4616 0/imm32/no-r32 -4617 1/imm32/imm32-is-first-inout -4618 0/imm32/output-is-write-only -4619 _Primitive-xor-reg-with-reg/imm32/next -4620 _Primitive-xor-reg-with-reg: -4621 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 -4622 "xor"/imm32/name -4623 Single-int-var-in-some-register/imm32/inouts -4624 Single-int-var-in-some-register/imm32/outputs -4625 "31/xor-with"/imm32/subx-name -4626 3/imm32/rm32-is-first-output -4627 1/imm32/r32-is-first-inout -4628 0/imm32/no-imm32 -4629 0/imm32/output-is-write-only -4630 _Primitive-xor-reg-with-mem/imm32/next -4631 _Primitive-xor-reg-with-mem: -4632 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 -4633 "xor-with"/imm32/name -4634 Int-var-and-second-int-var-in-some-register/imm32/inouts -4635 0/imm32/outputs -4636 "31/xor-with"/imm32/subx-name -4637 1/imm32/rm32-is-first-inout -4638 2/imm32/r32-is-second-inout -4639 0/imm32/no-imm32 -4640 0/imm32/output-is-write-only -4641 _Primitive-xor-mem-with-reg/imm32/next -4642 _Primitive-xor-mem-with-reg: -4643 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 -4644 "xor"/imm32/name -4645 Single-int-var-on-stack/imm32/inouts -4646 Single-int-var-in-some-register/imm32/outputs -4647 "33/xor"/imm32/subx-name -4648 1/imm32/rm32-is-first-inout -4649 3/imm32/r32-is-first-output -4650 0/imm32/no-imm32 -4651 0/imm32/output-is-write-only -4652 _Primitive-xor-lit-with-reg/imm32/next -4653 _Primitive-xor-lit-with-reg: -4654 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 -4655 "xor"/imm32/name -4656 Single-lit-var/imm32/inouts -4657 Single-int-var-in-some-register/imm32/outputs -4658 "81 4/subop/xor"/imm32/subx-name -4659 3/imm32/rm32-is-first-output -4660 0/imm32/no-r32 -4661 1/imm32/imm32-is-first-inout -4662 0/imm32/output-is-write-only -4663 _Primitive-xor-lit-with-mem/imm32/next -4664 _Primitive-xor-lit-with-mem: -4665 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 -4666 "xor-with"/imm32/name -4667 Int-var-and-literal/imm32/inouts -4668 0/imm32/outputs -4669 "81 4/subop/xor"/imm32/subx-name -4670 1/imm32/rm32-is-first-inout -4671 0/imm32/no-r32 -4672 2/imm32/imm32-is-first-inout -4673 0/imm32/output-is-write-only -4674 _Primitive-copy-to-eax/imm32/next -4675 # - copy -4676 _Primitive-copy-to-eax: -4677 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 -4678 "copy"/imm32/name -4679 Single-lit-var/imm32/inouts -4680 Single-int-var-in-eax/imm32/outputs -4681 "b8/copy-to-eax"/imm32/subx-name -4682 0/imm32/no-rm32 -4683 0/imm32/no-r32 -4684 1/imm32/imm32-is-first-inout -4685 1/imm32/output-is-write-only -4686 _Primitive-copy-to-ecx/imm32/next -4687 _Primitive-copy-to-ecx: -4688 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 -4689 "copy"/imm32/name -4690 Single-lit-var/imm32/inouts -4691 Single-int-var-in-ecx/imm32/outputs -4692 "b9/copy-to-ecx"/imm32/subx-name -4693 0/imm32/no-rm32 -4694 0/imm32/no-r32 -4695 1/imm32/imm32-is-first-inout -4696 1/imm32/output-is-write-only -4697 _Primitive-copy-to-edx/imm32/next -4698 _Primitive-copy-to-edx: -4699 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 -4700 "copy"/imm32/name -4701 Single-lit-var/imm32/inouts -4702 Single-int-var-in-edx/imm32/outputs -4703 "ba/copy-to-edx"/imm32/subx-name -4704 0/imm32/no-rm32 -4705 0/imm32/no-r32 -4706 1/imm32/imm32-is-first-inout -4707 1/imm32/output-is-write-only -4708 _Primitive-copy-to-ebx/imm32/next -4709 _Primitive-copy-to-ebx: -4710 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 -4711 "copy"/imm32/name -4712 Single-lit-var/imm32/inouts -4713 Single-int-var-in-ebx/imm32/outputs -4714 "bb/copy-to-ebx"/imm32/subx-name -4715 0/imm32/no-rm32 -4716 0/imm32/no-r32 -4717 1/imm32/imm32-is-first-inout -4718 1/imm32/output-is-write-only -4719 _Primitive-copy-to-esi/imm32/next -4720 _Primitive-copy-to-esi: -4721 # var/esi <- copy lit => be/copy-to-esi lit/imm32 -4722 "copy"/imm32/name -4723 Single-lit-var/imm32/inouts -4724 Single-int-var-in-esi/imm32/outputs -4725 "be/copy-to-esi"/imm32/subx-name -4726 0/imm32/no-rm32 -4727 0/imm32/no-r32 -4728 1/imm32/imm32-is-first-inout -4729 1/imm32/output-is-write-only -4730 _Primitive-copy-to-edi/imm32/next -4731 _Primitive-copy-to-edi: -4732 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 -4733 "copy"/imm32/name -4734 Single-lit-var/imm32/inouts -4735 Single-int-var-in-edi/imm32/outputs -4736 "bf/copy-to-edi"/imm32/subx-name -4737 0/imm32/no-rm32 -4738 0/imm32/no-r32 -4739 1/imm32/imm32-is-first-inout -4740 1/imm32/output-is-write-only -4741 _Primitive-copy-reg-to-reg/imm32/next -4742 _Primitive-copy-reg-to-reg: -4743 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 -4744 "copy"/imm32/name -4745 Single-int-var-in-some-register/imm32/inouts -4746 Single-int-var-in-some-register/imm32/outputs -4747 "89/copy-to"/imm32/subx-name -4748 3/imm32/rm32-is-first-output -4749 1/imm32/r32-is-first-inout -4750 0/imm32/no-imm32 -4751 1/imm32/output-is-write-only -4752 _Primitive-copy-reg-to-mem/imm32/next -4753 _Primitive-copy-reg-to-mem: -4754 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 -4755 "copy-to"/imm32/name -4756 Int-var-and-second-int-var-in-some-register/imm32/inouts -4757 0/imm32/outputs -4758 "89/copy-to"/imm32/subx-name -4759 1/imm32/rm32-is-first-inout -4760 2/imm32/r32-is-second-inout -4761 0/imm32/no-imm32 -4762 1/imm32/output-is-write-only -4763 _Primitive-copy-mem-to-reg/imm32/next -4764 _Primitive-copy-mem-to-reg: -4765 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 -4766 "copy"/imm32/name -4767 Single-int-var-on-stack/imm32/inouts -4768 Single-int-var-in-some-register/imm32/outputs -4769 "8b/copy-from"/imm32/subx-name -4770 1/imm32/rm32-is-first-inout -4771 3/imm32/r32-is-first-output -4772 0/imm32/no-imm32 -4773 1/imm32/output-is-write-only -4774 _Primitive-copy-lit-to-reg/imm32/next -4775 _Primitive-copy-lit-to-reg: -4776 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 -4777 "copy"/imm32/name -4778 Single-lit-var/imm32/inouts -4779 Single-int-var-in-some-register/imm32/outputs -4780 "c7 0/subop/copy"/imm32/subx-name -4781 3/imm32/rm32-is-first-output -4782 0/imm32/no-r32 -4783 1/imm32/imm32-is-first-inout -4784 1/imm32/output-is-write-only -4785 _Primitive-copy-lit-to-mem/imm32/next -4786 _Primitive-copy-lit-to-mem: -4787 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 -4788 "copy-to"/imm32/name -4789 Int-var-and-literal/imm32/inouts -4790 0/imm32/outputs -4791 "c7 0/subop/copy"/imm32/subx-name -4792 1/imm32/rm32-is-first-inout -4793 0/imm32/no-r32 -4794 2/imm32/imm32-is-first-inout -4795 1/imm32/output-is-write-only -4796 0/imm32/next -4797 -4798 Single-int-var-on-stack: -4799 Int-var-on-stack/imm32 -4800 0/imm32/next -4801 -4802 Int-var-on-stack: -4803 "arg1"/imm32/name -4804 Type-int/imm32 -4805 1/imm32/some-block-depth -4806 1/imm32/some-stack-offset -4807 0/imm32/no-register -4808 -4809 Int-var-and-second-int-var-in-some-register: -4810 Int-var-on-stack/imm32 -4811 Single-int-var-in-some-register/imm32/next -4812 -4813 Int-var-and-literal: -4814 Int-var-on-stack/imm32 -4815 Single-lit-var/imm32/next -4816 -4817 Single-int-var-in-some-register: -4818 Int-var-in-some-register/imm32 -4819 0/imm32/next -4820 -4821 Int-var-in-some-register: -4822 "arg1"/imm32/name -4823 Type-int/imm32 -4824 1/imm32/some-block-depth -4825 0/imm32/no-stack-offset -4826 "*"/imm32/register -4827 -4828 Single-int-var-in-eax: -4829 Int-var-in-eax/imm32 -4830 0/imm32/next -4831 -4832 Int-var-in-eax: -4833 "arg1"/imm32/name -4834 Type-int/imm32 -4835 1/imm32/some-block-depth -4836 0/imm32/no-stack-offset -4837 "eax"/imm32/register -4838 -4839 Single-int-var-in-ecx: -4840 Int-var-in-ecx/imm32 -4841 0/imm32/next -4842 -4843 Int-var-in-ecx: -4844 "arg1"/imm32/name -4845 Type-int/imm32 -4846 1/imm32/some-block-depth -4847 0/imm32/no-stack-offset -4848 "ecx"/imm32/register -4849 -4850 Single-int-var-in-edx: -4851 Int-var-in-edx/imm32 -4852 0/imm32/next -4853 -4854 Int-var-in-edx: -4855 "arg1"/imm32/name -4856 Type-int/imm32 -4857 1/imm32/some-block-depth -4858 0/imm32/no-stack-offset -4859 "edx"/imm32/register -4860 -4861 Single-int-var-in-ebx: -4862 Int-var-in-ebx/imm32 -4863 0/imm32/next -4864 -4865 Int-var-in-ebx: -4866 "arg1"/imm32/name -4867 Type-int/imm32 -4868 1/imm32/some-block-depth -4869 0/imm32/no-stack-offset -4870 "ebx"/imm32/register -4871 -4872 Single-int-var-in-esi: -4873 Int-var-in-esi/imm32 -4874 0/imm32/next -4875 -4876 Int-var-in-esi: -4877 "arg1"/imm32/name -4878 Type-int/imm32 -4879 1/imm32/some-block-depth -4880 0/imm32/no-stack-offset -4881 "esi"/imm32/register -4882 -4883 Single-int-var-in-edi: -4884 Int-var-in-edi/imm32 -4885 0/imm32/next -4886 -4887 Int-var-in-edi: -4888 "arg1"/imm32/name -4889 Type-int/imm32 -4890 1/imm32/some-block-depth -4891 0/imm32/no-stack-offset -4892 "edi"/imm32/register -4893 -4894 Single-lit-var: -4895 Lit-var/imm32 -4896 0/imm32/next -4897 -4898 Lit-var: -4899 "literal"/imm32/name -4900 Type-literal/imm32 -4901 1/imm32/some-block-depth -4902 0/imm32/no-stack-offset -4903 0/imm32/no-register -4904 -4905 Type-int: -4906 1/imm32/left/int -4907 0/imm32/right/null -4908 -4909 Type-literal: -4910 0/imm32/left/literal -4911 0/imm32/right/null -4912 -4913 == code -4914 emit-subx-primitive: # out: (addr buffered-file), stmt: (handle statement), primitive: (handle function) -4915 # . prologue -4916 55/push-ebp -4917 89/<- %ebp 4/r32/esp -4918 # . save registers -4919 50/push-eax -4920 51/push-ecx -4921 # ecx = primitive -4922 8b/-> *(ebp+0x10) 1/r32/ecx -4923 # emit primitive name -4924 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name -4925 # emit rm32 if necessary -4926 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt -4927 # emit r32 if necessary -4928 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt -4929 # emit imm32 if necessary -4930 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt -4931 $emit-subx-primitive:end: -4932 # . restore registers -4933 59/pop-to-ecx -4934 58/pop-to-eax -4935 # . epilogue -4936 89/<- %esp 5/r32/ebp -4937 5d/pop-to-ebp -4938 c3/return -4939 -4940 emit-subx-rm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) -4941 # . prologue -4942 55/push-ebp -4943 89/<- %ebp 4/r32/esp -4944 # . save registers -4945 50/push-eax -4946 # if (l == 0) return -4947 81 7/subop/compare *(ebp+0xc) 0/imm32 -4948 74/jump-if-= $emit-subx-rm32:end/disp8 -4949 # -4950 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4951 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var -4952 $emit-subx-rm32:end: -4953 # . restore registers -4954 58/pop-to-eax -4955 # . epilogue -4956 89/<- %esp 5/r32/ebp -4957 5d/pop-to-ebp -4958 c3/return -4959 -4960 get-stmt-operand-from-arg-location: # stmt: (handle statement), l: arg-location -> var/eax: (handle variable) -4961 # . prologue -4962 55/push-ebp -4963 89/<- %ebp 4/r32/esp -4964 # . save registers -4965 51/push-ecx -4966 # eax = l -4967 8b/-> *(ebp+0xc) 0/r32/eax -4968 # ecx = stmt -4969 8b/-> *(ebp+8) 1/r32/ecx -4970 # if (l == 1) return stmt->inouts->var -4971 { -4972 3d/compare-eax-and 1/imm32 -4973 75/jump-if-!= break/disp8 -4974 $get-stmt-operand-from-arg-location:1: -4975 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -4976 8b/-> *eax 0/r32/eax # Operand-var -4977 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4978 } -4979 # if (l == 2) return stmt->inouts->next->var -4980 { -4981 3d/compare-eax-and 2/imm32 -4982 75/jump-if-!= break/disp8 -4983 $get-stmt-operand-from-arg-location:2: -4984 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -4985 8b/-> *(eax+4) 0/r32/eax # Operand-next -4986 8b/-> *eax 0/r32/eax # Operand-var -4987 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4988 } -4989 # if (l == 3) return stmt->outputs -4990 { -4991 3d/compare-eax-and 3/imm32 -4992 75/jump-if-!= break/disp8 -4993 $get-stmt-operand-from-arg-location:3: -4994 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs -4995 8b/-> *eax 0/r32/eax # Operand-var -4996 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4997 } -4998 # abort -4999 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 -5000 $get-stmt-operand-from-arg-location:end: -5001 # . restore registers -5002 59/pop-to-ecx -5003 # . epilogue -5004 89/<- %esp 5/r32/ebp -5005 5d/pop-to-ebp -5006 c3/return -5007 -5008 $get-stmt-operand-from-arg-location:abort: -5009 # error("invalid arg-location " eax) -5010 (write-buffered Stderr "invalid arg-location ") -5011 (print-int32-buffered Stderr %eax) -5012 (write-buffered Stderr Newline) -5013 (flush Stderr) -5014 # . syscall(exit, 1) -5015 bb/copy-to-ebx 1/imm32 -5016 b8/copy-to-eax 1/imm32/exit -5017 cd/syscall 0x80/imm8 -5018 # never gets here +3432 75/jump-if-!= break/disp8 +3433 (lookup-var %esi *(ebp+0xc)) # => eax +3434 } +3435 $lookup-var-or-literal:end: +3436 # . restore registers +3437 5e/pop-to-esi +3438 59/pop-to-ecx +3439 # . epilogue +3440 89/<- %esp 5/r32/ebp +3441 5d/pop-to-ebp +3442 c3/return +3443 +3444 $lookup-var-or-literal:abort: +3445 (write-buffered Stderr "empty variable!") +3446 (flush Stderr) +3447 # . syscall(exit, 1) +3448 bb/copy-to-ebx 1/imm32 +3449 b8/copy-to-eax 1/imm32/exit +3450 cd/syscall 0x80/imm8 +3451 # never gets here +3452 +3453 # return first 'name' from the top (back) of 'vars' and abort if not found +3454 lookup-var: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) +3455 # . prologue +3456 55/push-ebp +3457 89/<- %ebp 4/r32/esp +3458 # var target/eax: (handle array byte) = slice-to-string(name) +3459 (slice-to-string Heap *(ebp+8)) # => eax +3460 # +3461 (lookup-var-helper %eax *(ebp+0xc)) # => eax +3462 # if (result == 0) abort +3463 3d/compare-eax-and 0/imm32 +3464 74/jump-if-= $lookup-var:abort/disp8 +3465 $lookup-var:end: +3466 # . epilogue +3467 89/<- %esp 5/r32/ebp +3468 5d/pop-to-ebp +3469 c3/return +3470 +3471 $lookup-var:abort: +3472 (write-buffered Stderr "unknown variable '") +3473 (write-slice-buffered Stderr *(ebp+8)) +3474 (write-buffered Stderr "'\n") +3475 (flush Stderr) +3476 # . syscall(exit, 1) +3477 bb/copy-to-ebx 1/imm32 +3478 b8/copy-to-eax 1/imm32/exit +3479 cd/syscall 0x80/imm8 +3480 # never gets here +3481 +3482 # return first 'name' from the top (back) of 'vars', and 0/null if not found +3483 lookup-var-helper: # name: (addr array byte), vars: (addr stack (handle var)) -> result/eax: (handle var) +3484 # pseudocode: +3485 # var curr: (addr handle var) = &vars->data[vars->top - 4] +3486 # var min = vars->data +3487 # while curr >= min +3488 # var v: (handle var) = *curr +3489 # if v->name == name +3490 # return v +3491 # return 0 +3492 # +3493 # . prologue +3494 55/push-ebp +3495 89/<- %ebp 4/r32/esp +3496 # . save registers +3497 52/push-edx +3498 53/push-ebx +3499 56/push-esi +3500 # esi = vars +3501 8b/-> *(ebp+0xc) 6/r32/esi +3502 # ebx = vars->top +3503 8b/-> *esi 3/r32/ebx +3504 # if (vars->top > vars->length) abort +3505 3b/compare 0/r32/eax *(esi+4) +3506 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 +3507 # var min/edx: (addr handle var) = vars->data +3508 8d/copy-address *(esi+8) 2/r32/edx +3509 # var curr/ebx: (addr handle var) = &vars->data[vars->top - 4] +3510 81 5/subop/subtract %ebx 4/imm32 +3511 8d/copy-address *(esi+ebx+8) 3/r32/ebx +3512 { +3513 # if (curr < min) return 0 +3514 39/compare %ebx 2/r32/edx +3515 b8/copy-to-eax 0/imm32 +3516 0f 82/jump-if-addr< break/disp32 +3517 # var v/eax: (handle var) = *curr +3518 8b/-> *ebx 0/r32/eax +3519 # if (v->name == name) return v +3520 (string-equal? *eax *(ebp+8)) # Var-name +3521 3d/compare-eax-and 0/imm32 +3522 8b/-> *ebx 0/r32/eax +3523 75/jump-if-!= break/disp8 +3524 # curr -= 4 +3525 81 5/subop/subtract %ebx 4/imm32 +3526 e9/jump loop/disp32 +3527 } +3528 $lookup-var-helper:end: +3529 # . restore registers +3530 5e/pop-to-esi +3531 5b/pop-to-ebx +3532 5a/pop-to-edx +3533 # . epilogue +3534 89/<- %esp 5/r32/ebp +3535 5d/pop-to-ebp +3536 c3/return +3537 +3538 $lookup-var-helper:error1: +3539 (write-buffered Stderr "malformed stack when looking up '") +3540 (write-slice-buffered Stderr *(ebp+8)) +3541 (write-buffered Stderr "'\n") +3542 (flush Stderr) +3543 # . syscall(exit, 1) +3544 bb/copy-to-ebx 1/imm32 +3545 b8/copy-to-eax 1/imm32/exit +3546 cd/syscall 0x80/imm8 +3547 # never gets here +3548 +3549 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found +3550 lookup-or-define-var: # name: (addr slice), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle var) +3551 # . prologue +3552 55/push-ebp +3553 89/<- %ebp 4/r32/esp +3554 # . save registers +3555 51/push-ecx +3556 # var target/ecx: (handle array byte) = slice-to-string(name) +3557 (slice-to-string Heap *(ebp+8)) # => eax +3558 89/<- %ecx 0/r32/eax +3559 # +3560 (lookup-var-helper %ecx *(ebp+0xc)) # => eax +3561 { +3562 # if (result != 0) return +3563 3d/compare-eax-and 0/imm32 +3564 75/jump-if-!= break/disp8 +3565 # if name is one of fn's outputs, return it +3566 { +3567 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax +3568 3d/compare-eax-and 0/imm32 +3569 # otherwise abort +3570 0f 84/jump-if-!= $lookup-var:abort/disp32 +3571 } +3572 } +3573 $lookup-or-define-var:end: +3574 # . restore registers +3575 59/pop-to-ecx +3576 # . epilogue +3577 89/<- %esp 5/r32/ebp +3578 5d/pop-to-ebp +3579 c3/return +3580 +3581 find-in-function-outputs: # fn: (handle function), name: (handle array byte) => result/eax: (handle var) +3582 # . prologue +3583 55/push-ebp +3584 89/<- %ebp 4/r32/esp +3585 # . save registers +3586 51/push-ecx +3587 # var curr/ecx: (handle list var) = fn->outputs +3588 8b/-> *(ebp+8) 1/r32/ecx +3589 8b/-> *(ecx+0xc) 1/r32/ecx +3590 # while curr != null +3591 { +3592 81 7/subop/compare %ecx 0/imm32 +3593 74/jump-if-= break/disp8 +3594 # var v: (handle var) = *curr +3595 8b/-> *ecx 0/r32/eax # List-value +3596 # if (curr->name == name) return curr +3597 50/push-eax +3598 (string-equal? *eax *(ebp+0xc)) +3599 3d/compare-eax-and 0/imm32 +3600 58/pop-to-eax +3601 75/jump-if-!= $find-in-function-outputs:end/disp8 +3602 # curr = curr->next +3603 8b/-> *(ecx+4) 1/r32/ecx # List-next +3604 eb/jump loop/disp8 +3605 } +3606 b8/copy-to-eax 0/imm32 +3607 $find-in-function-outputs:end: +3608 # . restore registers +3609 59/pop-to-ecx +3610 # . epilogue +3611 89/<- %esp 5/r32/ebp +3612 5d/pop-to-ebp +3613 c3/return +3614 +3615 test-parse-mu-stmt: +3616 # 'increment n' +3617 # . prologue +3618 55/push-ebp +3619 89/<- %ebp 4/r32/esp +3620 # setup +3621 (clear-stream _test-input-stream) +3622 (write _test-input-stream "increment n\n") +3623 # var vars/ecx: (stack (addr var) 4) +3624 81 5/subop/subtract %esp 0x10/imm32 +3625 68/push 0x10/imm32/length +3626 68/push 0/imm32/top +3627 89/<- %ecx 4/r32/esp +3628 (clear-stack %ecx) +3629 # var v/edx: var +3630 81 5/subop/subtract %esp 0x14/imm32 # Var-size +3631 89/<- %edx 4/r32/esp +3632 (zero-out %edx 0x14) +3633 # v->name = "n" +3634 c7 0/subop/copy *edx "n"/imm32 # Var-name +3635 # +3636 (push %ecx %edx) +3637 # convert +3638 (parse-mu-stmt _test-input-stream %ecx) # => eax +3639 # check result +3640 (check-ints-equal *eax 1 "F - test-parse-mu-stmt/tag") # Stmt-tag is Stmt1 +3641 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation +3642 # edx: (handle list var) = result->inouts +3643 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts +3644 # ebx: (handle var) = result->inouts->value +3645 8b/-> *edx 3/r32/ebx # List-value +3646 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name +3647 # . epilogue +3648 89/<- %esp 5/r32/ebp +3649 5d/pop-to-ebp +3650 c3/return +3651 +3652 test-parse-mu-stmt-with-comma: +3653 # 'increment n' +3654 # . prologue +3655 55/push-ebp +3656 89/<- %ebp 4/r32/esp +3657 # setup +3658 (clear-stream _test-input-stream) +3659 (write _test-input-stream "copy-to n, 3\n") +3660 # var vars/ecx: (stack (addr var) 4) +3661 81 5/subop/subtract %esp 0x10/imm32 +3662 68/push 0x10/imm32/length +3663 68/push 0/imm32/top +3664 89/<- %ecx 4/r32/esp +3665 (clear-stack %ecx) +3666 # var v/edx: var +3667 81 5/subop/subtract %esp 0x14/imm32 # Var-size +3668 89/<- %edx 4/r32/esp +3669 (zero-out %edx 0x14) +3670 # v->name = "n" +3671 c7 0/subop/copy *edx "n"/imm32 # Var-name +3672 # +3673 (push %ecx %edx) +3674 # convert +3675 (parse-mu-stmt _test-input-stream %ecx) # => eax +3676 # check result +3677 (check-ints-equal *eax 1 "F - test-parse-mu-stmt-with-comma/tag") # Stmt-tag is Stmt1 +3678 (check-strings-equal *(eax+4) "copy-to" "F - test-parse-mu-stmt-with-comma/name") # Stmt1-operation +3679 # edx: (handle list var) = result->inouts +3680 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts +3681 # ebx: (handle var) = result->inouts->value +3682 8b/-> *edx 3/r32/ebx # List-value +3683 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt-with-comma/inout:0") # Var-name +3684 # . epilogue +3685 89/<- %esp 5/r32/ebp +3686 5d/pop-to-ebp +3687 c3/return +3688 +3689 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) +3690 # . prologue +3691 55/push-ebp +3692 89/<- %ebp 4/r32/esp +3693 # . save registers +3694 51/push-ecx +3695 # +3696 (allocate *(ebp+8) *Function-size) # => eax +3697 8b/-> *(ebp+0xc) 1/r32/ecx +3698 89/<- *eax 1/r32/ecx # Function-name +3699 8b/-> *(ebp+0x10) 1/r32/ecx +3700 89/<- *(eax+4) 1/r32/ecx # Function-subx-name +3701 8b/-> *(ebp+0x14) 1/r32/ecx +3702 89/<- *(eax+8) 1/r32/ecx # Function-inouts +3703 8b/-> *(ebp+0x18) 1/r32/ecx +3704 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs +3705 8b/-> *(ebp+0x1c) 1/r32/ecx +3706 89/<- *(eax+0x10) 1/r32/ecx # Function-body +3707 8b/-> *(ebp+0x20) 1/r32/ecx +3708 89/<- *(eax+0x14) 1/r32/ecx # Function-next +3709 $new-function:end: +3710 # . restore registers +3711 59/pop-to-ecx +3712 # . epilogue +3713 89/<- %esp 5/r32/ebp +3714 5d/pop-to-ebp +3715 c3/return +3716 +3717 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) +3718 # . prologue +3719 55/push-ebp +3720 89/<- %ebp 4/r32/esp +3721 # . save registers +3722 51/push-ecx +3723 # +3724 (allocate *(ebp+8) *Var-size) # => eax +3725 8b/-> *(ebp+0xc) 1/r32/ecx +3726 89/<- *eax 1/r32/ecx # Var-name +3727 8b/-> *(ebp+0x10) 1/r32/ecx +3728 89/<- *(eax+4) 1/r32/ecx # Var-type +3729 8b/-> *(ebp+0x14) 1/r32/ecx +3730 89/<- *(eax+8) 1/r32/ecx # Var-block +3731 8b/-> *(ebp+0x18) 1/r32/ecx +3732 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset +3733 8b/-> *(ebp+0x1c) 1/r32/ecx +3734 89/<- *(eax+0x10) 1/r32/ecx # Var-register +3735 $new-var:end: +3736 # . restore registers +3737 59/pop-to-ecx +3738 # . epilogue +3739 89/<- %esp 5/r32/ebp +3740 5d/pop-to-ebp +3741 c3/return +3742 +3743 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) +3744 # . prologue +3745 55/push-ebp +3746 89/<- %ebp 4/r32/esp +3747 # . save registers +3748 51/push-ecx +3749 # if (!is-hex-int?(name)) abort +3750 (is-hex-int? *(ebp+0xc)) # => eax +3751 3d/compare-eax-and 0/imm32 +3752 0f 84/jump-if-= $new-literal-integer:abort/disp32 +3753 # var s/ecx: (addr array byte) +3754 (slice-to-string Heap *(ebp+0xc)) # => eax +3755 89/<- %ecx 0/r32/eax +3756 # +3757 (allocate *(ebp+8) *Var-size) # => eax +3758 89/<- *eax 1/r32/ecx # Var-name +3759 89/<- %ecx 0/r32/eax +3760 (allocate *(ebp+8) *Tree-size) # => eax +3761 89/<- *(ecx+4) 0/r32/eax # Var-type +3762 89/<- %eax 1/r32/ecx +3763 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block +3764 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset +3765 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register +3766 $new-literal-integer:end: +3767 # . restore registers +3768 59/pop-to-ecx +3769 # . epilogue +3770 89/<- %esp 5/r32/ebp +3771 5d/pop-to-ebp +3772 c3/return +3773 +3774 $new-literal-integer:abort: +3775 (write-buffered Stderr "variable cannot begin with a digit '") +3776 (write-slice-buffered Stderr *(ebp+0xc)) +3777 (write-buffered Stderr "'\n") +3778 (flush Stderr) +3779 # . syscall(exit, 1) +3780 bb/copy-to-ebx 1/imm32 +3781 b8/copy-to-eax 1/imm32/exit +3782 cd/syscall 0x80/imm8 +3783 # never gets here +3784 +3785 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) +3786 # . prologue +3787 55/push-ebp +3788 89/<- %ebp 4/r32/esp +3789 # . save registers +3790 51/push-ecx +3791 # +3792 (allocate *(ebp+8) *Stmt-size) # => eax +3793 (zero-out %eax *Stmt-size) +3794 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag +3795 8b/-> *(ebp+0xc) 1/r32/ecx +3796 89/<- *(eax+4) 1/r32/ecx # Block-statements +3797 $new-block:end: +3798 # . restore registers +3799 59/pop-to-ecx +3800 # . epilogue +3801 89/<- %esp 5/r32/ebp +3802 5d/pop-to-ebp +3803 c3/return +3804 +3805 new-vardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) +3806 # . prologue +3807 55/push-ebp +3808 89/<- %ebp 4/r32/esp +3809 # . save registers +3810 51/push-ecx +3811 # +3812 (allocate *(ebp+8) *Stmt-size) # => eax +3813 (zero-out %eax *Stmt-size) +3814 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag +3815 # result->var = var +3816 8b/-> *(ebp+0xc) 1/r32/ecx +3817 89/<- *(eax+4) 1/r32/ecx # Vardef-var +3818 $new-vardef:end: +3819 # . restore registers +3820 59/pop-to-ecx +3821 # . epilogue +3822 89/<- %esp 5/r32/ebp +3823 5d/pop-to-ebp +3824 c3/return +3825 +3826 new-regvardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) +3827 # . prologue +3828 55/push-ebp +3829 89/<- %ebp 4/r32/esp +3830 # . save registers +3831 51/push-ecx +3832 57/push-edi +3833 # ecx = var +3834 8b/-> *(ebp+0xc) 1/r32/ecx +3835 # edi = result +3836 (allocate *(ebp+8) *Stmt-size) # => eax +3837 89/<- %edi 0/r32/eax +3838 (zero-out %edi *Stmt-size) +3839 # set tag +3840 c7 0/subop/copy *edi 3/imm32/tag/var-in-register # Stmt-tag +3841 # set output +3842 (append-list Heap %ecx *(edi+0xc)) # Regvardef-outputs => eax +3843 89/<- *(edi+0xc) 0/r32/eax # Regvardef-outputs +3844 $new-regvardef:end: +3845 89/<- %eax 7/r32/edi +3846 # . restore registers +3847 5f/pop-to-edi +3848 59/pop-to-ecx +3849 # . epilogue +3850 89/<- %esp 5/r32/ebp +3851 5d/pop-to-ebp +3852 c3/return +3853 +3854 new-named-block: # ad: (addr allocation-descriptor), name: (addr array byte), data: (handle list statement) -> result/eax: (handle statement) +3855 # . prologue +3856 55/push-ebp +3857 89/<- %ebp 4/r32/esp +3858 # . save registers +3859 51/push-ecx +3860 # +3861 (allocate *(ebp+8) *Stmt-size) # => eax +3862 (zero-out %eax *Stmt-size) +3863 c7 0/subop/copy *eax 4/imm32/tag/named-block +3864 8b/-> *(ebp+0xc) 1/r32/ecx +3865 89/<- *(eax+8) 1/r32/ecx # Named-block-name +3866 8b/-> *(ebp+0x10) 1/r32/ecx +3867 89/<- *(eax+4) 1/r32/ecx # Named-block-statements +3868 $new-named-block:end: +3869 # . restore registers +3870 59/pop-to-ecx +3871 # . epilogue +3872 89/<- %esp 5/r32/ebp +3873 5d/pop-to-ebp +3874 c3/return +3875 +3876 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax: (handle list _type) +3877 # . prologue +3878 55/push-ebp +3879 89/<- %ebp 4/r32/esp +3880 # . save registers +3881 51/push-ecx +3882 # +3883 (allocate *(ebp+8) *List-size) # => eax +3884 8b/-> *(ebp+0xc) 1/r32/ecx +3885 89/<- *eax 1/r32/ecx # List-value +3886 8b/-> *(ebp+0x10) 1/r32/ecx +3887 89/<- *(eax+4) 1/r32/ecx # List-next +3888 $new-list:end: +3889 # . restore registers +3890 59/pop-to-ecx +3891 # . epilogue +3892 89/<- %esp 5/r32/ebp +3893 5d/pop-to-ebp +3894 c3/return +3895 +3896 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax: (handle list _type) +3897 # . prologue +3898 55/push-ebp +3899 89/<- %ebp 4/r32/esp +3900 # . save registers +3901 51/push-ecx +3902 # +3903 (allocate *(ebp+8) *List-size) # => eax +3904 8b/-> *(ebp+0xc) 1/r32/ecx +3905 89/<- *eax 1/r32/ecx # List-value +3906 # if (list == null) return result +3907 81 7/subop/compare *(ebp+0x10) 0/imm32 +3908 74/jump-if-= $new-list:end/disp8 +3909 # otherwise append +3910 # var curr/ecx = list +3911 8b/-> *(ebp+0x10) 1/r32/ecx +3912 # while (curr->next != null) curr = curr->next +3913 { +3914 81 7/subop/compare *(ecx+4) 0/imm32 # List-next +3915 74/jump-if-= break/disp8 +3916 # curr = curr->next +3917 8b/-> *(ecx+4) 1/r32/ecx +3918 eb/jump loop/disp8 +3919 } +3920 # curr->next = result +3921 89/<- *(ecx+4) 0/r32/eax +3922 # return list +3923 8b/-> *(ebp+0x10) 0/r32/eax +3924 $append-list:end: +3925 # . restore registers +3926 59/pop-to-ecx +3927 # . epilogue +3928 89/<- %esp 5/r32/ebp +3929 5d/pop-to-ebp +3930 c3/return +3931 +3932 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) +3933 # . prologue +3934 55/push-ebp +3935 89/<- %ebp 4/r32/esp +3936 # . save registers +3937 56/push-esi +3938 # esi = block +3939 8b/-> *(ebp+0xc) 6/r32/esi +3940 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements +3941 89/<- *(esi+4) 0/r32/eax # Block-statements +3942 $append-to-block:end: +3943 # . restore registers +3944 5e/pop-to-esi +3945 # . epilogue +3946 89/<- %esp 5/r32/ebp +3947 5d/pop-to-ebp +3948 c3/return +3949 +3950 ####################################################### +3951 # Type-checking +3952 ####################################################### +3953 +3954 check-mu-types: +3955 # . prologue +3956 55/push-ebp +3957 89/<- %ebp 4/r32/esp +3958 # +3959 $check-mu-types:end: +3960 # . epilogue +3961 89/<- %esp 5/r32/ebp +3962 5d/pop-to-ebp +3963 c3/return +3964 +3965 size-of: # n: (addr var) -> result/eax: int +3966 # . prologue +3967 55/push-ebp +3968 89/<- %ebp 4/r32/esp +3969 # hard-coded since we only support 'int' types for now +3970 b8/copy-to-eax 4/imm32 +3971 $size-of:end: +3972 # . epilogue +3973 89/<- %esp 5/r32/ebp +3974 5d/pop-to-ebp +3975 c3/return +3976 +3977 == data +3978 +3979 # not yet used, but it will be +3980 Type-size: # (stream int) +3981 0x18/imm32/write +3982 0/imm32/read +3983 0x100/imm32/length +3984 # data +3985 4/imm32 # literal +3986 4/imm32 # int +3987 4/imm32 # addr +3988 0/imm32 # array (logic elsewhere) +3989 8/imm32 # handle (fat pointer) +3990 4/imm32 # bool +3991 0/imm32 +3992 0/imm32 +3993 # 0x20 +3994 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3995 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3996 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3997 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3998 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +3999 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +4000 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +4001 +4002 == code +4003 +4004 ####################################################### +4005 # Code-generation +4006 ####################################################### +4007 +4008 emit-subx: # out: (addr buffered-file) +4009 # . prologue +4010 55/push-ebp +4011 89/<- %ebp 4/r32/esp +4012 # . save registers +4013 50/push-eax +4014 51/push-ecx +4015 57/push-edi +4016 # edi = out +4017 8b/-> *(ebp+8) 7/r32/edi +4018 # var curr/ecx: (handle function) = *Program +4019 8b/-> *Program 1/r32/ecx +4020 { +4021 # if (curr == null) break +4022 81 7/subop/compare %ecx 0/imm32 +4023 0f 84/jump-if-= break/disp32 +4024 (emit-subx-function %edi %ecx) +4025 # curr = curr->next +4026 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +4027 e9/jump loop/disp32 +4028 } +4029 $emit-subx:end: +4030 # . restore registers +4031 5f/pop-to-edi +4032 59/pop-to-ecx +4033 58/pop-to-eax +4034 # . epilogue +4035 89/<- %esp 5/r32/ebp +4036 5d/pop-to-ebp +4037 c3/return +4038 +4039 emit-subx-function: # out: (addr buffered-file), f: (handle function) +4040 # . prologue +4041 55/push-ebp +4042 89/<- %ebp 4/r32/esp +4043 # . save registers +4044 50/push-eax +4045 51/push-ecx +4046 52/push-edx +4047 57/push-edi +4048 # edi = out +4049 8b/-> *(ebp+8) 7/r32/edi +4050 # ecx = f +4051 8b/-> *(ebp+0xc) 1/r32/ecx +4052 # var vars/edx: (stack (addr var) 256) +4053 81 5/subop/subtract %esp 0x400/imm32 +4054 68/push 0x400/imm32/length +4055 68/push 0/imm32/top +4056 89/<- %edx 4/r32/esp +4057 # +4058 (write-buffered %edi *ecx) +4059 (write-buffered %edi ":\n") +4060 (emit-subx-prologue %edi) +4061 (emit-subx-block %edi *(ecx+0x10) %edx) # Function-body +4062 (emit-subx-epilogue %edi) +4063 $emit-subx-function:end: +4064 # . reclaim locals +4065 81 0/subop/add %esp 408/imm32 +4066 # . restore registers +4067 5f/pop-to-edi +4068 5a/pop-to-edx +4069 59/pop-to-ecx +4070 58/pop-to-eax +4071 # . epilogue +4072 89/<- %esp 5/r32/ebp +4073 5d/pop-to-ebp +4074 c3/return +4075 +4076 emit-subx-block: # out: (addr buffered-file), block: (handle block), vars: (addr stack (handle var)) +4077 # . prologue +4078 55/push-ebp +4079 89/<- %ebp 4/r32/esp +4080 # . save registers +4081 56/push-esi +4082 # var stmts/esi: (handle list statement) = block->statements +4083 8b/-> *(ebp+0xc) 6/r32/esi +4084 8b/-> *(esi+4) 6/r32/esi # Block-statements +4085 # +4086 { +4087 $emit-subx-block:check-empty: +4088 81 7/subop/compare %esi 0/imm32 +4089 0f 84/jump-if-= break/disp32 +4090 (write-buffered *(ebp+8) "{\n") +4091 (emit-subx-stmt-list *(ebp+8) %esi *(ebp+0x10)) +4092 (write-buffered *(ebp+8) "}\n") +4093 } +4094 $emit-subx-block:end: +4095 # . restore registers +4096 5e/pop-to-esi +4097 # . epilogue +4098 89/<- %esp 5/r32/ebp +4099 5d/pop-to-ebp +4100 c3/return +4101 +4102 emit-subx-stmt-list: # out: (addr buffered-file), stmts: (handle list stmt), vars: (addr stack (handle var)) +4103 # . prologue +4104 55/push-ebp +4105 89/<- %ebp 4/r32/esp +4106 # . save registers +4107 50/push-eax +4108 51/push-ecx +4109 56/push-esi +4110 # esi = stmts +4111 8b/-> *(ebp+0xc) 6/r32/esi +4112 # +4113 { +4114 $emit-subx-stmt-list:loop: +4115 81 7/subop/compare %esi 0/imm32 +4116 0f 84/jump-if-= break/disp32 +4117 # var curr-stmt/ecx = stmts->value +4118 8b/-> *esi 1/r32/ecx # List-value +4119 { +4120 $emit-subx-stmt-list:check-for-block: +4121 81 7/subop/compare *ecx 0/imm32/block # Stmt-tag +4122 75/jump-if-!= break/disp8 +4123 $emit-subx-stmt-list:block: +4124 (emit-subx-block *(ebp+8) %ecx *(ebp+0x10)) +4125 } +4126 { +4127 $emit-subx-stmt-list:check-for-stmt: +4128 81 7/subop/compare *ecx 1/imm32/stmt1 # Stmt-tag +4129 75/jump-if-!= break/disp8 +4130 $emit-subx-stmt-list:stmt: +4131 (emit-subx-statement *(ebp+8) %ecx Primitives *Program) +4132 } +4133 { +4134 $emit-subx-stmt-list:check-for-vardef: +4135 81 7/subop/compare *ecx 2/imm32/vardef # Stmt-tag +4136 75/jump-if-!= break/disp8 +4137 $emit-subx-stmt-list:vardef: +4138 (emit-subx-var-def *(ebp+8) %ecx) +4139 (push *(ebp+0x10) *(ecx+4)) # Vardef-var +4140 } +4141 { +4142 $emit-subx-stmt-list:check-for-regvardef: +4143 81 7/subop/compare *ecx 3/imm32/regvardef # Stmt-tag +4144 0f 85/jump-if-!= break/disp32 +4145 $emit-subx-stmt-list:regvardef: +4146 # TODO: ensure that there's exactly one output +4147 # var output/eax: (handle var) = curr-stmt->outputs->value +4148 8b/-> *(ecx+0xc) 0/r32/eax +4149 8b/-> *eax 0/r32/eax +4150 # ensure that output is in a register +4151 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +4152 0f 84/jump-if-equal $emit-subx-stmt-list:abort-regvardef-without-register/disp32 +4153 # emit spill +4154 (write-buffered *(ebp+8) "ff 6/subop/push %") +4155 (write-buffered *(ebp+8) *(eax+0x10)) +4156 (write-buffered *(ebp+8) Newline) +4157 # register variable definition +4158 (push *(ebp+0x10) %eax) +4159 # emit the instruction as usual +4160 (emit-subx-statement *(ebp+8) %ecx Primitives *Program) +4161 } +4162 { +4163 $emit-subx-stmt-list:check-for-named-block: +4164 81 7/subop/compare *ecx 4/imm32/named-block # Stmt-tag +4165 75/jump-if-!= break/disp8 +4166 $emit-subx-stmt-list:named-block: +4167 (emit-subx-named-block *(ebp+8) %ecx *(ebp+0x10)) +4168 } +4169 8b/-> *(esi+4) 6/r32/esi # List-next +4170 e9/jump loop/disp32 +4171 } +4172 # reclaim locals +4173 # TODO: support nested blocks; take block-ids into account +4174 { +4175 $emit-subx-stmt-list:reclaim-loop: +4176 8b/-> *(ebp+0x10) 0/r32/eax +4177 81 7/subop/compare *eax 0/imm32 # Stack-top +4178 0f 84/jump-if-= break/disp32 +4179 # var v/ecx : (handle var) = top(vars) +4180 (top %eax) # => eax +4181 89/<- %ecx 0/r32/eax +4182 # if v is in a register +4183 81 7/subop/compare *(ecx+0x10) 0/imm32 # Var-register +4184 { +4185 74/jump-if-= break/disp8 +4186 $emit-subx-stmt-list:reclaim-var-in-register: +4187 (write-buffered *(ebp+8) "8f 0/subop/pop %") +4188 (write-buffered *(ebp+8) *(ecx+0x10)) +4189 (write-buffered *(ebp+8) Newline) +4190 } +4191 # if v is on the stack +4192 { +4193 75/jump-if-!= break/disp8 +4194 $emit-subx-stmt-list:reclaim-var-on-stack: +4195 (size-of %ecx) # => eax +4196 01/add *Next-local-stack-offset 0/r32/eax +4197 (write-buffered *(ebp+8) "81 0/subop/add %esp ") +4198 (print-int32-buffered *(ebp+8) %eax) +4199 (write-buffered *(ebp+8) "/imm32\n") +4200 } +4201 # +4202 (pop *(ebp+0x10)) +4203 e9/jump loop/disp32 +4204 } +4205 $emit-subx-stmt-list:end: +4206 # . restore registers +4207 5e/pop-to-esi +4208 59/pop-to-ecx +4209 58/pop-to-eax +4210 # . epilogue +4211 89/<- %esp 5/r32/ebp +4212 5d/pop-to-ebp +4213 c3/return +4214 +4215 $emit-subx-stmt-list:abort-regvardef-without-register: +4216 # error("var '" var->name "' initialized from an instruction must live in a register\n") +4217 (write-buffered Stderr "var '") +4218 (write-buffered Stderr *eax) # Var-name +4219 (write-buffered Stderr "' initialized from an instruction must live in a register\n") +4220 (flush Stderr) +4221 # . syscall(exit, 1) +4222 bb/copy-to-ebx 1/imm32 +4223 b8/copy-to-eax 1/imm32/exit +4224 cd/syscall 0x80/imm8 +4225 # never gets here +4226 +4227 emit-subx-var-def: # out: (addr buffered-file), stmt: (handle statement) +4228 # . prologue +4229 55/push-ebp +4230 89/<- %ebp 4/r32/esp +4231 # . save registers +4232 50/push-eax +4233 51/push-ecx +4234 # eax = stmt +4235 8b/-> *(ebp+0xc) 0/r32/eax +4236 # var n/eax: int = size-of(stmt->var) +4237 (size-of *(eax+4)) # Vardef-var => eax +4238 # while n > 0 +4239 { +4240 3d/compare-eax-with 0/imm32 +4241 7e/jump-if-<= break/disp8 +4242 (write-buffered *(ebp+8) "68/push 0/imm32\n") +4243 # n -= 4 +4244 2d/subtract-from-eax 4/imm32 +4245 # +4246 eb/jump loop/disp8 +4247 } +4248 $emit-subx-var-def:end: +4249 # . restore registers +4250 59/pop-to-ecx +4251 58/pop-to-eax +4252 # . epilogue +4253 89/<- %esp 5/r32/ebp +4254 5d/pop-to-ebp +4255 c3/return +4256 +4257 emit-subx-statement: # out: (addr buffered-file), stmt: (handle statement), primitives: (handle primitive), functions: (handle function) +4258 # . prologue +4259 55/push-ebp +4260 89/<- %ebp 4/r32/esp +4261 # . save registers +4262 50/push-eax +4263 51/push-ecx +4264 # if stmt matches a primitive, emit it +4265 { +4266 $emit-subx-statement:primitive: +4267 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax +4268 3d/compare-eax-and 0/imm32 +4269 74/jump-if-= break/disp8 +4270 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +4271 e9/jump $emit-subx-statement:end/disp32 +4272 } +4273 # else if stmt matches a function, emit a call to it +4274 { +4275 $emit-subx-statement:call: +4276 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax +4277 3d/compare-eax-and 0/imm32 +4278 74/jump-if-= break/disp8 +4279 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +4280 e9/jump $emit-subx-statement:end/disp32 +4281 } +4282 # else abort +4283 e9/jump $emit-subx-statement:abort/disp32 +4284 $emit-subx-statement:end: +4285 # . restore registers +4286 59/pop-to-ecx +4287 58/pop-to-eax +4288 # . epilogue +4289 89/<- %esp 5/r32/ebp +4290 5d/pop-to-ebp +4291 c3/return +4292 +4293 $emit-subx-statement:abort: +4294 # error("couldn't translate '" stmt "'\n") +4295 (write-buffered Stderr "couldn't translate '") +4296 #? (emit-string Stderr *(ebp+0xc)) # TODO +4297 (write-buffered Stderr "'\n") +4298 (flush Stderr) +4299 # . syscall(exit, 1) +4300 bb/copy-to-ebx 1/imm32 +4301 b8/copy-to-eax 1/imm32/exit +4302 cd/syscall 0x80/imm8 +4303 # never gets here +4304 +4305 emit-subx-named-block: # out: (addr buffered-file), named-block: (handle named-block), vars: (addr stack (handle var)) +4306 # . prologue +4307 55/push-ebp +4308 89/<- %ebp 4/r32/esp +4309 # . save registers +4310 50/push-eax +4311 51/push-ecx +4312 56/push-esi +4313 # esi = block +4314 8b/-> *(ebp+0xc) 6/r32/esi +4315 # var stmts/ecx: (handle list statement) = block->statements +4316 8b/-> *(esi+4) 0/r32/eax # Block-statements +4317 # +4318 { +4319 $emit-subx-named-block:check-empty: +4320 81 7/subop/compare %eax 0/imm32 +4321 0f 84/jump-if-= break/disp32 +4322 (write-buffered *(ebp+8) "{\n") +4323 (write-buffered *(ebp+8) *(esi+8)) # Named-block-name +4324 (write-buffered *(ebp+8) "loop:\n") +4325 (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10)) +4326 (write-buffered *(ebp+8) "}\n") +4327 (write-buffered *(ebp+8) *(esi+8)) # Named-block-name +4328 (write-buffered *(ebp+8) "break:\n") +4329 } +4330 $emit-subx-named-block:end: +4331 # . restore registers +4332 5e/pop-to-esi +4333 59/pop-to-ecx +4334 58/pop-to-eax +4335 # . epilogue +4336 89/<- %esp 5/r32/ebp +4337 5d/pop-to-ebp +4338 c3/return +4339 +4340 # Primitives supported +4341 # For each operation, put variants with hard-coded registers before flexible ones. +4342 == data +4343 Primitives: +4344 # - increment/decrement +4345 _Primitive-inc-eax: +4346 # var/eax <- increment => 40/increment-eax +4347 "increment"/imm32/name +4348 0/imm32/no-inouts +4349 Single-int-var-in-eax/imm32/outputs +4350 "40/increment-eax"/imm32/subx-name +4351 0/imm32/no-rm32 +4352 0/imm32/no-r32 +4353 0/imm32/no-imm32 +4354 0/imm32/output-is-write-only +4355 _Primitive-inc-ecx/imm32/next +4356 _Primitive-inc-ecx: +4357 # var/ecx <- increment => 41/increment-ecx +4358 "increment"/imm32/name +4359 0/imm32/no-inouts +4360 Single-int-var-in-ecx/imm32/outputs +4361 "41/increment-ecx"/imm32/subx-name +4362 0/imm32/no-rm32 +4363 0/imm32/no-r32 +4364 0/imm32/no-imm32 +4365 0/imm32/output-is-write-only +4366 _Primitive-inc-edx/imm32/next +4367 _Primitive-inc-edx: +4368 # var/edx <- increment => 42/increment-edx +4369 "increment"/imm32/name +4370 0/imm32/no-inouts +4371 Single-int-var-in-edx/imm32/outputs +4372 "42/increment-edx"/imm32/subx-name +4373 0/imm32/no-rm32 +4374 0/imm32/no-r32 +4375 0/imm32/no-imm32 +4376 0/imm32/output-is-write-only +4377 _Primitive-inc-ebx/imm32/next +4378 _Primitive-inc-ebx: +4379 # var/ebx <- increment => 43/increment-ebx +4380 "increment"/imm32/name +4381 0/imm32/no-inouts +4382 Single-int-var-in-ebx/imm32/outputs +4383 "43/increment-ebx"/imm32/subx-name +4384 0/imm32/no-rm32 +4385 0/imm32/no-r32 +4386 0/imm32/no-imm32 +4387 0/imm32/output-is-write-only +4388 _Primitive-inc-esi/imm32/next +4389 _Primitive-inc-esi: +4390 # var/esi <- increment => 46/increment-esi +4391 "increment"/imm32/name +4392 0/imm32/no-inouts +4393 Single-int-var-in-esi/imm32/outputs +4394 "46/increment-esi"/imm32/subx-name +4395 0/imm32/no-rm32 +4396 0/imm32/no-r32 +4397 0/imm32/no-imm32 +4398 0/imm32/output-is-write-only +4399 _Primitive-inc-edi/imm32/next +4400 _Primitive-inc-edi: +4401 # var/edi <- increment => 47/increment-edi +4402 "increment"/imm32/name +4403 0/imm32/no-inouts +4404 Single-int-var-in-edi/imm32/outputs +4405 "47/increment-edi"/imm32/subx-name +4406 0/imm32/no-rm32 +4407 0/imm32/no-r32 +4408 0/imm32/no-imm32 +4409 0/imm32/output-is-write-only +4410 _Primitive-dec-eax/imm32/next +4411 _Primitive-dec-eax: +4412 # var/eax <- decrement => 48/decrement-eax +4413 "decrement"/imm32/name +4414 0/imm32/no-inouts +4415 Single-int-var-in-eax/imm32/outputs +4416 "48/decrement-eax"/imm32/subx-name +4417 0/imm32/no-rm32 +4418 0/imm32/no-r32 +4419 0/imm32/no-imm32 +4420 0/imm32/output-is-write-only +4421 _Primitive-dec-ecx/imm32/next +4422 _Primitive-dec-ecx: +4423 # var/ecx <- decrement => 49/decrement-ecx +4424 "decrement"/imm32/name +4425 0/imm32/no-inouts +4426 Single-int-var-in-ecx/imm32/outputs +4427 "49/decrement-ecx"/imm32/subx-name +4428 0/imm32/no-rm32 +4429 0/imm32/no-r32 +4430 0/imm32/no-imm32 +4431 0/imm32/output-is-write-only +4432 _Primitive-dec-edx/imm32/next +4433 _Primitive-dec-edx: +4434 # var/edx <- decrement => 4a/decrement-edx +4435 "decrement"/imm32/name +4436 0/imm32/no-inouts +4437 Single-int-var-in-edx/imm32/outputs +4438 "4a/decrement-edx"/imm32/subx-name +4439 0/imm32/no-rm32 +4440 0/imm32/no-r32 +4441 0/imm32/no-imm32 +4442 0/imm32/output-is-write-only +4443 _Primitive-dec-ebx/imm32/next +4444 _Primitive-dec-ebx: +4445 # var/ebx <- decrement => 4b/decrement-ebx +4446 "decrement"/imm32/name +4447 0/imm32/no-inouts +4448 Single-int-var-in-ebx/imm32/outputs +4449 "4b/decrement-ebx"/imm32/subx-name +4450 0/imm32/no-rm32 +4451 0/imm32/no-r32 +4452 0/imm32/no-imm32 +4453 0/imm32/output-is-write-only +4454 _Primitive-dec-esi/imm32/next +4455 _Primitive-dec-esi: +4456 # var/esi <- decrement => 4e/decrement-esi +4457 "decrement"/imm32/name +4458 0/imm32/no-inouts +4459 Single-int-var-in-esi/imm32/outputs +4460 "4e/decrement-esi"/imm32/subx-name +4461 0/imm32/no-rm32 +4462 0/imm32/no-r32 +4463 0/imm32/no-imm32 +4464 0/imm32/output-is-write-only +4465 _Primitive-dec-edi/imm32/next +4466 _Primitive-dec-edi: +4467 # var/edi <- decrement => 4f/decrement-edi +4468 "decrement"/imm32/name +4469 0/imm32/no-inouts +4470 Single-int-var-in-edi/imm32/outputs +4471 "4f/decrement-edi"/imm32/subx-name +4472 0/imm32/no-rm32 +4473 0/imm32/no-r32 +4474 0/imm32/no-imm32 +4475 0/imm32/output-is-write-only +4476 _Primitive-inc-mem/imm32/next +4477 _Primitive-inc-mem: +4478 # increment var => ff 0/subop/increment *(ebp+__) +4479 "increment"/imm32/name +4480 Single-int-var-on-stack/imm32/inouts +4481 0/imm32/no-outputs +4482 "ff 0/subop/increment"/imm32/subx-name +4483 1/imm32/rm32-is-first-inout +4484 0/imm32/no-r32 +4485 0/imm32/no-imm32 +4486 0/imm32/output-is-write-only +4487 _Primitive-inc-reg/imm32/next +4488 _Primitive-inc-reg: +4489 # var/reg <- increment => ff 0/subop/increment %__ +4490 "increment"/imm32/name +4491 0/imm32/no-inouts +4492 Single-int-var-in-some-register/imm32/outputs +4493 "ff 0/subop/increment"/imm32/subx-name +4494 3/imm32/rm32-is-first-output +4495 0/imm32/no-r32 +4496 0/imm32/no-imm32 +4497 0/imm32/output-is-write-only +4498 _Primitive-dec-mem/imm32/next +4499 _Primitive-dec-mem: +4500 # decrement var => ff 1/subop/decrement *(ebp+__) +4501 "decrement"/imm32/name +4502 Single-int-var-on-stack/imm32/inouts +4503 0/imm32/no-outputs +4504 "ff 1/subop/decrement"/imm32/subx-name +4505 1/imm32/rm32-is-first-inout +4506 0/imm32/no-r32 +4507 0/imm32/no-imm32 +4508 0/imm32/output-is-write-only +4509 _Primitive-dec-reg/imm32/next +4510 _Primitive-dec-reg: +4511 # var/reg <- decrement => ff 1/subop/decrement %__ +4512 "decrement"/imm32/name +4513 0/imm32/no-inouts +4514 Single-int-var-in-some-register/imm32/outputs +4515 "ff 1/subop/decrement"/imm32/subx-name +4516 3/imm32/rm32-is-first-output +4517 0/imm32/no-r32 +4518 0/imm32/no-imm32 +4519 0/imm32/output-is-write-only +4520 _Primitive-add-to-eax/imm32/next +4521 # - add +4522 _Primitive-add-to-eax: +4523 # var/eax <- add lit => 05/add-to-eax lit/imm32 +4524 "add"/imm32/name +4525 Single-lit-var/imm32/inouts +4526 Single-int-var-in-eax/imm32/outputs +4527 "05/add-to-eax"/imm32/subx-name +4528 0/imm32/no-rm32 +4529 0/imm32/no-r32 +4530 1/imm32/imm32-is-first-inout +4531 0/imm32/output-is-write-only +4532 _Primitive-add-reg-to-reg/imm32/next +4533 _Primitive-add-reg-to-reg: +4534 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 +4535 "add"/imm32/name +4536 Single-int-var-in-some-register/imm32/inouts +4537 Single-int-var-in-some-register/imm32/outputs +4538 "01/add-to"/imm32/subx-name +4539 3/imm32/rm32-is-first-output +4540 1/imm32/r32-is-first-inout +4541 0/imm32/no-imm32 +4542 0/imm32/output-is-write-only +4543 _Primitive-add-reg-to-mem/imm32/next +4544 _Primitive-add-reg-to-mem: +4545 # add-to var1 var2/reg => 01/add-to var1 var2/r32 +4546 "add-to"/imm32/name +4547 Int-var-and-second-int-var-in-some-register/imm32/inouts +4548 0/imm32/outputs +4549 "01/add-to"/imm32/subx-name +4550 1/imm32/rm32-is-first-inout +4551 2/imm32/r32-is-second-inout +4552 0/imm32/no-imm32 +4553 0/imm32/output-is-write-only +4554 _Primitive-add-mem-to-reg/imm32/next +4555 _Primitive-add-mem-to-reg: +4556 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 +4557 "add"/imm32/name +4558 Single-int-var-on-stack/imm32/inouts +4559 Single-int-var-in-some-register/imm32/outputs +4560 "03/add"/imm32/subx-name +4561 1/imm32/rm32-is-first-inout +4562 3/imm32/r32-is-first-output +4563 0/imm32/no-imm32 +4564 0/imm32/output-is-write-only +4565 _Primitive-add-lit-to-reg/imm32/next +4566 _Primitive-add-lit-to-reg: +4567 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 +4568 "add"/imm32/name +4569 Single-lit-var/imm32/inouts +4570 Single-int-var-in-some-register/imm32/outputs +4571 "81 0/subop/add"/imm32/subx-name +4572 3/imm32/rm32-is-first-output +4573 0/imm32/no-r32 +4574 1/imm32/imm32-is-first-inout +4575 0/imm32/output-is-write-only +4576 _Primitive-add-lit-to-mem/imm32/next +4577 _Primitive-add-lit-to-mem: +4578 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 +4579 "add-to"/imm32/name +4580 Int-var-and-literal/imm32/inouts +4581 0/imm32/outputs +4582 "81 0/subop/add"/imm32/subx-name +4583 1/imm32/rm32-is-first-inout +4584 0/imm32/no-r32 +4585 2/imm32/imm32-is-first-inout +4586 0/imm32/output-is-write-only +4587 _Primitive-subtract-from-eax/imm32/next +4588 # - subtract +4589 _Primitive-subtract-from-eax: +4590 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 +4591 "subtract"/imm32/name +4592 Single-lit-var/imm32/inouts +4593 Single-int-var-in-eax/imm32/outputs +4594 "2d/subtract-from-eax"/imm32/subx-name +4595 0/imm32/no-rm32 +4596 0/imm32/no-r32 +4597 1/imm32/imm32-is-first-inout +4598 0/imm32/output-is-write-only +4599 _Primitive-subtract-reg-from-reg/imm32/next +4600 _Primitive-subtract-reg-from-reg: +4601 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 +4602 "subtract"/imm32/name +4603 Single-int-var-in-some-register/imm32/inouts +4604 Single-int-var-in-some-register/imm32/outputs +4605 "29/subtract-from"/imm32/subx-name +4606 3/imm32/rm32-is-first-output +4607 1/imm32/r32-is-first-inout +4608 0/imm32/no-imm32 +4609 0/imm32/output-is-write-only +4610 _Primitive-subtract-reg-from-mem/imm32/next +4611 _Primitive-subtract-reg-from-mem: +4612 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 +4613 "subtract-from"/imm32/name +4614 Int-var-and-second-int-var-in-some-register/imm32/inouts +4615 0/imm32/outputs +4616 "29/subtract-from"/imm32/subx-name +4617 1/imm32/rm32-is-first-inout +4618 2/imm32/r32-is-second-inout +4619 0/imm32/no-imm32 +4620 0/imm32/output-is-write-only +4621 _Primitive-subtract-mem-from-reg/imm32/next +4622 _Primitive-subtract-mem-from-reg: +4623 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 +4624 "subtract"/imm32/name +4625 Single-int-var-on-stack/imm32/inouts +4626 Single-int-var-in-some-register/imm32/outputs +4627 "2b/subtract"/imm32/subx-name +4628 1/imm32/rm32-is-first-inout +4629 3/imm32/r32-is-first-output +4630 0/imm32/no-imm32 +4631 0/imm32/output-is-write-only +4632 _Primitive-subtract-lit-from-reg/imm32/next +4633 _Primitive-subtract-lit-from-reg: +4634 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 +4635 "subtract"/imm32/name +4636 Single-lit-var/imm32/inouts +4637 Single-int-var-in-some-register/imm32/outputs +4638 "81 5/subop/subtract"/imm32/subx-name +4639 3/imm32/rm32-is-first-output +4640 0/imm32/no-r32 +4641 1/imm32/imm32-is-first-inout +4642 0/imm32/output-is-write-only +4643 _Primitive-subtract-lit-from-mem/imm32/next +4644 _Primitive-subtract-lit-from-mem: +4645 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 +4646 "subtract-from"/imm32/name +4647 Int-var-and-literal/imm32/inouts +4648 0/imm32/outputs +4649 "81 5/subop/subtract"/imm32/subx-name +4650 1/imm32/rm32-is-first-inout +4651 0/imm32/no-r32 +4652 2/imm32/imm32-is-first-inout +4653 0/imm32/output-is-write-only +4654 _Primitive-and-with-eax/imm32/next +4655 # - and +4656 _Primitive-and-with-eax: +4657 # var/eax <- and lit => 25/and-with-eax lit/imm32 +4658 "and"/imm32/name +4659 Single-lit-var/imm32/inouts +4660 Single-int-var-in-eax/imm32/outputs +4661 "25/and-with-eax"/imm32/subx-name +4662 0/imm32/no-rm32 +4663 0/imm32/no-r32 +4664 1/imm32/imm32-is-first-inout +4665 0/imm32/output-is-write-only +4666 _Primitive-and-reg-with-reg/imm32/next +4667 _Primitive-and-reg-with-reg: +4668 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 +4669 "and"/imm32/name +4670 Single-int-var-in-some-register/imm32/inouts +4671 Single-int-var-in-some-register/imm32/outputs +4672 "21/and-with"/imm32/subx-name +4673 3/imm32/rm32-is-first-output +4674 1/imm32/r32-is-first-inout +4675 0/imm32/no-imm32 +4676 0/imm32/output-is-write-only +4677 _Primitive-and-reg-with-mem/imm32/next +4678 _Primitive-and-reg-with-mem: +4679 # and-with var1 var2/reg => 21/and-with var1 var2/r32 +4680 "and-with"/imm32/name +4681 Int-var-and-second-int-var-in-some-register/imm32/inouts +4682 0/imm32/outputs +4683 "21/and-with"/imm32/subx-name +4684 1/imm32/rm32-is-first-inout +4685 2/imm32/r32-is-second-inout +4686 0/imm32/no-imm32 +4687 0/imm32/output-is-write-only +4688 _Primitive-and-mem-with-reg/imm32/next +4689 _Primitive-and-mem-with-reg: +4690 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 +4691 "and"/imm32/name +4692 Single-int-var-on-stack/imm32/inouts +4693 Single-int-var-in-some-register/imm32/outputs +4694 "23/and"/imm32/subx-name +4695 1/imm32/rm32-is-first-inout +4696 3/imm32/r32-is-first-output +4697 0/imm32/no-imm32 +4698 0/imm32/output-is-write-only +4699 _Primitive-and-lit-with-reg/imm32/next +4700 _Primitive-and-lit-with-reg: +4701 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 +4702 "and"/imm32/name +4703 Single-lit-var/imm32/inouts +4704 Single-int-var-in-some-register/imm32/outputs +4705 "81 4/subop/and"/imm32/subx-name +4706 3/imm32/rm32-is-first-output +4707 0/imm32/no-r32 +4708 1/imm32/imm32-is-first-inout +4709 0/imm32/output-is-write-only +4710 _Primitive-and-lit-with-mem/imm32/next +4711 _Primitive-and-lit-with-mem: +4712 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 +4713 "and-with"/imm32/name +4714 Int-var-and-literal/imm32/inouts +4715 0/imm32/outputs +4716 "81 4/subop/and"/imm32/subx-name +4717 1/imm32/rm32-is-first-inout +4718 0/imm32/no-r32 +4719 2/imm32/imm32-is-first-inout +4720 0/imm32/output-is-write-only +4721 _Primitive-or-with-eax/imm32/next +4722 # - or +4723 _Primitive-or-with-eax: +4724 # var/eax <- or lit => 0d/or-with-eax lit/imm32 +4725 "or"/imm32/name +4726 Single-lit-var/imm32/inouts +4727 Single-int-var-in-eax/imm32/outputs +4728 "0d/or-with-eax"/imm32/subx-name +4729 0/imm32/no-rm32 +4730 0/imm32/no-r32 +4731 1/imm32/imm32-is-first-inout +4732 0/imm32/output-is-write-only +4733 _Primitive-or-reg-with-reg/imm32/next +4734 _Primitive-or-reg-with-reg: +4735 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 +4736 "or"/imm32/name +4737 Single-int-var-in-some-register/imm32/inouts +4738 Single-int-var-in-some-register/imm32/outputs +4739 "09/or-with"/imm32/subx-name +4740 3/imm32/rm32-is-first-output +4741 1/imm32/r32-is-first-inout +4742 0/imm32/no-imm32 +4743 0/imm32/output-is-write-only +4744 _Primitive-or-reg-with-mem/imm32/next +4745 _Primitive-or-reg-with-mem: +4746 # or-with var1 var2/reg => 09/or-with var1 var2/r32 +4747 "or-with"/imm32/name +4748 Int-var-and-second-int-var-in-some-register/imm32/inouts +4749 0/imm32/outputs +4750 "09/or-with"/imm32/subx-name +4751 1/imm32/rm32-is-first-inout +4752 2/imm32/r32-is-second-inout +4753 0/imm32/no-imm32 +4754 0/imm32/output-is-write-only +4755 _Primitive-or-mem-with-reg/imm32/next +4756 _Primitive-or-mem-with-reg: +4757 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 +4758 "or"/imm32/name +4759 Single-int-var-on-stack/imm32/inouts +4760 Single-int-var-in-some-register/imm32/outputs +4761 "0b/or"/imm32/subx-name +4762 1/imm32/rm32-is-first-inout +4763 3/imm32/r32-is-first-output +4764 0/imm32/no-imm32 +4765 0/imm32/output-is-write-only +4766 _Primitive-or-lit-with-reg/imm32/next +4767 _Primitive-or-lit-with-reg: +4768 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 +4769 "or"/imm32/name +4770 Single-lit-var/imm32/inouts +4771 Single-int-var-in-some-register/imm32/outputs +4772 "81 4/subop/or"/imm32/subx-name +4773 3/imm32/rm32-is-first-output +4774 0/imm32/no-r32 +4775 1/imm32/imm32-is-first-inout +4776 0/imm32/output-is-write-only +4777 _Primitive-or-lit-with-mem/imm32/next +4778 _Primitive-or-lit-with-mem: +4779 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 +4780 "or-with"/imm32/name +4781 Int-var-and-literal/imm32/inouts +4782 0/imm32/outputs +4783 "81 4/subop/or"/imm32/subx-name +4784 1/imm32/rm32-is-first-inout +4785 0/imm32/no-r32 +4786 2/imm32/imm32-is-first-inout +4787 0/imm32/output-is-write-only +4788 _Primitive-xor-with-eax/imm32/next +4789 # - xor +4790 _Primitive-xor-with-eax: +4791 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 +4792 "xor"/imm32/name +4793 Single-lit-var/imm32/inouts +4794 Single-int-var-in-eax/imm32/outputs +4795 "35/xor-with-eax"/imm32/subx-name +4796 0/imm32/no-rm32 +4797 0/imm32/no-r32 +4798 1/imm32/imm32-is-first-inout +4799 0/imm32/output-is-write-only +4800 _Primitive-xor-reg-with-reg/imm32/next +4801 _Primitive-xor-reg-with-reg: +4802 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 +4803 "xor"/imm32/name +4804 Single-int-var-in-some-register/imm32/inouts +4805 Single-int-var-in-some-register/imm32/outputs +4806 "31/xor-with"/imm32/subx-name +4807 3/imm32/rm32-is-first-output +4808 1/imm32/r32-is-first-inout +4809 0/imm32/no-imm32 +4810 0/imm32/output-is-write-only +4811 _Primitive-xor-reg-with-mem/imm32/next +4812 _Primitive-xor-reg-with-mem: +4813 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 +4814 "xor-with"/imm32/name +4815 Int-var-and-second-int-var-in-some-register/imm32/inouts +4816 0/imm32/outputs +4817 "31/xor-with"/imm32/subx-name +4818 1/imm32/rm32-is-first-inout +4819 2/imm32/r32-is-second-inout +4820 0/imm32/no-imm32 +4821 0/imm32/output-is-write-only +4822 _Primitive-xor-mem-with-reg/imm32/next +4823 _Primitive-xor-mem-with-reg: +4824 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 +4825 "xor"/imm32/name +4826 Single-int-var-on-stack/imm32/inouts +4827 Single-int-var-in-some-register/imm32/outputs +4828 "33/xor"/imm32/subx-name +4829 1/imm32/rm32-is-first-inout +4830 3/imm32/r32-is-first-output +4831 0/imm32/no-imm32 +4832 0/imm32/output-is-write-only +4833 _Primitive-xor-lit-with-reg/imm32/next +4834 _Primitive-xor-lit-with-reg: +4835 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 +4836 "xor"/imm32/name +4837 Single-lit-var/imm32/inouts +4838 Single-int-var-in-some-register/imm32/outputs +4839 "81 4/subop/xor"/imm32/subx-name +4840 3/imm32/rm32-is-first-output +4841 0/imm32/no-r32 +4842 1/imm32/imm32-is-first-inout +4843 0/imm32/output-is-write-only +4844 _Primitive-xor-lit-with-mem/imm32/next +4845 _Primitive-xor-lit-with-mem: +4846 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 +4847 "xor-with"/imm32/name +4848 Int-var-and-literal/imm32/inouts +4849 0/imm32/outputs +4850 "81 4/subop/xor"/imm32/subx-name +4851 1/imm32/rm32-is-first-inout +4852 0/imm32/no-r32 +4853 2/imm32/imm32-is-first-inout +4854 0/imm32/output-is-write-only +4855 _Primitive-copy-to-eax/imm32/next +4856 # - copy +4857 _Primitive-copy-to-eax: +4858 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 +4859 "copy"/imm32/name +4860 Single-lit-var/imm32/inouts +4861 Single-int-var-in-eax/imm32/outputs +4862 "b8/copy-to-eax"/imm32/subx-name +4863 0/imm32/no-rm32 +4864 0/imm32/no-r32 +4865 1/imm32/imm32-is-first-inout +4866 1/imm32/output-is-write-only +4867 _Primitive-copy-to-ecx/imm32/next +4868 _Primitive-copy-to-ecx: +4869 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 +4870 "copy"/imm32/name +4871 Single-lit-var/imm32/inouts +4872 Single-int-var-in-ecx/imm32/outputs +4873 "b9/copy-to-ecx"/imm32/subx-name +4874 0/imm32/no-rm32 +4875 0/imm32/no-r32 +4876 1/imm32/imm32-is-first-inout +4877 1/imm32/output-is-write-only +4878 _Primitive-copy-to-edx/imm32/next +4879 _Primitive-copy-to-edx: +4880 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 +4881 "copy"/imm32/name +4882 Single-lit-var/imm32/inouts +4883 Single-int-var-in-edx/imm32/outputs +4884 "ba/copy-to-edx"/imm32/subx-name +4885 0/imm32/no-rm32 +4886 0/imm32/no-r32 +4887 1/imm32/imm32-is-first-inout +4888 1/imm32/output-is-write-only +4889 _Primitive-copy-to-ebx/imm32/next +4890 _Primitive-copy-to-ebx: +4891 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 +4892 "copy"/imm32/name +4893 Single-lit-var/imm32/inouts +4894 Single-int-var-in-ebx/imm32/outputs +4895 "bb/copy-to-ebx"/imm32/subx-name +4896 0/imm32/no-rm32 +4897 0/imm32/no-r32 +4898 1/imm32/imm32-is-first-inout +4899 1/imm32/output-is-write-only +4900 _Primitive-copy-to-esi/imm32/next +4901 _Primitive-copy-to-esi: +4902 # var/esi <- copy lit => be/copy-to-esi lit/imm32 +4903 "copy"/imm32/name +4904 Single-lit-var/imm32/inouts +4905 Single-int-var-in-esi/imm32/outputs +4906 "be/copy-to-esi"/imm32/subx-name +4907 0/imm32/no-rm32 +4908 0/imm32/no-r32 +4909 1/imm32/imm32-is-first-inout +4910 1/imm32/output-is-write-only +4911 _Primitive-copy-to-edi/imm32/next +4912 _Primitive-copy-to-edi: +4913 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 +4914 "copy"/imm32/name +4915 Single-lit-var/imm32/inouts +4916 Single-int-var-in-edi/imm32/outputs +4917 "bf/copy-to-edi"/imm32/subx-name +4918 0/imm32/no-rm32 +4919 0/imm32/no-r32 +4920 1/imm32/imm32-is-first-inout +4921 1/imm32/output-is-write-only +4922 _Primitive-copy-reg-to-reg/imm32/next +4923 _Primitive-copy-reg-to-reg: +4924 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 +4925 "copy"/imm32/name +4926 Single-int-var-in-some-register/imm32/inouts +4927 Single-int-var-in-some-register/imm32/outputs +4928 "89/copy-to"/imm32/subx-name +4929 3/imm32/rm32-is-first-output +4930 1/imm32/r32-is-first-inout +4931 0/imm32/no-imm32 +4932 1/imm32/output-is-write-only +4933 _Primitive-copy-reg-to-mem/imm32/next +4934 _Primitive-copy-reg-to-mem: +4935 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 +4936 "copy-to"/imm32/name +4937 Int-var-and-second-int-var-in-some-register/imm32/inouts +4938 0/imm32/outputs +4939 "89/copy-to"/imm32/subx-name +4940 1/imm32/rm32-is-first-inout +4941 2/imm32/r32-is-second-inout +4942 0/imm32/no-imm32 +4943 1/imm32/output-is-write-only +4944 _Primitive-copy-mem-to-reg/imm32/next +4945 _Primitive-copy-mem-to-reg: +4946 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 +4947 "copy"/imm32/name +4948 Single-int-var-on-stack/imm32/inouts +4949 Single-int-var-in-some-register/imm32/outputs +4950 "8b/copy-from"/imm32/subx-name +4951 1/imm32/rm32-is-first-inout +4952 3/imm32/r32-is-first-output +4953 0/imm32/no-imm32 +4954 1/imm32/output-is-write-only +4955 _Primitive-copy-lit-to-reg/imm32/next +4956 _Primitive-copy-lit-to-reg: +4957 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 +4958 "copy"/imm32/name +4959 Single-lit-var/imm32/inouts +4960 Single-int-var-in-some-register/imm32/outputs +4961 "c7 0/subop/copy"/imm32/subx-name +4962 3/imm32/rm32-is-first-output +4963 0/imm32/no-r32 +4964 1/imm32/imm32-is-first-inout +4965 1/imm32/output-is-write-only +4966 _Primitive-copy-lit-to-mem/imm32/next +4967 _Primitive-copy-lit-to-mem: +4968 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 +4969 "copy-to"/imm32/name +4970 Int-var-and-literal/imm32/inouts +4971 0/imm32/outputs +4972 "c7 0/subop/copy"/imm32/subx-name +4973 1/imm32/rm32-is-first-inout +4974 0/imm32/no-r32 +4975 2/imm32/imm32-is-first-inout +4976 1/imm32/output-is-write-only +4977 0/imm32/next +4978 +4979 Single-int-var-on-stack: +4980 Int-var-on-stack/imm32 +4981 0/imm32/next +4982 +4983 Int-var-on-stack: +4984 "arg1"/imm32/name +4985 Type-int/imm32 +4986 1/imm32/some-block-depth +4987 1/imm32/some-stack-offset +4988 0/imm32/no-register +4989 +4990 Int-var-and-second-int-var-in-some-register: +4991 Int-var-on-stack/imm32 +4992 Single-int-var-in-some-register/imm32/next +4993 +4994 Int-var-and-literal: +4995 Int-var-on-stack/imm32 +4996 Single-lit-var/imm32/next +4997 +4998 Single-int-var-in-some-register: +4999 Int-var-in-some-register/imm32 +5000 0/imm32/next +5001 +5002 Int-var-in-some-register: +5003 "arg1"/imm32/name +5004 Type-int/imm32 +5005 1/imm32/some-block-depth +5006 0/imm32/no-stack-offset +5007 "*"/imm32/register +5008 +5009 Single-int-var-in-eax: +5010 Int-var-in-eax/imm32 +5011 0/imm32/next +5012 +5013 Int-var-in-eax: +5014 "arg1"/imm32/name +5015 Type-int/imm32 +5016 1/imm32/some-block-depth +5017 0/imm32/no-stack-offset +5018 "eax"/imm32/register 5019 -5020 emit-subx-r32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) -5021 # . prologue -5022 55/push-ebp -5023 89/<- %ebp 4/r32/esp -5024 # . save registers -5025 50/push-eax -5026 51/push-ecx -5027 # if (location == 0) return -5028 81 7/subop/compare *(ebp+0xc) 0/imm32 -5029 0f 84/jump-if-= $emit-subx-r32:end/disp32 -5030 # -5031 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -5032 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax: (addr register-index) -5033 (write-buffered *(ebp+8) Space) -5034 (print-int32-buffered *(ebp+8) *eax) -5035 (write-buffered *(ebp+8) "/r32") -5036 $emit-subx-r32:end: -5037 # . restore registers -5038 59/pop-to-ecx -5039 58/pop-to-eax -5040 # . epilogue -5041 89/<- %esp 5/r32/ebp -5042 5d/pop-to-ebp -5043 c3/return -5044 -5045 emit-subx-imm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) -5046 # . prologue -5047 55/push-ebp -5048 89/<- %ebp 4/r32/esp -5049 # . save registers -5050 50/push-eax -5051 51/push-ecx -5052 # if (location == 0) return -5053 81 7/subop/compare *(ebp+0xc) 0/imm32 -5054 74/jump-if-= $emit-subx-imm32:end/disp8 -5055 # -5056 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -5057 (write-buffered *(ebp+8) Space) -5058 (write-buffered *(ebp+8) *eax) # Var-name -5059 (write-buffered *(ebp+8) "/imm32") -5060 $emit-subx-imm32:end: -5061 # . restore registers -5062 59/pop-to-ecx -5063 58/pop-to-eax -5064 # . epilogue -5065 89/<- %esp 5/r32/ebp -5066 5d/pop-to-ebp -5067 c3/return -5068 -5069 emit-subx-call: # out: (addr buffered-file), stmt: (handle statement), callee: (handle function) -5070 # . prologue -5071 55/push-ebp -5072 89/<- %ebp 4/r32/esp -5073 # . save registers -5074 50/push-eax -5075 51/push-ecx -5076 # -5077 (write-buffered *(ebp+8) "(") -5078 # - emit function name -5079 8b/-> *(ebp+0x10) 1/r32/ecx -5080 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name -5081 # - emit arguments -5082 # var curr/ecx: (handle list var) = stmt->inouts -5083 8b/-> *(ebp+0xc) 1/r32/ecx -5084 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts -5085 { -5086 # if (curr == null) break -5087 81 7/subop/compare %ecx 0/imm32 -5088 74/jump-if-= break/disp8 -5089 # -5090 (emit-subx-call-operand *(ebp+8) *ecx) -5091 # curr = curr->next -5092 8b/-> *(ecx+4) 1/r32/ecx -5093 eb/jump loop/disp8 -5094 } -5095 # -5096 (write-buffered *(ebp+8) ")") -5097 $emit-subx-call:end: -5098 # . restore registers -5099 59/pop-to-ecx -5100 58/pop-to-eax -5101 # . epilogue -5102 89/<- %esp 5/r32/ebp -5103 5d/pop-to-ebp -5104 c3/return -5105 -5106 emit-subx-call-operand: # out: (addr buffered-file), operand: (handle variable) -5107 # shares code with emit-subx-var-as-rm32 -5108 # . prologue -5109 55/push-ebp -5110 89/<- %ebp 4/r32/esp -5111 # . save registers -5112 50/push-eax -5113 # eax = operand -5114 8b/-> *(ebp+0xc) 0/r32/eax -5115 # if (operand->register) emit "%__" -5116 { -5117 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -5118 74/jump-if-= break/disp8 -5119 $emit-subx-call-operand:register: -5120 (write-buffered *(ebp+8) " %") -5121 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -5122 e9/jump $emit-subx-call-operand:end/disp32 -5123 } -5124 # else if (operand->stack-offset) emit "*(ebp+__)" -5125 { -5126 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -5127 74/jump-if-= break/disp8 -5128 $emit-subx-call-operand:stack: -5129 (write-buffered *(ebp+8) Space) -5130 (write-buffered *(ebp+8) "*(ebp+") -5131 8b/-> *(ebp+0xc) 0/r32/eax -5132 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -5133 (write-buffered *(ebp+8) ")") -5134 e9/jump $emit-subx-call-operand:end/disp32 -5135 } -5136 # else if (operand->type == literal) emit "__" -5137 { -5138 50/push-eax -5139 8b/-> *(eax+4) 0/r32/eax # Var-type -5140 81 7/subop/compare *eax 0/imm32 # Tree-left -5141 58/pop-to-eax -5142 75/jump-if-!= break/disp8 -5143 $emit-subx-call-operand:literal: -5144 (write-buffered *(ebp+8) Space) -5145 (write-buffered *(ebp+8) *eax) -5146 } -5147 $emit-subx-call-operand:end: -5148 # . restore registers -5149 58/pop-to-eax -5150 # . epilogue -5151 89/<- %esp 5/r32/ebp -5152 5d/pop-to-ebp -5153 c3/return -5154 -5155 emit-subx-var-as-rm32: # out: (addr buffered-file), operand: (handle variable) -5156 # . prologue -5157 55/push-ebp -5158 89/<- %ebp 4/r32/esp -5159 # . save registers -5160 50/push-eax -5161 # eax = operand -5162 8b/-> *(ebp+0xc) 0/r32/eax -5163 # if (operand->register) emit "%__" -5164 { -5165 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -5166 74/jump-if-= break/disp8 -5167 $emit-subx-var-as-rm32:register: -5168 (write-buffered *(ebp+8) " %") -5169 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +5020 Single-int-var-in-ecx: +5021 Int-var-in-ecx/imm32 +5022 0/imm32/next +5023 +5024 Int-var-in-ecx: +5025 "arg1"/imm32/name +5026 Type-int/imm32 +5027 1/imm32/some-block-depth +5028 0/imm32/no-stack-offset +5029 "ecx"/imm32/register +5030 +5031 Single-int-var-in-edx: +5032 Int-var-in-edx/imm32 +5033 0/imm32/next +5034 +5035 Int-var-in-edx: +5036 "arg1"/imm32/name +5037 Type-int/imm32 +5038 1/imm32/some-block-depth +5039 0/imm32/no-stack-offset +5040 "edx"/imm32/register +5041 +5042 Single-int-var-in-ebx: +5043 Int-var-in-ebx/imm32 +5044 0/imm32/next +5045 +5046 Int-var-in-ebx: +5047 "arg1"/imm32/name +5048 Type-int/imm32 +5049 1/imm32/some-block-depth +5050 0/imm32/no-stack-offset +5051 "ebx"/imm32/register +5052 +5053 Single-int-var-in-esi: +5054 Int-var-in-esi/imm32 +5055 0/imm32/next +5056 +5057 Int-var-in-esi: +5058 "arg1"/imm32/name +5059 Type-int/imm32 +5060 1/imm32/some-block-depth +5061 0/imm32/no-stack-offset +5062 "esi"/imm32/register +5063 +5064 Single-int-var-in-edi: +5065 Int-var-in-edi/imm32 +5066 0/imm32/next +5067 +5068 Int-var-in-edi: +5069 "arg1"/imm32/name +5070 Type-int/imm32 +5071 1/imm32/some-block-depth +5072 0/imm32/no-stack-offset +5073 "edi"/imm32/register +5074 +5075 Single-lit-var: +5076 Lit-var/imm32 +5077 0/imm32/next +5078 +5079 Lit-var: +5080 "literal"/imm32/name +5081 Type-literal/imm32 +5082 1/imm32/some-block-depth +5083 0/imm32/no-stack-offset +5084 0/imm32/no-register +5085 +5086 Type-int: +5087 1/imm32/left/int +5088 0/imm32/right/null +5089 +5090 Type-literal: +5091 0/imm32/left/literal +5092 0/imm32/right/null +5093 +5094 == code +5095 emit-subx-primitive: # out: (addr buffered-file), stmt: (handle statement), primitive: (handle function) +5096 # . prologue +5097 55/push-ebp +5098 89/<- %ebp 4/r32/esp +5099 # . save registers +5100 50/push-eax +5101 51/push-ecx +5102 # ecx = primitive +5103 8b/-> *(ebp+0x10) 1/r32/ecx +5104 # emit primitive name +5105 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name +5106 # emit rm32 if necessary +5107 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt +5108 # emit r32 if necessary +5109 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt +5110 # emit imm32 if necessary +5111 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt +5112 (write-buffered *(ebp+8) Newline) +5113 $emit-subx-primitive:end: +5114 # . restore registers +5115 59/pop-to-ecx +5116 58/pop-to-eax +5117 # . epilogue +5118 89/<- %esp 5/r32/ebp +5119 5d/pop-to-ebp +5120 c3/return +5121 +5122 emit-subx-rm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) +5123 # . prologue +5124 55/push-ebp +5125 89/<- %ebp 4/r32/esp +5126 # . save registers +5127 50/push-eax +5128 # if (l == 0) return +5129 81 7/subop/compare *(ebp+0xc) 0/imm32 +5130 74/jump-if-= $emit-subx-rm32:end/disp8 +5131 # +5132 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +5133 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var +5134 $emit-subx-rm32:end: +5135 # . restore registers +5136 58/pop-to-eax +5137 # . epilogue +5138 89/<- %esp 5/r32/ebp +5139 5d/pop-to-ebp +5140 c3/return +5141 +5142 get-stmt-operand-from-arg-location: # stmt: (handle statement), l: arg-location -> var/eax: (handle variable) +5143 # . prologue +5144 55/push-ebp +5145 89/<- %ebp 4/r32/esp +5146 # . save registers +5147 51/push-ecx +5148 # eax = l +5149 8b/-> *(ebp+0xc) 0/r32/eax +5150 # ecx = stmt +5151 8b/-> *(ebp+8) 1/r32/ecx +5152 # if (l == 1) return stmt->inouts->var +5153 { +5154 3d/compare-eax-and 1/imm32 +5155 75/jump-if-!= break/disp8 +5156 $get-stmt-operand-from-arg-location:1: +5157 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +5158 8b/-> *eax 0/r32/eax # Operand-var +5159 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +5160 } +5161 # if (l == 2) return stmt->inouts->next->var +5162 { +5163 3d/compare-eax-and 2/imm32 +5164 75/jump-if-!= break/disp8 +5165 $get-stmt-operand-from-arg-location:2: +5166 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +5167 8b/-> *(eax+4) 0/r32/eax # Operand-next +5168 8b/-> *eax 0/r32/eax # Operand-var +5169 eb/jump $get-stmt-operand-from-arg-location:end/disp8 5170 } -5171 # else if (operand->stack-offset) emit "*(ebp+__)" +5171 # if (l == 3) return stmt->outputs 5172 { -5173 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -5174 74/jump-if-= break/disp8 -5175 $emit-subx-var-as-rm32:stack: -5176 (write-buffered *(ebp+8) Space) -5177 (write-buffered *(ebp+8) "*(ebp+") -5178 8b/-> *(ebp+0xc) 0/r32/eax -5179 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -5180 (write-buffered *(ebp+8) ")") -5181 } -5182 $emit-subx-var-as-rm32:end: +5173 3d/compare-eax-and 3/imm32 +5174 75/jump-if-!= break/disp8 +5175 $get-stmt-operand-from-arg-location:3: +5176 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs +5177 8b/-> *eax 0/r32/eax # Operand-var +5178 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +5179 } +5180 # abort +5181 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 +5182 $get-stmt-operand-from-arg-location:end: 5183 # . restore registers -5184 58/pop-to-eax +5184 59/pop-to-ecx 5185 # . epilogue 5186 89/<- %esp 5/r32/ebp 5187 5d/pop-to-ebp 5188 c3/return 5189 -5190 find-matching-function: # functions: (addr function), stmt: (handle statement) -> result/eax: (handle function) -5191 # . prologue -5192 55/push-ebp -5193 89/<- %ebp 4/r32/esp -5194 # . save registers -5195 51/push-ecx -5196 # var curr/ecx: (handle function) = functions -5197 8b/-> *(ebp+8) 1/r32/ecx -5198 { -5199 # if (curr == null) break -5200 81 7/subop/compare %ecx 0/imm32 -5201 74/jump-if-= break/disp8 -5202 # if match(stmt, curr) return curr -5203 { -5204 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax -5205 3d/compare-eax-and 0/imm32 -5206 74/jump-if-= break/disp8 -5207 89/<- %eax 1/r32/ecx -5208 eb/jump $find-matching-function:end/disp8 -5209 } -5210 # curr = curr->next -5211 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -5212 eb/jump loop/disp8 -5213 } -5214 # return null -5215 b8/copy-to-eax 0/imm32 -5216 $find-matching-function:end: -5217 # . restore registers -5218 59/pop-to-ecx -5219 # . epilogue -5220 89/<- %esp 5/r32/ebp -5221 5d/pop-to-ebp -5222 c3/return -5223 -5224 find-matching-primitive: # primitives: (handle primitive), stmt: (handle statement) -> result/eax: (handle primitive) -5225 # . prologue -5226 55/push-ebp -5227 89/<- %ebp 4/r32/esp -5228 # . save registers -5229 51/push-ecx -5230 # var curr/ecx: (handle primitive) = primitives -5231 8b/-> *(ebp+8) 1/r32/ecx -5232 { -5233 $find-matching-primitive:loop: -5234 # if (curr == null) break -5235 81 7/subop/compare %ecx 0/imm32 -5236 0f 84/jump-if-= break/disp32 -5237 #? (write-buffered Stderr "prim: ") -5238 #? (write-buffered Stderr *ecx) # Primitive-name -5239 #? (write-buffered Stderr " => ") -5240 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name -5241 #? (write-buffered Stderr Newline) -5242 #? (flush Stderr) -5243 # if match(curr, stmt) return curr -5244 { -5245 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax -5246 3d/compare-eax-and 0/imm32 -5247 74/jump-if-= break/disp8 -5248 89/<- %eax 1/r32/ecx -5249 eb/jump $find-matching-primitive:end/disp8 -5250 } -5251 $find-matching-primitive:next-primitive: -5252 # curr = curr->next -5253 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next -5254 e9/jump loop/disp32 -5255 } -5256 # return null -5257 b8/copy-to-eax 0/imm32 -5258 $find-matching-primitive:end: -5259 # . restore registers -5260 59/pop-to-ecx -5261 # . epilogue -5262 89/<- %esp 5/r32/ebp -5263 5d/pop-to-ebp -5264 c3/return -5265 -5266 mu-stmt-matches-function?: # stmt: (handle statement), function: (handle function) => result/eax: boolean -5267 # . prologue -5268 55/push-ebp -5269 89/<- %ebp 4/r32/esp -5270 # . save registers -5271 51/push-ecx -5272 # return function->name == stmt->operation -5273 8b/-> *(ebp+8) 1/r32/ecx -5274 8b/-> *(ebp+0xc) 0/r32/eax -5275 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax -5276 $mu-stmt-matches-function?:end: -5277 # . restore registers -5278 59/pop-to-ecx -5279 # . epilogue -5280 89/<- %esp 5/r32/ebp -5281 5d/pop-to-ebp -5282 c3/return -5283 -5284 mu-stmt-matches-primitive?: # stmt: (handle statement), primitive: (handle primitive) => result/eax: boolean -5285 # A mu stmt matches a primitive if the name matches, all the inout vars -5286 # match, and all the output vars match. -5287 # Vars match if types match and registers match. -5288 # In addition, a stmt output matches a primitive's output if types match -5289 # and the primitive has a wildcard register. +5190 $get-stmt-operand-from-arg-location:abort: +5191 # error("invalid arg-location " eax) +5192 (write-buffered Stderr "invalid arg-location ") +5193 (print-int32-buffered Stderr %eax) +5194 (write-buffered Stderr Newline) +5195 (flush Stderr) +5196 # . syscall(exit, 1) +5197 bb/copy-to-ebx 1/imm32 +5198 b8/copy-to-eax 1/imm32/exit +5199 cd/syscall 0x80/imm8 +5200 # never gets here +5201 +5202 emit-subx-r32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) +5203 # . prologue +5204 55/push-ebp +5205 89/<- %ebp 4/r32/esp +5206 # . save registers +5207 50/push-eax +5208 51/push-ecx +5209 # if (location == 0) return +5210 81 7/subop/compare *(ebp+0xc) 0/imm32 +5211 0f 84/jump-if-= $emit-subx-r32:end/disp32 +5212 # +5213 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +5214 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax: (addr register-index) +5215 (write-buffered *(ebp+8) Space) +5216 (print-int32-buffered *(ebp+8) *eax) +5217 (write-buffered *(ebp+8) "/r32") +5218 $emit-subx-r32:end: +5219 # . restore registers +5220 59/pop-to-ecx +5221 58/pop-to-eax +5222 # . epilogue +5223 89/<- %esp 5/r32/ebp +5224 5d/pop-to-ebp +5225 c3/return +5226 +5227 emit-subx-imm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) +5228 # . prologue +5229 55/push-ebp +5230 89/<- %ebp 4/r32/esp +5231 # . save registers +5232 50/push-eax +5233 51/push-ecx +5234 # if (location == 0) return +5235 81 7/subop/compare *(ebp+0xc) 0/imm32 +5236 74/jump-if-= $emit-subx-imm32:end/disp8 +5237 # +5238 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +5239 (write-buffered *(ebp+8) Space) +5240 (write-buffered *(ebp+8) *eax) # Var-name +5241 (write-buffered *(ebp+8) "/imm32") +5242 $emit-subx-imm32:end: +5243 # . restore registers +5244 59/pop-to-ecx +5245 58/pop-to-eax +5246 # . epilogue +5247 89/<- %esp 5/r32/ebp +5248 5d/pop-to-ebp +5249 c3/return +5250 +5251 emit-subx-call: # out: (addr buffered-file), stmt: (handle statement), callee: (handle function) +5252 # . prologue +5253 55/push-ebp +5254 89/<- %ebp 4/r32/esp +5255 # . save registers +5256 50/push-eax +5257 51/push-ecx +5258 # +5259 (write-buffered *(ebp+8) "(") +5260 # - emit function name +5261 8b/-> *(ebp+0x10) 1/r32/ecx +5262 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name +5263 # - emit arguments +5264 # var curr/ecx: (handle list var) = stmt->inouts +5265 8b/-> *(ebp+0xc) 1/r32/ecx +5266 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts +5267 { +5268 # if (curr == null) break +5269 81 7/subop/compare %ecx 0/imm32 +5270 74/jump-if-= break/disp8 +5271 # +5272 (emit-subx-call-operand *(ebp+8) *ecx) +5273 # curr = curr->next +5274 8b/-> *(ecx+4) 1/r32/ecx +5275 eb/jump loop/disp8 +5276 } +5277 # +5278 (write-buffered *(ebp+8) ")\n") +5279 $emit-subx-call:end: +5280 # . restore registers +5281 59/pop-to-ecx +5282 58/pop-to-eax +5283 # . epilogue +5284 89/<- %esp 5/r32/ebp +5285 5d/pop-to-ebp +5286 c3/return +5287 +5288 emit-subx-call-operand: # out: (addr buffered-file), operand: (handle variable) +5289 # shares code with emit-subx-var-as-rm32 5290 # . prologue 5291 55/push-ebp 5292 89/<- %ebp 4/r32/esp 5293 # . save registers -5294 51/push-ecx -5295 52/push-edx -5296 53/push-ebx -5297 56/push-esi -5298 57/push-edi -5299 # ecx = stmt -5300 8b/-> *(ebp+8) 1/r32/ecx -5301 # edx = primitive -5302 8b/-> *(ebp+0xc) 2/r32/edx -5303 { -5304 $mu-stmt-matches-primitive?:check-name: -5305 # if (primitive->name != stmt->operation) return false -5306 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax -5307 3d/compare-eax-and 0/imm32 -5308 75/jump-if-!= break/disp8 -5309 b8/copy-to-eax 0/imm32 -5310 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5311 } -5312 $mu-stmt-matches-primitive?:check-inouts: -5313 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) -5314 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts -5315 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts -5316 { -5317 # if (curr == 0 && curr2 == 0) move on to check outputs -5318 { -5319 81 7/subop/compare %esi 0/imm32 -5320 75/jump-if-!= break/disp8 -5321 $mu-stmt-matches-primitive?:stmt-inout-is-null: -5322 { -5323 81 7/subop/compare %edi 0/imm32 -5324 75/jump-if-!= break/disp8 -5325 # -5326 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 -5327 } -5328 # return false -5329 b8/copy-to-eax 0/imm32/false -5330 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5331 } -5332 # if (curr2 == 0) return false -5333 { -5334 81 7/subop/compare %edi 0/imm32 -5335 75/jump-if-!= break/disp8 -5336 $mu-stmt-matches-primitive?:prim-inout-is-null: -5337 b8/copy-to-eax 0/imm32/false -5338 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5339 } -5340 # if (curr != curr2) return false -5341 { -5342 (operand-matches-primitive? *esi *edi) # => eax -5343 3d/compare-eax-and 0/imm32 -5344 75/jump-if-!= break/disp8 -5345 b8/copy-to-eax 0/imm32/false -5346 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5347 } -5348 # curr=curr->next -5349 8b/-> *(esi+4) 6/r32/esi # Operand-next -5350 # curr2=curr2->next -5351 8b/-> *(edi+4) 7/r32/edi # Operand-next -5352 eb/jump loop/disp8 -5353 } -5354 $mu-stmt-matches-primitive?:check-outputs: -5355 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) -5356 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs -5357 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs -5358 { -5359 # if (curr == 0) return (curr2 == 0) -5360 { -5361 $mu-stmt-matches-primitive?:check-output: -5362 81 7/subop/compare %esi 0/imm32 -5363 75/jump-if-!= break/disp8 -5364 { -5365 81 7/subop/compare %edi 0/imm32 -5366 75/jump-if-!= break/disp8 -5367 # return true -5368 b8/copy-to-eax 1/imm32 -5369 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5370 } -5371 # return false -5372 b8/copy-to-eax 0/imm32 -5373 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5374 } -5375 # if (curr2 == 0) return false -5376 { -5377 81 7/subop/compare %edi 0/imm32 -5378 75/jump-if-!= break/disp8 -5379 b8/copy-to-eax 0/imm32 -5380 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5381 } -5382 # if (curr != curr2) return false -5383 { -5384 (operand-matches-primitive? *esi *edi) # List-value List-value => eax -5385 3d/compare-eax-and 0/imm32 -5386 75/jump-if-!= break/disp8 -5387 b8/copy-to-eax 0/imm32 -5388 e9/jump $mu-stmt-matches-primitive?:end/disp32 -5389 } -5390 # curr=curr->next -5391 8b/-> *(esi+4) 6/r32/esi # Operand-next -5392 # curr2=curr2->next -5393 8b/-> *(edi+4) 7/r32/edi # Operand-next +5294 50/push-eax +5295 # eax = operand +5296 8b/-> *(ebp+0xc) 0/r32/eax +5297 # if (operand->register) emit "%__" +5298 { +5299 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +5300 74/jump-if-= break/disp8 +5301 $emit-subx-call-operand:register: +5302 (write-buffered *(ebp+8) " %") +5303 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +5304 e9/jump $emit-subx-call-operand:end/disp32 +5305 } +5306 # else if (operand->stack-offset) emit "*(ebp+__)" +5307 { +5308 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +5309 74/jump-if-= break/disp8 +5310 $emit-subx-call-operand:stack: +5311 (write-buffered *(ebp+8) Space) +5312 (write-buffered *(ebp+8) "*(ebp+") +5313 8b/-> *(ebp+0xc) 0/r32/eax +5314 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +5315 (write-buffered *(ebp+8) ")") +5316 e9/jump $emit-subx-call-operand:end/disp32 +5317 } +5318 # else if (operand->type == literal) emit "__" +5319 { +5320 50/push-eax +5321 8b/-> *(eax+4) 0/r32/eax # Var-type +5322 81 7/subop/compare *eax 0/imm32 # Tree-left +5323 58/pop-to-eax +5324 75/jump-if-!= break/disp8 +5325 $emit-subx-call-operand:literal: +5326 (write-buffered *(ebp+8) Space) +5327 (write-buffered *(ebp+8) *eax) +5328 } +5329 $emit-subx-call-operand:end: +5330 # . restore registers +5331 58/pop-to-eax +5332 # . epilogue +5333 89/<- %esp 5/r32/ebp +5334 5d/pop-to-ebp +5335 c3/return +5336 +5337 emit-subx-var-as-rm32: # out: (addr buffered-file), operand: (handle variable) +5338 # . prologue +5339 55/push-ebp +5340 89/<- %ebp 4/r32/esp +5341 # . save registers +5342 50/push-eax +5343 # eax = operand +5344 8b/-> *(ebp+0xc) 0/r32/eax +5345 # if (operand->register) emit "%__" +5346 { +5347 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +5348 74/jump-if-= break/disp8 +5349 $emit-subx-var-as-rm32:register: +5350 (write-buffered *(ebp+8) " %") +5351 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +5352 } +5353 # else if (operand->stack-offset) emit "*(ebp+__)" +5354 { +5355 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +5356 74/jump-if-= break/disp8 +5357 $emit-subx-var-as-rm32:stack: +5358 (write-buffered *(ebp+8) Space) +5359 (write-buffered *(ebp+8) "*(ebp+") +5360 8b/-> *(ebp+0xc) 0/r32/eax +5361 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +5362 (write-buffered *(ebp+8) ")") +5363 } +5364 $emit-subx-var-as-rm32:end: +5365 # . restore registers +5366 58/pop-to-eax +5367 # . epilogue +5368 89/<- %esp 5/r32/ebp +5369 5d/pop-to-ebp +5370 c3/return +5371 +5372 find-matching-function: # functions: (addr function), stmt: (handle statement) -> result/eax: (handle function) +5373 # . prologue +5374 55/push-ebp +5375 89/<- %ebp 4/r32/esp +5376 # . save registers +5377 51/push-ecx +5378 # var curr/ecx: (handle function) = functions +5379 8b/-> *(ebp+8) 1/r32/ecx +5380 { +5381 # if (curr == null) break +5382 81 7/subop/compare %ecx 0/imm32 +5383 74/jump-if-= break/disp8 +5384 # if match(stmt, curr) return curr +5385 { +5386 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax +5387 3d/compare-eax-and 0/imm32 +5388 74/jump-if-= break/disp8 +5389 89/<- %eax 1/r32/ecx +5390 eb/jump $find-matching-function:end/disp8 +5391 } +5392 # curr = curr->next +5393 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next 5394 eb/jump loop/disp8 5395 } -5396 $mu-stmt-matches-primitive?:return-true: -5397 b8/copy-to-eax 1/imm32 -5398 $mu-stmt-matches-primitive?:end: +5396 # return null +5397 b8/copy-to-eax 0/imm32 +5398 $find-matching-function:end: 5399 # . restore registers -5400 5f/pop-to-edi -5401 5e/pop-to-esi -5402 5b/pop-to-ebx -5403 5a/pop-to-edx -5404 59/pop-to-ecx -5405 # . epilogue -5406 89/<- %esp 5/r32/ebp -5407 5d/pop-to-ebp -5408 c3/return -5409 -5410 operand-matches-primitive?: # var: (handle var), prim-var: (handle var) => result/eax: boolean -5411 # . prologue -5412 55/push-ebp -5413 89/<- %ebp 4/r32/esp -5414 # . save registers -5415 56/push-esi -5416 57/push-edi -5417 # esi = var -5418 8b/-> *(ebp+8) 6/r32/esi -5419 # edi = prim-var -5420 8b/-> *(ebp+0xc) 7/r32/edi -5421 # if (var->type != prim-var->type) return false -5422 (type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax -5423 3d/compare-eax-and 0/imm32 -5424 b8/copy-to-eax 0/imm32/false -5425 74/jump-if-= $operand-matches-primitive?:end/disp8 -5426 # return false if var->register doesn't match prim-var->register -5427 { -5428 # if addresses are equal, don't return here -5429 8b/-> *(esi+0x10) 0/r32/eax -5430 39/compare *(edi+0x10) 0/r32/eax -5431 74/jump-if-= break/disp8 -5432 # if either address is 0, return false -5433 3d/compare-eax-and 0/imm32 -5434 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -5435 81 7/subop/compare *(edi+0x10) 0/imm32 -5436 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -5437 # if prim-var->register is "*", return true -5438 (string-equal? *(edi+0x10) "*") # Var-register -5439 3d/compare-eax-and 0/imm32 -5440 b8/copy-to-eax 1/imm32/true -5441 75/jump-if-!= $operand-matches-primitive?:end/disp8 -5442 # if string contents don't match, return false -5443 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register -5444 3d/compare-eax-and 0/imm32 -5445 b8/copy-to-eax 0/imm32/false -5446 74/jump-if-= $operand-matches-primitive?:end/disp8 -5447 } -5448 # return true -5449 b8/copy-to-eax 1/imm32/true -5450 $operand-matches-primitive?:end: -5451 # . restore registers -5452 5f/pop-to-edi -5453 5e/pop-to-esi -5454 # . epilogue -5455 89/<- %esp 5/r32/ebp -5456 5d/pop-to-ebp -5457 c3/return -5458 -5459 type-equal?: # a: (handle tree type-id), b: (handle tree type-id) => result/eax: boolean -5460 # . prologue -5461 55/push-ebp -5462 89/<- %ebp 4/r32/esp -5463 # . save registers -5464 51/push-ecx -5465 52/push-edx -5466 # ecx = a -5467 8b/-> *(ebp+8) 1/r32/ecx -5468 # edx = b -5469 8b/-> *(ebp+0xc) 2/r32/edx -5470 # if (a == b) return true -5471 8b/-> %ecx 0/r32/eax # Var-type -5472 39/compare %edx 0/r32/eax # Var-type -5473 b8/copy-to-eax 1/imm32/true -5474 74/jump-if-= $type-equal?:end/disp8 -5475 # if (a < MAX_TYPE_ID) return false -5476 81 7/subop/compare %ecx 0x10000/imm32 -5477 b8/copy-to-eax 0/imm32/false -5478 72/jump-if-addr< $type-equal?:end/disp8 -5479 # if (b < MAX_TYPE_ID) return false -5480 81 7/subop/compare %edx 0x10000/imm32 -5481 b8/copy-to-eax 0/imm32/false -5482 72/jump-if-addr< $type-equal?:end/disp8 -5483 # if (!type-equal?(a->left, b->left)) return false -5484 (type-equal? *ecx *edx) # Tree-left, Tree-left => eax -5485 3d/compare-eax-and 0/imm32 -5486 74/jump-if-= $type-equal?:end/disp8 -5487 # return type-equal?(a->right, b->right) -5488 (type-equal? *(ecx+4) *(edx+4)) # Tree-right, Tree-right => eax -5489 $type-equal?:end: -5490 # . restore registers -5491 5a/pop-to-edx -5492 59/pop-to-ecx -5493 # . epilogue -5494 89/<- %esp 5/r32/ebp -5495 5d/pop-to-ebp -5496 c3/return -5497 -5498 test-emit-subx-statement-primitive: -5499 # Primitive operation on a variable on the stack. -5500 # increment foo -5501 # => -5502 # ff 0/subop/increment *(ebp-8) -5503 # -5504 # There's a variable on the var stack as follows: -5505 # name: 'foo' -5506 # type: int -5507 # stack-offset: -8 -5508 # -5509 # There's a primitive with this info: -5510 # name: 'increment' -5511 # inouts: int/mem -5512 # value: 'ff 0/subop/increment' -5513 # -5514 # There's nothing in functions. -5515 # -5516 # . prologue -5517 55/push-ebp -5518 89/<- %ebp 4/r32/esp -5519 # setup -5520 (clear-stream _test-output-stream) -5521 (clear-stream $_test-output-buffered-file->buffer) -5522 # var type/ecx: (handle tree type-id) = int -5523 68/push 0/imm32/right/null -5524 68/push 1/imm32/left/int -5525 89/<- %ecx 4/r32/esp -5526 # var var-foo/ecx: var -5527 68/push 0/imm32/no-register -5528 68/push -8/imm32/stack-offset -5529 68/push 1/imm32/block-depth -5530 51/push-ecx -5531 68/push "foo"/imm32 -5532 89/<- %ecx 4/r32/esp -5533 # var operand/ebx: (list var) -5534 68/push 0/imm32/next -5535 51/push-ecx/var-foo -5536 89/<- %ebx 4/r32/esp -5537 # var stmt/esi: statement -5538 68/push 0/imm32/next -5539 68/push 0/imm32/outputs -5540 53/push-ebx/operands -5541 68/push "increment"/imm32/operation -5542 68/push 1/imm32 -5543 89/<- %esi 4/r32/esp -5544 # var primitives/ebx: primitive -5545 68/push 0/imm32/next -5546 68/push 0/imm32/output-is-write-only -5547 68/push 0/imm32/no-imm32 -5548 68/push 0/imm32/no-r32 -5549 68/push 1/imm32/rm32-is-first-inout -5550 68/push "ff 0/subop/increment"/imm32/subx-name -5551 68/push 0/imm32/outputs -5552 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call -5553 68/push "increment"/imm32/name -5554 89/<- %ebx 4/r32/esp -5555 # convert -5556 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5557 (flush _test-output-buffered-file) -5558 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5564 # check output -5565 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") -5566 # . epilogue -5567 89/<- %esp 5/r32/ebp -5568 5d/pop-to-ebp -5569 c3/return -5570 -5571 test-emit-subx-statement-primitive-register: -5572 # Primitive operation on a variable in a register. -5573 # foo <- increment -5574 # => -5575 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5576 # -5577 # There's a variable on the var stack as follows: -5578 # name: 'foo' -5579 # type: int -5580 # register: 'eax' -5581 # -5582 # There's a primitive with this info: -5583 # name: 'increment' -5584 # out: int/reg -5585 # value: 'ff 0/subop/increment' -5586 # -5587 # There's nothing in functions. -5588 # -5589 # . prologue -5590 55/push-ebp -5591 89/<- %ebp 4/r32/esp -5592 # setup -5593 (clear-stream _test-output-stream) -5594 (clear-stream $_test-output-buffered-file->buffer) -5595 # var type/ecx: (handle tree type-id) = int -5596 68/push 0/imm32/right/null -5597 68/push 1/imm32/left/int -5598 89/<- %ecx 4/r32/esp -5599 # var var-foo/ecx: var in eax -5600 68/push "eax"/imm32/register -5601 68/push 0/imm32/no-stack-offset -5602 68/push 1/imm32/block-depth -5603 51/push-ecx -5604 68/push "foo"/imm32 -5605 89/<- %ecx 4/r32/esp -5606 # var operand/ebx: (list var) -5607 68/push 0/imm32/next -5608 51/push-ecx/var-foo -5609 89/<- %ebx 4/r32/esp -5610 # var stmt/esi: statement -5611 68/push 0/imm32/next -5612 53/push-ebx/outputs -5613 68/push 0/imm32/inouts -5614 68/push "increment"/imm32/operation -5615 68/push 1/imm32 -5616 89/<- %esi 4/r32/esp -5617 # var formal-var/ebx: var in any register -5618 68/push Any-register/imm32 -5619 68/push 0/imm32/no-stack-offset -5620 68/push 1/imm32/block-depth -5621 ff 6/subop/push *(ecx+4) # Var-type -5622 68/push "dummy"/imm32 -5623 89/<- %ebx 4/r32/esp -5624 # var operand/ebx: (list var) -5625 68/push 0/imm32/next -5626 53/push-ebx/formal-var -5627 89/<- %ebx 4/r32/esp -5628 # var primitives/ebx: primitive -5629 68/push 0/imm32/next -5630 68/push 0/imm32/output-is-write-only -5631 68/push 0/imm32/no-imm32 -5632 68/push 0/imm32/no-r32 -5633 68/push 3/imm32/rm32-in-first-output -5634 68/push "ff 0/subop/increment"/imm32/subx-name -5635 53/push-ebx/outputs -5636 68/push 0/imm32/inouts -5637 68/push "increment"/imm32/name -5638 89/<- %ebx 4/r32/esp -5639 # convert -5640 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5641 (flush _test-output-buffered-file) -5642 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5648 # check output -5649 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") -5650 # . epilogue -5651 89/<- %esp 5/r32/ebp -5652 5d/pop-to-ebp -5653 c3/return -5654 -5655 test-emit-subx-statement-select-primitive: -5656 # Select the right primitive between overloads. -5657 # foo <- increment -5658 # => -5659 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5660 # -5661 # There's a variable on the var stack as follows: -5662 # name: 'foo' -5663 # type: int -5664 # register: 'eax' -5665 # -5666 # There's two primitives, as follows: -5667 # - name: 'increment' -5668 # out: int/reg -5669 # value: 'ff 0/subop/increment' -5670 # - name: 'increment' -5671 # inout: int/mem -5672 # value: 'ff 0/subop/increment' -5673 # -5674 # There's nothing in functions. -5675 # -5676 # . prologue -5677 55/push-ebp -5678 89/<- %ebp 4/r32/esp -5679 # setup -5680 (clear-stream _test-output-stream) -5681 (clear-stream $_test-output-buffered-file->buffer) -5682 # var type/ecx: (handle tree type-id) = int -5683 68/push 0/imm32/right/null -5684 68/push 1/imm32/left/int -5685 89/<- %ecx 4/r32/esp -5686 # var var-foo/ecx: var in eax -5687 68/push "eax"/imm32/register -5688 68/push 0/imm32/no-stack-offset -5689 68/push 1/imm32/block-depth -5690 51/push-ecx -5691 68/push "foo"/imm32 -5692 89/<- %ecx 4/r32/esp -5693 # var real-outputs/edi: (list var) -5694 68/push 0/imm32/next -5695 51/push-ecx/var-foo -5696 89/<- %edi 4/r32/esp -5697 # var stmt/esi: statement -5698 68/push 0/imm32/next -5699 57/push-edi/outputs -5700 68/push 0/imm32/inouts -5701 68/push "increment"/imm32/operation -5702 68/push 1/imm32 -5703 89/<- %esi 4/r32/esp -5704 # var formal-var/ebx: var in any register -5705 68/push Any-register/imm32 -5706 68/push 0/imm32/no-stack-offset -5707 68/push 1/imm32/block-depth -5708 ff 6/subop/push *(ecx+4) # Var-type -5709 68/push "dummy"/imm32 -5710 89/<- %ebx 4/r32/esp -5711 # var formal-outputs/ebx: (list var) = {formal-var, 0} -5712 68/push 0/imm32/next -5713 53/push-ebx/formal-var -5714 89/<- %ebx 4/r32/esp -5715 # var primitive1/ebx: primitive +5400 59/pop-to-ecx +5401 # . epilogue +5402 89/<- %esp 5/r32/ebp +5403 5d/pop-to-ebp +5404 c3/return +5405 +5406 find-matching-primitive: # primitives: (handle primitive), stmt: (handle statement) -> result/eax: (handle primitive) +5407 # . prologue +5408 55/push-ebp +5409 89/<- %ebp 4/r32/esp +5410 # . save registers +5411 51/push-ecx +5412 # var curr/ecx: (handle primitive) = primitives +5413 8b/-> *(ebp+8) 1/r32/ecx +5414 { +5415 $find-matching-primitive:loop: +5416 # if (curr == null) break +5417 81 7/subop/compare %ecx 0/imm32 +5418 0f 84/jump-if-= break/disp32 +5419 #? (write-buffered Stderr "prim: ") +5420 #? (write-buffered Stderr *ecx) # Primitive-name +5421 #? (write-buffered Stderr " => ") +5422 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name +5423 #? (write-buffered Stderr Newline) +5424 #? (flush Stderr) +5425 # if match(curr, stmt) return curr +5426 { +5427 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax +5428 3d/compare-eax-and 0/imm32 +5429 74/jump-if-= break/disp8 +5430 89/<- %eax 1/r32/ecx +5431 eb/jump $find-matching-primitive:end/disp8 +5432 } +5433 $find-matching-primitive:next-primitive: +5434 # curr = curr->next +5435 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next +5436 e9/jump loop/disp32 +5437 } +5438 # return null +5439 b8/copy-to-eax 0/imm32 +5440 $find-matching-primitive:end: +5441 # . restore registers +5442 59/pop-to-ecx +5443 # . epilogue +5444 89/<- %esp 5/r32/ebp +5445 5d/pop-to-ebp +5446 c3/return +5447 +5448 mu-stmt-matches-function?: # stmt: (handle statement), function: (handle function) => result/eax: boolean +5449 # . prologue +5450 55/push-ebp +5451 89/<- %ebp 4/r32/esp +5452 # . save registers +5453 51/push-ecx +5454 # return function->name == stmt->operation +5455 8b/-> *(ebp+8) 1/r32/ecx +5456 8b/-> *(ebp+0xc) 0/r32/eax +5457 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax +5458 $mu-stmt-matches-function?:end: +5459 # . restore registers +5460 59/pop-to-ecx +5461 # . epilogue +5462 89/<- %esp 5/r32/ebp +5463 5d/pop-to-ebp +5464 c3/return +5465 +5466 mu-stmt-matches-primitive?: # stmt: (handle statement), primitive: (handle primitive) => result/eax: boolean +5467 # A mu stmt matches a primitive if the name matches, all the inout vars +5468 # match, and all the output vars match. +5469 # Vars match if types match and registers match. +5470 # In addition, a stmt output matches a primitive's output if types match +5471 # and the primitive has a wildcard register. +5472 # . prologue +5473 55/push-ebp +5474 89/<- %ebp 4/r32/esp +5475 # . save registers +5476 51/push-ecx +5477 52/push-edx +5478 53/push-ebx +5479 56/push-esi +5480 57/push-edi +5481 # ecx = stmt +5482 8b/-> *(ebp+8) 1/r32/ecx +5483 # edx = primitive +5484 8b/-> *(ebp+0xc) 2/r32/edx +5485 { +5486 $mu-stmt-matches-primitive?:check-name: +5487 # if (primitive->name != stmt->operation) return false +5488 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax +5489 3d/compare-eax-and 0/imm32 +5490 75/jump-if-!= break/disp8 +5491 b8/copy-to-eax 0/imm32 +5492 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5493 } +5494 $mu-stmt-matches-primitive?:check-inouts: +5495 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) +5496 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts +5497 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts +5498 { +5499 # if (curr == 0 && curr2 == 0) move on to check outputs +5500 { +5501 81 7/subop/compare %esi 0/imm32 +5502 75/jump-if-!= break/disp8 +5503 $mu-stmt-matches-primitive?:stmt-inout-is-null: +5504 { +5505 81 7/subop/compare %edi 0/imm32 +5506 75/jump-if-!= break/disp8 +5507 # +5508 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 +5509 } +5510 # return false +5511 b8/copy-to-eax 0/imm32/false +5512 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5513 } +5514 # if (curr2 == 0) return false +5515 { +5516 81 7/subop/compare %edi 0/imm32 +5517 75/jump-if-!= break/disp8 +5518 $mu-stmt-matches-primitive?:prim-inout-is-null: +5519 b8/copy-to-eax 0/imm32/false +5520 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5521 } +5522 # if (curr != curr2) return false +5523 { +5524 (operand-matches-primitive? *esi *edi) # => eax +5525 3d/compare-eax-and 0/imm32 +5526 75/jump-if-!= break/disp8 +5527 b8/copy-to-eax 0/imm32/false +5528 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5529 } +5530 # curr=curr->next +5531 8b/-> *(esi+4) 6/r32/esi # Operand-next +5532 # curr2=curr2->next +5533 8b/-> *(edi+4) 7/r32/edi # Operand-next +5534 eb/jump loop/disp8 +5535 } +5536 $mu-stmt-matches-primitive?:check-outputs: +5537 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) +5538 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs +5539 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs +5540 { +5541 # if (curr == 0) return (curr2 == 0) +5542 { +5543 $mu-stmt-matches-primitive?:check-output: +5544 81 7/subop/compare %esi 0/imm32 +5545 75/jump-if-!= break/disp8 +5546 { +5547 81 7/subop/compare %edi 0/imm32 +5548 75/jump-if-!= break/disp8 +5549 # return true +5550 b8/copy-to-eax 1/imm32 +5551 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5552 } +5553 # return false +5554 b8/copy-to-eax 0/imm32 +5555 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5556 } +5557 # if (curr2 == 0) return false +5558 { +5559 81 7/subop/compare %edi 0/imm32 +5560 75/jump-if-!= break/disp8 +5561 b8/copy-to-eax 0/imm32 +5562 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5563 } +5564 # if (curr != curr2) return false +5565 { +5566 (operand-matches-primitive? *esi *edi) # List-value List-value => eax +5567 3d/compare-eax-and 0/imm32 +5568 75/jump-if-!= break/disp8 +5569 b8/copy-to-eax 0/imm32 +5570 e9/jump $mu-stmt-matches-primitive?:end/disp32 +5571 } +5572 # curr=curr->next +5573 8b/-> *(esi+4) 6/r32/esi # Operand-next +5574 # curr2=curr2->next +5575 8b/-> *(edi+4) 7/r32/edi # Operand-next +5576 eb/jump loop/disp8 +5577 } +5578 $mu-stmt-matches-primitive?:return-true: +5579 b8/copy-to-eax 1/imm32 +5580 $mu-stmt-matches-primitive?:end: +5581 # . restore registers +5582 5f/pop-to-edi +5583 5e/pop-to-esi +5584 5b/pop-to-ebx +5585 5a/pop-to-edx +5586 59/pop-to-ecx +5587 # . epilogue +5588 89/<- %esp 5/r32/ebp +5589 5d/pop-to-ebp +5590 c3/return +5591 +5592 operand-matches-primitive?: # var: (handle var), prim-var: (handle var) => result/eax: boolean +5593 # . prologue +5594 55/push-ebp +5595 89/<- %ebp 4/r32/esp +5596 # . save registers +5597 56/push-esi +5598 57/push-edi +5599 # esi = var +5600 8b/-> *(ebp+8) 6/r32/esi +5601 # edi = prim-var +5602 8b/-> *(ebp+0xc) 7/r32/edi +5603 # if (var->type != prim-var->type) return false +5604 (type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax +5605 3d/compare-eax-and 0/imm32 +5606 b8/copy-to-eax 0/imm32/false +5607 74/jump-if-= $operand-matches-primitive?:end/disp8 +5608 # return false if var->register doesn't match prim-var->register +5609 { +5610 # if addresses are equal, don't return here +5611 8b/-> *(esi+0x10) 0/r32/eax +5612 39/compare *(edi+0x10) 0/r32/eax +5613 74/jump-if-= break/disp8 +5614 # if either address is 0, return false +5615 3d/compare-eax-and 0/imm32 +5616 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +5617 81 7/subop/compare *(edi+0x10) 0/imm32 +5618 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +5619 # if prim-var->register is "*", return true +5620 (string-equal? *(edi+0x10) "*") # Var-register +5621 3d/compare-eax-and 0/imm32 +5622 b8/copy-to-eax 1/imm32/true +5623 75/jump-if-!= $operand-matches-primitive?:end/disp8 +5624 # if string contents don't match, return false +5625 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register +5626 3d/compare-eax-and 0/imm32 +5627 b8/copy-to-eax 0/imm32/false +5628 74/jump-if-= $operand-matches-primitive?:end/disp8 +5629 } +5630 # return true +5631 b8/copy-to-eax 1/imm32/true +5632 $operand-matches-primitive?:end: +5633 # . restore registers +5634 5f/pop-to-edi +5635 5e/pop-to-esi +5636 # . epilogue +5637 89/<- %esp 5/r32/ebp +5638 5d/pop-to-ebp +5639 c3/return +5640 +5641 type-equal?: # a: (handle tree type-id), b: (handle tree type-id) => result/eax: boolean +5642 # . prologue +5643 55/push-ebp +5644 89/<- %ebp 4/r32/esp +5645 # . save registers +5646 51/push-ecx +5647 52/push-edx +5648 # ecx = a +5649 8b/-> *(ebp+8) 1/r32/ecx +5650 # edx = b +5651 8b/-> *(ebp+0xc) 2/r32/edx +5652 # if (a == b) return true +5653 8b/-> %ecx 0/r32/eax # Var-type +5654 39/compare %edx 0/r32/eax # Var-type +5655 b8/copy-to-eax 1/imm32/true +5656 74/jump-if-= $type-equal?:end/disp8 +5657 # if (a < MAX_TYPE_ID) return false +5658 81 7/subop/compare %ecx 0x10000/imm32 +5659 b8/copy-to-eax 0/imm32/false +5660 72/jump-if-addr< $type-equal?:end/disp8 +5661 # if (b < MAX_TYPE_ID) return false +5662 81 7/subop/compare %edx 0x10000/imm32 +5663 b8/copy-to-eax 0/imm32/false +5664 72/jump-if-addr< $type-equal?:end/disp8 +5665 # if (!type-equal?(a->left, b->left)) return false +5666 (type-equal? *ecx *edx) # Tree-left, Tree-left => eax +5667 3d/compare-eax-and 0/imm32 +5668 74/jump-if-= $type-equal?:end/disp8 +5669 # return type-equal?(a->right, b->right) +5670 (type-equal? *(ecx+4) *(edx+4)) # Tree-right, Tree-right => eax +5671 $type-equal?:end: +5672 # . restore registers +5673 5a/pop-to-edx +5674 59/pop-to-ecx +5675 # . epilogue +5676 89/<- %esp 5/r32/ebp +5677 5d/pop-to-ebp +5678 c3/return +5679 +5680 test-emit-subx-statement-primitive: +5681 # Primitive operation on a variable on the stack. +5682 # increment foo +5683 # => +5684 # ff 0/subop/increment *(ebp-8) +5685 # +5686 # There's a variable on the var stack as follows: +5687 # name: 'foo' +5688 # type: int +5689 # stack-offset: -8 +5690 # +5691 # There's a primitive with this info: +5692 # name: 'increment' +5693 # inouts: int/mem +5694 # value: 'ff 0/subop/increment' +5695 # +5696 # There's nothing in functions. +5697 # +5698 # . prologue +5699 55/push-ebp +5700 89/<- %ebp 4/r32/esp +5701 # setup +5702 (clear-stream _test-output-stream) +5703 (clear-stream $_test-output-buffered-file->buffer) +5704 # var type/ecx: (handle tree type-id) = int +5705 68/push 0/imm32/right/null +5706 68/push 1/imm32/left/int +5707 89/<- %ecx 4/r32/esp +5708 # var var-foo/ecx: var +5709 68/push 0/imm32/no-register +5710 68/push -8/imm32/stack-offset +5711 68/push 1/imm32/block-depth +5712 51/push-ecx +5713 68/push "foo"/imm32 +5714 89/<- %ecx 4/r32/esp +5715 # var operand/ebx: (list var) 5716 68/push 0/imm32/next -5717 68/push 0/imm32/output-is-write-only -5718 68/push 0/imm32/no-imm32 -5719 68/push 0/imm32/no-r32 -5720 68/push 3/imm32/rm32-in-first-output -5721 68/push "ff 0/subop/increment"/imm32/subx-name -5722 53/push-ebx/outputs/formal-outputs -5723 68/push 0/imm32/inouts -5724 68/push "increment"/imm32/name -5725 89/<- %ebx 4/r32/esp +5717 51/push-ecx/var-foo +5718 89/<- %ebx 4/r32/esp +5719 # var stmt/esi: statement +5720 68/push 0/imm32/next +5721 68/push 0/imm32/outputs +5722 53/push-ebx/operands +5723 68/push "increment"/imm32/operation +5724 68/push 1/imm32 +5725 89/<- %esi 4/r32/esp 5726 # var primitives/ebx: primitive -5727 53/push-ebx/next +5727 68/push 0/imm32/next 5728 68/push 0/imm32/output-is-write-only 5729 68/push 0/imm32/no-imm32 5730 68/push 0/imm32/no-r32 5731 68/push 1/imm32/rm32-is-first-inout 5732 68/push "ff 0/subop/increment"/imm32/subx-name 5733 68/push 0/imm32/outputs -5734 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +5734 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call 5735 68/push "increment"/imm32/name 5736 89/<- %ebx 4/r32/esp 5737 # convert -5738 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5738 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) 5739 (flush _test-output-buffered-file) 5740 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- 5746 # check output -5747 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") +5747 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") 5748 # . epilogue 5749 89/<- %esp 5/r32/ebp 5750 5d/pop-to-ebp 5751 c3/return 5752 -5753 test-emit-subx-statement-select-primitive-2: -5754 # Select the right primitive between overloads. +5753 test-emit-subx-statement-primitive-register: +5754 # Primitive operation on a variable in a register. 5755 # foo <- increment 5756 # => 5757 # ff 0/subop/increment %eax # sub-optimal, but should suffice @@ -5748,686 +5748,858 @@ if ('onhashchange' in window) { 5761 # type: int 5762 # register: 'eax' 5763 # -5764 # There's two primitives, as follows: -5765 # - name: 'increment' -5766 # out: int/reg -5767 # value: 'ff 0/subop/increment' -5768 # - name: 'increment' -5769 # inout: int/mem -5770 # value: 'ff 0/subop/increment' -5771 # -5772 # There's nothing in functions. -5773 # -5774 # . prologue -5775 55/push-ebp -5776 89/<- %ebp 4/r32/esp -5777 # setup -5778 (clear-stream _test-output-stream) -5779 (clear-stream $_test-output-buffered-file->buffer) -5780 # var type/ecx: (handle tree type-id) = int -5781 68/push 0/imm32/right/null -5782 68/push 1/imm32/left/int -5783 89/<- %ecx 4/r32/esp -5784 # var var-foo/ecx: var in eax -5785 68/push "eax"/imm32/register -5786 68/push 0/imm32/no-stack-offset -5787 68/push 1/imm32/block-depth -5788 51/push-ecx -5789 68/push "foo"/imm32 -5790 89/<- %ecx 4/r32/esp -5791 # var inouts/edi: (list var) -5792 68/push 0/imm32/next -5793 51/push-ecx/var-foo -5794 89/<- %edi 4/r32/esp -5795 # var stmt/esi: statement -5796 68/push 0/imm32/next -5797 68/push 0/imm32/outputs -5798 57/push-edi/inouts -5799 68/push "increment"/imm32/operation -5800 68/push 1/imm32 -5801 89/<- %esi 4/r32/esp -5802 # var formal-var/ebx: var in any register -5803 68/push Any-register/imm32 -5804 68/push 0/imm32/no-stack-offset -5805 68/push 1/imm32/block-depth -5806 ff 6/subop/push *(ecx+4) # Var-type -5807 68/push "dummy"/imm32 -5808 89/<- %ebx 4/r32/esp -5809 # var operand/ebx: (list var) -5810 68/push 0/imm32/next -5811 53/push-ebx/formal-var -5812 89/<- %ebx 4/r32/esp -5813 # var primitive1/ebx: primitive -5814 68/push 0/imm32/next -5815 68/push 0/imm32/output-is-write-only -5816 68/push 0/imm32/no-imm32 -5817 68/push 0/imm32/no-r32 -5818 68/push 3/imm32/rm32-in-first-output -5819 68/push "ff 0/subop/increment"/imm32/subx-name -5820 53/push-ebx/outputs/formal-outputs -5821 68/push 0/imm32/inouts -5822 68/push "increment"/imm32/name -5823 89/<- %ebx 4/r32/esp -5824 # var primitives/ebx: primitive -5825 53/push-ebx/next -5826 68/push 0/imm32/output-is-write-only -5827 68/push 0/imm32/no-imm32 -5828 68/push 0/imm32/no-r32 -5829 68/push 1/imm32/rm32-is-first-inout -5830 68/push "ff 0/subop/increment"/imm32/subx-name -5831 68/push 0/imm32/outputs -5832 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -5833 68/push "increment"/imm32/name -5834 89/<- %ebx 4/r32/esp -5835 # convert -5836 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5837 (flush _test-output-buffered-file) -5838 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5844 # check output -5845 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") -5846 # . epilogue -5847 89/<- %esp 5/r32/ebp -5848 5d/pop-to-ebp -5849 c3/return -5850 -5851 test-increment-register: -5852 # Select the right primitive between overloads. -5853 # foo <- increment -5854 # => -5855 # 50/increment-eax -5856 # -5857 # There's a variable on the var stack as follows: -5858 # name: 'foo' -5859 # type: int -5860 # register: 'eax' -5861 # -5862 # Primitives are the global definitions. -5863 # -5864 # There are no functions defined. -5865 # -5866 # . prologue -5867 55/push-ebp -5868 89/<- %ebp 4/r32/esp -5869 # setup -5870 (clear-stream _test-output-stream) -5871 (clear-stream $_test-output-buffered-file->buffer) -5872 # var type/ecx: (handle tree type-id) = int -5873 68/push 0/imm32/right/null -5874 68/push 1/imm32/left/int -5875 89/<- %ecx 4/r32/esp -5876 # var var-foo/ecx: var in eax -5877 68/push "eax"/imm32/register -5878 68/push 0/imm32/no-stack-offset -5879 68/push 1/imm32/block-depth -5880 51/push-ecx -5881 68/push "foo"/imm32 -5882 89/<- %ecx 4/r32/esp -5883 # var real-outputs/edi: (list var) -5884 68/push 0/imm32/next -5885 51/push-ecx/var-foo -5886 89/<- %edi 4/r32/esp -5887 # var stmt/esi: statement -5888 68/push 0/imm32/next -5889 57/push-edi/outputs -5890 68/push 0/imm32/inouts -5891 68/push "increment"/imm32/operation -5892 68/push 1/imm32/regular-statement -5893 89/<- %esi 4/r32/esp -5894 # convert -5895 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5896 (flush _test-output-buffered-file) -5897 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5903 # check output -5904 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") -5905 # . epilogue -5906 89/<- %esp 5/r32/ebp -5907 5d/pop-to-ebp -5908 c3/return -5909 -5910 test-increment-var: -5911 # Select the right primitive between overloads. -5912 # foo <- increment -5913 # => -5914 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5915 # -5916 # There's a variable on the var stack as follows: -5917 # name: 'foo' -5918 # type: int -5919 # register: 'eax' -5920 # -5921 # Primitives are the global definitions. -5922 # -5923 # There are no functions defined. -5924 # -5925 # . prologue -5926 55/push-ebp -5927 89/<- %ebp 4/r32/esp -5928 # setup -5929 (clear-stream _test-output-stream) -5930 (clear-stream $_test-output-buffered-file->buffer) -5931 # var type/ecx: (handle tree type-id) = int -5932 68/push 0/imm32/right/null -5933 68/push 1/imm32/left/int -5934 89/<- %ecx 4/r32/esp -5935 # var var-foo/ecx: var in eax -5936 68/push "eax"/imm32/register -5937 68/push 0/imm32/no-stack-offset -5938 68/push 1/imm32/block-depth -5939 51/push-ecx -5940 68/push "foo"/imm32 -5941 89/<- %ecx 4/r32/esp -5942 # var inouts/edi: (list var) -5943 68/push 0/imm32/next -5944 51/push-ecx/var-foo -5945 89/<- %edi 4/r32/esp -5946 # var stmt/esi: statement -5947 68/push 0/imm32/next -5948 68/push 0/imm32/outputs -5949 57/push-edi/inouts -5950 68/push "increment"/imm32/operation -5951 68/push 1/imm32 -5952 89/<- %esi 4/r32/esp -5953 # convert -5954 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5955 (flush _test-output-buffered-file) -5956 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5962 # check output -5963 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") -5964 # . epilogue -5965 89/<- %esp 5/r32/ebp -5966 5d/pop-to-ebp -5967 c3/return -5968 -5969 test-add-reg-to-reg: -5970 # var1/reg <- add var2/reg -5971 # => -5972 # 01/add %var1 var2 -5973 # -5974 # . prologue -5975 55/push-ebp -5976 89/<- %ebp 4/r32/esp -5977 # setup -5978 (clear-stream _test-output-stream) -5979 (clear-stream $_test-output-buffered-file->buffer) -5980 # var type/ecx: (handle tree type-id) = int -5981 68/push 0/imm32/right/null -5982 68/push 1/imm32/left/int -5983 89/<- %ecx 4/r32/esp -5984 # var var-var1/ecx: var in eax -5985 68/push "eax"/imm32/register +5764 # There's a primitive with this info: +5765 # name: 'increment' +5766 # out: int/reg +5767 # value: 'ff 0/subop/increment' +5768 # +5769 # There's nothing in functions. +5770 # +5771 # . prologue +5772 55/push-ebp +5773 89/<- %ebp 4/r32/esp +5774 # setup +5775 (clear-stream _test-output-stream) +5776 (clear-stream $_test-output-buffered-file->buffer) +5777 # var type/ecx: (handle tree type-id) = int +5778 68/push 0/imm32/right/null +5779 68/push 1/imm32/left/int +5780 89/<- %ecx 4/r32/esp +5781 # var var-foo/ecx: var in eax +5782 68/push "eax"/imm32/register +5783 68/push 0/imm32/no-stack-offset +5784 68/push 1/imm32/block-depth +5785 51/push-ecx +5786 68/push "foo"/imm32 +5787 89/<- %ecx 4/r32/esp +5788 # var operand/ebx: (list var) +5789 68/push 0/imm32/next +5790 51/push-ecx/var-foo +5791 89/<- %ebx 4/r32/esp +5792 # var stmt/esi: statement +5793 68/push 0/imm32/next +5794 53/push-ebx/outputs +5795 68/push 0/imm32/inouts +5796 68/push "increment"/imm32/operation +5797 68/push 1/imm32 +5798 89/<- %esi 4/r32/esp +5799 # var formal-var/ebx: var in any register +5800 68/push Any-register/imm32 +5801 68/push 0/imm32/no-stack-offset +5802 68/push 1/imm32/block-depth +5803 ff 6/subop/push *(ecx+4) # Var-type +5804 68/push "dummy"/imm32 +5805 89/<- %ebx 4/r32/esp +5806 # var operand/ebx: (list var) +5807 68/push 0/imm32/next +5808 53/push-ebx/formal-var +5809 89/<- %ebx 4/r32/esp +5810 # var primitives/ebx: primitive +5811 68/push 0/imm32/next +5812 68/push 0/imm32/output-is-write-only +5813 68/push 0/imm32/no-imm32 +5814 68/push 0/imm32/no-r32 +5815 68/push 3/imm32/rm32-in-first-output +5816 68/push "ff 0/subop/increment"/imm32/subx-name +5817 53/push-ebx/outputs +5818 68/push 0/imm32/inouts +5819 68/push "increment"/imm32/name +5820 89/<- %ebx 4/r32/esp +5821 # convert +5822 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5823 (flush _test-output-buffered-file) +5824 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5830 # check output +5831 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") +5832 # . epilogue +5833 89/<- %esp 5/r32/ebp +5834 5d/pop-to-ebp +5835 c3/return +5836 +5837 test-emit-subx-statement-select-primitive: +5838 # Select the right primitive between overloads. +5839 # foo <- increment +5840 # => +5841 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5842 # +5843 # There's a variable on the var stack as follows: +5844 # name: 'foo' +5845 # type: int +5846 # register: 'eax' +5847 # +5848 # There's two primitives, as follows: +5849 # - name: 'increment' +5850 # out: int/reg +5851 # value: 'ff 0/subop/increment' +5852 # - name: 'increment' +5853 # inout: int/mem +5854 # value: 'ff 0/subop/increment' +5855 # +5856 # There's nothing in functions. +5857 # +5858 # . prologue +5859 55/push-ebp +5860 89/<- %ebp 4/r32/esp +5861 # setup +5862 (clear-stream _test-output-stream) +5863 (clear-stream $_test-output-buffered-file->buffer) +5864 # var type/ecx: (handle tree type-id) = int +5865 68/push 0/imm32/right/null +5866 68/push 1/imm32/left/int +5867 89/<- %ecx 4/r32/esp +5868 # var var-foo/ecx: var in eax +5869 68/push "eax"/imm32/register +5870 68/push 0/imm32/no-stack-offset +5871 68/push 1/imm32/block-depth +5872 51/push-ecx +5873 68/push "foo"/imm32 +5874 89/<- %ecx 4/r32/esp +5875 # var real-outputs/edi: (list var) +5876 68/push 0/imm32/next +5877 51/push-ecx/var-foo +5878 89/<- %edi 4/r32/esp +5879 # var stmt/esi: statement +5880 68/push 0/imm32/next +5881 57/push-edi/outputs +5882 68/push 0/imm32/inouts +5883 68/push "increment"/imm32/operation +5884 68/push 1/imm32 +5885 89/<- %esi 4/r32/esp +5886 # var formal-var/ebx: var in any register +5887 68/push Any-register/imm32 +5888 68/push 0/imm32/no-stack-offset +5889 68/push 1/imm32/block-depth +5890 ff 6/subop/push *(ecx+4) # Var-type +5891 68/push "dummy"/imm32 +5892 89/<- %ebx 4/r32/esp +5893 # var formal-outputs/ebx: (list var) = {formal-var, 0} +5894 68/push 0/imm32/next +5895 53/push-ebx/formal-var +5896 89/<- %ebx 4/r32/esp +5897 # var primitive1/ebx: primitive +5898 68/push 0/imm32/next +5899 68/push 0/imm32/output-is-write-only +5900 68/push 0/imm32/no-imm32 +5901 68/push 0/imm32/no-r32 +5902 68/push 3/imm32/rm32-in-first-output +5903 68/push "ff 0/subop/increment"/imm32/subx-name +5904 53/push-ebx/outputs/formal-outputs +5905 68/push 0/imm32/inouts +5906 68/push "increment"/imm32/name +5907 89/<- %ebx 4/r32/esp +5908 # var primitives/ebx: primitive +5909 53/push-ebx/next +5910 68/push 0/imm32/output-is-write-only +5911 68/push 0/imm32/no-imm32 +5912 68/push 0/imm32/no-r32 +5913 68/push 1/imm32/rm32-is-first-inout +5914 68/push "ff 0/subop/increment"/imm32/subx-name +5915 68/push 0/imm32/outputs +5916 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +5917 68/push "increment"/imm32/name +5918 89/<- %ebx 4/r32/esp +5919 # convert +5920 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5921 (flush _test-output-buffered-file) +5922 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5928 # check output +5929 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") +5930 # . epilogue +5931 89/<- %esp 5/r32/ebp +5932 5d/pop-to-ebp +5933 c3/return +5934 +5935 test-emit-subx-statement-select-primitive-2: +5936 # Select the right primitive between overloads. +5937 # foo <- increment +5938 # => +5939 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5940 # +5941 # There's a variable on the var stack as follows: +5942 # name: 'foo' +5943 # type: int +5944 # register: 'eax' +5945 # +5946 # There's two primitives, as follows: +5947 # - name: 'increment' +5948 # out: int/reg +5949 # value: 'ff 0/subop/increment' +5950 # - name: 'increment' +5951 # inout: int/mem +5952 # value: 'ff 0/subop/increment' +5953 # +5954 # There's nothing in functions. +5955 # +5956 # . prologue +5957 55/push-ebp +5958 89/<- %ebp 4/r32/esp +5959 # setup +5960 (clear-stream _test-output-stream) +5961 (clear-stream $_test-output-buffered-file->buffer) +5962 # var type/ecx: (handle tree type-id) = int +5963 68/push 0/imm32/right/null +5964 68/push 1/imm32/left/int +5965 89/<- %ecx 4/r32/esp +5966 # var var-foo/ecx: var in eax +5967 68/push "eax"/imm32/register +5968 68/push 0/imm32/no-stack-offset +5969 68/push 1/imm32/block-depth +5970 51/push-ecx +5971 68/push "foo"/imm32 +5972 89/<- %ecx 4/r32/esp +5973 # var inouts/edi: (list var) +5974 68/push 0/imm32/next +5975 51/push-ecx/var-foo +5976 89/<- %edi 4/r32/esp +5977 # var stmt/esi: statement +5978 68/push 0/imm32/next +5979 68/push 0/imm32/outputs +5980 57/push-edi/inouts +5981 68/push "increment"/imm32/operation +5982 68/push 1/imm32 +5983 89/<- %esi 4/r32/esp +5984 # var formal-var/ebx: var in any register +5985 68/push Any-register/imm32 5986 68/push 0/imm32/no-stack-offset 5987 68/push 1/imm32/block-depth -5988 51/push-ecx -5989 68/push "var1"/imm32 -5990 89/<- %ecx 4/r32/esp -5991 # var var-var2/edx: var in ecx -5992 68/push "ecx"/imm32/register -5993 68/push 0/imm32/no-stack-offset -5994 68/push 1/imm32/block-depth -5995 ff 6/subop/push *(ecx+4) # Var-type -5996 68/push "var2"/imm32 -5997 89/<- %edx 4/r32/esp -5998 # var inouts/esi: (list var2) -5999 68/push 0/imm32/next -6000 52/push-edx/var-var2 -6001 89/<- %esi 4/r32/esp -6002 # var outputs/edi: (list var1) -6003 68/push 0/imm32/next -6004 51/push-ecx/var-var1 -6005 89/<- %edi 4/r32/esp -6006 # var stmt/esi: statement -6007 68/push 0/imm32/next -6008 57/push-edi/outputs -6009 56/push-esi/inouts -6010 68/push "add"/imm32/operation -6011 68/push 1/imm32 -6012 89/<- %esi 4/r32/esp -6013 # convert -6014 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -6015 (flush _test-output-buffered-file) -6016 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -6022 # check output -6023 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") -6024 # . epilogue -6025 89/<- %esp 5/r32/ebp -6026 5d/pop-to-ebp -6027 c3/return -6028 -6029 test-add-reg-to-mem: -6030 # add-to var1 var2/reg -6031 # => -6032 # 01/add *(ebp+__) var2 -6033 # -6034 # . prologue -6035 55/push-ebp -6036 89/<- %ebp 4/r32/esp -6037 # setup -6038 (clear-stream _test-output-stream) -6039 (clear-stream $_test-output-buffered-file->buffer) -6040 # var type/ecx: (handle tree type-id) = int -6041 68/push 0/imm32/right/null -6042 68/push 1/imm32/left/int -6043 89/<- %ecx 4/r32/esp -6044 # var var-var1/ecx: var -6045 68/push 0/imm32/no-register -6046 68/push 8/imm32/stack-offset -6047 68/push 1/imm32/block-depth -6048 51/push-ecx -6049 68/push "var1"/imm32 -6050 89/<- %ecx 4/r32/esp -6051 # var var-var2/edx: var in ecx -6052 68/push "ecx"/imm32/register -6053 68/push 0/imm32/no-stack-offset -6054 68/push 1/imm32/block-depth -6055 ff 6/subop/push *(ecx+4) # Var-type -6056 68/push "var2"/imm32 -6057 89/<- %edx 4/r32/esp -6058 # var inouts/esi: (list var2) -6059 68/push 0/imm32/next -6060 52/push-edx/var-var2 -6061 89/<- %esi 4/r32/esp -6062 # var inouts = (list var1 var2) -6063 56/push-esi/next -6064 51/push-ecx/var-var1 -6065 89/<- %esi 4/r32/esp -6066 # var stmt/esi: statement -6067 68/push 0/imm32/next -6068 68/push 0/imm32/outputs -6069 56/push-esi/inouts -6070 68/push "add-to"/imm32/operation -6071 68/push 1/imm32 -6072 89/<- %esi 4/r32/esp -6073 # convert -6074 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -6075 (flush _test-output-buffered-file) -6076 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -6082 # check output -6083 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") -6084 # . epilogue -6085 89/<- %esp 5/r32/ebp -6086 5d/pop-to-ebp -6087 c3/return -6088 -6089 test-add-mem-to-reg: -6090 # var1/reg <- add var2 -6091 # => -6092 # 03/add *(ebp+__) var1 -6093 # -6094 # . prologue -6095 55/push-ebp -6096 89/<- %ebp 4/r32/esp -6097 # setup -6098 (clear-stream _test-output-stream) -6099 (clear-stream $_test-output-buffered-file->buffer) -6100 # var type/ecx: (handle tree type-id) = int -6101 68/push 0/imm32/right/null -6102 68/push 1/imm32/left/int -6103 89/<- %ecx 4/r32/esp -6104 # var var-var1/ecx: var in eax -6105 68/push "eax"/imm32/register -6106 68/push 0/imm32/no-stack-offset -6107 68/push 1/imm32/block-depth -6108 51/push-ecx -6109 68/push "var1"/imm32 -6110 89/<- %ecx 4/r32/esp -6111 # var var-var2/edx: var -6112 68/push 0/imm32/no-register -6113 68/push 8/imm32/stack-offset -6114 68/push 1/imm32/block-depth -6115 ff 6/subop/push *(ecx+4) # Var-type -6116 68/push "var2"/imm32 -6117 89/<- %edx 4/r32/esp -6118 # var inouts/esi: (list var2) -6119 68/push 0/imm32/next -6120 52/push-edx/var-var2 -6121 89/<- %esi 4/r32/esp -6122 # var outputs/edi: (list var1) -6123 68/push 0/imm32/next -6124 51/push-ecx/var-var1 -6125 89/<- %edi 4/r32/esp -6126 # var stmt/esi: statement -6127 68/push 0/imm32/next -6128 57/push-edi/outputs -6129 56/push-esi/inouts -6130 68/push "add"/imm32/operation -6131 68/push 1/imm32 -6132 89/<- %esi 4/r32/esp -6133 # convert -6134 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -6135 (flush _test-output-buffered-file) -6136 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -6142 # check output -6143 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") -6144 # . epilogue -6145 89/<- %esp 5/r32/ebp -6146 5d/pop-to-ebp -6147 c3/return -6148 -6149 test-add-literal-to-eax: -6150 # var1/eax <- add 0x34 -6151 # => -6152 # 05/add-to-eax 0x34/imm32 -6153 # -6154 # . prologue -6155 55/push-ebp -6156 89/<- %ebp 4/r32/esp -6157 # setup -6158 (clear-stream _test-output-stream) -6159 (clear-stream $_test-output-buffered-file->buffer) -6160 # var type/ecx: (handle tree type-id) = int -6161 68/push 0/imm32/right/null -6162 68/push 1/imm32/left/int -6163 89/<- %ecx 4/r32/esp -6164 # var var-var1/ecx: var in eax -6165 68/push "eax"/imm32/register -6166 68/push 0/imm32/no-stack-offset -6167 68/push 1/imm32/block-depth -6168 51/push-ecx -6169 68/push "var1"/imm32 -6170 89/<- %ecx 4/r32/esp -6171 # var type/edx: (handle tree type-id) = literal -6172 68/push 0/imm32/right/null -6173 68/push 0/imm32/left/literal -6174 89/<- %edx 4/r32/esp -6175 # var var-var2/edx: var literal -6176 68/push 0/imm32/no-register -6177 68/push 0/imm32/no-stack-offset -6178 68/push 1/imm32/block-depth -6179 52/push-edx -6180 68/push "0x34"/imm32 -6181 89/<- %edx 4/r32/esp -6182 # var inouts/esi: (list var2) -6183 68/push 0/imm32/next -6184 52/push-edx/var-var2 -6185 89/<- %esi 4/r32/esp -6186 # var outputs/edi: (list var1) -6187 68/push 0/imm32/next -6188 51/push-ecx/var-var1 -6189 89/<- %edi 4/r32/esp -6190 # var stmt/esi: statement -6191 68/push 0/imm32/next -6192 57/push-edi/outputs -6193 56/push-esi/inouts -6194 68/push "add"/imm32/operation -6195 68/push 1/imm32 -6196 89/<- %esi 4/r32/esp -6197 # convert -6198 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -6199 (flush _test-output-buffered-file) -6200 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -6206 # check output -6207 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") -6208 # . epilogue -6209 89/<- %esp 5/r32/ebp -6210 5d/pop-to-ebp -6211 c3/return -6212 -6213 test-add-literal-to-reg: -6214 # var1/ecx <- add 0x34 -6215 # => -6216 # 81 0/subop/add %ecx 0x34/imm32 -6217 # -6218 # . prologue -6219 55/push-ebp -6220 89/<- %ebp 4/r32/esp -6221 # setup -6222 (clear-stream _test-output-stream) -6223 (clear-stream $_test-output-buffered-file->buffer) -6224 # var type/ecx: (handle tree type-id) = int -6225 68/push 0/imm32/right/null -6226 68/push 1/imm32/left/int -6227 89/<- %ecx 4/r32/esp -6228 # var var-var1/ecx: var in ecx -6229 68/push "ecx"/imm32/register -6230 68/push 0/imm32/no-stack-offset -6231 68/push 1/imm32/block-depth -6232 51/push-ecx -6233 68/push "var1"/imm32 -6234 89/<- %ecx 4/r32/esp -6235 # var type/edx: (handle tree type-id) = literal -6236 68/push 0/imm32/right/null -6237 68/push 0/imm32/left/literal -6238 89/<- %edx 4/r32/esp -6239 # var var-var2/edx: var literal -6240 68/push 0/imm32/no-register -6241 68/push 0/imm32/no-stack-offset -6242 68/push 1/imm32/block-depth -6243 52/push-edx -6244 68/push "0x34"/imm32 -6245 89/<- %edx 4/r32/esp -6246 # var inouts/esi: (list var2) -6247 68/push 0/imm32/next -6248 52/push-edx/var-var2 -6249 89/<- %esi 4/r32/esp -6250 # var outputs/edi: (list var1) -6251 68/push 0/imm32/next -6252 51/push-ecx/var-var1 -6253 89/<- %edi 4/r32/esp -6254 # var stmt/esi: statement -6255 68/push 0/imm32/next -6256 57/push-edi/outputs -6257 56/push-esi/inouts -6258 68/push "add"/imm32/operation -6259 68/push 1/imm32 -6260 89/<- %esi 4/r32/esp -6261 # convert -6262 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -6263 (flush _test-output-buffered-file) -6264 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -6270 # check output -6271 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") -6272 # . epilogue -6273 89/<- %esp 5/r32/ebp -6274 5d/pop-to-ebp -6275 c3/return -6276 -6277 test-add-literal-to-mem: -6278 # add-to var1, 0x34 -6279 # => -6280 # 81 0/subop/add %eax 0x34/imm32 -6281 # -6282 # . prologue -6283 55/push-ebp -6284 89/<- %ebp 4/r32/esp -6285 # setup -6286 (clear-stream _test-output-stream) -6287 (clear-stream $_test-output-buffered-file->buffer) -6288 # var type/ecx: (handle tree type-id) = int -6289 68/push 0/imm32/right/null -6290 68/push 1/imm32/left/int -6291 89/<- %ecx 4/r32/esp -6292 # var var-var1/ecx: var -6293 68/push 0/imm32/no-register -6294 68/push 8/imm32/stack-offset -6295 68/push 1/imm32/block-depth -6296 51/push-ecx -6297 68/push "var1"/imm32 -6298 89/<- %ecx 4/r32/esp -6299 # var type/edx: (handle tree type-id) = literal -6300 68/push 0/imm32/right/null -6301 68/push 0/imm32/left/literal -6302 89/<- %edx 4/r32/esp -6303 # var var-var2/edx: var literal -6304 68/push 0/imm32/no-register -6305 68/push 0/imm32/no-stack-offset -6306 68/push 1/imm32/block-depth -6307 52/push-edx -6308 68/push "0x34"/imm32 -6309 89/<- %edx 4/r32/esp -6310 # var inouts/esi: (list var2) -6311 68/push 0/imm32/next -6312 52/push-edx/var-var2 -6313 89/<- %esi 4/r32/esp -6314 # var inouts = (list var1 inouts) -6315 56/push-esi/next -6316 51/push-ecx/var-var1 -6317 89/<- %esi 4/r32/esp -6318 # var stmt/esi: statement -6319 68/push 0/imm32/next -6320 68/push 0/imm32/outputs -6321 56/push-esi/inouts -6322 68/push "add-to"/imm32/operation -6323 68/push 1/imm32 -6324 89/<- %esi 4/r32/esp -6325 # convert -6326 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -6327 (flush _test-output-buffered-file) -6328 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -6334 # check output -6335 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") -6336 # . epilogue -6337 89/<- %esp 5/r32/ebp -6338 5d/pop-to-ebp -6339 c3/return -6340 -6341 test-emit-subx-statement-function-call: -6342 # Call a function on a variable on the stack. -6343 # f foo -6344 # => -6345 # (f2 *(ebp-8)) -6346 # (Changing the function name supports overloading in general, but here it -6347 # just serves to help disambiguate things.) -6348 # -6349 # There's a variable on the var stack as follows: -6350 # name: 'foo' -6351 # type: int -6352 # stack-offset: -8 -6353 # -6354 # There's nothing in primitives. -6355 # -6356 # There's a function with this info: -6357 # name: 'f' -6358 # inout: int/mem -6359 # value: 'f2' -6360 # -6361 # . prologue -6362 55/push-ebp -6363 89/<- %ebp 4/r32/esp -6364 # setup -6365 (clear-stream _test-output-stream) -6366 (clear-stream $_test-output-buffered-file->buffer) -6367 # var type/ecx: (handle tree type-id) = int -6368 68/push 0/imm32/right/null -6369 68/push 1/imm32/left/int -6370 89/<- %ecx 4/r32/esp -6371 # var var-foo/ecx: var -6372 68/push 0/imm32/no-register -6373 68/push -8/imm32/stack-offset -6374 68/push 0/imm32/block-depth -6375 51/push-ecx -6376 68/push "foo"/imm32 -6377 89/<- %ecx 4/r32/esp -6378 # var operands/esi: (list var) -6379 68/push 0/imm32/next -6380 51/push-ecx/var-foo -6381 89/<- %esi 4/r32/esp -6382 # var stmt/esi: statement -6383 68/push 0/imm32/next -6384 68/push 0/imm32/outputs -6385 56/push-esi/inouts -6386 68/push "f"/imm32/operation -6387 68/push 1/imm32 -6388 89/<- %esi 4/r32/esp -6389 # var functions/ebx: function -6390 68/push 0/imm32/next -6391 68/push 0/imm32/body -6392 68/push 0/imm32/outputs -6393 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -6394 68/push "f2"/imm32/subx-name -6395 68/push "f"/imm32/name -6396 89/<- %ebx 4/r32/esp -6397 # convert -6398 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -6399 (flush _test-output-buffered-file) -6400 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -6406 # check output -6407 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") -6408 # . epilogue -6409 89/<- %esp 5/r32/ebp -6410 5d/pop-to-ebp -6411 c3/return -6412 -6413 test-emit-subx-statement-function-call-with-literal-arg: -6414 # Call a function on a literal. -6415 # f 34 -6416 # => -6417 # (f2 34) -6418 # -6419 # . prologue -6420 55/push-ebp -6421 89/<- %ebp 4/r32/esp -6422 # setup -6423 (clear-stream _test-output-stream) -6424 (clear-stream $_test-output-buffered-file->buffer) -6425 # var type/ecx: (handle tree type-id) = literal -6426 68/push 0/imm32/right/null -6427 68/push 0/imm32/left/literal -6428 89/<- %ecx 4/r32/esp -6429 # var var-foo/ecx: var literal -6430 68/push 0/imm32/no-register -6431 68/push 0/imm32/no-stack-offset -6432 68/push 0/imm32/block-depth -6433 51/push-ecx -6434 68/push "34"/imm32 -6435 89/<- %ecx 4/r32/esp -6436 # var operands/esi: (list var) +5988 ff 6/subop/push *(ecx+4) # Var-type +5989 68/push "dummy"/imm32 +5990 89/<- %ebx 4/r32/esp +5991 # var operand/ebx: (list var) +5992 68/push 0/imm32/next +5993 53/push-ebx/formal-var +5994 89/<- %ebx 4/r32/esp +5995 # var primitive1/ebx: primitive +5996 68/push 0/imm32/next +5997 68/push 0/imm32/output-is-write-only +5998 68/push 0/imm32/no-imm32 +5999 68/push 0/imm32/no-r32 +6000 68/push 3/imm32/rm32-in-first-output +6001 68/push "ff 0/subop/increment"/imm32/subx-name +6002 53/push-ebx/outputs/formal-outputs +6003 68/push 0/imm32/inouts +6004 68/push "increment"/imm32/name +6005 89/<- %ebx 4/r32/esp +6006 # var primitives/ebx: primitive +6007 53/push-ebx/next +6008 68/push 0/imm32/output-is-write-only +6009 68/push 0/imm32/no-imm32 +6010 68/push 0/imm32/no-r32 +6011 68/push 1/imm32/rm32-is-first-inout +6012 68/push "ff 0/subop/increment"/imm32/subx-name +6013 68/push 0/imm32/outputs +6014 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +6015 68/push "increment"/imm32/name +6016 89/<- %ebx 4/r32/esp +6017 # convert +6018 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +6019 (flush _test-output-buffered-file) +6020 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6026 # check output +6027 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") +6028 # . epilogue +6029 89/<- %esp 5/r32/ebp +6030 5d/pop-to-ebp +6031 c3/return +6032 +6033 test-increment-register: +6034 # Select the right primitive between overloads. +6035 # foo <- increment +6036 # => +6037 # 50/increment-eax +6038 # +6039 # There's a variable on the var stack as follows: +6040 # name: 'foo' +6041 # type: int +6042 # register: 'eax' +6043 # +6044 # Primitives are the global definitions. +6045 # +6046 # There are no functions defined. +6047 # +6048 # . prologue +6049 55/push-ebp +6050 89/<- %ebp 4/r32/esp +6051 # setup +6052 (clear-stream _test-output-stream) +6053 (clear-stream $_test-output-buffered-file->buffer) +6054 # var type/ecx: (handle tree type-id) = int +6055 68/push 0/imm32/right/null +6056 68/push 1/imm32/left/int +6057 89/<- %ecx 4/r32/esp +6058 # var var-foo/ecx: var in eax +6059 68/push "eax"/imm32/register +6060 68/push 0/imm32/no-stack-offset +6061 68/push 1/imm32/block-depth +6062 51/push-ecx +6063 68/push "foo"/imm32 +6064 89/<- %ecx 4/r32/esp +6065 # var real-outputs/edi: (list var) +6066 68/push 0/imm32/next +6067 51/push-ecx/var-foo +6068 89/<- %edi 4/r32/esp +6069 # var stmt/esi: statement +6070 68/push 0/imm32/next +6071 57/push-edi/outputs +6072 68/push 0/imm32/inouts +6073 68/push "increment"/imm32/operation +6074 68/push 1/imm32/regular-statement +6075 89/<- %esi 4/r32/esp +6076 # convert +6077 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +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 "40/increment-eax" "F - test-increment-register") +6087 # . epilogue +6088 89/<- %esp 5/r32/ebp +6089 5d/pop-to-ebp +6090 c3/return +6091 +6092 test-increment-var: +6093 # Select the right primitive between overloads. +6094 # foo <- increment +6095 # => +6096 # ff 0/subop/increment %eax # sub-optimal, but should suffice +6097 # +6098 # There's a variable on the var stack as follows: +6099 # name: 'foo' +6100 # type: int +6101 # register: 'eax' +6102 # +6103 # Primitives are the global definitions. +6104 # +6105 # There are no functions defined. +6106 # +6107 # . prologue +6108 55/push-ebp +6109 89/<- %ebp 4/r32/esp +6110 # setup +6111 (clear-stream _test-output-stream) +6112 (clear-stream $_test-output-buffered-file->buffer) +6113 # var type/ecx: (handle tree type-id) = int +6114 68/push 0/imm32/right/null +6115 68/push 1/imm32/left/int +6116 89/<- %ecx 4/r32/esp +6117 # var var-foo/ecx: var in eax +6118 68/push "eax"/imm32/register +6119 68/push 0/imm32/no-stack-offset +6120 68/push 1/imm32/block-depth +6121 51/push-ecx +6122 68/push "foo"/imm32 +6123 89/<- %ecx 4/r32/esp +6124 # var inouts/edi: (list var) +6125 68/push 0/imm32/next +6126 51/push-ecx/var-foo +6127 89/<- %edi 4/r32/esp +6128 # var stmt/esi: statement +6129 68/push 0/imm32/next +6130 68/push 0/imm32/outputs +6131 57/push-edi/inouts +6132 68/push "increment"/imm32/operation +6133 68/push 1/imm32 +6134 89/<- %esi 4/r32/esp +6135 # convert +6136 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +6137 (flush _test-output-buffered-file) +6138 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6144 # check output +6145 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") +6146 # . epilogue +6147 89/<- %esp 5/r32/ebp +6148 5d/pop-to-ebp +6149 c3/return +6150 +6151 test-add-reg-to-reg: +6152 # var1/reg <- add var2/reg +6153 # => +6154 # 01/add %var1 var2 +6155 # +6156 # . prologue +6157 55/push-ebp +6158 89/<- %ebp 4/r32/esp +6159 # setup +6160 (clear-stream _test-output-stream) +6161 (clear-stream $_test-output-buffered-file->buffer) +6162 # var type/ecx: (handle tree type-id) = int +6163 68/push 0/imm32/right/null +6164 68/push 1/imm32/left/int +6165 89/<- %ecx 4/r32/esp +6166 # var var-var1/ecx: var in eax +6167 68/push "eax"/imm32/register +6168 68/push 0/imm32/no-stack-offset +6169 68/push 1/imm32/block-depth +6170 51/push-ecx +6171 68/push "var1"/imm32 +6172 89/<- %ecx 4/r32/esp +6173 # var var-var2/edx: var in ecx +6174 68/push "ecx"/imm32/register +6175 68/push 0/imm32/no-stack-offset +6176 68/push 1/imm32/block-depth +6177 ff 6/subop/push *(ecx+4) # Var-type +6178 68/push "var2"/imm32 +6179 89/<- %edx 4/r32/esp +6180 # var inouts/esi: (list var2) +6181 68/push 0/imm32/next +6182 52/push-edx/var-var2 +6183 89/<- %esi 4/r32/esp +6184 # var outputs/edi: (list var1) +6185 68/push 0/imm32/next +6186 51/push-ecx/var-var1 +6187 89/<- %edi 4/r32/esp +6188 # var stmt/esi: statement +6189 68/push 0/imm32/next +6190 57/push-edi/outputs +6191 56/push-esi/inouts +6192 68/push "add"/imm32/operation +6193 68/push 1/imm32 +6194 89/<- %esi 4/r32/esp +6195 # convert +6196 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +6197 (flush _test-output-buffered-file) +6198 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6204 # check output +6205 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") +6206 # . epilogue +6207 89/<- %esp 5/r32/ebp +6208 5d/pop-to-ebp +6209 c3/return +6210 +6211 test-add-reg-to-mem: +6212 # add-to var1 var2/reg +6213 # => +6214 # 01/add *(ebp+__) var2 +6215 # +6216 # . prologue +6217 55/push-ebp +6218 89/<- %ebp 4/r32/esp +6219 # setup +6220 (clear-stream _test-output-stream) +6221 (clear-stream $_test-output-buffered-file->buffer) +6222 # var type/ecx: (handle tree type-id) = int +6223 68/push 0/imm32/right/null +6224 68/push 1/imm32/left/int +6225 89/<- %ecx 4/r32/esp +6226 # var var-var1/ecx: var +6227 68/push 0/imm32/no-register +6228 68/push 8/imm32/stack-offset +6229 68/push 1/imm32/block-depth +6230 51/push-ecx +6231 68/push "var1"/imm32 +6232 89/<- %ecx 4/r32/esp +6233 # var var-var2/edx: var in ecx +6234 68/push "ecx"/imm32/register +6235 68/push 0/imm32/no-stack-offset +6236 68/push 1/imm32/block-depth +6237 ff 6/subop/push *(ecx+4) # Var-type +6238 68/push "var2"/imm32 +6239 89/<- %edx 4/r32/esp +6240 # var inouts/esi: (list var2) +6241 68/push 0/imm32/next +6242 52/push-edx/var-var2 +6243 89/<- %esi 4/r32/esp +6244 # var inouts = (list var1 var2) +6245 56/push-esi/next +6246 51/push-ecx/var-var1 +6247 89/<- %esi 4/r32/esp +6248 # var stmt/esi: statement +6249 68/push 0/imm32/next +6250 68/push 0/imm32/outputs +6251 56/push-esi/inouts +6252 68/push "add-to"/imm32/operation +6253 68/push 1/imm32 +6254 89/<- %esi 4/r32/esp +6255 # convert +6256 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +6257 (flush _test-output-buffered-file) +6258 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6264 # check output +6265 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") +6266 # . epilogue +6267 89/<- %esp 5/r32/ebp +6268 5d/pop-to-ebp +6269 c3/return +6270 +6271 test-add-mem-to-reg: +6272 # var1/reg <- add var2 +6273 # => +6274 # 03/add *(ebp+__) var1 +6275 # +6276 # . prologue +6277 55/push-ebp +6278 89/<- %ebp 4/r32/esp +6279 # setup +6280 (clear-stream _test-output-stream) +6281 (clear-stream $_test-output-buffered-file->buffer) +6282 # var type/ecx: (handle tree type-id) = int +6283 68/push 0/imm32/right/null +6284 68/push 1/imm32/left/int +6285 89/<- %ecx 4/r32/esp +6286 # var var-var1/ecx: var in eax +6287 68/push "eax"/imm32/register +6288 68/push 0/imm32/no-stack-offset +6289 68/push 1/imm32/block-depth +6290 51/push-ecx +6291 68/push "var1"/imm32 +6292 89/<- %ecx 4/r32/esp +6293 # var var-var2/edx: var +6294 68/push 0/imm32/no-register +6295 68/push 8/imm32/stack-offset +6296 68/push 1/imm32/block-depth +6297 ff 6/subop/push *(ecx+4) # Var-type +6298 68/push "var2"/imm32 +6299 89/<- %edx 4/r32/esp +6300 # var inouts/esi: (list var2) +6301 68/push 0/imm32/next +6302 52/push-edx/var-var2 +6303 89/<- %esi 4/r32/esp +6304 # var outputs/edi: (list var1) +6305 68/push 0/imm32/next +6306 51/push-ecx/var-var1 +6307 89/<- %edi 4/r32/esp +6308 # var stmt/esi: statement +6309 68/push 0/imm32/next +6310 57/push-edi/outputs +6311 56/push-esi/inouts +6312 68/push "add"/imm32/operation +6313 68/push 1/imm32 +6314 89/<- %esi 4/r32/esp +6315 # convert +6316 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +6317 (flush _test-output-buffered-file) +6318 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6324 # check output +6325 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") +6326 # . epilogue +6327 89/<- %esp 5/r32/ebp +6328 5d/pop-to-ebp +6329 c3/return +6330 +6331 test-add-literal-to-eax: +6332 # var1/eax <- add 0x34 +6333 # => +6334 # 05/add-to-eax 0x34/imm32 +6335 # +6336 # . prologue +6337 55/push-ebp +6338 89/<- %ebp 4/r32/esp +6339 # setup +6340 (clear-stream _test-output-stream) +6341 (clear-stream $_test-output-buffered-file->buffer) +6342 # var type/ecx: (handle tree type-id) = int +6343 68/push 0/imm32/right/null +6344 68/push 1/imm32/left/int +6345 89/<- %ecx 4/r32/esp +6346 # var var-var1/ecx: var in eax +6347 68/push "eax"/imm32/register +6348 68/push 0/imm32/no-stack-offset +6349 68/push 1/imm32/block-depth +6350 51/push-ecx +6351 68/push "var1"/imm32 +6352 89/<- %ecx 4/r32/esp +6353 # var type/edx: (handle tree type-id) = literal +6354 68/push 0/imm32/right/null +6355 68/push 0/imm32/left/literal +6356 89/<- %edx 4/r32/esp +6357 # var var-var2/edx: var literal +6358 68/push 0/imm32/no-register +6359 68/push 0/imm32/no-stack-offset +6360 68/push 1/imm32/block-depth +6361 52/push-edx +6362 68/push "0x34"/imm32 +6363 89/<- %edx 4/r32/esp +6364 # var inouts/esi: (list var2) +6365 68/push 0/imm32/next +6366 52/push-edx/var-var2 +6367 89/<- %esi 4/r32/esp +6368 # var outputs/edi: (list var1) +6369 68/push 0/imm32/next +6370 51/push-ecx/var-var1 +6371 89/<- %edi 4/r32/esp +6372 # var stmt/esi: statement +6373 68/push 0/imm32/next +6374 57/push-edi/outputs +6375 56/push-esi/inouts +6376 68/push "add"/imm32/operation +6377 68/push 1/imm32 +6378 89/<- %esi 4/r32/esp +6379 # convert +6380 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +6381 (flush _test-output-buffered-file) +6382 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6388 # check output +6389 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") +6390 # . epilogue +6391 89/<- %esp 5/r32/ebp +6392 5d/pop-to-ebp +6393 c3/return +6394 +6395 test-add-literal-to-reg: +6396 # var1/ecx <- add 0x34 +6397 # => +6398 # 81 0/subop/add %ecx 0x34/imm32 +6399 # +6400 # . prologue +6401 55/push-ebp +6402 89/<- %ebp 4/r32/esp +6403 # setup +6404 (clear-stream _test-output-stream) +6405 (clear-stream $_test-output-buffered-file->buffer) +6406 # var type/ecx: (handle tree type-id) = int +6407 68/push 0/imm32/right/null +6408 68/push 1/imm32/left/int +6409 89/<- %ecx 4/r32/esp +6410 # var var-var1/ecx: var in ecx +6411 68/push "ecx"/imm32/register +6412 68/push 0/imm32/no-stack-offset +6413 68/push 1/imm32/block-depth +6414 51/push-ecx +6415 68/push "var1"/imm32 +6416 89/<- %ecx 4/r32/esp +6417 # var type/edx: (handle tree type-id) = literal +6418 68/push 0/imm32/right/null +6419 68/push 0/imm32/left/literal +6420 89/<- %edx 4/r32/esp +6421 # var var-var2/edx: var literal +6422 68/push 0/imm32/no-register +6423 68/push 0/imm32/no-stack-offset +6424 68/push 1/imm32/block-depth +6425 52/push-edx +6426 68/push "0x34"/imm32 +6427 89/<- %edx 4/r32/esp +6428 # var inouts/esi: (list var2) +6429 68/push 0/imm32/next +6430 52/push-edx/var-var2 +6431 89/<- %esi 4/r32/esp +6432 # var outputs/edi: (list var1) +6433 68/push 0/imm32/next +6434 51/push-ecx/var-var1 +6435 89/<- %edi 4/r32/esp +6436 # var stmt/esi: statement 6437 68/push 0/imm32/next -6438 51/push-ecx/var-foo -6439 89/<- %esi 4/r32/esp -6440 # var stmt/esi: statement -6441 68/push 0/imm32/next -6442 68/push 0/imm32/outputs -6443 56/push-esi/inouts -6444 68/push "f"/imm32/operation -6445 68/push 1/imm32 -6446 89/<- %esi 4/r32/esp -6447 # var functions/ebx: function -6448 68/push 0/imm32/next -6449 68/push 0/imm32/body -6450 68/push 0/imm32/outputs -6451 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -6452 68/push "f2"/imm32/subx-name -6453 68/push "f"/imm32/name -6454 89/<- %ebx 4/r32/esp -6455 # convert -6456 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -6457 (flush _test-output-buffered-file) -6458 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -6464 # check output -6465 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") -6466 # . epilogue -6467 89/<- %esp 5/r32/ebp -6468 5d/pop-to-ebp -6469 c3/return -6470 -6471 emit-subx-prologue: # out: (addr buffered-file) -6472 # . prologue -6473 55/push-ebp -6474 89/<- %ebp 4/r32/esp -6475 # -6476 (write-buffered *(ebp+8) "# . prologue\n") -6477 (write-buffered *(ebp+8) "55/push-ebp\n") -6478 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") -6479 $emit-subx-prologue:end: -6480 # . epilogue -6481 89/<- %esp 5/r32/ebp -6482 5d/pop-to-ebp -6483 c3/return -6484 -6485 emit-subx-epilogue: # out: (addr buffered-file) -6486 # . prologue -6487 55/push-ebp -6488 89/<- %ebp 4/r32/esp -6489 # -6490 (write-buffered *(ebp+8) "# . epilogue\n") -6491 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") -6492 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") -6493 (write-buffered *(ebp+8) "c3/return\n") -6494 $emit-subx-epilogue:end: -6495 # . epilogue -6496 89/<- %esp 5/r32/ebp -6497 5d/pop-to-ebp -6498 c3/return +6438 57/push-edi/outputs +6439 56/push-esi/inouts +6440 68/push "add"/imm32/operation +6441 68/push 1/imm32 +6442 89/<- %esi 4/r32/esp +6443 # convert +6444 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +6445 (flush _test-output-buffered-file) +6446 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6452 # check output +6453 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") +6454 # . epilogue +6455 89/<- %esp 5/r32/ebp +6456 5d/pop-to-ebp +6457 c3/return +6458 +6459 test-add-literal-to-mem: +6460 # add-to var1, 0x34 +6461 # => +6462 # 81 0/subop/add %eax 0x34/imm32 +6463 # +6464 # . prologue +6465 55/push-ebp +6466 89/<- %ebp 4/r32/esp +6467 # setup +6468 (clear-stream _test-output-stream) +6469 (clear-stream $_test-output-buffered-file->buffer) +6470 # var type/ecx: (handle tree type-id) = int +6471 68/push 0/imm32/right/null +6472 68/push 1/imm32/left/int +6473 89/<- %ecx 4/r32/esp +6474 # var var-var1/ecx: var +6475 68/push 0/imm32/no-register +6476 68/push 8/imm32/stack-offset +6477 68/push 1/imm32/block-depth +6478 51/push-ecx +6479 68/push "var1"/imm32 +6480 89/<- %ecx 4/r32/esp +6481 # var type/edx: (handle tree type-id) = literal +6482 68/push 0/imm32/right/null +6483 68/push 0/imm32/left/literal +6484 89/<- %edx 4/r32/esp +6485 # var var-var2/edx: var literal +6486 68/push 0/imm32/no-register +6487 68/push 0/imm32/no-stack-offset +6488 68/push 1/imm32/block-depth +6489 52/push-edx +6490 68/push "0x34"/imm32 +6491 89/<- %edx 4/r32/esp +6492 # var inouts/esi: (list var2) +6493 68/push 0/imm32/next +6494 52/push-edx/var-var2 +6495 89/<- %esi 4/r32/esp +6496 # var inouts = (list var1 inouts) +6497 56/push-esi/next +6498 51/push-ecx/var-var1 +6499 89/<- %esi 4/r32/esp +6500 # var stmt/esi: statement +6501 68/push 0/imm32/next +6502 68/push 0/imm32/outputs +6503 56/push-esi/inouts +6504 68/push "add-to"/imm32/operation +6505 68/push 1/imm32 +6506 89/<- %esi 4/r32/esp +6507 # convert +6508 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +6509 (flush _test-output-buffered-file) +6510 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6516 # check output +6517 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") +6518 # . epilogue +6519 89/<- %esp 5/r32/ebp +6520 5d/pop-to-ebp +6521 c3/return +6522 +6523 test-emit-subx-statement-function-call: +6524 # Call a function on a variable on the stack. +6525 # f foo +6526 # => +6527 # (f2 *(ebp-8)) +6528 # (Changing the function name supports overloading in general, but here it +6529 # just serves to help disambiguate things.) +6530 # +6531 # There's a variable on the var stack as follows: +6532 # name: 'foo' +6533 # type: int +6534 # stack-offset: -8 +6535 # +6536 # There's nothing in primitives. +6537 # +6538 # There's a function with this info: +6539 # name: 'f' +6540 # inout: int/mem +6541 # value: 'f2' +6542 # +6543 # . prologue +6544 55/push-ebp +6545 89/<- %ebp 4/r32/esp +6546 # setup +6547 (clear-stream _test-output-stream) +6548 (clear-stream $_test-output-buffered-file->buffer) +6549 # var type/ecx: (handle tree type-id) = int +6550 68/push 0/imm32/right/null +6551 68/push 1/imm32/left/int +6552 89/<- %ecx 4/r32/esp +6553 # var var-foo/ecx: var +6554 68/push 0/imm32/no-register +6555 68/push -8/imm32/stack-offset +6556 68/push 0/imm32/block-depth +6557 51/push-ecx +6558 68/push "foo"/imm32 +6559 89/<- %ecx 4/r32/esp +6560 # var operands/esi: (list var) +6561 68/push 0/imm32/next +6562 51/push-ecx/var-foo +6563 89/<- %esi 4/r32/esp +6564 # var stmt/esi: statement +6565 68/push 0/imm32/next +6566 68/push 0/imm32/outputs +6567 56/push-esi/inouts +6568 68/push "f"/imm32/operation +6569 68/push 1/imm32 +6570 89/<- %esi 4/r32/esp +6571 # var functions/ebx: function +6572 68/push 0/imm32/next +6573 68/push 0/imm32/body +6574 68/push 0/imm32/outputs +6575 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +6576 68/push "f2"/imm32/subx-name +6577 68/push "f"/imm32/name +6578 89/<- %ebx 4/r32/esp +6579 # convert +6580 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +6581 (flush _test-output-buffered-file) +6582 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6588 # check output +6589 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") +6590 # . epilogue +6591 89/<- %esp 5/r32/ebp +6592 5d/pop-to-ebp +6593 c3/return +6594 +6595 test-emit-subx-statement-function-call-with-literal-arg: +6596 # Call a function on a literal. +6597 # f 34 +6598 # => +6599 # (f2 34) +6600 # +6601 # . prologue +6602 55/push-ebp +6603 89/<- %ebp 4/r32/esp +6604 # setup +6605 (clear-stream _test-output-stream) +6606 (clear-stream $_test-output-buffered-file->buffer) +6607 # var type/ecx: (handle tree type-id) = literal +6608 68/push 0/imm32/right/null +6609 68/push 0/imm32/left/literal +6610 89/<- %ecx 4/r32/esp +6611 # var var-foo/ecx: var literal +6612 68/push 0/imm32/no-register +6613 68/push 0/imm32/no-stack-offset +6614 68/push 0/imm32/block-depth +6615 51/push-ecx +6616 68/push "34"/imm32 +6617 89/<- %ecx 4/r32/esp +6618 # var operands/esi: (list var) +6619 68/push 0/imm32/next +6620 51/push-ecx/var-foo +6621 89/<- %esi 4/r32/esp +6622 # var stmt/esi: statement +6623 68/push 0/imm32/next +6624 68/push 0/imm32/outputs +6625 56/push-esi/inouts +6626 68/push "f"/imm32/operation +6627 68/push 1/imm32 +6628 89/<- %esi 4/r32/esp +6629 # var functions/ebx: function +6630 68/push 0/imm32/next +6631 68/push 0/imm32/body +6632 68/push 0/imm32/outputs +6633 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +6634 68/push "f2"/imm32/subx-name +6635 68/push "f"/imm32/name +6636 89/<- %ebx 4/r32/esp +6637 # convert +6638 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +6639 (flush _test-output-buffered-file) +6640 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +6646 # check output +6647 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") +6648 # . epilogue +6649 89/<- %esp 5/r32/ebp +6650 5d/pop-to-ebp +6651 c3/return +6652 +6653 emit-subx-prologue: # out: (addr buffered-file) +6654 # . prologue +6655 55/push-ebp +6656 89/<- %ebp 4/r32/esp +6657 # +6658 (write-buffered *(ebp+8) "# . prologue\n") +6659 (write-buffered *(ebp+8) "55/push-ebp\n") +6660 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") +6661 $emit-subx-prologue:end: +6662 # . epilogue +6663 89/<- %esp 5/r32/ebp +6664 5d/pop-to-ebp +6665 c3/return +6666 +6667 emit-subx-epilogue: # out: (addr buffered-file) +6668 # . prologue +6669 55/push-ebp +6670 89/<- %ebp 4/r32/esp +6671 # +6672 (write-buffered *(ebp+8) "# . epilogue\n") +6673 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") +6674 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") +6675 (write-buffered *(ebp+8) "c3/return\n") +6676 $emit-subx-epilogue:end: +6677 # . epilogue +6678 89/<- %esp 5/r32/ebp +6679 5d/pop-to-ebp +6680 c3/return -- cgit 1.4.1-2-gfad0