From 8d79145eaa1aa18b5680c0927a372f262c610d17 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Tue, 18 Feb 2020 01:38:13 -0800 Subject: 6025 --- html/apps/factorial.mu.html | 73 +- html/apps/mu.subx.html | 13671 +++++++++++++++++++++--------------------- 2 files changed, 7029 insertions(+), 6715 deletions(-) diff --git a/html/apps/factorial.mu.html b/html/apps/factorial.mu.html index ce28a765..92db0c5b 100644 --- a/html/apps/factorial.mu.html +++ b/html/apps/factorial.mu.html @@ -14,10 +14,11 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } -.CommentedCode { color: #8a8a8a; } .LineNr { } +.Comment { color: #005faf; } .Constant { color: #008787; } .Special { color: #ff6060; } +.Identifier { color: #af5f00; } .Delimiter { color: #c000c0; } .PreProc { color: #c000c0; } --> @@ -55,32 +56,50 @@ if ('onhashchange' in window) { https://github.com/akkartik/mu/blob/master/apps/factorial.mu
- 1 fn main args: (addr array kernel-string) -> exit-status/ebx: int {
- 2 #?   run-tests
- 3 #?   result <- copy 0
- 4   var tmp/eax: int <- factorial 5
- 5   exit-status <- copy tmp
- 6 }
- 7 
- 8 fn factorial n: int -> result/eax: int {
- 9   compare n 1
-10   {
-11     break-if->
-12     result <- copy 1
-13   }
-14   {
-15     break-if-<=
-16     var tmp/ecx: int <- copy n
-17     tmp <- decrement
-18     result <- factorial tmp
-19     result <- multiply n
-20   }
-21 }
-22 
-23 fn test-factorial {
-24   var result/eax: int <- factorial 5
-25   check-ints-equal result 0x78 "F - test-factorial"
-26 }
+ 1 # usage is finicky for now:
+ 2 #   ./translate_mu apps/factorial.mu
+ 3 #   ./a.elf test  # any args? run tests
+ 4 #   ./a.elf       # no args? run factorial(5)
+ 5 fn main args: (addr array kernel-string) -> exit-status/ebx: int {
+ 6   var a/eax: (addr array kernel-string) <- copy args
+ 7   var tmp/ecx: int <- length a
+ 8   $main-body: {
+ 9     compare tmp, 1
+10     # if (len(args) != 1) run-tests()
+11     {
+12       break-if-=
+13       run-tests
+14       exit-status <- copy 0
+15       break $main-body
+16     }
+17     # if (len(args) == 1) factorial(5)
+18     {
+19       break-if-!=
+20       var tmp/eax: int <- factorial 5
+21       exit-status <- copy tmp
+22     }
+23   }
+24 }
+25 
+26 fn factorial n: int -> result/eax: int {
+27   compare n 1
+28   {
+29     break-if->
+30     result <- copy 1
+31   }
+32   {
+33     break-if-<=
+34     var tmp/ecx: int <- copy n
+35     tmp <- decrement
+36     result <- factorial tmp
+37     result <- multiply n
+38   }
+39 }
+40 
+41 fn test-factorial {
+42   var result/eax: int <- factorial 5
+43   check-ints-equal result 0x78 "F - test-factorial"
+44 }
 
diff --git a/html/apps/mu.subx.html b/html/apps/mu.subx.html index 400caeeb..6373baf8 100644 --- a/html/apps/mu.subx.html +++ b/html/apps/mu.subx.html @@ -450,9 +450,9 @@ if ('onhashchange' in window) { 388 55/push-ebp 389 89/<- %ebp 4/r32/esp 390 # - 391 (parse-mu *(ebp+8)) - 392 (check-mu-types) - 393 (emit-subx *(ebp+0xc)) + 391 (parse-mu *(ebp+8)) + 392 (check-mu-types) + 393 (emit-subx *(ebp+0xc)) 394 $convert-mu:end: 395 # . epilogue 396 89/<- %esp 5/r32/ebp @@ -588,7 +588,7 @@ if ('onhashchange' in window) { 541 (clear-stream $_test-input-buffered-file->buffer) 542 (clear-stream _test-output-stream) 543 (clear-stream $_test-output-buffered-file->buffer) - 544 c7 0/subop/copy *Next-block-index 1/imm32 + 544 c7 0/subop/copy *Next-block-index 1/imm32 545 # 546 (write _test-input-stream "fn foo n: int {\n") 547 (write _test-input-stream " increment n\n") @@ -625,7 +625,7 @@ if ('onhashchange' in window) { 583 (clear-stream $_test-input-buffered-file->buffer) 584 (clear-stream _test-output-stream) 585 (clear-stream $_test-output-buffered-file->buffer) - 586 c7 0/subop/copy *Next-block-index 1/imm32 + 586 c7 0/subop/copy *Next-block-index 1/imm32 587 # 588 (write _test-input-stream "fn foo a: int, b: int {\n") 589 (write _test-input-stream " increment b\n") @@ -662,7 +662,7 @@ if ('onhashchange' in window) { 625 (clear-stream $_test-input-buffered-file->buffer) 626 (clear-stream _test-output-stream) 627 (clear-stream $_test-output-buffered-file->buffer) - 628 c7 0/subop/copy *Next-block-index 1/imm32 + 628 c7 0/subop/copy *Next-block-index 1/imm32 629 # 630 (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n") 631 (write _test-input-stream " result <- copy a\n") @@ -701,7 +701,7 @@ if ('onhashchange' in window) { 669 (clear-stream $_test-input-buffered-file->buffer) 670 (clear-stream _test-output-stream) 671 (clear-stream $_test-output-buffered-file->buffer) - 672 c7 0/subop/copy *Next-block-index 1/imm32 + 672 c7 0/subop/copy *Next-block-index 1/imm32 673 # 674 (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n") 675 (write _test-input-stream " result <- copy a\n") @@ -740,7 +740,7 @@ if ('onhashchange' in window) { 713 (clear-stream $_test-input-buffered-file->buffer) 714 (clear-stream _test-output-stream) 715 (clear-stream $_test-output-buffered-file->buffer) - 716 c7 0/subop/copy *Next-block-index 1/imm32 + 716 c7 0/subop/copy *Next-block-index 1/imm32 717 # 718 (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n") 719 (write _test-input-stream " result <- copy a\n") @@ -779,7 +779,7 @@ if ('onhashchange' in window) { 757 (clear-stream $_test-input-buffered-file->buffer) 758 (clear-stream _test-output-stream) 759 (clear-stream $_test-output-buffered-file->buffer) - 760 c7 0/subop/copy *Next-block-index 1/imm32 + 760 c7 0/subop/copy *Next-block-index 1/imm32 761 # 762 (write _test-input-stream "fn main -> result/ebx: int {\n") 763 (write _test-input-stream " result <- do-add 3 4\n") @@ -834,7 +834,7 @@ if ('onhashchange' in window) { 817 (clear-stream $_test-input-buffered-file->buffer) 818 (clear-stream _test-output-stream) 819 (clear-stream $_test-output-buffered-file->buffer) - 820 c7 0/subop/copy *Next-block-index 1/imm32 + 820 c7 0/subop/copy *Next-block-index 1/imm32 821 # 822 (write _test-input-stream "fn foo {\n") 823 (write _test-input-stream " var x: int\n") @@ -874,7 +874,7 @@ if ('onhashchange' in window) { 862 (clear-stream $_test-input-buffered-file->buffer) 863 (clear-stream _test-output-stream) 864 (clear-stream $_test-output-buffered-file->buffer) - 865 c7 0/subop/copy *Next-block-index 1/imm32 + 865 c7 0/subop/copy *Next-block-index 1/imm32 866 # 867 (write _test-input-stream "fn foo {\n") 868 (write _test-input-stream " var x/ecx: int <- copy 3\n") @@ -915,7 +915,7 @@ if ('onhashchange' in window) { 908 (clear-stream $_test-input-buffered-file->buffer) 909 (clear-stream _test-output-stream) 910 (clear-stream $_test-output-buffered-file->buffer) - 911 c7 0/subop/copy *Next-block-index 1/imm32 + 911 c7 0/subop/copy *Next-block-index 1/imm32 912 # 913 (write _test-input-stream "fn foo {\n") 914 (write _test-input-stream " {\n") @@ -961,7 +961,7 @@ if ('onhashchange' in window) { 959 (clear-stream $_test-input-buffered-file->buffer) 960 (clear-stream _test-output-stream) 961 (clear-stream $_test-output-buffered-file->buffer) - 962 c7 0/subop/copy *Next-block-index 1/imm32 + 962 c7 0/subop/copy *Next-block-index 1/imm32 963 # 964 (write _test-input-stream "fn foo {\n") 965 (write _test-input-stream " $bar: {\n") @@ -1007,7 +1007,7 @@ if ('onhashchange' in window) { 1010 (clear-stream $_test-input-buffered-file->buffer) 1011 (clear-stream _test-output-stream) 1012 (clear-stream $_test-output-buffered-file->buffer) -1013 c7 0/subop/copy *Next-block-index 1/imm32 +1013 c7 0/subop/copy *Next-block-index 1/imm32 1014 # 1015 (write _test-input-stream "fn foo x: int {\n") 1016 (write _test-input-stream " {\n") @@ -1056,7 +1056,7 @@ if ('onhashchange' in window) { 1064 (clear-stream $_test-input-buffered-file->buffer) 1065 (clear-stream _test-output-stream) 1066 (clear-stream $_test-output-buffered-file->buffer) -1067 c7 0/subop/copy *Next-block-index 1/imm32 +1067 c7 0/subop/copy *Next-block-index 1/imm32 1068 # 1069 (write _test-input-stream "fn foo x: int {\n") 1070 (write _test-input-stream " $bar: {\n") @@ -1105,7 +1105,7 @@ if ('onhashchange' in window) { 1118 (clear-stream $_test-input-buffered-file->buffer) 1119 (clear-stream _test-output-stream) 1120 (clear-stream $_test-output-buffered-file->buffer) -1121 c7 0/subop/copy *Next-block-index 1/imm32 +1121 c7 0/subop/copy *Next-block-index 1/imm32 1122 # 1123 (write _test-input-stream "fn foo x: int {\n") 1124 (write _test-input-stream " {\n") @@ -1157,7 +1157,7 @@ if ('onhashchange' in window) { 1175 (clear-stream $_test-input-buffered-file->buffer) 1176 (clear-stream _test-output-stream) 1177 (clear-stream $_test-output-buffered-file->buffer) -1178 c7 0/subop/copy *Next-block-index 1/imm32 +1178 c7 0/subop/copy *Next-block-index 1/imm32 1179 # 1180 (write _test-input-stream "fn foo x: int {\n") 1181 (write _test-input-stream " {\n") @@ -1216,7 +1216,7 @@ if ('onhashchange' in window) { 1239 (clear-stream $_test-input-buffered-file->buffer) 1240 (clear-stream _test-output-stream) 1241 (clear-stream $_test-output-buffered-file->buffer) -1242 c7 0/subop/copy *Next-block-index 1/imm32 +1242 c7 0/subop/copy *Next-block-index 1/imm32 1243 # 1244 (write _test-input-stream "fn foo {\n") 1245 (write _test-input-stream " {\n") @@ -1271,7 +1271,7 @@ if ('onhashchange' in window) { 1299 (clear-stream $_test-input-buffered-file->buffer) 1300 (clear-stream _test-output-stream) 1301 (clear-stream $_test-output-buffered-file->buffer) -1302 c7 0/subop/copy *Next-block-index 1/imm32 +1302 c7 0/subop/copy *Next-block-index 1/imm32 1303 # 1304 (write _test-input-stream "fn foo {\n") 1305 (write _test-input-stream " {\n") @@ -1326,7 +1326,7 @@ if ('onhashchange' in window) { 1359 (clear-stream $_test-input-buffered-file->buffer) 1360 (clear-stream _test-output-stream) 1361 (clear-stream $_test-output-buffered-file->buffer) -1362 c7 0/subop/copy *Next-block-index 1/imm32 +1362 c7 0/subop/copy *Next-block-index 1/imm32 1363 # 1364 (write _test-input-stream "fn foo {\n") 1365 (write _test-input-stream " {\n") @@ -1374,7 +1374,7 @@ if ('onhashchange' in window) { 1412 (clear-stream $_test-input-buffered-file->buffer) 1413 (clear-stream _test-output-stream) 1414 (clear-stream $_test-output-buffered-file->buffer) -1415 c7 0/subop/copy *Next-block-index 1/imm32 +1415 c7 0/subop/copy *Next-block-index 1/imm32 1416 # 1417 (write _test-input-stream "fn foo {\n") 1418 (write _test-input-stream " {\n") @@ -1428,7 +1428,7 @@ if ('onhashchange' in window) { 1471 (clear-stream $_test-input-buffered-file->buffer) 1472 (clear-stream _test-output-stream) 1473 (clear-stream $_test-output-buffered-file->buffer) -1474 c7 0/subop/copy *Next-block-index 1/imm32 +1474 c7 0/subop/copy *Next-block-index 1/imm32 1475 # 1476 (write _test-input-stream "fn foo {\n") 1477 (write _test-input-stream " a: {\n") @@ -1483,6688 +1483,6679 @@ if ('onhashchange' in window) { 1531 5d/pop-to-ebp 1532 c3/return 1533 -1534 ####################################################### -1535 # Parsing -1536 ####################################################### -1537 -1538 parse-mu: # in: (addr buffered-file) -1539 # pseudocode -1540 # var curr-function: (addr (handle function)) = Program -1541 # var line: (stream byte 512) -1542 # var word-slice: slice -1543 # while true # line loop -1544 # clear-stream(line) -1545 # read-line-buffered(in, line) -1546 # if (line->write == 0) break # end of file -1547 # word-slice = next-mu-token(line) -1548 # if slice-empty?(word-slice) # end of line -1549 # continue -1550 # else if slice-starts-with?(word-slice, "#") # comment -1551 # continue # end of line -1552 # else if slice-equal(word-slice, "fn") -1553 # var new-function: (handle function) = allocate(function) -1554 # var vars: (stack (addr var) 256) -1555 # populate-mu-function-header(in, new-function, vars) -1556 # populate-mu-function-body(in, new-function, vars) -1557 # assert(vars->top == 0) -1558 # *curr-function = new-function -1559 # curr-function = &new-function->next -1560 # else -1561 # abort() -1562 # -1563 # . prologue -1564 55/push-ebp -1565 89/<- %ebp 4/r32/esp -1566 # . save registers -1567 50/push-eax -1568 51/push-ecx -1569 52/push-edx -1570 53/push-ebx -1571 57/push-edi -1572 # var line/ecx: (stream byte 512) -1573 81 5/subop/subtract %esp 0x200/imm32 -1574 68/push 0x200/imm32/length -1575 68/push 0/imm32/read -1576 68/push 0/imm32/write -1577 89/<- %ecx 4/r32/esp -1578 # var word-slice/edx: slice -1579 68/push 0/imm32/end -1580 68/push 0/imm32/start -1581 89/<- %edx 4/r32/esp -1582 # var curr-function/edi: (addr (handle function)) = Program -1583 bf/copy-to-edi Program/imm32 -1584 # var vars/ebx: (stack (addr var) 256) -1585 81 5/subop/subtract %esp 0x400/imm32 -1586 68/push 0x400/imm32/length -1587 68/push 0/imm32/top -1588 89/<- %ebx 4/r32/esp -1589 { -1590 $parse-mu:line-loop: -1591 (clear-stream %ecx) -1592 (read-line-buffered *(ebp+8) %ecx) -1593 # if (line->write == 0) break -1594 81 7/subop/compare *ecx 0/imm32 -1595 0f 84/jump-if-= break/disp32 -1596 +-- 6 lines: #? # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------ -1602 (next-mu-token %ecx %edx) -1603 # if slice-empty?(word-slice) continue -1604 (slice-empty? %edx) -1605 3d/compare-eax-and 0/imm32/false -1606 0f 85/jump-if-!= loop/disp32 -1607 # if (*word-slice->start == "#") continue -1608 # . eax = *word-slice->start -1609 8b/-> *edx 0/r32/eax -1610 8a/copy-byte *eax 0/r32/AL -1611 81 4/subop/and %eax 0xff/imm32 -1612 # . if (eax == '#') continue -1613 3d/compare-eax-and 0x23/imm32/hash -1614 0f 84/jump-if-= loop/disp32 -1615 # if (slice-equal?(word-slice, "fn")) parse a function -1616 { -1617 $parse-mu:fn: -1618 (slice-equal? %edx "fn") -1619 3d/compare-eax-and 0/imm32/false -1620 0f 84/jump-if-= break/disp32 -1621 # var new-function/eax: (handle function) = populate-mu-function(in, new-function, vars) -1622 (allocate Heap *Function-size) # => eax -1623 (zero-out %eax *Function-size) -1624 (clear-stack %ebx) -1625 (populate-mu-function-header %ecx %eax %ebx) -1626 (populate-mu-function-body *(ebp+8) %eax %ebx) -1627 # *curr-function = new-function -1628 89/<- *edi 0/r32/eax -1629 # curr-function = &new-function->next -1630 8d/address-> *(eax+0x14) 7/r32/edi # Function-next -1631 e9/jump $parse-mu:line-loop/disp32 -1632 } -1633 # otherwise abort -1634 e9/jump $parse-mu:error1/disp32 -1635 } # end line loop -1636 $parse-mu:end: -1637 # . reclaim locals -1638 81 0/subop/add %esp 0x630/imm32 -1639 # . restore registers -1640 5f/pop-to-edi -1641 5b/pop-to-ebx -1642 5a/pop-to-edx -1643 59/pop-to-ecx -1644 58/pop-to-eax -1645 # . epilogue -1646 89/<- %esp 5/r32/ebp -1647 5d/pop-to-ebp -1648 c3/return -1649 -1650 $parse-mu:error1: -1651 # error("unexpected top-level command: " word-slice "\n") -1652 (write-buffered Stderr "unexpected top-level command: ") -1653 (write-slice-buffered Stderr %edx) -1654 (write-buffered Stderr "\n") -1655 (flush Stderr) -1656 # . syscall(exit, 1) -1657 bb/copy-to-ebx 1/imm32 -1658 b8/copy-to-eax 1/imm32/exit -1659 cd/syscall 0x80/imm8 -1660 # never gets here -1661 -1662 $parse-mu:error2: -1663 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") -1664 (print-int32-buffered Stderr *ebx) -1665 (write-buffered Stderr " vars not reclaimed after fn '") -1666 (write-slice-buffered Stderr *eax) # Function-name -1667 (write-buffered Stderr "'\n") -1668 (flush Stderr) -1669 # . syscall(exit, 1) -1670 bb/copy-to-ebx 1/imm32 -1671 b8/copy-to-eax 1/imm32/exit -1672 cd/syscall 0x80/imm8 -1673 # never gets here -1674 -1675 # scenarios considered: -1676 # ✗ fn foo # no block -1677 # ✓ fn foo { -1678 # ✗ fn foo { { -1679 # ✗ fn foo { } -1680 # ✗ fn foo { } { -1681 # ✗ fn foo x { -1682 # ✗ fn foo x: { -1683 # ✓ fn foo x: int { -1684 # ✓ fn foo x: int { -1685 # ✓ fn foo x: int -> y/eax: int { -1686 populate-mu-function-header: # first-line: (addr stream byte), out: (handle function), vars: (addr stack (handle var)) -1687 # pseudocode: -1688 # var name: slice -1689 # next-mu-token(first-line, name) -1690 # assert(name not in '{' '}' '->') -1691 # out->name = slice-to-string(name) -1692 # var next-offset: int = 8 -1693 # ## inouts -1694 # while true -1695 # ## name -1696 # name = next-mu-token(first-line) -1697 # if (name == '{') goto done -1698 # if (name == '->') break -1699 # assert(name != '}') -1700 # var v: (handle var) = parse-var-with-type(name, first-line) -1701 # assert(v->register == null) -1702 # v->stack-offset = next-offset -1703 # next-offset += size-of(v) -1704 # # v->block-depth is implicitly 0 -1705 # out->inouts = append(out->inouts, v) -1706 # push(vars, v) -1707 # ## outputs -1708 # while true -1709 # ## name -1710 # name = next-mu-token(first-line) -1711 # assert(name not in '{' '}' '->') -1712 # var v: (handle var) = parse-var-with-type(name, first-line) -1713 # assert(v->register != null) -1714 # out->outputs = append(out->outputs, v) -1715 # done: -1716 # -1717 # . prologue -1718 55/push-ebp -1719 89/<- %ebp 4/r32/esp -1720 # . save registers -1721 50/push-eax -1722 51/push-ecx -1723 52/push-edx -1724 53/push-ebx -1725 57/push-edi -1726 # edi = out -1727 8b/-> *(ebp+0xc) 7/r32/edi -1728 # var word-slice/ecx: slice -1729 68/push 0/imm32/end -1730 68/push 0/imm32/start -1731 89/<- %ecx 4/r32/esp -1732 # var next-offset/edx = 8 -1733 ba/copy-to-edx 8/imm32 -1734 # read function name -1735 (next-mu-token *(ebp+8) %ecx) -1736 # error checking -1737 # TODO: error if name starts with 'break' or 'loop' -1738 # if (word-slice == '{') abort -1739 (slice-equal? %ecx "{") # => eax -1740 3d/compare-eax-and 0/imm32/false -1741 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1742 # if (word-slice == '->') abort -1743 (slice-equal? %ecx "->") # => eax -1744 3d/compare-eax-and 0/imm32/false -1745 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1746 # if (word-slice == '}') abort -1747 (slice-equal? %ecx "}") # => eax -1748 3d/compare-eax-and 0/imm32/false -1749 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1750 # save function name -1751 (slice-to-string Heap %ecx) # => eax -1752 89/<- *edi 0/r32/eax # Function-name -1753 # initialize default subx-name as well -1754 89/<- *(edi+4) 0/r32/eax # Function-subx-name -1755 # save function inouts -1756 { -1757 $populate-mu-function-header:check-for-inout: -1758 (next-mu-token *(ebp+8) %ecx) -1759 # if (word-slice == '{') goto done -1760 (slice-equal? %ecx "{") # => eax -1761 3d/compare-eax-and 0/imm32/false -1762 0f 85/jump-if-!= $populate-mu-function-header:done/disp32 -1763 # if (word-slice == '->') break -1764 (slice-equal? %ecx "->") # => eax -1765 3d/compare-eax-and 0/imm32/false -1766 0f 85/jump-if-!= break/disp32 -1767 # if (word-slice == '}') abort -1768 (slice-equal? %ecx "}") # => eax -1769 3d/compare-eax-and 0/imm32/false -1770 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1771 # var v/ebx: (handle var) = parse-var-with-type(word-slice, first-line) -1772 (parse-var-with-type %ecx *(ebp+8)) # => eax -1773 89/<- %ebx 0/r32/eax -1774 # assert(v->register == null) -1775 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register -1776 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 -1777 # v->stack-offset = next-offset -1778 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset -1779 # next-offset += size-of(v) -1780 (size-of %ebx) # => eax -1781 01/add %edx 0/r32/eax -1782 # v->block-depth is implicitly 0 -1783 # -1784 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax -1785 89/<- *(edi+8) 0/r32/eax # Function-inouts -1786 (push *(ebp+0x10) %ebx) -1787 # -1788 e9/jump loop/disp32 -1789 } -1790 # save function outputs -1791 { -1792 $populate-mu-function-header:check-for-out: -1793 (next-mu-token *(ebp+8) %ecx) -1794 # if (word-slice == '{') break -1795 (slice-equal? %ecx "{") # => eax -1796 3d/compare-eax-and 0/imm32/false -1797 0f 85/jump-if-!= break/disp32 -1798 # if (word-slice == '->') abort -1799 (slice-equal? %ecx "->") # => eax -1800 3d/compare-eax-and 0/imm32/false -1801 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1802 # if (word-slice == '}') abort -1803 (slice-equal? %ecx "}") # => eax -1804 3d/compare-eax-and 0/imm32/false -1805 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 -1806 # -1807 (parse-var-with-type %ecx *(ebp+8)) # => eax -1808 89/<- %ebx 0/r32/eax -1809 # assert(var->register != null) -1810 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register -1811 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 -1812 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax -1813 89/<- *(edi+0xc) 0/r32/eax # Function-outputs -1814 e9/jump loop/disp32 -1815 } -1816 $populate-mu-function-header:done: -1817 (check-no-tokens-left *(ebp+8)) -1818 $populate-mu-function-header:end: -1819 # . reclaim locals -1820 81 0/subop/add %esp 8/imm32 -1821 # . restore registers -1822 5f/pop-to-edi -1823 5b/pop-to-ebx -1824 5a/pop-to-edx -1825 59/pop-to-ecx -1826 58/pop-to-eax -1827 # . epilogue -1828 89/<- %esp 5/r32/ebp -1829 5d/pop-to-ebp -1830 c3/return -1831 -1832 $populate-mu-function-header:error1: -1833 # error("function header not in form 'fn <name> {'") -1834 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") -1835 (flush Stderr) -1836 (rewind-stream *(ebp+8)) -1837 (write-stream 2 *(ebp+8)) -1838 (write-buffered Stderr "'\n") -1839 (flush Stderr) -1840 # . syscall(exit, 1) -1841 bb/copy-to-ebx 1/imm32 -1842 b8/copy-to-eax 1/imm32/exit -1843 cd/syscall 0x80/imm8 -1844 # never gets here -1845 -1846 $populate-mu-function-header:error2: -1847 # error("function input '" var "' cannot be in a register") -1848 (write-buffered Stderr "function input '") -1849 (write-buffered Stderr *ebx) # Var-name -1850 (write-buffered Stderr "' cannot be in a register") -1851 (flush Stderr) -1852 # . syscall(exit, 1) -1853 bb/copy-to-ebx 1/imm32 -1854 b8/copy-to-eax 1/imm32/exit -1855 cd/syscall 0x80/imm8 -1856 # never gets here -1857 -1858 $populate-mu-function-header:error3: -1859 # error("function input '" var "' must be in a register") -1860 (write-buffered Stderr "function input '") -1861 (write-buffered Stderr *eax) # Var-name -1862 (write-buffered Stderr " must be in a register'") -1863 (flush Stderr) -1864 (rewind-stream *(ebp+8)) -1865 (write-stream 2 *(ebp+8)) -1866 (write-buffered Stderr "'\n") -1867 (flush Stderr) -1868 # . syscall(exit, 1) -1869 bb/copy-to-ebx 1/imm32 -1870 b8/copy-to-eax 1/imm32/exit -1871 cd/syscall 0x80/imm8 -1872 # never gets here -1873 -1874 test-function-header-with-arg: -1875 # . prologue -1876 55/push-ebp -1877 89/<- %ebp 4/r32/esp -1878 # setup -1879 (clear-stream _test-input-stream) -1880 (write _test-input-stream "foo n: int {\n") -1881 # var result/ecx: function -1882 2b/subtract-> *Function-size 4/r32/esp -1883 89/<- %ecx 4/r32/esp -1884 (zero-out %ecx *Function-size) -1885 # var vars/ebx: (stack (addr var) 16) -1886 81 5/subop/subtract %esp 0x10/imm32 -1887 68/push 0x10/imm32/length -1888 68/push 0/imm32/top -1889 89/<- %ebx 4/r32/esp -1890 # convert -1891 (populate-mu-function-header _test-input-stream %ecx %ebx) -1892 # check result -1893 (check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name -1894 # edx: (handle list var) = result->inouts -1895 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1896 # ebx: (handle var) = result->inouts->value -1897 8b/-> *edx 3/r32/ebx # List-value -1898 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name -1899 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1900 (check-ints-equal *ebx 1 "F - test-function-header-with-arg/inout:0/type:0") # Tree-left -1901 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-arg/inout:0/type:1") # Tree-right -1902 # . epilogue -1903 89/<- %esp 5/r32/ebp -1904 5d/pop-to-ebp -1905 c3/return +1534 test-convert-function-with-nonlocal-unconditional-break-and-local-vars: +1535 # . prologue +1536 55/push-ebp +1537 89/<- %ebp 4/r32/esp +1538 # setup +1539 (clear-stream _test-input-stream) +1540 (clear-stream $_test-input-buffered-file->buffer) +1541 (clear-stream _test-output-stream) +1542 (clear-stream $_test-output-buffered-file->buffer) +1543 c7 0/subop/copy *Next-block-index 1/imm32 +1544 # +1545 (write _test-input-stream "fn foo {\n") +1546 (write _test-input-stream " a: {\n") +1547 (write _test-input-stream " var x: int\n") +1548 (write _test-input-stream " {\n") +1549 (write _test-input-stream " var y: int\n") +1550 (write _test-input-stream " break a\n") +1551 (write _test-input-stream " increment x\n") +1552 (write _test-input-stream " }\n") +1553 (write _test-input-stream " }\n") +1554 (write _test-input-stream "}\n") +1555 # convert +1556 (convert-mu _test-input-buffered-file _test-output-buffered-file) +1557 (flush _test-output-buffered-file) +1558 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +1564 # check output +1565 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0") +1566 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1") +1567 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2") +1568 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/3") +1569 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4") +1570 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5") +1571 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6") +1572 (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7") +1573 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8") +1574 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9") +1575 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10") +1576 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11") +1577 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/12") +1578 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/13") +1579 (check-next-stream-line-equal _test-output-stream " e9/jump a:break/disp32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/14") +1580 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15") +1581 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16") +1582 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/17") +1583 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18") +1584 (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19") +1585 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20") +1586 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21") +1587 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22") +1588 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/23") +1589 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24") +1590 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25") +1591 # . epilogue +1592 89/<- %esp 5/r32/ebp +1593 5d/pop-to-ebp +1594 c3/return +1595 +1596 test-convert-function-with-unconditional-break-and-local-vars: +1597 # . prologue +1598 55/push-ebp +1599 89/<- %ebp 4/r32/esp +1600 # setup +1601 (clear-stream _test-input-stream) +1602 (clear-stream $_test-input-buffered-file->buffer) +1603 (clear-stream _test-output-stream) +1604 (clear-stream $_test-output-buffered-file->buffer) +1605 c7 0/subop/copy *Next-block-index 1/imm32 +1606 # +1607 (write _test-input-stream "fn foo {\n") +1608 (write _test-input-stream " {\n") +1609 (write _test-input-stream " var x: int\n") +1610 (write _test-input-stream " {\n") +1611 (write _test-input-stream " var y: int\n") +1612 (write _test-input-stream " break\n") +1613 (write _test-input-stream " increment x\n") +1614 (write _test-input-stream " }\n") +1615 (write _test-input-stream " }\n") +1616 (write _test-input-stream "}\n") +1617 # convert +1618 (convert-mu _test-input-buffered-file _test-output-buffered-file) +1619 (flush _test-output-buffered-file) +1620 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +1626 # check output +1627 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-unconditional-break-and-local-vars/0") +1628 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-unconditional-break-and-local-vars/1") +1629 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/2") +1630 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-unconditional-break-and-local-vars/3") +1631 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/4") +1632 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/5") +1633 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/6") +1634 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/7") +1635 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/8") +1636 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-unconditional-break-and-local-vars/9") +1637 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-unconditional-break-and-local-vars/10") +1638 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11") +1639 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/12") +1640 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/13") +1641 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/14") +1642 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/15") +1643 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/16") +1644 (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/17") +1645 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-unconditional-break-and-local-vars/18") +1646 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-unconditional-break-and-local-vars/19") +1647 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-unconditional-break-and-local-vars/20") +1648 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/21") +1649 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-unconditional-break-and-local-vars/22") +1650 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-unconditional-break-and-local-vars/23") +1651 # . epilogue +1652 89/<- %esp 5/r32/ebp +1653 5d/pop-to-ebp +1654 c3/return +1655 +1656 test-convert-function-with-nonlocal-unconditional-loop-and-local-vars: +1657 # . prologue +1658 55/push-ebp +1659 89/<- %ebp 4/r32/esp +1660 # setup +1661 (clear-stream _test-input-stream) +1662 (clear-stream $_test-input-buffered-file->buffer) +1663 (clear-stream _test-output-stream) +1664 (clear-stream $_test-output-buffered-file->buffer) +1665 c7 0/subop/copy *Next-block-index 1/imm32 +1666 # +1667 (write _test-input-stream "fn foo {\n") +1668 (write _test-input-stream " a: {\n") +1669 (write _test-input-stream " var x: int\n") +1670 (write _test-input-stream " {\n") +1671 (write _test-input-stream " var y: int\n") +1672 (write _test-input-stream " loop a\n") +1673 (write _test-input-stream " increment x\n") +1674 (write _test-input-stream " }\n") +1675 (write _test-input-stream " }\n") +1676 (write _test-input-stream "}\n") +1677 # convert +1678 (convert-mu _test-input-buffered-file _test-output-buffered-file) +1679 (flush _test-output-buffered-file) +1680 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +1686 # check output +1687 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0") +1688 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1") +1689 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2") +1690 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/3") +1691 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4") +1692 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5") +1693 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6") +1694 (check-next-stream-line-equal _test-output-stream "a:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7") +1695 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8") +1696 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9") +1697 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10") +1698 (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11") +1699 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/12") +1700 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/13") +1701 (check-next-stream-line-equal _test-output-stream " e9/jump a:loop/disp32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/14") +1702 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15") +1703 (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16") +1704 (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/17") +1705 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18") +1706 (check-next-stream-line-equal _test-output-stream "a:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19") +1707 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20") +1708 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21") +1709 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22") +1710 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/23") +1711 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24") +1712 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25") +1713 # . epilogue +1714 89/<- %esp 5/r32/ebp +1715 5d/pop-to-ebp +1716 c3/return +1717 +1718 test-convert-length-of-array: +1719 # . prologue +1720 55/push-ebp +1721 89/<- %ebp 4/r32/esp +1722 # setup +1723 (clear-stream _test-input-stream) +1724 (clear-stream $_test-input-buffered-file->buffer) +1725 (clear-stream _test-output-stream) +1726 (clear-stream $_test-output-buffered-file->buffer) +1727 c7 0/subop/copy *Next-block-index 1/imm32 +1728 # +1729 (write _test-input-stream "fn foo a: (addr array int) {\n") +1730 (write _test-input-stream " var b/eax: (addr array int) <- copy a\n") +1731 (write _test-input-stream " var c/eax: int <- length b\n") +1732 (write _test-input-stream "}\n") +1733 # convert +1734 (convert-mu _test-input-buffered-file _test-output-buffered-file) +1735 (flush _test-output-buffered-file) +1736 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +1742 # check output +1743 (check-next-stream-line-equal _test-output-stream "foo:" "F - test-convert-length-of-array/0") +1744 (check-next-stream-line-equal _test-output-stream " # . prologue" "F - test-convert-length-of-array/1") +1745 (check-next-stream-line-equal _test-output-stream " 55/push-ebp" "F - test-convert-length-of-array/2") +1746 (check-next-stream-line-equal _test-output-stream " 89/<- %ebp 4/r32/esp" "F - test-convert-length-of-array/3") +1747 (check-next-stream-line-equal _test-output-stream " {" "F - test-convert-length-of-array/4") +1748 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-length-of-array/5") +1749 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-length-of-array/6") +1750 (check-next-stream-line-equal _test-output-stream " 8b/copy-from *(ebp+0x00000008) 0x00000000/r32" "F - test-convert-length-of-array/7") +1751 (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-length-of-array/8") +1752 (check-next-stream-line-equal _test-output-stream " 8b/copy-from *eax 0x00000000/r32" "F - test-convert-length-of-array/9") +1753 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array/10") +1754 (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-length-of-array/11") +1755 (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-length-of-array/12") +1756 (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-length-of-array/13") +1757 (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-length-of-array/14") +1758 (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-length-of-array/15") +1759 (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-length-of-array/16") +1760 (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-length-of-array/17") +1761 # . epilogue +1762 89/<- %esp 5/r32/ebp +1763 5d/pop-to-ebp +1764 c3/return +1765 +1766 ####################################################### +1767 # Parsing +1768 ####################################################### +1769 +1770 parse-mu: # in: (addr buffered-file) +1771 # pseudocode +1772 # var curr-function: (addr (handle function)) = Program +1773 # var line: (stream byte 512) +1774 # var word-slice: slice +1775 # while true # line loop +1776 # clear-stream(line) +1777 # read-line-buffered(in, line) +1778 # if (line->write == 0) break # end of file +1779 # word-slice = next-mu-token(line) +1780 # if slice-empty?(word-slice) # end of line +1781 # continue +1782 # else if slice-starts-with?(word-slice, "#") # comment +1783 # continue # end of line +1784 # else if slice-equal(word-slice, "fn") +1785 # var new-function: (handle function) = allocate(function) +1786 # var vars: (stack (addr var) 256) +1787 # populate-mu-function-header(in, new-function, vars) +1788 # populate-mu-function-body(in, new-function, vars) +1789 # assert(vars->top == 0) +1790 # *curr-function = new-function +1791 # curr-function = &new-function->next +1792 # else +1793 # abort() +1794 # +1795 # . prologue +1796 55/push-ebp +1797 89/<- %ebp 4/r32/esp +1798 # . save registers +1799 50/push-eax +1800 51/push-ecx +1801 52/push-edx +1802 53/push-ebx +1803 57/push-edi +1804 # var line/ecx: (stream byte 512) +1805 81 5/subop/subtract %esp 0x200/imm32 +1806 68/push 0x200/imm32/length +1807 68/push 0/imm32/read +1808 68/push 0/imm32/write +1809 89/<- %ecx 4/r32/esp +1810 # var word-slice/edx: slice +1811 68/push 0/imm32/end +1812 68/push 0/imm32/start +1813 89/<- %edx 4/r32/esp +1814 # var curr-function/edi: (addr (handle function)) = Program +1815 bf/copy-to-edi Program/imm32 +1816 # var vars/ebx: (stack (addr var) 256) +1817 81 5/subop/subtract %esp 0x400/imm32 +1818 68/push 0x400/imm32/length +1819 68/push 0/imm32/top +1820 89/<- %ebx 4/r32/esp +1821 { +1822 $parse-mu:line-loop: +1823 (clear-stream %ecx) +1824 (read-line-buffered *(ebp+8) %ecx) +1825 # if (line->write == 0) break +1826 81 7/subop/compare *ecx 0/imm32 +1827 0f 84/jump-if-= break/disp32 +1828 +-- 6 lines: #? # dump line ------------------------------------------------------------------------------------------------------------------------------------------------------ +1834 (next-mu-token %ecx %edx) +1835 # if slice-empty?(word-slice) continue +1836 (slice-empty? %edx) +1837 3d/compare-eax-and 0/imm32/false +1838 0f 85/jump-if-!= loop/disp32 +1839 # if (*word-slice->start == "#") continue +1840 # . eax = *word-slice->start +1841 8b/-> *edx 0/r32/eax +1842 8a/copy-byte *eax 0/r32/AL +1843 81 4/subop/and %eax 0xff/imm32 +1844 # . if (eax == '#') continue +1845 3d/compare-eax-and 0x23/imm32/hash +1846 0f 84/jump-if-= loop/disp32 +1847 # if (slice-equal?(word-slice, "fn")) parse a function +1848 { +1849 $parse-mu:fn: +1850 (slice-equal? %edx "fn") +1851 3d/compare-eax-and 0/imm32/false +1852 0f 84/jump-if-= break/disp32 +1853 # var new-function/eax: (handle function) = populate-mu-function(in, new-function, vars) +1854 (allocate Heap *Function-size) # => eax +1855 (zero-out %eax *Function-size) +1856 (clear-stack %ebx) +1857 (populate-mu-function-header %ecx %eax %ebx) +1858 (populate-mu-function-body *(ebp+8) %eax %ebx) +1859 # *curr-function = new-function +1860 89/<- *edi 0/r32/eax +1861 # curr-function = &new-function->next +1862 8d/address-> *(eax+0x14) 7/r32/edi # Function-next +1863 e9/jump $parse-mu:line-loop/disp32 +1864 } +1865 # otherwise abort +1866 e9/jump $parse-mu:error1/disp32 +1867 } # end line loop +1868 $parse-mu:end: +1869 # . reclaim locals +1870 81 0/subop/add %esp 0x630/imm32 +1871 # . restore registers +1872 5f/pop-to-edi +1873 5b/pop-to-ebx +1874 5a/pop-to-edx +1875 59/pop-to-ecx +1876 58/pop-to-eax +1877 # . epilogue +1878 89/<- %esp 5/r32/ebp +1879 5d/pop-to-ebp +1880 c3/return +1881 +1882 $parse-mu:error1: +1883 # error("unexpected top-level command: " word-slice "\n") +1884 (write-buffered Stderr "unexpected top-level command: ") +1885 (write-slice-buffered Stderr %edx) +1886 (write-buffered Stderr "\n") +1887 (flush Stderr) +1888 # . syscall(exit, 1) +1889 bb/copy-to-ebx 1/imm32 +1890 b8/copy-to-eax 1/imm32/exit +1891 cd/syscall 0x80/imm8 +1892 # never gets here +1893 +1894 $parse-mu:error2: +1895 # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n") +1896 (print-int32-buffered Stderr *ebx) +1897 (write-buffered Stderr " vars not reclaimed after fn '") +1898 (write-slice-buffered Stderr *eax) # Function-name +1899 (write-buffered Stderr "'\n") +1900 (flush Stderr) +1901 # . syscall(exit, 1) +1902 bb/copy-to-ebx 1/imm32 +1903 b8/copy-to-eax 1/imm32/exit +1904 cd/syscall 0x80/imm8 +1905 # never gets here 1906 -1907 test-function-header-with-multiple-args: -1908 # . prologue -1909 55/push-ebp -1910 89/<- %ebp 4/r32/esp -1911 # setup -1912 (clear-stream _test-input-stream) -1913 (write _test-input-stream "foo a: int, b: int c: int {\n") -1914 # result/ecx: (handle function) -1915 2b/subtract-> *Function-size 4/r32/esp -1916 89/<- %ecx 4/r32/esp -1917 (zero-out %ecx *Function-size) -1918 # var vars/ebx: (stack (addr var) 16) -1919 81 5/subop/subtract %esp 0x10/imm32 -1920 68/push 0x10/imm32/length -1921 68/push 0/imm32/top -1922 89/<- %ebx 4/r32/esp -1923 # convert -1924 (populate-mu-function-header _test-input-stream %ecx %ebx) -1925 # check result -1926 (check-strings-equal *ecx "foo") # Function-name -1927 # edx: (handle list var) = result->inouts -1928 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1929 $test-function-header-with-multiple-args:inout0: -1930 # ebx: (handle var) = result->inouts->value -1931 8b/-> *edx 3/r32/ebx # List-value -1932 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name -1933 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1934 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Tree-left -1935 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-right -1936 # edx = result->inouts->next -1937 8b/-> *(edx+4) 2/r32/edx # List-next -1938 $test-function-header-with-multiple-args:inout1: -1939 # ebx = result->inouts->next->value -1940 8b/-> *edx 3/r32/ebx # List-value -1941 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name -1942 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1943 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Tree-left -1944 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-right -1945 # edx = result->inouts->next->next -1946 8b/-> *(edx+4) 2/r32/edx # List-next -1947 $test-function-header-with-multiple-args:inout2: -1948 # ebx = result->inouts->next->next->value -1949 8b/-> *edx 3/r32/ebx # List-value -1950 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name -1951 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1952 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Tree-left -1953 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-right -1954 # . epilogue -1955 89/<- %esp 5/r32/ebp -1956 5d/pop-to-ebp -1957 c3/return -1958 -1959 test-function-with-multiple-args-and-outputs: -1960 # . prologue -1961 55/push-ebp -1962 89/<- %ebp 4/r32/esp -1963 # setup -1964 (clear-stream _test-input-stream) -1965 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n") -1966 # result/ecx: (handle function) -1967 2b/subtract-> *Function-size 4/r32/esp -1968 89/<- %ecx 4/r32/esp -1969 (zero-out %ecx *Function-size) -1970 # var vars/ebx: (stack (addr var) 16) -1971 81 5/subop/subtract %esp 0x10/imm32 -1972 68/push 0x10/imm32/length -1973 68/push 0/imm32/top -1974 89/<- %ebx 4/r32/esp -1975 # convert -1976 (populate-mu-function-header _test-input-stream %ecx %ebx) -1977 # check result -1978 (check-strings-equal *ecx "foo") # Function-name -1979 # edx: (handle list var) = result->inouts -1980 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1981 # ebx: (handle var) = result->inouts->value -1982 8b/-> *edx 3/r32/ebx # List-value -1983 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") # Var-name -1984 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1985 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Tree-left -1986 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-right -1987 # edx = result->inouts->next -1988 8b/-> *(edx+4) 2/r32/edx # List-next -1989 # ebx = result->inouts->next->value -1990 8b/-> *edx 3/r32/ebx # List-value -1991 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") # Var-name -1992 8b/-> *(ebx+4) 3/r32/ebx # Var-type -1993 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Tree-left -1994 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-right -1995 # edx = result->inouts->next->next -1996 8b/-> *(edx+4) 2/r32/edx # List-next -1997 # ebx = result->inouts->next->next->value -1998 8b/-> *edx 3/r32/ebx # List-value -1999 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") # Var-name -2000 8b/-> *(ebx+4) 3/r32/ebx # Var-type -2001 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Tree-left -2002 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-right -2003 # edx: (handle list var) = result->outputs -2004 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs -2005 # ebx: (handle var) = result->outputs->value -2006 8b/-> *edx 3/r32/ebx # List-value -2007 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") # Var-name -2008 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register -2009 8b/-> *(ebx+4) 3/r32/ebx # Var-type -2010 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-left -2011 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-right -2012 # edx = result->outputs->next -2013 8b/-> *(edx+4) 2/r32/edx # List-next -2014 # ebx = result->outputs->next->value -2015 8b/-> *edx 3/r32/ebx # List-value -2016 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") # Var-name -2017 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register -2018 8b/-> *(ebx+4) 3/r32/ebx # Var-type -2019 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-left -2020 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-right -2021 # . epilogue -2022 89/<- %esp 5/r32/ebp -2023 5d/pop-to-ebp -2024 c3/return -2025 -2026 # format for variables with types -2027 # x: int -2028 # x: int, -2029 # x/eax: int -2030 # x/eax: int, -2031 # ignores at most one trailing comma -2032 # WARNING: modifies name -2033 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte) -> result/eax: (handle var) -2034 # pseudocode: -2035 # var v: (handle var) = allocate(Heap, Var-size) -2036 # var s: slice -2037 # if (!slice-ends-with(name, ":")) -2038 # abort -2039 # --name->end to skip ':' -2040 # next-token-from-slice(name->start, name->end, '/', s) -2041 # v->name = slice-to-string(s) -2042 # ## register -2043 # next-token-from-slice(s->end, name->end, '/', s) -2044 # if (!slice-empty?(s)) -2045 # v->register = slice-to-string(s) -2046 # ## type -2047 # var type: (handle tree type-id) = parse-type(first-line) -2048 # v->type = type -2049 # return v -2050 # -2051 # . prologue -2052 55/push-ebp -2053 89/<- %ebp 4/r32/esp -2054 # . save registers -2055 51/push-ecx -2056 52/push-edx -2057 53/push-ebx -2058 56/push-esi -2059 57/push-edi -2060 # esi = name -2061 8b/-> *(ebp+8) 6/r32/esi -2062 # if (!slice-ends-with?(name, ":")) abort -2063 8b/-> *(esi+4) 1/r32/ecx # Slice-end -2064 49/decrement-ecx -2065 8a/copy-byte *ecx 1/r32/CL -2066 81 4/subop/and %ecx 0xff/imm32 -2067 81 7/subop/compare %ecx 0x3a/imm32/colon -2068 0f 85/jump-if-!= $parse-var-with-type:abort/disp32 -2069 # --name->end to skip ':' -2070 ff 1/subop/decrement *(esi+4) -2071 # var result/edi: (handle var) = allocate(Heap, Var-size) -2072 (allocate Heap *Var-size) # => eax -2073 (zero-out %eax *Var-size) -2074 89/<- %edi 0/r32/eax -2075 # var s/ecx: slice -2076 68/push 0/imm32/end -2077 68/push 0/imm32/start -2078 89/<- %ecx 4/r32/esp -2079 $parse-var-with-type:save-name: -2080 # save v->name -2081 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' -2082 # . end/edx = s->end -2083 8b/-> *(ecx+4) 2/r32/edx -2084 $parse-var-with-type:write-name: -2085 (slice-to-string Heap %ecx) # => eax -2086 89/<- *edi 0/r32/eax # Var-name -2087 # save v->register -2088 $parse-var-with-type:save-register: -2089 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' -2090 # if (!slice-empty?(s)) v->register = slice-to-string(s) -2091 { -2092 $parse-var-with-type:write-register: -2093 (slice-empty? %ecx) # => eax -2094 3d/compare-eax-and 0/imm32/false -2095 75/jump-if-!= break/disp8 -2096 (slice-to-string Heap %ecx) -2097 89/<- *(edi+0x10) 0/r32/eax # Var-register -2098 } -2099 $parse-var-with-type:save-type: -2100 (parse-type Heap *(ebp+0xc)) # => eax -2101 89/<- *(edi+4) 0/r32/eax # Var-type -2102 $parse-var-with-type:end: -2103 # return result -2104 89/<- %eax 7/r32/edi -2105 # . reclaim locals -2106 81 0/subop/add %esp 8/imm32 -2107 # . restore registers -2108 5f/pop-to-edi -2109 5e/pop-to-esi -2110 5b/pop-to-ebx -2111 5a/pop-to-edx -2112 59/pop-to-ecx -2113 # . epilogue -2114 89/<- %esp 5/r32/ebp -2115 5d/pop-to-ebp -2116 c3/return -2117 -2118 $parse-var-with-type:abort: -2119 # error("var should have form 'name: type' in '" line "'\n") -2120 (write-buffered Stderr "var should have form 'name: type' in '") -2121 (flush Stderr) -2122 (rewind-stream *(ebp+0xc)) -2123 (write-stream 2 *(ebp+0xc)) -2124 (write-buffered Stderr "'\n") -2125 (flush Stderr) -2126 # . syscall(exit, 1) -2127 bb/copy-to-ebx 1/imm32 -2128 b8/copy-to-eax 1/imm32/exit -2129 cd/syscall 0x80/imm8 -2130 # never gets here -2131 -2132 parse-type: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) -2133 # pseudocode: -2134 # var s: slice = next-mu-token(in) -2135 # assert s != "" -2136 # assert s != "->" -2137 # assert s != "{" -2138 # assert s != "}" -2139 # if s == ")" -2140 # return 0 -2141 # result = allocate(Tree) -2142 # zero-out(result, *Tree-size) -2143 # if s != "(" -2144 # result->left = pos-slice(Type-id, s) -2145 # return -2146 # result->left = parse-type(ad, in) -2147 # result->right = parse-type-tree(ad, in) -2148 # -2149 # . prologue -2150 55/push-ebp -2151 89/<- %ebp 4/r32/esp -2152 # . save registers -2153 51/push-ecx -2154 52/push-edx -2155 # var s/ecx: slice -2156 68/push 0/imm32 -2157 68/push 0/imm32 -2158 89/<- %ecx 4/r32/esp -2159 # s = next-mu-token(in) -2160 (next-mu-token *(ebp+0xc) %ecx) -2161 #? (write-buffered Stderr "tok: ") -2162 #? (write-slice-buffered Stderr %ecx) -2163 #? (write-buffered Stderr "$\n") -2164 #? (flush Stderr) -2165 # assert s != "" -2166 (slice-equal? %ecx "") -2167 3d/compare-eax-and 0/imm32/false -2168 0f 85/jump-if-!= $parse-type:abort/disp32 -2169 # assert s != "{" -2170 (slice-equal? %ecx "{") -2171 3d/compare-eax-and 0/imm32/false -2172 0f 85/jump-if-!= $parse-type:abort/disp32 -2173 # assert s != "}" -2174 (slice-equal? %ecx "}") -2175 3d/compare-eax-and 0/imm32/false -2176 0f 85/jump-if-!= $parse-type:abort/disp32 -2177 # assert s != "->" -2178 (slice-equal? %ecx "->") -2179 3d/compare-eax-and 0/imm32/false -2180 0f 85/jump-if-!= $parse-type:abort/disp32 -2181 # if (s == ")") return 0 -2182 (slice-equal? %ecx ")") -2183 3d/compare-eax-and 0/imm32/false -2184 b8/copy-to-eax 0/imm32 -2185 0f 85/jump-if-!= $parse-type:end/disp32 -2186 # var result/edx: (handle tree type-id) -2187 (allocate *(ebp+8) *Tree-size) # => eax -2188 (zero-out %eax *Tree-size) -2189 89/<- %edx 0/r32/eax -2190 { -2191 # if (s != "(") break -2192 (slice-equal? %ecx "(") -2193 3d/compare-eax-and 0/imm32/false -2194 75/jump-if-!= break/disp8 -2195 # result->left = pos-slice(Type-id, s) -2196 (pos-slice Type-id %ecx) -2197 #? (write-buffered Stderr "=> {") -2198 #? (print-int32-buffered Stderr %eax) -2199 #? (write-buffered Stderr ", 0}\n") -2200 #? (flush Stderr) -2201 89/<- *edx 0/r32/eax # Tree-left -2202 e9/jump $parse-type:return-edx/disp32 -2203 } -2204 # otherwise s == "(" -2205 # result->left = parse-type(ad, in) -2206 (parse-type *(ebp+8) *(ebp+0xc)) -2207 #? (write-buffered Stderr "=> {") -2208 #? (print-int32-buffered Stderr %eax) -2209 89/<- *edx 0/r32/eax # Tree-left -2210 # result->right = parse-type-tree(ad, in) -2211 (parse-type-tree *(ebp+8) *(ebp+0xc)) -2212 #? (write-buffered Stderr Space) -2213 #? (print-int32-buffered Stderr %eax) -2214 #? (write-buffered Stderr "}\n") -2215 #? (flush Stderr) -2216 89/<- *(edx+4) 0/r32/eax # Tree-right -2217 $parse-type:return-edx: -2218 89/<- %eax 2/r32/edx -2219 $parse-type:end: -2220 # . reclaim locals -2221 81 0/subop/add %esp 8/imm32 -2222 # . restore registers -2223 5a/pop-to-edx -2224 59/pop-to-ecx -2225 # . epilogue -2226 89/<- %esp 5/r32/ebp -2227 5d/pop-to-ebp -2228 c3/return -2229 -2230 $parse-type:abort: -2231 # error("unexpected token when parsing type: '" s "'\n") -2232 (write-buffered Stderr "unexpected token when parsing type: '") -2233 (write-slice-buffered Stderr %ecx) -2234 (write-buffered Stderr "'\n") -2235 (flush Stderr) -2236 # . syscall(exit, 1) -2237 bb/copy-to-ebx 1/imm32 -2238 b8/copy-to-eax 1/imm32/exit -2239 cd/syscall 0x80/imm8 -2240 # never gets here -2241 -2242 parse-type-tree: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) -2243 # pseudocode: -2244 # var tmp: (handle tree type-id) = parse-type(ad, in) -2245 # if tmp == 0 -2246 # return 0 -2247 # result = allocate(Tree) -2248 # zero-out(result, *Tree-size) -2249 # result->left = tmp -2250 # result->right = parse-type-tree(ad, in) -2251 # -2252 # . prologue -2253 55/push-ebp -2254 89/<- %ebp 4/r32/esp -2255 # . save registers -2256 51/push-ecx -2257 52/push-edx -2258 # var tmp/eax: (handle tree type-id) = parse-type(ad, in) -2259 (parse-type *(ebp+8) *(ebp+0xc)) -2260 # if (tmp == 0) return tmp -2261 3d/compare-eax-and 0/imm32 -2262 74/jump-if-= $parse-type-tree:end/disp8 -2263 # var tmp2/ecx = tmp -2264 89/<- %ecx 0/r32/eax -2265 # var result/edx: (handle tree type-id) -2266 (allocate *(ebp+8) *Tree-size) # => eax -2267 (zero-out %eax *Tree-size) -2268 89/<- %edx 0/r32/eax -2269 # result->left = tmp2 -2270 89/<- *edx 1/r32/ecx # Tree-left -2271 # result->right = parse-type-tree(ad, in) -2272 (parse-type-tree *(ebp+8) *(ebp+0xc)) -2273 89/<- *(edx+4) 0/r32/eax # Tree-right -2274 $parse-type-tree:return-edx: -2275 89/<- %eax 2/r32/edx -2276 $parse-type-tree:end: -2277 # . restore registers -2278 5a/pop-to-edx -2279 59/pop-to-ecx -2280 # . epilogue -2281 89/<- %esp 5/r32/ebp -2282 5d/pop-to-ebp -2283 c3/return -2284 -2285 next-mu-token: # in: (addr stream byte), out: (addr slice) -2286 # pseudocode: -2287 # start: -2288 # skip-chars-matching-whitespace(in) -2289 # if in->read >= in->write # end of in -2290 # out = {0, 0} -2291 # return -2292 # out->start = &in->data[in->read] -2293 # var curr-byte/eax: byte = in->data[in->read] -2294 # if curr->byte == ',' # comment token -2295 # ++in->read -2296 # goto start -2297 # if curr-byte == '#' # comment -2298 # goto done # treat as eof -2299 # if curr-byte == '"' # string literal -2300 # skip-string(in) -2301 # goto done # no metadata -2302 # if curr-byte == '(' -2303 # ++in->read -2304 # goto done -2305 # if curr-byte == ')' -2306 # ++in->read -2307 # goto done -2308 # # read a word -2309 # while true -2310 # if in->read >= in->write -2311 # break -2312 # curr-byte = in->data[in->read] -2313 # if curr-byte == ' ' -2314 # break -2315 # if curr-byte == '\r' -2316 # break -2317 # if curr-byte == '\n' -2318 # break -2319 # if curr-byte == '(' -2320 # break -2321 # if curr-byte == ')' -2322 # break -2323 # if curr-byte == ',' -2324 # break -2325 # ++in->read -2326 # done: -2327 # out->end = &in->data[in->read] -2328 # -2329 # . prologue -2330 55/push-ebp -2331 89/<- %ebp 4/r32/esp -2332 # . save registers -2333 50/push-eax -2334 51/push-ecx -2335 56/push-esi -2336 57/push-edi -2337 # esi = in -2338 8b/-> *(ebp+8) 6/r32/esi -2339 # edi = out -2340 8b/-> *(ebp+0xc) 7/r32/edi -2341 $next-mu-token:start: -2342 (skip-chars-matching-whitespace %esi) -2343 $next-mu-token:check0: -2344 # if (in->read >= in->write) return out = {0, 0} -2345 # . ecx = in->read -2346 8b/-> *(esi+4) 1/r32/ecx -2347 # . if (ecx >= in->write) return out = {0, 0} -2348 3b/compare 1/r32/ecx *esi -2349 c7 0/subop/copy *edi 0/imm32 -2350 c7 0/subop/copy *(edi+4) 0/imm32 -2351 0f 8d/jump-if->= $next-mu-token:end/disp32 -2352 # out->start = &in->data[in->read] -2353 8d/copy-address *(esi+ecx+0xc) 0/r32/eax -2354 89/<- *edi 0/r32/eax -2355 # var curr-byte/eax: byte = in->data[in->read] -2356 31/xor %eax 0/r32/eax -2357 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL -2358 { -2359 $next-mu-token:check-for-comma: -2360 # if (curr-byte != ',') break -2361 3d/compare-eax-and 0x2c/imm32/comma -2362 75/jump-if-!= break/disp8 -2363 # ++in->read -2364 ff 0/subop/increment *(esi+4) -2365 # restart -2366 e9/jump $next-mu-token:start/disp32 -2367 } -2368 { -2369 $next-mu-token:check-for-comment: -2370 # if (curr-byte != '#') break -2371 3d/compare-eax-and 0x23/imm32/pound -2372 75/jump-if-!= break/disp8 -2373 # return eof -2374 e9/jump $next-mu-token:done/disp32 -2375 } -2376 { -2377 $next-mu-token:check-for-string-literal: -2378 # if (curr-byte != '"') break -2379 3d/compare-eax-and 0x22/imm32/dquote -2380 75/jump-if-!= break/disp8 -2381 (skip-string %esi) -2382 # return -2383 e9/jump $next-mu-token:done/disp32 -2384 } -2385 { -2386 $next-mu-token:check-for-open-paren: -2387 # if (curr-byte != '(') break -2388 3d/compare-eax-and 0x28/imm32/open-paren -2389 75/jump-if-!= break/disp8 -2390 # ++in->read -2391 ff 0/subop/increment *(esi+4) -2392 # return -2393 e9/jump $next-mu-token:done/disp32 -2394 } -2395 { -2396 $next-mu-token:check-for-close-paren: -2397 # if (curr-byte != ')') break -2398 3d/compare-eax-and 0x29/imm32/close-paren -2399 75/jump-if-!= break/disp8 -2400 # ++in->read -2401 ff 0/subop/increment *(esi+4) -2402 # return -2403 e9/jump $next-mu-token:done/disp32 -2404 } -2405 { -2406 $next-mu-token:regular-word-without-metadata: -2407 # if (in->read >= in->write) break -2408 # . ecx = in->read -2409 8b/-> *(esi+4) 1/r32/ecx -2410 # . if (ecx >= in->write) break -2411 3b/compare *esi 1/r32/ecx -2412 7d/jump-if->= break/disp8 -2413 # var c/eax: byte = in->data[in->read] -2414 31/xor %eax 0/r32/eax -2415 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL -2416 # if (c == ' ') break -2417 3d/compare-eax-and 0x20/imm32/space -2418 74/jump-if-= break/disp8 -2419 # if (c == '\r') break -2420 3d/compare-eax-and 0xd/imm32/carriage-return -2421 74/jump-if-= break/disp8 -2422 # if (c == '\n') break -2423 3d/compare-eax-and 0xa/imm32/newline -2424 74/jump-if-= break/disp8 -2425 # if (c == '(') break -2426 3d/compare-eax-and 0x28/imm32/open-paren -2427 0f 84/jump-if-= break/disp32 -2428 # if (c == ')') break -2429 3d/compare-eax-and 0x29/imm32/close-paren -2430 0f 84/jump-if-= break/disp32 -2431 # if (c == ',') break -2432 3d/compare-eax-and 0x2c/imm32/comma -2433 0f 84/jump-if-= break/disp32 -2434 # ++in->read -2435 ff 0/subop/increment *(esi+4) -2436 # -2437 e9/jump loop/disp32 -2438 } -2439 $next-mu-token:done: -2440 # out->end = &in->data[in->read] -2441 8b/-> *(esi+4) 1/r32/ecx -2442 8d/copy-address *(esi+ecx+0xc) 0/r32/eax -2443 89/<- *(edi+4) 0/r32/eax -2444 $next-mu-token:end: -2445 # . restore registers -2446 5f/pop-to-edi -2447 5e/pop-to-esi -2448 59/pop-to-ecx -2449 58/pop-to-eax -2450 # . epilogue -2451 89/<- %esp 5/r32/ebp -2452 5d/pop-to-ebp -2453 c3/return -2454 -2455 # return the index in an array of strings matching 's' -2456 # index is denominated in elements, not bytes -2457 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int -2458 # . prologue -2459 55/push-ebp -2460 89/<- %ebp 4/r32/esp -2461 # . save registers -2462 51/push-ecx -2463 52/push-edx -2464 53/push-ebx -2465 56/push-esi -2466 #? (write-buffered Stderr "pos-slice: ") -2467 #? (write-slice-buffered Stderr *(ebp+0xc)) -2468 #? (write-buffered Stderr "\n") -2469 #? (flush Stderr) -2470 # esi = arr -2471 8b/-> *(ebp+8) 6/r32/esi -2472 # var index/ecx: int = 0 -2473 b9/copy-to-ecx 0/imm32 -2474 # var curr/edx: (addr (addr array byte)) = arr->data -2475 8d/copy-address *(esi+0xc) 2/r32/edx -2476 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] -2477 8b/-> *esi 3/r32/ebx -2478 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx -2479 { -2480 #? (write-buffered Stderr " ") -2481 #? (print-int32-buffered Stderr %ecx) -2482 #? (write-buffered Stderr "\n") -2483 #? (flush Stderr) -2484 # if (curr >= max) return -1 -2485 39/compare %edx 3/r32/ebx -2486 b8/copy-to-eax -1/imm32 -2487 73/jump-if-addr>= $pos-slice:end/disp8 -2488 # if (slice-equal?(s, *curr)) break -2489 (slice-equal? *(ebp+0xc) *edx) # => eax -2490 3d/compare-eax-and 0/imm32/false -2491 75/jump-if-!= break/disp8 -2492 # ++index -2493 41/increment-ecx -2494 # curr += 4 -2495 81 0/subop/add %edx 4/imm32 -2496 # -2497 eb/jump loop/disp8 -2498 } -2499 # return index -2500 89/<- %eax 1/r32/ecx -2501 $pos-slice:end: -2502 #? (write-buffered Stderr "=> ") -2503 #? (print-int32-buffered Stderr %eax) -2504 #? (write-buffered Stderr "\n") -2505 # . restore registers -2506 5e/pop-to-esi -2507 5b/pop-to-ebx -2508 5a/pop-to-edx -2509 59/pop-to-ecx -2510 # . epilogue -2511 89/<- %esp 5/r32/ebp -2512 5d/pop-to-ebp -2513 c3/return -2514 -2515 == data +1907 # scenarios considered: +1908 # ✗ fn foo # no block +1909 # ✓ fn foo { +1910 # ✗ fn foo { { +1911 # ✗ fn foo { } +1912 # ✗ fn foo { } { +1913 # ✗ fn foo x { +1914 # ✗ fn foo x: { +1915 # ✓ fn foo x: int { +1916 # ✓ fn foo x: int { +1917 # ✓ fn foo x: int -> y/eax: int { +1918 populate-mu-function-header: # first-line: (addr stream byte), out: (handle function), vars: (addr stack (handle var)) +1919 # pseudocode: +1920 # var name: slice +1921 # next-mu-token(first-line, name) +1922 # assert(name not in '{' '}' '->') +1923 # out->name = slice-to-string(name) +1924 # var next-offset: int = 8 +1925 # ## inouts +1926 # while true +1927 # ## name +1928 # name = next-mu-token(first-line) +1929 # if (name == '{') goto done +1930 # if (name == '->') break +1931 # assert(name != '}') +1932 # var v: (handle var) = parse-var-with-type(name, first-line) +1933 # assert(v->register == null) +1934 # v->stack-offset = next-offset +1935 # next-offset += size-of(v) +1936 # # v->block-depth is implicitly 0 +1937 # out->inouts = append(out->inouts, v) +1938 # push(vars, v) +1939 # ## outputs +1940 # while true +1941 # ## name +1942 # name = next-mu-token(first-line) +1943 # assert(name not in '{' '}' '->') +1944 # var v: (handle var) = parse-var-with-type(name, first-line) +1945 # assert(v->register != null) +1946 # out->outputs = append(out->outputs, v) +1947 # done: +1948 # +1949 # . prologue +1950 55/push-ebp +1951 89/<- %ebp 4/r32/esp +1952 # . save registers +1953 50/push-eax +1954 51/push-ecx +1955 52/push-edx +1956 53/push-ebx +1957 57/push-edi +1958 # edi = out +1959 8b/-> *(ebp+0xc) 7/r32/edi +1960 # var word-slice/ecx: slice +1961 68/push 0/imm32/end +1962 68/push 0/imm32/start +1963 89/<- %ecx 4/r32/esp +1964 # var next-offset/edx = 8 +1965 ba/copy-to-edx 8/imm32 +1966 # read function name +1967 (next-mu-token *(ebp+8) %ecx) +1968 # error checking +1969 # TODO: error if name starts with 'break' or 'loop' +1970 # if (word-slice == '{') abort +1971 (slice-equal? %ecx "{") # => eax +1972 3d/compare-eax-and 0/imm32/false +1973 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1974 # if (word-slice == '->') abort +1975 (slice-equal? %ecx "->") # => eax +1976 3d/compare-eax-and 0/imm32/false +1977 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1978 # if (word-slice == '}') abort +1979 (slice-equal? %ecx "}") # => eax +1980 3d/compare-eax-and 0/imm32/false +1981 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +1982 # save function name +1983 (slice-to-string Heap %ecx) # => eax +1984 89/<- *edi 0/r32/eax # Function-name +1985 # initialize default subx-name as well +1986 89/<- *(edi+4) 0/r32/eax # Function-subx-name +1987 # save function inouts +1988 { +1989 $populate-mu-function-header:check-for-inout: +1990 (next-mu-token *(ebp+8) %ecx) +1991 # if (word-slice == '{') goto done +1992 (slice-equal? %ecx "{") # => eax +1993 3d/compare-eax-and 0/imm32/false +1994 0f 85/jump-if-!= $populate-mu-function-header:done/disp32 +1995 # if (word-slice == '->') break +1996 (slice-equal? %ecx "->") # => eax +1997 3d/compare-eax-and 0/imm32/false +1998 0f 85/jump-if-!= break/disp32 +1999 # if (word-slice == '}') abort +2000 (slice-equal? %ecx "}") # => eax +2001 3d/compare-eax-and 0/imm32/false +2002 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +2003 # var v/ebx: (handle var) = parse-var-with-type(word-slice, first-line) +2004 (parse-var-with-type %ecx *(ebp+8)) # => eax +2005 89/<- %ebx 0/r32/eax +2006 # assert(v->register == null) +2007 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +2008 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 +2009 # v->stack-offset = next-offset +2010 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset +2011 # next-offset += size-of(v) +2012 (size-of %ebx) # => eax +2013 01/add %edx 0/r32/eax +2014 # v->block-depth is implicitly 0 +2015 # +2016 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax +2017 89/<- *(edi+8) 0/r32/eax # Function-inouts +2018 (push *(ebp+0x10) %ebx) +2019 # +2020 e9/jump loop/disp32 +2021 } +2022 # save function outputs +2023 { +2024 $populate-mu-function-header:check-for-out: +2025 (next-mu-token *(ebp+8) %ecx) +2026 # if (word-slice == '{') break +2027 (slice-equal? %ecx "{") # => eax +2028 3d/compare-eax-and 0/imm32/false +2029 0f 85/jump-if-!= break/disp32 +2030 # if (word-slice == '->') abort +2031 (slice-equal? %ecx "->") # => eax +2032 3d/compare-eax-and 0/imm32/false +2033 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +2034 # if (word-slice == '}') abort +2035 (slice-equal? %ecx "}") # => eax +2036 3d/compare-eax-and 0/imm32/false +2037 0f 85/jump-if-!= $populate-mu-function-header:error1/disp32 +2038 # +2039 (parse-var-with-type %ecx *(ebp+8)) # => eax +2040 89/<- %ebx 0/r32/eax +2041 # assert(var->register != null) +2042 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +2043 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 +2044 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax +2045 89/<- *(edi+0xc) 0/r32/eax # Function-outputs +2046 e9/jump loop/disp32 +2047 } +2048 $populate-mu-function-header:done: +2049 (check-no-tokens-left *(ebp+8)) +2050 $populate-mu-function-header:end: +2051 # . reclaim locals +2052 81 0/subop/add %esp 8/imm32 +2053 # . restore registers +2054 5f/pop-to-edi +2055 5b/pop-to-ebx +2056 5a/pop-to-edx +2057 59/pop-to-ecx +2058 58/pop-to-eax +2059 # . epilogue +2060 89/<- %esp 5/r32/ebp +2061 5d/pop-to-ebp +2062 c3/return +2063 +2064 $populate-mu-function-header:error1: +2065 # error("function header not in form 'fn <name> {'") +2066 (write-buffered Stderr "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '") +2067 (flush Stderr) +2068 (rewind-stream *(ebp+8)) +2069 (write-stream 2 *(ebp+8)) +2070 (write-buffered Stderr "'\n") +2071 (flush Stderr) +2072 # . syscall(exit, 1) +2073 bb/copy-to-ebx 1/imm32 +2074 b8/copy-to-eax 1/imm32/exit +2075 cd/syscall 0x80/imm8 +2076 # never gets here +2077 +2078 $populate-mu-function-header:error2: +2079 # error("function input '" var "' cannot be in a register") +2080 (write-buffered Stderr "function input '") +2081 (write-buffered Stderr *ebx) # Var-name +2082 (write-buffered Stderr "' cannot be in a register") +2083 (flush Stderr) +2084 # . syscall(exit, 1) +2085 bb/copy-to-ebx 1/imm32 +2086 b8/copy-to-eax 1/imm32/exit +2087 cd/syscall 0x80/imm8 +2088 # never gets here +2089 +2090 $populate-mu-function-header:error3: +2091 # error("function input '" var "' must be in a register") +2092 (write-buffered Stderr "function input '") +2093 (write-buffered Stderr *eax) # Var-name +2094 (write-buffered Stderr " must be in a register'") +2095 (flush Stderr) +2096 (rewind-stream *(ebp+8)) +2097 (write-stream 2 *(ebp+8)) +2098 (write-buffered Stderr "'\n") +2099 (flush Stderr) +2100 # . syscall(exit, 1) +2101 bb/copy-to-ebx 1/imm32 +2102 b8/copy-to-eax 1/imm32/exit +2103 cd/syscall 0x80/imm8 +2104 # never gets here +2105 +2106 test-function-header-with-arg: +2107 # . prologue +2108 55/push-ebp +2109 89/<- %ebp 4/r32/esp +2110 # setup +2111 (clear-stream _test-input-stream) +2112 (write _test-input-stream "foo n: int {\n") +2113 # var result/ecx: function +2114 2b/subtract-> *Function-size 4/r32/esp +2115 89/<- %ecx 4/r32/esp +2116 (zero-out %ecx *Function-size) +2117 # var vars/ebx: (stack (addr var) 16) +2118 81 5/subop/subtract %esp 0x10/imm32 +2119 68/push 0x10/imm32/length +2120 68/push 0/imm32/top +2121 89/<- %ebx 4/r32/esp +2122 # convert +2123 (populate-mu-function-header _test-input-stream %ecx %ebx) +2124 # check result +2125 (check-strings-equal *ecx "foo" "F - test-function-header-with-arg/name") # Function-name +2126 # edx: (handle list var) = result->inouts +2127 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +2128 # ebx: (handle var) = result->inouts->value +2129 8b/-> *edx 3/r32/ebx # List-value +2130 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name +2131 8b/-> *(ebx+4) 3/r32/ebx # Var-type +2132 (check-ints-equal *ebx 1 "F - test-function-header-with-arg/inout:0/type:0") # Tree-left +2133 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-arg/inout:0/type:1") # Tree-right +2134 # . epilogue +2135 89/<- %esp 5/r32/ebp +2136 5d/pop-to-ebp +2137 c3/return +2138 +2139 test-function-header-with-multiple-args: +2140 # . prologue +2141 55/push-ebp +2142 89/<- %ebp 4/r32/esp +2143 # setup +2144 (clear-stream _test-input-stream) +2145 (write _test-input-stream "foo a: int, b: int c: int {\n") +2146 # result/ecx: (handle function) +2147 2b/subtract-> *Function-size 4/r32/esp +2148 89/<- %ecx 4/r32/esp +2149 (zero-out %ecx *Function-size) +2150 # var vars/ebx: (stack (addr var) 16) +2151 81 5/subop/subtract %esp 0x10/imm32 +2152 68/push 0x10/imm32/length +2153 68/push 0/imm32/top +2154 89/<- %ebx 4/r32/esp +2155 # convert +2156 (populate-mu-function-header _test-input-stream %ecx %ebx) +2157 # check result +2158 (check-strings-equal *ecx "foo") # Function-name +2159 # edx: (handle list var) = result->inouts +2160 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +2161 $test-function-header-with-multiple-args:inout0: +2162 # ebx: (handle var) = result->inouts->value +2163 8b/-> *edx 3/r32/ebx # List-value +2164 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name +2165 8b/-> *(ebx+4) 3/r32/ebx # Var-type +2166 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Tree-left +2167 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-right +2168 # edx = result->inouts->next +2169 8b/-> *(edx+4) 2/r32/edx # List-next +2170 $test-function-header-with-multiple-args:inout1: +2171 # ebx = result->inouts->next->value +2172 8b/-> *edx 3/r32/ebx # List-value +2173 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name +2174 8b/-> *(ebx+4) 3/r32/ebx # Var-type +2175 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Tree-left +2176 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-right +2177 # edx = result->inouts->next->next +2178 8b/-> *(edx+4) 2/r32/edx # List-next +2179 $test-function-header-with-multiple-args:inout2: +2180 # ebx = result->inouts->next->next->value +2181 8b/-> *edx 3/r32/ebx # List-value +2182 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name +2183 8b/-> *(ebx+4) 3/r32/ebx # Var-type +2184 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Tree-left +2185 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-right +2186 # . epilogue +2187 89/<- %esp 5/r32/ebp +2188 5d/pop-to-ebp +2189 c3/return +2190 +2191 test-function-with-multiple-args-and-outputs: +2192 # . prologue +2193 55/push-ebp +2194 89/<- %ebp 4/r32/esp +2195 # setup +2196 (clear-stream _test-input-stream) +2197 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n") +2198 # result/ecx: (handle function) +2199 2b/subtract-> *Function-size 4/r32/esp +2200 89/<- %ecx 4/r32/esp +2201 (zero-out %ecx *Function-size) +2202 # var vars/ebx: (stack (addr var) 16) +2203 81 5/subop/subtract %esp 0x10/imm32 +2204 68/push 0x10/imm32/length +2205 68/push 0/imm32/top +2206 89/<- %ebx 4/r32/esp +2207 # convert +2208 (populate-mu-function-header _test-input-stream %ecx %ebx) +2209 # check result +2210 (check-strings-equal *ecx "foo") # Function-name +2211 # edx: (handle list var) = result->inouts +2212 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +2213 # ebx: (handle var) = result->inouts->value +2214 8b/-> *edx 3/r32/ebx # List-value +2215 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") # Var-name +2216 8b/-> *(ebx+4) 3/r32/ebx # Var-type +2217 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Tree-left +2218 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-right +2219 # edx = result->inouts->next +2220 8b/-> *(edx+4) 2/r32/edx # List-next +2221 # ebx = result->inouts->next->value +2222 8b/-> *edx 3/r32/ebx # List-value +2223 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") # Var-name +2224 8b/-> *(ebx+4) 3/r32/ebx # Var-type +2225 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Tree-left +2226 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-right +2227 # edx = result->inouts->next->next +2228 8b/-> *(edx+4) 2/r32/edx # List-next +2229 # ebx = result->inouts->next->next->value +2230 8b/-> *edx 3/r32/ebx # List-value +2231 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") # Var-name +2232 8b/-> *(ebx+4) 3/r32/ebx # Var-type +2233 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Tree-left +2234 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-right +2235 # edx: (handle list var) = result->outputs +2236 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs +2237 # ebx: (handle var) = result->outputs->value +2238 8b/-> *edx 3/r32/ebx # List-value +2239 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") # Var-name +2240 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register +2241 8b/-> *(ebx+4) 3/r32/ebx # Var-type +2242 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-left +2243 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-right +2244 # edx = result->outputs->next +2245 8b/-> *(edx+4) 2/r32/edx # List-next +2246 # ebx = result->outputs->next->value +2247 8b/-> *edx 3/r32/ebx # List-value +2248 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") # Var-name +2249 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register +2250 8b/-> *(ebx+4) 3/r32/ebx # Var-type +2251 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-left +2252 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-right +2253 # . epilogue +2254 89/<- %esp 5/r32/ebp +2255 5d/pop-to-ebp +2256 c3/return +2257 +2258 # format for variables with types +2259 # x: int +2260 # x: int, +2261 # x/eax: int +2262 # x/eax: int, +2263 # ignores at most one trailing comma +2264 # WARNING: modifies name +2265 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte) -> result/eax: (handle var) +2266 # pseudocode: +2267 # var v: (handle var) = allocate(Heap, Var-size) +2268 # var s: slice +2269 # if (!slice-ends-with(name, ":")) +2270 # abort +2271 # --name->end to skip ':' +2272 # next-token-from-slice(name->start, name->end, '/', s) +2273 # v->name = slice-to-string(s) +2274 # ## register +2275 # next-token-from-slice(s->end, name->end, '/', s) +2276 # if (!slice-empty?(s)) +2277 # v->register = slice-to-string(s) +2278 # ## type +2279 # var type: (handle tree type-id) = parse-type(first-line) +2280 # v->type = type +2281 # return v +2282 # +2283 # . prologue +2284 55/push-ebp +2285 89/<- %ebp 4/r32/esp +2286 # . save registers +2287 51/push-ecx +2288 52/push-edx +2289 53/push-ebx +2290 56/push-esi +2291 57/push-edi +2292 # esi = name +2293 8b/-> *(ebp+8) 6/r32/esi +2294 # if (!slice-ends-with?(name, ":")) abort +2295 8b/-> *(esi+4) 1/r32/ecx # Slice-end +2296 49/decrement-ecx +2297 8a/copy-byte *ecx 1/r32/CL +2298 81 4/subop/and %ecx 0xff/imm32 +2299 81 7/subop/compare %ecx 0x3a/imm32/colon +2300 0f 85/jump-if-!= $parse-var-with-type:abort/disp32 +2301 # --name->end to skip ':' +2302 ff 1/subop/decrement *(esi+4) +2303 # var result/edi: (handle var) = allocate(Heap, Var-size) +2304 (allocate Heap *Var-size) # => eax +2305 (zero-out %eax *Var-size) +2306 89/<- %edi 0/r32/eax +2307 # var s/ecx: slice +2308 68/push 0/imm32/end +2309 68/push 0/imm32/start +2310 89/<- %ecx 4/r32/esp +2311 $parse-var-with-type:save-name: +2312 # save v->name +2313 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' +2314 # . end/edx = s->end +2315 8b/-> *(ecx+4) 2/r32/edx +2316 $parse-var-with-type:write-name: +2317 (slice-to-string Heap %ecx) # => eax +2318 89/<- *edi 0/r32/eax # Var-name +2319 # save v->register +2320 $parse-var-with-type:save-register: +2321 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' +2322 # if (!slice-empty?(s)) v->register = slice-to-string(s) +2323 { +2324 $parse-var-with-type:write-register: +2325 (slice-empty? %ecx) # => eax +2326 3d/compare-eax-and 0/imm32/false +2327 75/jump-if-!= break/disp8 +2328 (slice-to-string Heap %ecx) +2329 89/<- *(edi+0x10) 0/r32/eax # Var-register +2330 } +2331 $parse-var-with-type:save-type: +2332 (parse-type Heap *(ebp+0xc)) # => eax +2333 89/<- *(edi+4) 0/r32/eax # Var-type +2334 $parse-var-with-type:end: +2335 # return result +2336 89/<- %eax 7/r32/edi +2337 # . reclaim locals +2338 81 0/subop/add %esp 8/imm32 +2339 # . restore registers +2340 5f/pop-to-edi +2341 5e/pop-to-esi +2342 5b/pop-to-ebx +2343 5a/pop-to-edx +2344 59/pop-to-ecx +2345 # . epilogue +2346 89/<- %esp 5/r32/ebp +2347 5d/pop-to-ebp +2348 c3/return +2349 +2350 $parse-var-with-type:abort: +2351 # error("var should have form 'name: type' in '" line "'\n") +2352 (write-buffered Stderr "var should have form 'name: type' in '") +2353 (flush Stderr) +2354 (rewind-stream *(ebp+0xc)) +2355 (write-stream 2 *(ebp+0xc)) +2356 (write-buffered Stderr "'\n") +2357 (flush Stderr) +2358 # . syscall(exit, 1) +2359 bb/copy-to-ebx 1/imm32 +2360 b8/copy-to-eax 1/imm32/exit +2361 cd/syscall 0x80/imm8 +2362 # never gets here +2363 +2364 parse-type: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) +2365 # pseudocode: +2366 # var s: slice = next-mu-token(in) +2367 # assert s != "" +2368 # assert s != "->" +2369 # assert s != "{" +2370 # assert s != "}" +2371 # if s == ")" +2372 # return 0 +2373 # result = allocate(Tree) +2374 # zero-out(result, *Tree-size) +2375 # if s != "(" +2376 # result->left = pos-slice(Type-id, s) +2377 # return +2378 # result->left = parse-type(ad, in) +2379 # result->right = parse-type-tree(ad, in) +2380 # +2381 # . prologue +2382 55/push-ebp +2383 89/<- %ebp 4/r32/esp +2384 # . save registers +2385 51/push-ecx +2386 52/push-edx +2387 # var s/ecx: slice +2388 68/push 0/imm32 +2389 68/push 0/imm32 +2390 89/<- %ecx 4/r32/esp +2391 # s = next-mu-token(in) +2392 (next-mu-token *(ebp+0xc) %ecx) +2393 #? (write-buffered Stderr "tok: ") +2394 #? (write-slice-buffered Stderr %ecx) +2395 #? (write-buffered Stderr "$\n") +2396 #? (flush Stderr) +2397 # assert s != "" +2398 (slice-equal? %ecx "") +2399 3d/compare-eax-and 0/imm32/false +2400 0f 85/jump-if-!= $parse-type:abort/disp32 +2401 # assert s != "{" +2402 (slice-equal? %ecx "{") +2403 3d/compare-eax-and 0/imm32/false +2404 0f 85/jump-if-!= $parse-type:abort/disp32 +2405 # assert s != "}" +2406 (slice-equal? %ecx "}") +2407 3d/compare-eax-and 0/imm32/false +2408 0f 85/jump-if-!= $parse-type:abort/disp32 +2409 # assert s != "->" +2410 (slice-equal? %ecx "->") +2411 3d/compare-eax-and 0/imm32/false +2412 0f 85/jump-if-!= $parse-type:abort/disp32 +2413 # if (s == ")") return 0 +2414 (slice-equal? %ecx ")") +2415 3d/compare-eax-and 0/imm32/false +2416 b8/copy-to-eax 0/imm32 +2417 0f 85/jump-if-!= $parse-type:end/disp32 +2418 # var result/edx: (handle tree type-id) +2419 (allocate *(ebp+8) *Tree-size) # => eax +2420 (zero-out %eax *Tree-size) +2421 89/<- %edx 0/r32/eax +2422 { +2423 # if (s != "(") break +2424 (slice-equal? %ecx "(") +2425 3d/compare-eax-and 0/imm32/false +2426 75/jump-if-!= break/disp8 +2427 # result->left = pos-slice(Type-id, s) +2428 (pos-slice Type-id %ecx) +2429 #? (write-buffered Stderr "=> {") +2430 #? (print-int32-buffered Stderr %eax) +2431 #? (write-buffered Stderr ", 0}\n") +2432 #? (flush Stderr) +2433 89/<- *edx 0/r32/eax # Tree-left +2434 e9/jump $parse-type:return-edx/disp32 +2435 } +2436 # otherwise s == "(" +2437 # result->left = parse-type(ad, in) +2438 (parse-type *(ebp+8) *(ebp+0xc)) +2439 #? (write-buffered Stderr "=> {") +2440 #? (print-int32-buffered Stderr %eax) +2441 89/<- *edx 0/r32/eax # Tree-left +2442 # result->right = parse-type-tree(ad, in) +2443 (parse-type-tree *(ebp+8) *(ebp+0xc)) +2444 #? (write-buffered Stderr Space) +2445 #? (print-int32-buffered Stderr %eax) +2446 #? (write-buffered Stderr "}\n") +2447 #? (flush Stderr) +2448 89/<- *(edx+4) 0/r32/eax # Tree-right +2449 $parse-type:return-edx: +2450 89/<- %eax 2/r32/edx +2451 $parse-type:end: +2452 # . reclaim locals +2453 81 0/subop/add %esp 8/imm32 +2454 # . restore registers +2455 5a/pop-to-edx +2456 59/pop-to-ecx +2457 # . epilogue +2458 89/<- %esp 5/r32/ebp +2459 5d/pop-to-ebp +2460 c3/return +2461 +2462 $parse-type:abort: +2463 # error("unexpected token when parsing type: '" s "'\n") +2464 (write-buffered Stderr "unexpected token when parsing type: '") +2465 (write-slice-buffered Stderr %ecx) +2466 (write-buffered Stderr "'\n") +2467 (flush Stderr) +2468 # . syscall(exit, 1) +2469 bb/copy-to-ebx 1/imm32 +2470 b8/copy-to-eax 1/imm32/exit +2471 cd/syscall 0x80/imm8 +2472 # never gets here +2473 +2474 parse-type-tree: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) +2475 # pseudocode: +2476 # var tmp: (handle tree type-id) = parse-type(ad, in) +2477 # if tmp == 0 +2478 # return 0 +2479 # result = allocate(Tree) +2480 # zero-out(result, *Tree-size) +2481 # result->left = tmp +2482 # result->right = parse-type-tree(ad, in) +2483 # +2484 # . prologue +2485 55/push-ebp +2486 89/<- %ebp 4/r32/esp +2487 # . save registers +2488 51/push-ecx +2489 52/push-edx +2490 # var tmp/eax: (handle tree type-id) = parse-type(ad, in) +2491 (parse-type *(ebp+8) *(ebp+0xc)) +2492 # if (tmp == 0) return tmp +2493 3d/compare-eax-and 0/imm32 +2494 74/jump-if-= $parse-type-tree:end/disp8 +2495 # var tmp2/ecx = tmp +2496 89/<- %ecx 0/r32/eax +2497 # var result/edx: (handle tree type-id) +2498 (allocate *(ebp+8) *Tree-size) # => eax +2499 (zero-out %eax *Tree-size) +2500 89/<- %edx 0/r32/eax +2501 # result->left = tmp2 +2502 89/<- *edx 1/r32/ecx # Tree-left +2503 # result->right = parse-type-tree(ad, in) +2504 (parse-type-tree *(ebp+8) *(ebp+0xc)) +2505 89/<- *(edx+4) 0/r32/eax # Tree-right +2506 $parse-type-tree:return-edx: +2507 89/<- %eax 2/r32/edx +2508 $parse-type-tree:end: +2509 # . restore registers +2510 5a/pop-to-edx +2511 59/pop-to-ecx +2512 # . epilogue +2513 89/<- %esp 5/r32/ebp +2514 5d/pop-to-ebp +2515 c3/return 2516 -2517 Type-id: # (stream (address array byte)) -2518 0x18/imm32/write -2519 0/imm32/read -2520 0x100/imm32/length -2521 # data -2522 "literal"/imm32 # 0 -2523 "int"/imm32 # 1 -2524 "addr"/imm32 # 2 -2525 "array"/imm32 # 3 -2526 "handle"/imm32 # 4 -2527 "bool"/imm32 # 5 -2528 0/imm32 -2529 0/imm32 -2530 # 0x20 -2531 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2532 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2533 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2534 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2535 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2536 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2537 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -2538 -2539 == code -2540 -2541 test-parse-var-with-type: -2542 # . prologue -2543 55/push-ebp -2544 89/<- %ebp 4/r32/esp -2545 # (eax..ecx) = "x:" -2546 b8/copy-to-eax "x:"/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 # _test-input-stream contains "int" -2555 (clear-stream _test-input-stream) -2556 (write _test-input-stream "int") -2557 # -2558 (parse-var-with-type %ecx _test-input-stream) -2559 8b/-> *eax 2/r32/edx # Var-name -2560 (check-strings-equal %edx "x" "F - test-var-with-type/name") -2561 8b/-> *(eax+4) 2/r32/edx # Var-type -2562 (check-ints-equal *edx 1 "F - test-var-with-type/type") -2563 (check-ints-equal *(edx+4) 0 "F - test-var-with-type/type") -2564 # . epilogue -2565 89/<- %esp 5/r32/ebp -2566 5d/pop-to-ebp -2567 c3/return -2568 -2569 test-parse-var-with-type-and-register: -2570 # . prologue -2571 55/push-ebp -2572 89/<- %ebp 4/r32/esp -2573 # (eax..ecx) = "x/eax:" -2574 b8/copy-to-eax "x/eax:"/imm32 -2575 8b/-> *eax 1/r32/ecx -2576 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2577 05/add-to-eax 4/imm32 -2578 # var slice/ecx: slice = {eax, ecx} -2579 51/push-ecx -2580 50/push-eax -2581 89/<- %ecx 4/r32/esp -2582 # _test-input-stream contains "int" -2583 (clear-stream _test-input-stream) -2584 (write _test-input-stream "int") -2585 # -2586 (parse-var-with-type %ecx _test-input-stream) -2587 8b/-> *eax 2/r32/edx # Var-name -2588 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") -2589 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2590 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") -2591 8b/-> *(eax+4) 2/r32/edx # Var-type -2592 (check-ints-equal *edx 1 "F - test-var-with-type-and-register/type") -2593 (check-ints-equal *(edx+4) 0 "F - test-var-with-type-and-register/type") -2594 # . epilogue -2595 89/<- %esp 5/r32/ebp -2596 5d/pop-to-ebp -2597 c3/return -2598 -2599 test-parse-var-with-trailing-characters: -2600 # . prologue -2601 55/push-ebp -2602 89/<- %ebp 4/r32/esp -2603 # (eax..ecx) = "x:" -2604 b8/copy-to-eax "x:"/imm32 -2605 8b/-> *eax 1/r32/ecx -2606 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2607 05/add-to-eax 4/imm32 -2608 # var slice/ecx: slice = {eax, ecx} -2609 51/push-ecx -2610 50/push-eax -2611 89/<- %ecx 4/r32/esp -2612 # _test-input-stream contains "int," -2613 (clear-stream _test-input-stream) -2614 (write _test-input-stream "int,") -2615 # -2616 (parse-var-with-type %ecx _test-input-stream) -2617 8b/-> *eax 2/r32/edx # Var-name -2618 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") -2619 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2620 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") -2621 8b/-> *(eax+4) 2/r32/edx # Var-type -2622 (check-ints-equal *edx 1 "F - test-var-with-trailing-characters/type") -2623 (check-ints-equal *(edx+4) 0 "F - test-var-with-trailing-characters/type") -2624 # . epilogue -2625 89/<- %esp 5/r32/ebp -2626 5d/pop-to-ebp -2627 c3/return -2628 -2629 test-parse-var-with-register-and-trailing-characters: -2630 # . prologue -2631 55/push-ebp -2632 89/<- %ebp 4/r32/esp -2633 # (eax..ecx) = "x/eax:" -2634 b8/copy-to-eax "x/eax:"/imm32 -2635 8b/-> *eax 1/r32/ecx -2636 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2637 05/add-to-eax 4/imm32 -2638 # var slice/ecx: slice = {eax, ecx} -2639 51/push-ecx -2640 50/push-eax -2641 89/<- %ecx 4/r32/esp -2642 # _test-input-stream contains "int," -2643 (clear-stream _test-input-stream) -2644 (write _test-input-stream "int,") -2645 # -2646 (parse-var-with-type %ecx _test-input-stream) -2647 8b/-> *eax 2/r32/edx # Var-name -2648 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") -2649 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2650 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") -2651 8b/-> *(eax+4) 2/r32/edx # Var-type -2652 (check-ints-equal *edx 1 "F - test-var-with-register-and-trailing-characters/type") -2653 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") -2654 # . epilogue -2655 89/<- %esp 5/r32/ebp -2656 5d/pop-to-ebp -2657 c3/return -2658 -2659 test-parse-var-with-compound-type: -2660 # . prologue -2661 55/push-ebp -2662 89/<- %ebp 4/r32/esp -2663 # (eax..ecx) = "x:" -2664 b8/copy-to-eax "x:"/imm32 -2665 8b/-> *eax 1/r32/ecx -2666 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2667 05/add-to-eax 4/imm32 -2668 # var slice/ecx: slice = {eax, ecx} -2669 51/push-ecx -2670 50/push-eax -2671 89/<- %ecx 4/r32/esp -2672 # _test-input-stream contains "(addr int)" -2673 (clear-stream _test-input-stream) -2674 (write _test-input-stream "(addr int)") -2675 # -2676 (parse-var-with-type %ecx _test-input-stream) -2677 8b/-> *eax 2/r32/edx # Var-name -2678 (check-strings-equal %edx "x" "F - test-var-with-compound-type/name") -2679 8b/-> *(eax+0x10) 2/r32/edx # Var-register -2680 (check-ints-equal %edx 0 "F - test-var-with-compound-type/register") -2681 # var type/edx: (handle tree type-id) = var->type -2682 8b/-> *(eax+4) 2/r32/edx # Var-type -2683 # type->left == atom(addr) -2684 8b/-> *edx 0/r32/eax # Atom-value -2685 (check-ints-equal *eax 2 "F - test-var-with-compound-type/type:0") # Tree-left -2686 # type->right->left == atom(int) -2687 8b/-> *(edx+4) 2/r32/edx # Tree-right -2688 8b/-> *edx 0/r32/eax # Tree-left -2689 (check-ints-equal *eax 1 "F - test-var-with-compound-type/type:1") # Atom-value -2690 # type->right->right == null -2691 (check-ints-equal *(edx+4) 0 "F - test-var-with-compound-type/type:2") # Tree-right -2692 # . epilogue -2693 89/<- %esp 5/r32/ebp -2694 5d/pop-to-ebp -2695 c3/return -2696 -2697 # identifier starts with a letter or '$' or '_' -2698 # no constraints at the moment on later letters -2699 # all we really want to do so far is exclude '{', '}' and '->' -2700 is-identifier?: # in: (addr slice) -> result/eax: boolean -2701 # . prologue -2702 55/push-ebp -2703 89/<- %ebp 4/r32/esp -2704 # if (slice-empty?(in)) return false -2705 (slice-empty? *(ebp+8)) # => eax -2706 3d/compare-eax-and 0/imm32/false -2707 75/jump-if-!= $is-identifier?:false/disp8 -2708 # var c/eax: byte = *in->start -2709 8b/-> *(ebp+8) 0/r32/eax -2710 8b/-> *eax 0/r32/eax -2711 8a/copy-byte *eax 0/r32/AL -2712 81 4/subop/and %eax 0xff/imm32 -2713 # if (c == '$') return true -2714 3d/compare-eax-and 0x24/imm32/$ -2715 74/jump-if-= $is-identifier?:true/disp8 -2716 # if (c == '_') return true -2717 3d/compare-eax-and 0x5f/imm32/_ -2718 74/jump-if-= $is-identifier?:true/disp8 -2719 # drop case -2720 25/and-eax-with 0x5f/imm32 -2721 # if (c < 'A') return false -2722 3d/compare-eax-and 0x41/imm32/A -2723 7c/jump-if-< $is-identifier?:false/disp8 -2724 # if (c > 'Z') return false -2725 3d/compare-eax-and 0x5a/imm32/Z -2726 7f/jump-if-> $is-identifier?:false/disp8 -2727 # otherwise return true -2728 $is-identifier?:true: -2729 b8/copy-to-eax 1/imm32/true -2730 eb/jump $is-identifier?:end/disp8 -2731 $is-identifier?:false: -2732 b8/copy-to-eax 0/imm32/false -2733 $is-identifier?:end: -2734 # . epilogue -2735 89/<- %esp 5/r32/ebp -2736 5d/pop-to-ebp -2737 c3/return -2738 -2739 test-is-identifier-dollar: -2740 # . prologue -2741 55/push-ebp -2742 89/<- %ebp 4/r32/esp -2743 # (eax..ecx) = "$a" -2744 b8/copy-to-eax "$a"/imm32 -2745 8b/-> *eax 1/r32/ecx -2746 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2747 05/add-to-eax 4/imm32 -2748 # var slice/ecx: slice = {eax, ecx} -2749 51/push-ecx -2750 50/push-eax -2751 89/<- %ecx 4/r32/esp -2752 # -2753 (is-identifier? %ecx) -2754 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") -2755 # . epilogue -2756 89/<- %esp 5/r32/ebp -2757 5d/pop-to-ebp -2758 c3/return -2759 -2760 test-is-identifier-underscore: -2761 # . prologue -2762 55/push-ebp -2763 89/<- %ebp 4/r32/esp -2764 # (eax..ecx) = "_a" -2765 b8/copy-to-eax "_a"/imm32 -2766 8b/-> *eax 1/r32/ecx -2767 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2768 05/add-to-eax 4/imm32 -2769 # var slice/ecx: slice = {eax, ecx} -2770 51/push-ecx -2771 50/push-eax -2772 89/<- %ecx 4/r32/esp -2773 # -2774 (is-identifier? %ecx) -2775 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") -2776 # . epilogue -2777 89/<- %esp 5/r32/ebp -2778 5d/pop-to-ebp -2779 c3/return -2780 -2781 test-is-identifier-a: -2782 # . prologue -2783 55/push-ebp -2784 89/<- %ebp 4/r32/esp -2785 # (eax..ecx) = "a$" -2786 b8/copy-to-eax "a$"/imm32 -2787 8b/-> *eax 1/r32/ecx -2788 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2789 05/add-to-eax 4/imm32 -2790 # var slice/ecx: slice = {eax, ecx} -2791 51/push-ecx -2792 50/push-eax -2793 89/<- %ecx 4/r32/esp -2794 # -2795 (is-identifier? %ecx) -2796 (check-ints-equal %eax 1 "F - test-is-identifier-a") -2797 # . epilogue -2798 89/<- %esp 5/r32/ebp -2799 5d/pop-to-ebp -2800 c3/return -2801 -2802 test-is-identifier-z: -2803 # . prologue -2804 55/push-ebp -2805 89/<- %ebp 4/r32/esp -2806 # (eax..ecx) = "z$" -2807 b8/copy-to-eax "z$"/imm32 -2808 8b/-> *eax 1/r32/ecx -2809 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2810 05/add-to-eax 4/imm32 -2811 # var slice/ecx: slice = {eax, ecx} -2812 51/push-ecx -2813 50/push-eax -2814 89/<- %ecx 4/r32/esp -2815 # -2816 (is-identifier? %ecx) -2817 (check-ints-equal %eax 1 "F - test-is-identifier-z") -2818 # . epilogue -2819 89/<- %esp 5/r32/ebp -2820 5d/pop-to-ebp -2821 c3/return -2822 -2823 test-is-identifier-A: -2824 # . prologue -2825 55/push-ebp -2826 89/<- %ebp 4/r32/esp -2827 # (eax..ecx) = "A$" -2828 b8/copy-to-eax "A$"/imm32 -2829 8b/-> *eax 1/r32/ecx -2830 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2831 05/add-to-eax 4/imm32 -2832 # var slice/ecx: slice = {eax, ecx} -2833 51/push-ecx -2834 50/push-eax -2835 89/<- %ecx 4/r32/esp -2836 # -2837 (is-identifier? %ecx) -2838 (check-ints-equal %eax 1 "F - test-is-identifier-A") -2839 # . epilogue -2840 89/<- %esp 5/r32/ebp -2841 5d/pop-to-ebp -2842 c3/return -2843 -2844 test-is-identifier-Z: -2845 # . prologue -2846 55/push-ebp -2847 89/<- %ebp 4/r32/esp -2848 # (eax..ecx) = "Z$" -2849 b8/copy-to-eax "Z$"/imm32 -2850 8b/-> *eax 1/r32/ecx -2851 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2852 05/add-to-eax 4/imm32 -2853 # var slice/ecx: slice = {eax, ecx} -2854 51/push-ecx -2855 50/push-eax -2856 89/<- %ecx 4/r32/esp -2857 # -2858 (is-identifier? %ecx) -2859 (check-ints-equal %eax 1 "F - test-is-identifier-Z") -2860 # . epilogue -2861 89/<- %esp 5/r32/ebp -2862 5d/pop-to-ebp -2863 c3/return -2864 -2865 test-is-identifier-@: -2866 # character before 'A' is invalid -2867 # . prologue -2868 55/push-ebp -2869 89/<- %ebp 4/r32/esp -2870 # (eax..ecx) = "@a" -2871 b8/copy-to-eax "@a"/imm32 -2872 8b/-> *eax 1/r32/ecx -2873 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2874 05/add-to-eax 4/imm32 -2875 # var slice/ecx: slice = {eax, ecx} -2876 51/push-ecx -2877 50/push-eax -2878 89/<- %ecx 4/r32/esp -2879 # -2880 (is-identifier? %ecx) -2881 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2882 # . epilogue -2883 89/<- %esp 5/r32/ebp -2884 5d/pop-to-ebp -2885 c3/return -2886 -2887 test-is-identifier-square-bracket: -2888 # character after 'Z' is invalid -2889 # . prologue -2890 55/push-ebp -2891 89/<- %ebp 4/r32/esp -2892 # (eax..ecx) = "[a" -2893 b8/copy-to-eax "[a"/imm32 -2894 8b/-> *eax 1/r32/ecx -2895 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2896 05/add-to-eax 4/imm32 -2897 # var slice/ecx: slice = {eax, ecx} -2898 51/push-ecx -2899 50/push-eax -2900 89/<- %ecx 4/r32/esp -2901 # -2902 (is-identifier? %ecx) -2903 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2904 # . epilogue -2905 89/<- %esp 5/r32/ebp -2906 5d/pop-to-ebp -2907 c3/return -2908 -2909 test-is-identifier-backtick: -2910 # character before 'a' is invalid -2911 # . prologue -2912 55/push-ebp -2913 89/<- %ebp 4/r32/esp -2914 # (eax..ecx) = "`a" -2915 b8/copy-to-eax "`a"/imm32 -2916 8b/-> *eax 1/r32/ecx -2917 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2918 05/add-to-eax 4/imm32 -2919 # var slice/ecx: slice = {eax, ecx} -2920 51/push-ecx -2921 50/push-eax -2922 89/<- %ecx 4/r32/esp -2923 # -2924 (is-identifier? %ecx) -2925 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") -2926 # . epilogue -2927 89/<- %esp 5/r32/ebp -2928 5d/pop-to-ebp -2929 c3/return -2930 -2931 test-is-identifier-curly-brace-open: -2932 # character after 'z' is invalid; also used for blocks +2517 next-mu-token: # in: (addr stream byte), out: (addr slice) +2518 # pseudocode: +2519 # start: +2520 # skip-chars-matching-whitespace(in) +2521 # if in->read >= in->write # end of in +2522 # out = {0, 0} +2523 # return +2524 # out->start = &in->data[in->read] +2525 # var curr-byte/eax: byte = in->data[in->read] +2526 # if curr->byte == ',' # comment token +2527 # ++in->read +2528 # goto start +2529 # if curr-byte == '#' # comment +2530 # goto done # treat as eof +2531 # if curr-byte == '"' # string literal +2532 # skip-string(in) +2533 # goto done # no metadata +2534 # if curr-byte == '(' +2535 # ++in->read +2536 # goto done +2537 # if curr-byte == ')' +2538 # ++in->read +2539 # goto done +2540 # # read a word +2541 # while true +2542 # if in->read >= in->write +2543 # break +2544 # curr-byte = in->data[in->read] +2545 # if curr-byte == ' ' +2546 # break +2547 # if curr-byte == '\r' +2548 # break +2549 # if curr-byte == '\n' +2550 # break +2551 # if curr-byte == '(' +2552 # break +2553 # if curr-byte == ')' +2554 # break +2555 # if curr-byte == ',' +2556 # break +2557 # ++in->read +2558 # done: +2559 # out->end = &in->data[in->read] +2560 # +2561 # . prologue +2562 55/push-ebp +2563 89/<- %ebp 4/r32/esp +2564 # . save registers +2565 50/push-eax +2566 51/push-ecx +2567 56/push-esi +2568 57/push-edi +2569 # esi = in +2570 8b/-> *(ebp+8) 6/r32/esi +2571 # edi = out +2572 8b/-> *(ebp+0xc) 7/r32/edi +2573 $next-mu-token:start: +2574 (skip-chars-matching-whitespace %esi) +2575 $next-mu-token:check0: +2576 # if (in->read >= in->write) return out = {0, 0} +2577 # . ecx = in->read +2578 8b/-> *(esi+4) 1/r32/ecx +2579 # . if (ecx >= in->write) return out = {0, 0} +2580 3b/compare 1/r32/ecx *esi +2581 c7 0/subop/copy *edi 0/imm32 +2582 c7 0/subop/copy *(edi+4) 0/imm32 +2583 0f 8d/jump-if->= $next-mu-token:end/disp32 +2584 # out->start = &in->data[in->read] +2585 8d/copy-address *(esi+ecx+0xc) 0/r32/eax +2586 89/<- *edi 0/r32/eax +2587 # var curr-byte/eax: byte = in->data[in->read] +2588 31/xor %eax 0/r32/eax +2589 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +2590 { +2591 $next-mu-token:check-for-comma: +2592 # if (curr-byte != ',') break +2593 3d/compare-eax-and 0x2c/imm32/comma +2594 75/jump-if-!= break/disp8 +2595 # ++in->read +2596 ff 0/subop/increment *(esi+4) +2597 # restart +2598 e9/jump $next-mu-token:start/disp32 +2599 } +2600 { +2601 $next-mu-token:check-for-comment: +2602 # if (curr-byte != '#') break +2603 3d/compare-eax-and 0x23/imm32/pound +2604 75/jump-if-!= break/disp8 +2605 # return eof +2606 e9/jump $next-mu-token:done/disp32 +2607 } +2608 { +2609 $next-mu-token:check-for-string-literal: +2610 # if (curr-byte != '"') break +2611 3d/compare-eax-and 0x22/imm32/dquote +2612 75/jump-if-!= break/disp8 +2613 (skip-string %esi) +2614 # return +2615 e9/jump $next-mu-token:done/disp32 +2616 } +2617 { +2618 $next-mu-token:check-for-open-paren: +2619 # if (curr-byte != '(') break +2620 3d/compare-eax-and 0x28/imm32/open-paren +2621 75/jump-if-!= break/disp8 +2622 # ++in->read +2623 ff 0/subop/increment *(esi+4) +2624 # return +2625 e9/jump $next-mu-token:done/disp32 +2626 } +2627 { +2628 $next-mu-token:check-for-close-paren: +2629 # if (curr-byte != ')') break +2630 3d/compare-eax-and 0x29/imm32/close-paren +2631 75/jump-if-!= break/disp8 +2632 # ++in->read +2633 ff 0/subop/increment *(esi+4) +2634 # return +2635 e9/jump $next-mu-token:done/disp32 +2636 } +2637 { +2638 $next-mu-token:regular-word-without-metadata: +2639 # if (in->read >= in->write) break +2640 # . ecx = in->read +2641 8b/-> *(esi+4) 1/r32/ecx +2642 # . if (ecx >= in->write) break +2643 3b/compare *esi 1/r32/ecx +2644 7d/jump-if->= break/disp8 +2645 # var c/eax: byte = in->data[in->read] +2646 31/xor %eax 0/r32/eax +2647 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +2648 # if (c == ' ') break +2649 3d/compare-eax-and 0x20/imm32/space +2650 74/jump-if-= break/disp8 +2651 # if (c == '\r') break +2652 3d/compare-eax-and 0xd/imm32/carriage-return +2653 74/jump-if-= break/disp8 +2654 # if (c == '\n') break +2655 3d/compare-eax-and 0xa/imm32/newline +2656 74/jump-if-= break/disp8 +2657 # if (c == '(') break +2658 3d/compare-eax-and 0x28/imm32/open-paren +2659 0f 84/jump-if-= break/disp32 +2660 # if (c == ')') break +2661 3d/compare-eax-and 0x29/imm32/close-paren +2662 0f 84/jump-if-= break/disp32 +2663 # if (c == ',') break +2664 3d/compare-eax-and 0x2c/imm32/comma +2665 0f 84/jump-if-= break/disp32 +2666 # ++in->read +2667 ff 0/subop/increment *(esi+4) +2668 # +2669 e9/jump loop/disp32 +2670 } +2671 $next-mu-token:done: +2672 # out->end = &in->data[in->read] +2673 8b/-> *(esi+4) 1/r32/ecx +2674 8d/copy-address *(esi+ecx+0xc) 0/r32/eax +2675 89/<- *(edi+4) 0/r32/eax +2676 $next-mu-token:end: +2677 # . restore registers +2678 5f/pop-to-edi +2679 5e/pop-to-esi +2680 59/pop-to-ecx +2681 58/pop-to-eax +2682 # . epilogue +2683 89/<- %esp 5/r32/ebp +2684 5d/pop-to-ebp +2685 c3/return +2686 +2687 # return the index in an array of strings matching 's' +2688 # index is denominated in elements, not bytes +2689 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int +2690 # . prologue +2691 55/push-ebp +2692 89/<- %ebp 4/r32/esp +2693 # . save registers +2694 51/push-ecx +2695 52/push-edx +2696 53/push-ebx +2697 56/push-esi +2698 #? (write-buffered Stderr "pos-slice: ") +2699 #? (write-slice-buffered Stderr *(ebp+0xc)) +2700 #? (write-buffered Stderr "\n") +2701 #? (flush Stderr) +2702 # esi = arr +2703 8b/-> *(ebp+8) 6/r32/esi +2704 # var index/ecx: int = 0 +2705 b9/copy-to-ecx 0/imm32 +2706 # var curr/edx: (addr (addr array byte)) = arr->data +2707 8d/copy-address *(esi+0xc) 2/r32/edx +2708 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] +2709 8b/-> *esi 3/r32/ebx +2710 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx +2711 { +2712 #? (write-buffered Stderr " ") +2713 #? (print-int32-buffered Stderr %ecx) +2714 #? (write-buffered Stderr "\n") +2715 #? (flush Stderr) +2716 # if (curr >= max) return -1 +2717 39/compare %edx 3/r32/ebx +2718 b8/copy-to-eax -1/imm32 +2719 73/jump-if-addr>= $pos-slice:end/disp8 +2720 # if (slice-equal?(s, *curr)) break +2721 (slice-equal? *(ebp+0xc) *edx) # => eax +2722 3d/compare-eax-and 0/imm32/false +2723 75/jump-if-!= break/disp8 +2724 # ++index +2725 41/increment-ecx +2726 # curr += 4 +2727 81 0/subop/add %edx 4/imm32 +2728 # +2729 eb/jump loop/disp8 +2730 } +2731 # return index +2732 89/<- %eax 1/r32/ecx +2733 $pos-slice:end: +2734 #? (write-buffered Stderr "=> ") +2735 #? (print-int32-buffered Stderr %eax) +2736 #? (write-buffered Stderr "\n") +2737 # . restore registers +2738 5e/pop-to-esi +2739 5b/pop-to-ebx +2740 5a/pop-to-edx +2741 59/pop-to-ecx +2742 # . epilogue +2743 89/<- %esp 5/r32/ebp +2744 5d/pop-to-ebp +2745 c3/return +2746 +2747 == data +2748 +2749 Type-id: # (stream (address array byte)) +2750 0x18/imm32/write +2751 0/imm32/read +2752 0x100/imm32/length +2753 # data +2754 "literal"/imm32 # 0 +2755 "int"/imm32 # 1 +2756 "addr"/imm32 # 2 +2757 "array"/imm32 # 3 +2758 "handle"/imm32 # 4 +2759 "bool"/imm32 # 5 +2760 0/imm32 +2761 0/imm32 +2762 # 0x20 +2763 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2764 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2765 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2766 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2767 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2768 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2769 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2770 +2771 == code +2772 +2773 test-parse-var-with-type: +2774 # . prologue +2775 55/push-ebp +2776 89/<- %ebp 4/r32/esp +2777 # (eax..ecx) = "x:" +2778 b8/copy-to-eax "x:"/imm32 +2779 8b/-> *eax 1/r32/ecx +2780 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2781 05/add-to-eax 4/imm32 +2782 # var slice/ecx: slice = {eax, ecx} +2783 51/push-ecx +2784 50/push-eax +2785 89/<- %ecx 4/r32/esp +2786 # _test-input-stream contains "int" +2787 (clear-stream _test-input-stream) +2788 (write _test-input-stream "int") +2789 # +2790 (parse-var-with-type %ecx _test-input-stream) +2791 8b/-> *eax 2/r32/edx # Var-name +2792 (check-strings-equal %edx "x" "F - test-var-with-type/name") +2793 8b/-> *(eax+4) 2/r32/edx # Var-type +2794 (check-ints-equal *edx 1 "F - test-var-with-type/type") +2795 (check-ints-equal *(edx+4) 0 "F - test-var-with-type/type") +2796 # . epilogue +2797 89/<- %esp 5/r32/ebp +2798 5d/pop-to-ebp +2799 c3/return +2800 +2801 test-parse-var-with-type-and-register: +2802 # . prologue +2803 55/push-ebp +2804 89/<- %ebp 4/r32/esp +2805 # (eax..ecx) = "x/eax:" +2806 b8/copy-to-eax "x/eax:"/imm32 +2807 8b/-> *eax 1/r32/ecx +2808 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2809 05/add-to-eax 4/imm32 +2810 # var slice/ecx: slice = {eax, ecx} +2811 51/push-ecx +2812 50/push-eax +2813 89/<- %ecx 4/r32/esp +2814 # _test-input-stream contains "int" +2815 (clear-stream _test-input-stream) +2816 (write _test-input-stream "int") +2817 # +2818 (parse-var-with-type %ecx _test-input-stream) +2819 8b/-> *eax 2/r32/edx # Var-name +2820 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") +2821 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2822 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") +2823 8b/-> *(eax+4) 2/r32/edx # Var-type +2824 (check-ints-equal *edx 1 "F - test-var-with-type-and-register/type") +2825 (check-ints-equal *(edx+4) 0 "F - test-var-with-type-and-register/type") +2826 # . epilogue +2827 89/<- %esp 5/r32/ebp +2828 5d/pop-to-ebp +2829 c3/return +2830 +2831 test-parse-var-with-trailing-characters: +2832 # . prologue +2833 55/push-ebp +2834 89/<- %ebp 4/r32/esp +2835 # (eax..ecx) = "x:" +2836 b8/copy-to-eax "x:"/imm32 +2837 8b/-> *eax 1/r32/ecx +2838 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2839 05/add-to-eax 4/imm32 +2840 # var slice/ecx: slice = {eax, ecx} +2841 51/push-ecx +2842 50/push-eax +2843 89/<- %ecx 4/r32/esp +2844 # _test-input-stream contains "int," +2845 (clear-stream _test-input-stream) +2846 (write _test-input-stream "int,") +2847 # +2848 (parse-var-with-type %ecx _test-input-stream) +2849 8b/-> *eax 2/r32/edx # Var-name +2850 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") +2851 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2852 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") +2853 8b/-> *(eax+4) 2/r32/edx # Var-type +2854 (check-ints-equal *edx 1 "F - test-var-with-trailing-characters/type") +2855 (check-ints-equal *(edx+4) 0 "F - test-var-with-trailing-characters/type") +2856 # . epilogue +2857 89/<- %esp 5/r32/ebp +2858 5d/pop-to-ebp +2859 c3/return +2860 +2861 test-parse-var-with-register-and-trailing-characters: +2862 # . prologue +2863 55/push-ebp +2864 89/<- %ebp 4/r32/esp +2865 # (eax..ecx) = "x/eax:" +2866 b8/copy-to-eax "x/eax:"/imm32 +2867 8b/-> *eax 1/r32/ecx +2868 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2869 05/add-to-eax 4/imm32 +2870 # var slice/ecx: slice = {eax, ecx} +2871 51/push-ecx +2872 50/push-eax +2873 89/<- %ecx 4/r32/esp +2874 # _test-input-stream contains "int," +2875 (clear-stream _test-input-stream) +2876 (write _test-input-stream "int,") +2877 # +2878 (parse-var-with-type %ecx _test-input-stream) +2879 8b/-> *eax 2/r32/edx # Var-name +2880 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") +2881 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2882 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") +2883 8b/-> *(eax+4) 2/r32/edx # Var-type +2884 (check-ints-equal *edx 1 "F - test-var-with-register-and-trailing-characters/type") +2885 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") +2886 # . epilogue +2887 89/<- %esp 5/r32/ebp +2888 5d/pop-to-ebp +2889 c3/return +2890 +2891 test-parse-var-with-compound-type: +2892 # . prologue +2893 55/push-ebp +2894 89/<- %ebp 4/r32/esp +2895 # (eax..ecx) = "x:" +2896 b8/copy-to-eax "x:"/imm32 +2897 8b/-> *eax 1/r32/ecx +2898 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2899 05/add-to-eax 4/imm32 +2900 # var slice/ecx: slice = {eax, ecx} +2901 51/push-ecx +2902 50/push-eax +2903 89/<- %ecx 4/r32/esp +2904 # _test-input-stream contains "(addr int)" +2905 (clear-stream _test-input-stream) +2906 (write _test-input-stream "(addr int)") +2907 # +2908 (parse-var-with-type %ecx _test-input-stream) +2909 8b/-> *eax 2/r32/edx # Var-name +2910 (check-strings-equal %edx "x" "F - test-var-with-compound-type/name") +2911 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2912 (check-ints-equal %edx 0 "F - test-var-with-compound-type/register") +2913 # var type/edx: (handle tree type-id) = var->type +2914 8b/-> *(eax+4) 2/r32/edx # Var-type +2915 # type->left == atom(addr) +2916 8b/-> *edx 0/r32/eax # Atom-value +2917 (check-ints-equal *eax 2 "F - test-var-with-compound-type/type:0") # Tree-left +2918 # type->right->left == atom(int) +2919 8b/-> *(edx+4) 2/r32/edx # Tree-right +2920 8b/-> *edx 0/r32/eax # Tree-left +2921 (check-ints-equal *eax 1 "F - test-var-with-compound-type/type:1") # Atom-value +2922 # type->right->right == null +2923 (check-ints-equal *(edx+4) 0 "F - test-var-with-compound-type/type:2") # Tree-right +2924 # . epilogue +2925 89/<- %esp 5/r32/ebp +2926 5d/pop-to-ebp +2927 c3/return +2928 +2929 # identifier starts with a letter or '$' or '_' +2930 # no constraints at the moment on later letters +2931 # all we really want to do so far is exclude '{', '}' and '->' +2932 is-identifier?: # in: (addr slice) -> result/eax: boolean 2933 # . prologue 2934 55/push-ebp 2935 89/<- %ebp 4/r32/esp -2936 # (eax..ecx) = "{a" -2937 b8/copy-to-eax "{a"/imm32 -2938 8b/-> *eax 1/r32/ecx -2939 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2940 05/add-to-eax 4/imm32 -2941 # var slice/ecx: slice = {eax, ecx} -2942 51/push-ecx -2943 50/push-eax -2944 89/<- %ecx 4/r32/esp -2945 # -2946 (is-identifier? %ecx) -2947 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") -2948 # . epilogue -2949 89/<- %esp 5/r32/ebp -2950 5d/pop-to-ebp -2951 c3/return -2952 -2953 test-is-identifier-curly-brace-close: -2954 # . prologue -2955 55/push-ebp -2956 89/<- %ebp 4/r32/esp -2957 # (eax..ecx) = "}a" -2958 b8/copy-to-eax "}a"/imm32 -2959 8b/-> *eax 1/r32/ecx -2960 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2961 05/add-to-eax 4/imm32 -2962 # var slice/ecx: slice = {eax, ecx} -2963 51/push-ecx -2964 50/push-eax -2965 89/<- %ecx 4/r32/esp -2966 # -2967 (is-identifier? %ecx) -2968 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") -2969 # . epilogue -2970 89/<- %esp 5/r32/ebp -2971 5d/pop-to-ebp -2972 c3/return -2973 -2974 test-is-identifier-hyphen: -2975 # disallow leading '-' since '->' has special meaning -2976 # . prologue -2977 55/push-ebp -2978 89/<- %ebp 4/r32/esp -2979 # (eax..ecx) = "-a" -2980 b8/copy-to-eax "-a"/imm32 -2981 8b/-> *eax 1/r32/ecx -2982 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2983 05/add-to-eax 4/imm32 -2984 # var slice/ecx: slice = {eax, ecx} -2985 51/push-ecx -2986 50/push-eax -2987 89/<- %ecx 4/r32/esp -2988 # -2989 (is-identifier? %ecx) -2990 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") -2991 # . epilogue -2992 89/<- %esp 5/r32/ebp -2993 5d/pop-to-ebp -2994 c3/return -2995 -2996 populate-mu-function-body: # in: (addr buffered-file), out: (handle function), vars: (addr stack (handle var)) -2997 # . prologue -2998 55/push-ebp -2999 89/<- %ebp 4/r32/esp -3000 # . save registers -3001 50/push-eax -3002 56/push-esi -3003 57/push-edi -3004 # esi = in -3005 8b/-> *(ebp+8) 6/r32/esi -3006 # edi = out -3007 8b/-> *(ebp+0xc) 7/r32/edi -3008 # initialize some global state -3009 c7 0/subop/copy *Curr-block-depth 1/imm32 -3010 c7 0/subop/copy *Next-local-stack-offset -4/imm32 -3011 # var eax: (handle block) = parse-mu-block(in, vars, fn) -3012 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax -3013 # out->body = eax -3014 89/<- *(edi+0x10) 0/r32/eax # Function-body -3015 $populate-mu-function-body:end: -3016 # . restore registers -3017 5f/pop-to-edi -3018 5e/pop-to-esi -3019 58/pop-to-eax -3020 # . epilogue -3021 89/<- %esp 5/r32/ebp -3022 5d/pop-to-ebp -3023 c3/return -3024 -3025 == data -3026 -3027 # Global state added to each var record when parsing a function -3028 -3029 Curr-block-depth: # (addr int) -3030 0/imm32 -3031 Next-local-stack-offset: # (addr int) -3032 -4/imm32 +2936 # if (slice-empty?(in)) return false +2937 (slice-empty? *(ebp+8)) # => eax +2938 3d/compare-eax-and 0/imm32/false +2939 75/jump-if-!= $is-identifier?:false/disp8 +2940 # var c/eax: byte = *in->start +2941 8b/-> *(ebp+8) 0/r32/eax +2942 8b/-> *eax 0/r32/eax +2943 8a/copy-byte *eax 0/r32/AL +2944 81 4/subop/and %eax 0xff/imm32 +2945 # if (c == '$') return true +2946 3d/compare-eax-and 0x24/imm32/$ +2947 74/jump-if-= $is-identifier?:true/disp8 +2948 # if (c == '_') return true +2949 3d/compare-eax-and 0x5f/imm32/_ +2950 74/jump-if-= $is-identifier?:true/disp8 +2951 # drop case +2952 25/and-eax-with 0x5f/imm32 +2953 # if (c < 'A') return false +2954 3d/compare-eax-and 0x41/imm32/A +2955 7c/jump-if-< $is-identifier?:false/disp8 +2956 # if (c > 'Z') return false +2957 3d/compare-eax-and 0x5a/imm32/Z +2958 7f/jump-if-> $is-identifier?:false/disp8 +2959 # otherwise return true +2960 $is-identifier?:true: +2961 b8/copy-to-eax 1/imm32/true +2962 eb/jump $is-identifier?:end/disp8 +2963 $is-identifier?:false: +2964 b8/copy-to-eax 0/imm32/false +2965 $is-identifier?:end: +2966 # . epilogue +2967 89/<- %esp 5/r32/ebp +2968 5d/pop-to-ebp +2969 c3/return +2970 +2971 test-is-identifier-dollar: +2972 # . prologue +2973 55/push-ebp +2974 89/<- %ebp 4/r32/esp +2975 # (eax..ecx) = "$a" +2976 b8/copy-to-eax "$a"/imm32 +2977 8b/-> *eax 1/r32/ecx +2978 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2979 05/add-to-eax 4/imm32 +2980 # var slice/ecx: slice = {eax, ecx} +2981 51/push-ecx +2982 50/push-eax +2983 89/<- %ecx 4/r32/esp +2984 # +2985 (is-identifier? %ecx) +2986 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") +2987 # . epilogue +2988 89/<- %esp 5/r32/ebp +2989 5d/pop-to-ebp +2990 c3/return +2991 +2992 test-is-identifier-underscore: +2993 # . prologue +2994 55/push-ebp +2995 89/<- %ebp 4/r32/esp +2996 # (eax..ecx) = "_a" +2997 b8/copy-to-eax "_a"/imm32 +2998 8b/-> *eax 1/r32/ecx +2999 8d/copy-address *(eax+ecx+4) 1/r32/ecx +3000 05/add-to-eax 4/imm32 +3001 # var slice/ecx: slice = {eax, ecx} +3002 51/push-ecx +3003 50/push-eax +3004 89/<- %ecx 4/r32/esp +3005 # +3006 (is-identifier? %ecx) +3007 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") +3008 # . epilogue +3009 89/<- %esp 5/r32/ebp +3010 5d/pop-to-ebp +3011 c3/return +3012 +3013 test-is-identifier-a: +3014 # . prologue +3015 55/push-ebp +3016 89/<- %ebp 4/r32/esp +3017 # (eax..ecx) = "a$" +3018 b8/copy-to-eax "a$"/imm32 +3019 8b/-> *eax 1/r32/ecx +3020 8d/copy-address *(eax+ecx+4) 1/r32/ecx +3021 05/add-to-eax 4/imm32 +3022 # var slice/ecx: slice = {eax, ecx} +3023 51/push-ecx +3024 50/push-eax +3025 89/<- %ecx 4/r32/esp +3026 # +3027 (is-identifier? %ecx) +3028 (check-ints-equal %eax 1 "F - test-is-identifier-a") +3029 # . epilogue +3030 89/<- %esp 5/r32/ebp +3031 5d/pop-to-ebp +3032 c3/return 3033 -3034 Next-block-index: # (addr int) -3035 1/imm32 -3036 -3037 == code -3038 -3039 # parses a block, assuming that the leading '{' has already been read by the caller -3040 parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle block) -3041 # pseudocode: -3042 # var line: (stream byte 512) -3043 # var word-slice: slice -3044 # increment *Curr-block-depth -3045 # result/eax = allocate(Heap, Stmt-size) -3046 # result->tag = 0/block -3047 # result->name = some unique name -3048 # while true # line loop -3049 # clear-stream(line) -3050 # read-line-buffered(in, line) -3051 # if (line->write == 0) break # end of file -3052 # word-slice = next-mu-token(line) -3053 # if slice-empty?(word-slice) # end of line -3054 # continue -3055 # else if slice-starts-with?(word-slice, "#") -3056 # continue -3057 # else if slice-equal?(word-slice, "{") -3058 # assert(no-tokens-in(line)) -3059 # block = parse-mu-block(in, vars, fn) -3060 # append-to-block(result, block) -3061 # else if slice-equal?(word-slice, "}") -3062 # break -3063 # else if slice-ends-with?(word-slice, ":") -3064 # # TODO: error-check the rest of 'line' -3065 # --word-slice->end to skip ':' -3066 # named-block = parse-mu-named-block(word-slice, in, vars, fn) -3067 # append-to-block(result, named-block) -3068 # else if slice-equal?(word-slice, "var") -3069 # var-def = parse-mu-var-def(line, vars) -3070 # append-to-block(result, var-def) -3071 # else -3072 # stmt = parse-mu-stmt(line, vars, fn) -3073 # append-to-block(result, stmt) -3074 # decrement *Curr-block-depth -3075 # return result -3076 # +3034 test-is-identifier-z: +3035 # . prologue +3036 55/push-ebp +3037 89/<- %ebp 4/r32/esp +3038 # (eax..ecx) = "z$" +3039 b8/copy-to-eax "z$"/imm32 +3040 8b/-> *eax 1/r32/ecx +3041 8d/copy-address *(eax+ecx+4) 1/r32/ecx +3042 05/add-to-eax 4/imm32 +3043 # var slice/ecx: slice = {eax, ecx} +3044 51/push-ecx +3045 50/push-eax +3046 89/<- %ecx 4/r32/esp +3047 # +3048 (is-identifier? %ecx) +3049 (check-ints-equal %eax 1 "F - test-is-identifier-z") +3050 # . epilogue +3051 89/<- %esp 5/r32/ebp +3052 5d/pop-to-ebp +3053 c3/return +3054 +3055 test-is-identifier-A: +3056 # . prologue +3057 55/push-ebp +3058 89/<- %ebp 4/r32/esp +3059 # (eax..ecx) = "A$" +3060 b8/copy-to-eax "A$"/imm32 +3061 8b/-> *eax 1/r32/ecx +3062 8d/copy-address *(eax+ecx+4) 1/r32/ecx +3063 05/add-to-eax 4/imm32 +3064 # var slice/ecx: slice = {eax, ecx} +3065 51/push-ecx +3066 50/push-eax +3067 89/<- %ecx 4/r32/esp +3068 # +3069 (is-identifier? %ecx) +3070 (check-ints-equal %eax 1 "F - test-is-identifier-A") +3071 # . epilogue +3072 89/<- %esp 5/r32/ebp +3073 5d/pop-to-ebp +3074 c3/return +3075 +3076 test-is-identifier-Z: 3077 # . prologue 3078 55/push-ebp 3079 89/<- %ebp 4/r32/esp -3080 # . save registers -3081 51/push-ecx -3082 52/push-edx -3083 53/push-ebx -3084 57/push-edi -3085 # var line/ecx: (stream byte 512) -3086 81 5/subop/subtract %esp 0x200/imm32 -3087 68/push 0x200/imm32/length -3088 68/push 0/imm32/read -3089 68/push 0/imm32/write -3090 89/<- %ecx 4/r32/esp -3091 # var word-slice/edx: slice -3092 68/push 0/imm32/end -3093 68/push 0/imm32/start -3094 89/<- %edx 4/r32/esp -3095 # edi = result -3096 (allocate Heap *Stmt-size) # => eax -3097 (zero-out %eax *Stmt-size) -3098 89/<- %edi 0/r32/eax -3099 # set result->tag -3100 c7 0/subop/copy *edi 0/imm32/block # Stmt-tag -3101 # set result->var -3102 (new-block-name *(ebp+0x10)) # => eax -3103 89/<- *(edi+8) 0/r32/eax # Block-var -3104 # push result->var to vars -3105 (push *(ebp+0xc) %eax) -3106 # increment *Curr-block-depth -3107 ff 0/subop/increment *Curr-block-depth -3108 { -3109 $parse-mu-block:line-loop: -3110 # line = read-line-buffered(in) -3111 (clear-stream %ecx) -3112 (read-line-buffered *(ebp+8) %ecx) -3113 #? (write-buffered Stderr "line: ") -3114 #? (write-stream-data Stderr %ecx) -3115 #? (write-buffered Stderr Newline) -3116 #? (flush Stderr) -3117 # if (line->write == 0) break -3118 81 7/subop/compare *ecx 0/imm32 -3119 0f 84/jump-if-= break/disp32 -3120 # word-slice = next-mu-token(line) -3121 (next-mu-token %ecx %edx) -3122 #? (write-buffered Stderr "word: ") -3123 #? (write-slice-buffered Stderr %edx) -3124 #? (write-buffered Stderr Newline) -3125 #? (flush Stderr) -3126 # if slice-empty?(word-slice) continue -3127 (slice-empty? %edx) -3128 3d/compare-eax-and 0/imm32/false -3129 0f 85/jump-if-!= loop/disp32 -3130 # if (slice-starts-with?(word-slice, '#') continue -3131 # . eax = *word-slice->start -3132 8b/-> *edx 0/r32/eax -3133 8a/copy-byte *eax 0/r32/AL -3134 81 4/subop/and %eax 0xff/imm32 -3135 # . if (eax == '#') continue -3136 3d/compare-eax-and 0x23/imm32/hash -3137 0f 84/jump-if-= loop/disp32 -3138 # if slice-equal?(word-slice, "{") -3139 { -3140 $parse-mu-block:check-for-block: -3141 (slice-equal? %edx "{") -3142 3d/compare-eax-and 0/imm32/false -3143 74/jump-if-= break/disp8 -3144 (check-no-tokens-left %ecx) -3145 # parse new block and append -3146 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -3147 (append-to-block Heap %edi %eax) -3148 e9/jump $parse-mu-block:line-loop/disp32 -3149 } -3150 # if slice-equal?(word-slice, "}") break -3151 $parse-mu-block:check-for-end: -3152 (slice-equal? %edx "}") -3153 3d/compare-eax-and 0/imm32/false -3154 0f 85/jump-if-!= break/disp32 -3155 # if slice-ends-with?(word-slice, ":") parse named block and append -3156 { -3157 $parse-mu-block:check-for-named-block: -3158 # . eax = *(word-slice->end-1) -3159 8b/-> *(edx+4) 0/r32/eax -3160 48/decrement-eax -3161 8a/copy-byte *eax 0/r32/AL -3162 81 4/subop/and %eax 0xff/imm32 -3163 # . if (eax != ':') break -3164 3d/compare-eax-and 0x3a/imm32/colon -3165 0f 85/jump-if-!= break/disp32 -3166 # TODO: error-check the rest of 'line' -3167 # -3168 # skip ':' -3169 ff 1/subop/decrement *(edx+4) # Slice-end -3170 # -3171 (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -3172 (append-to-block Heap %edi %eax) -3173 e9/jump $parse-mu-block:line-loop/disp32 -3174 } -3175 # if slice-equal?(word-slice, "var") -3176 { -3177 $parse-mu-block:check-for-var: -3178 (slice-equal? %edx "var") -3179 3d/compare-eax-and 0/imm32/false -3180 74/jump-if-= break/disp8 -3181 # -3182 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax -3183 (append-to-block Heap %edi %eax) -3184 e9/jump $parse-mu-block:line-loop/disp32 -3185 } -3186 $parse-mu-block:regular-stmt: -3187 # otherwise -3188 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -3189 (append-to-block Heap %edi %eax) -3190 e9/jump loop/disp32 -3191 } # end line loop -3192 # decrement *Curr-block-depth -3193 ff 1/subop/decrement *Curr-block-depth -3194 # -3195 (pop *(ebp+0xc)) # => eax -3196 # return result -3197 89/<- %eax 7/r32/edi -3198 $parse-mu-block:end: -3199 # . reclaim locals -3200 81 0/subop/add %esp 0x214/imm32 -3201 # . restore registers -3202 5f/pop-to-edi -3203 5b/pop-to-ebx -3204 5a/pop-to-edx -3205 59/pop-to-ecx -3206 # . epilogue -3207 89/<- %esp 5/r32/ebp -3208 5d/pop-to-ebp -3209 c3/return -3210 -3211 $parse-mu-block:abort: -3212 # error("'{' or '}' should be on its own line, but got '") -3213 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -3214 (rewind-stream %ecx) -3215 (write-stream 2 %ecx) -3216 (write-buffered Stderr "'\n") -3217 (flush Stderr) -3218 # . syscall(exit, 1) -3219 bb/copy-to-ebx 1/imm32 -3220 b8/copy-to-eax 1/imm32/exit -3221 cd/syscall 0x80/imm8 -3222 # never gets here -3223 -3224 new-block-name: # fn: (handle function) -> result/eax: (handle var) -3225 # . prologue -3226 55/push-ebp -3227 89/<- %ebp 4/r32/esp -3228 # . save registers -3229 51/push-ecx -3230 52/push-edx -3231 # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:' -3232 8b/-> *(ebp+8) 0/r32/eax -3233 8b/-> *eax 0/r32/eax # Function-name -3234 8b/-> *eax 0/r32/eax # String-length -3235 05/add-to-eax 0xd/imm32 # 10 + 2 for '$:' -3236 89/<- %ecx 0/r32/eax -3237 # var name/edx: (stream byte n) -3238 29/subtract %esp 1/r32/ecx -3239 ff 6/subop/push %ecx -3240 68/push 0/imm32/read -3241 68/push 0/imm32/write -3242 89/<- %edx 4/r32/esp -3243 (clear-stream %edx) -3244 # eax = fn->name -3245 8b/-> *(ebp+8) 0/r32/eax -3246 8b/-> *eax 0/r32/eax # Function-name -3247 # construct result using Next-block-index (and increment it) -3248 (write %edx "$") -3249 (write %edx %eax) -3250 (write %edx ":") -3251 (print-int32 %edx *Next-block-index) -3252 ff 0/subop/increment *Next-block-index -3253 # var s/eax: slice = {name->data, name->data + name->write} (clobbering edx) -3254 # . eax = name->write -3255 8b/-> *edx 0/r32/eax -3256 # . edx = name->data -3257 8d/copy-address *(edx+0xc) 2/r32/edx -3258 # . eax = name->write + name->data -3259 01/add %eax 2/r32/edx -3260 # . push {edx, eax} -3261 ff 6/subop/push %eax -3262 ff 6/subop/push %edx -3263 89/<- %eax 4/r32/esp -3264 # var final-name/edx: (addr array byte) = slice-to-string(s) -3265 (slice-to-string Heap %eax) # => eax -3266 89/<- %edx 0/r32/eax -3267 # set result->var -3268 # . var type/eax: (handle tree type-id) = literal -3269 (allocate Heap *Tree-size) # => eax -3270 (zero-out %eax *Tree-size) # default type is 'literal' -3271 # . var result/eax: (handle var) = new-var(final-name, type) -3272 (new-var Heap %edx %eax *Curr-block-depth 0 0) # => eax -3273 $new-block-name:end: -3274 # . reclaim locals -3275 81 0/subop/add %ecx 0xc/imm32 # name.{read/write/len} -3276 81 0/subop/add %ecx 8/imm32 # slice -3277 01/add %esp 1/r32/ecx -3278 # . restore registers -3279 5a/pop-to-edx -3280 59/pop-to-ecx -3281 # . epilogue -3282 89/<- %esp 5/r32/ebp -3283 5d/pop-to-ebp -3284 c3/return -3285 -3286 check-no-tokens-left: # line: (addr stream byte) -3287 # . prologue -3288 55/push-ebp -3289 89/<- %ebp 4/r32/esp -3290 # . save registers -3291 50/push-eax -3292 51/push-ecx -3293 # var s/ecx: slice -3294 68/push 0/imm32/end -3295 68/push 0/imm32/start -3296 89/<- %ecx 4/r32/esp -3297 # -3298 (next-mu-token *(ebp+8) %ecx) -3299 # if slice-empty?(s) return -3300 (slice-empty? %ecx) -3301 3d/compare-eax-and 0/imm32/false -3302 75/jump-if-!= $check-no-tokens-left:end/disp8 -3303 # if (slice-starts-with?(s, '#') return -3304 # . eax = *s->start -3305 8b/-> *edx 0/r32/eax -3306 8a/copy-byte *eax 0/r32/AL -3307 81 4/subop/and %eax 0xff/imm32 -3308 # . if (eax == '#') continue -3309 3d/compare-eax-and 0x23/imm32/hash -3310 74/jump-if-= $check-no-tokens-left:end/disp8 -3311 # abort -3312 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -3313 (rewind-stream %ecx) -3314 (write-stream 2 %ecx) -3315 (write-buffered Stderr "'\n") -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 $check-no-tokens-left:end: -3323 # . reclaim locals -3324 81 0/subop/add %esp 8/imm32 -3325 # . restore registers -3326 59/pop-to-ecx -3327 58/pop-to-eax -3328 # . epilogue -3329 89/<- %esp 5/r32/ebp -3330 5d/pop-to-ebp -3331 c3/return -3332 -3333 parse-mu-named-block: # name: (addr slice), in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) -3334 # pseudocode: -3335 # var s: (addr array byte) = slice-to-string(name) -3336 # var v: (handle var) = new-var(s, 0) -3337 # v->block-depth = *Curr-block-depth # containing block depth -3338 # push(vars, v) -3339 # result = parse-mu-block(in, vars, fn) -3340 # pop(vars) -3341 # result->name = s -3342 # return result -3343 # -3344 # . prologue -3345 55/push-ebp -3346 89/<- %ebp 4/r32/esp -3347 # . save registers -3348 51/push-ecx -3349 # var s/ecx: (addr array byte) = slice-to-string(name) -3350 (slice-to-string Heap *(ebp+8)) # => eax -3351 89/<- %ecx 0/r32/eax -3352 # var type/eax: (handle tree type-id) = literal -3353 (allocate Heap *Tree-size) # => eax -3354 (zero-out %eax *Tree-size) # default type is 'literal' -3355 # var v/ecx: (handle var) = new-var(s, type) -3356 (new-var Heap %ecx %eax *Curr-block-depth 0 0) # => eax -3357 89/<- %ecx 0/r32/eax -3358 # push(vars, v) -3359 (push *(ebp+0x10) %ecx) -3360 # eax = result -3361 (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) # => eax -3362 # pop the var -3363 50/push-eax -3364 (pop *(ebp+0x10)) # => eax -3365 58/pop-to-eax -3366 # result->tag = named-block -3367 c7 0/subop/copy *eax 0/imm32/block # Stmt-tag -3368 # result->var = v -3369 89/<- *(eax+8) 1/r32/ecx # Block-var -3370 $parse-mu-named-block:end: -3371 # . restore registers -3372 59/pop-to-ecx -3373 # . epilogue -3374 89/<- %esp 5/r32/ebp -3375 5d/pop-to-ebp -3376 c3/return -3377 -3378 parse-mu-var-def: # line: (addr stream byte), vars: (addr stack (handle var)) -> result/eax: (handle stmt) -3379 # . prologue -3380 55/push-ebp -3381 89/<- %ebp 4/r32/esp -3382 # . save registers -3383 51/push-ecx -3384 52/push-edx -3385 # var word-slice/ecx: slice -3386 68/push 0/imm32/end -3387 68/push 0/imm32/start -3388 89/<- %ecx 4/r32/esp -3389 # var v/edx: (handle var) = parse-var-with-type(line) -3390 (next-mu-token *(ebp+8) %ecx) -3391 (parse-var-with-type %ecx *(ebp+8)) # => eax -3392 89/<- %edx 0/r32/eax -3393 # v->stack-offset = *Next-local-stack-offset -3394 8b/-> *Next-local-stack-offset 0/r32/eax -3395 89/<- *(edx+0xc) 0/r32/eax # Var-stack-offset -3396 # *Next-local-stack-offset -= size-of(v) -3397 (size-of %edx) # => eax -3398 29/subtract-from *Next-local-stack-offset 0/r32/eax -3399 # v->block-depth = *Curr-block-depth -3400 8b/-> *Curr-block-depth 0/r32/eax -3401 89/<- *(edx+8) 0/r32/eax -3402 # -3403 (push *(ebp+0xc) %edx) -3404 # either v has no register and there's no more to this line -3405 8b/-> *(edx+0x10) 0/r32/eax # Var-register -3406 3d/compare-eax-and 0/imm32 -3407 { -3408 75/jump-if-!= break/disp8 -3409 # TODO: ensure that there's nothing else on this line -3410 (new-vardef Heap %edx) # => eax -3411 eb/jump $parse-mu-var-def:end/disp8 -3412 } -3413 # or v has a register and there's more to this line -3414 { -3415 74/jump-if-= break/disp8 -3416 # ensure that the next word is '<-' -3417 (next-mu-token *(ebp+8) %ecx) -3418 (slice-equal? %ecx "<-") # => eax -3419 3d/compare-eax-and 0/imm32/false -3420 74/jump-if-= $parse-mu-var-def:abort/disp8 -3421 # -3422 (new-regvardef Heap %edx) # => eax -3423 (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc)) -3424 } -3425 $parse-mu-var-def:end: -3426 # . reclaim locals -3427 81 0/subop/add %esp 8/imm32 -3428 # . restore registers -3429 5a/pop-to-edx -3430 59/pop-to-ecx -3431 # . epilogue -3432 89/<- %esp 5/r32/ebp -3433 5d/pop-to-ebp -3434 c3/return -3435 -3436 $parse-mu-var-def:abort: -3437 (rewind-stream *(ebp+8)) -3438 # error("register variable requires a valid instruction to initialize but got '" line "'\n") -3439 (write-buffered Stderr "register variable requires a valid instruction to initialize but got '") -3440 (flush Stderr) -3441 (write-stream 2 *(ebp+8)) -3442 (write-buffered Stderr "'\n") -3443 (flush Stderr) -3444 # . syscall(exit, 1) -3445 bb/copy-to-ebx 1/imm32 -3446 b8/copy-to-eax 1/imm32/exit -3447 cd/syscall 0x80/imm8 -3448 # never gets here -3449 -3450 test-parse-mu-var-def: -3451 # 'var n: int' -3452 # . prologue -3453 55/push-ebp -3454 89/<- %ebp 4/r32/esp -3455 # setup -3456 (clear-stream _test-input-stream) -3457 (write _test-input-stream "n: int\n") # caller has consumed the 'var' -3458 # var vars/ecx: (stack (addr var) 4) -3459 81 5/subop/subtract %esp 0x10/imm32 -3460 68/push 0x10/imm32/length -3461 68/push 0/imm32/top -3462 89/<- %ecx 4/r32/esp -3463 (clear-stack %ecx) -3464 # convert -3465 (parse-mu-var-def _test-input-stream %ecx) # => eax -3466 # check result -3467 (check-ints-equal *eax 2 "F - test-parse-mu-var-def/tag") # Stmt-tag is vardef -3468 8b/-> *(eax+4) 0/r32/eax # Vardef-var -3469 (check-strings-equal *eax "n" "F - test-parse-mu-var-def/var-name") # Var-name -3470 (check-ints-equal *(eax+0x10) 0 "F - test-parse-mu-var-def/var-register") # Var-register -3471 # TODO: ensure stack-offset is -4 -3472 # TODO: ensure block-depth is 1 -3473 # ensure type is int -3474 8b/-> *(eax+4) 0/r32/eax # Var-type -3475 (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0") # Tree-left -3476 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-var-def/var-type:0") # Tree-right -3477 # . epilogue -3478 89/<- %esp 5/r32/ebp -3479 5d/pop-to-ebp -3480 c3/return -3481 -3482 test-parse-mu-reg-var-def: -3483 # 'var n/eax: int <- copy 0' -3484 # . prologue -3485 55/push-ebp -3486 89/<- %ebp 4/r32/esp -3487 # setup -3488 (clear-stream _test-input-stream) -3489 (write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var' -3490 # var vars/ecx: (stack (addr var) 4) -3491 81 5/subop/subtract %esp 0x10/imm32 -3492 68/push 0x10/imm32/length -3493 68/push 0/imm32/top -3494 89/<- %ecx 4/r32/esp -3495 (clear-stack %ecx) -3496 # convert -3497 (parse-mu-var-def _test-input-stream %ecx) # => eax -3498 # check result -3499 (check-ints-equal *eax 3 "F - test-parse-mu-reg-var-def/tag") # Stmt-tag is regvardef -3500 8b/-> *(eax+0xc) 0/r32/eax # Regvardef-outputs -3501 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/single-output") # List-next -3502 8b/-> *eax 0/r32/eax # List-value -3503 (check-strings-equal *eax "n" "F - test-parse-mu-reg-var-def/output-name") # Var-name -3504 (check-strings-equal *(eax+0x10) "eax" "F - test-parse-mu-reg-var-def/output-register") # Var-register -3505 # TODO: ensure stack-offset is -4 -3506 # TODO: ensure block-depth is 1 -3507 # ensure type is int -3508 8b/-> *(eax+4) 0/r32/eax # Var-type -3509 (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-left -3510 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-right -3511 # . epilogue -3512 89/<- %esp 5/r32/ebp -3513 5d/pop-to-ebp -3514 c3/return -3515 -3516 parse-mu-stmt: # line: (addr stream byte), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) -3517 # pseudocode: -3518 # var name: slice -3519 # result = allocate(Heap, Stmt-size) -3520 # if stmt-has-outputs?(line) -3521 # while true -3522 # name = next-mu-token(line) -3523 # if (name == '<-') break -3524 # assert(is-identifier?(name)) -3525 # var v: (handle var) = lookup-or-define-var(name, vars, fn) # regular stmts may define vars in fn outputs -3526 # result->outputs = append(result->outputs, v) -3527 # add-operation-and-inputs-to-stmt(result, line, vars) -3528 # -3529 # . prologue -3530 55/push-ebp -3531 89/<- %ebp 4/r32/esp -3532 # . save registers -3533 51/push-ecx -3534 57/push-edi -3535 # var name/ecx: slice -3536 68/push 0/imm32/end -3537 68/push 0/imm32/start -3538 89/<- %ecx 4/r32/esp -3539 # result/edi: (handle stmt) -3540 (allocate Heap *Stmt-size) # => eax -3541 (zero-out %eax *Stmt-size) -3542 89/<- %edi 0/r32/eax -3543 # result->tag = 1/stmt -3544 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag -3545 { -3546 (stmt-has-outputs? *(ebp+8)) -3547 3d/compare-eax-and 0/imm32/false -3548 0f 84/jump-if-= break/disp32 -3549 { -3550 $parse-mu-stmt:read-outputs: -3551 # name = next-mu-token(line) -3552 (next-mu-token *(ebp+8) %ecx) -3553 # if slice-empty?(word-slice) break -3554 (slice-empty? %ecx) -3555 3d/compare-eax-and 0/imm32/false -3556 0f 85/jump-if-!= break/disp32 -3557 # if (name == "<-") break -3558 (slice-equal? %ecx "<-") -3559 3d/compare-eax-and 0/imm32/false -3560 75/jump-if-!= break/disp8 -3561 # assert(is-identifier?(name)) -3562 (is-identifier? %ecx) -3563 3d/compare-eax-and 0/imm32/false -3564 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 -3565 # -3566 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -3567 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax -3568 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs -3569 e9/jump loop/disp32 -3570 } -3571 } -3572 (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc)) -3573 $parse-mu-stmt:end: -3574 # return result -3575 89/<- %eax 7/r32/edi -3576 # . reclaim locals -3577 81 0/subop/add %esp 8/imm32 -3578 # . restore registers -3579 5f/pop-to-edi -3580 59/pop-to-ecx -3581 # . epilogue -3582 89/<- %esp 5/r32/ebp -3583 5d/pop-to-ebp -3584 c3/return -3585 -3586 $parse-mu-stmt:abort: -3587 # error("invalid identifier '" name "'\n") -3588 (write-buffered Stderr "invalid identifier '") -3589 (write-slice-buffered Stderr %ecx) -3590 (write-buffered Stderr "'\n") -3591 (flush Stderr) -3592 # . syscall(exit, 1) -3593 bb/copy-to-ebx 1/imm32 -3594 b8/copy-to-eax 1/imm32/exit -3595 cd/syscall 0x80/imm8 -3596 # never gets here -3597 -3598 add-operation-and-inputs-to-stmt: # stmt: (handle stmt), line: (addr stream byte), vars: (addr stack (handle var)) -3599 # pseudocode: -3600 # stmt->name = slice-to-string(next-mu-token(line)) -3601 # while true -3602 # name = next-mu-token(line) -3603 # v = lookup-var-or-literal(name) -3604 # stmt->inouts = append(stmt->inouts, v) -3605 # -3606 # . prologue -3607 55/push-ebp -3608 89/<- %ebp 4/r32/esp -3609 # . save registers -3610 50/push-eax -3611 51/push-ecx -3612 57/push-edi -3613 # edi = stmt -3614 8b/-> *(ebp+8) 7/r32/edi -3615 # var name/ecx: slice -3616 68/push 0/imm32/end -3617 68/push 0/imm32/start -3618 89/<- %ecx 4/r32/esp -3619 $add-operation-and-inputs-to-stmt:read-operation: -3620 (next-mu-token *(ebp+0xc) %ecx) -3621 (slice-to-string Heap %ecx) # => eax -3622 89/<- *(edi+4) 0/r32/eax # Stmt1-operation or Regvardef-operation -3623 { -3624 $add-operation-and-inputs-to-stmt:read-inouts: -3625 # name = next-mu-token(line) -3626 (next-mu-token *(ebp+0xc) %ecx) -3627 # if slice-empty?(word-slice) break -3628 (slice-empty? %ecx) # => eax -3629 3d/compare-eax-and 0/imm32/false -3630 0f 85/jump-if-!= break/disp32 -3631 # if (name == "<-") abort -3632 (slice-equal? %ecx "<-") -3633 3d/compare-eax-and 0/imm32/false -3634 0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32 -3635 # -3636 (lookup-var-or-literal %ecx *(ebp+0x10)) # => eax -3637 (append-list Heap %eax *(edi+8)) # Stmt1-inouts or Regvardef-inouts => eax -3638 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts -3639 e9/jump loop/disp32 -3640 } -3641 $add-operation-and-inputs-to-stmt:end: -3642 # . reclaim locals -3643 81 0/subop/add %esp 8/imm32 -3644 # . restore registers -3645 5f/pop-to-edi -3646 59/pop-to-ecx -3647 58/pop-to-eax -3648 # . epilogue -3649 89/<- %esp 5/r32/ebp -3650 5d/pop-to-ebp -3651 c3/return -3652 -3653 $add-operation-and-inputs-to-stmt:abort: -3654 # error("invalid statement '" line "'\n") -3655 (rewind-stream *(ebp+8)) -3656 (write-buffered Stderr "invalid identifier '") -3657 (flush Stderr) -3658 (write-stream 2 *(ebp+8)) -3659 (write-buffered Stderr "'\n") -3660 (flush Stderr) -3661 # . syscall(exit, 1) -3662 bb/copy-to-ebx 1/imm32 -3663 b8/copy-to-eax 1/imm32/exit -3664 cd/syscall 0x80/imm8 -3665 # never gets here -3666 -3667 stmt-has-outputs?: # line: (addr stream byte) -> result/eax: boolean -3668 # . prologue -3669 55/push-ebp -3670 89/<- %ebp 4/r32/esp -3671 # . save registers -3672 51/push-ecx -3673 # var word-slice/ecx: slice -3674 68/push 0/imm32/end -3675 68/push 0/imm32/start -3676 89/<- %ecx 4/r32/esp -3677 # result = false -3678 b8/copy-to-eax 0/imm32/false -3679 (rewind-stream *(ebp+8)) -3680 { -3681 (next-mu-token *(ebp+8) %ecx) -3682 # if slice-empty?(word-slice) break -3683 (slice-empty? %ecx) -3684 3d/compare-eax-and 0/imm32/false -3685 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -3686 0f 85/jump-if-!= break/disp32 -3687 # if slice-starts-with?(word-slice, '#') break -3688 # . eax = *word-slice->start -3689 8b/-> *ecx 0/r32/eax -3690 8a/copy-byte *eax 0/r32/AL -3691 81 4/subop/and %eax 0xff/imm32 -3692 # . if (eax == '#') break -3693 3d/compare-eax-and 0x23/imm32/hash -3694 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -3695 0f 84/jump-if-= break/disp32 -3696 # if slice-equal?(word-slice, '<-') return true -3697 (slice-equal? %ecx "<-") -3698 3d/compare-eax-and 0/imm32/false -3699 74/jump-if-= loop/disp8 -3700 b8/copy-to-eax 1/imm32/true -3701 } -3702 $stmt-has-outputs:end: -3703 (rewind-stream *(ebp+8)) -3704 # . reclaim locals -3705 81 0/subop/add %esp 8/imm32 -3706 # . restore registers -3707 59/pop-to-ecx -3708 # . epilogue -3709 89/<- %esp 5/r32/ebp -3710 5d/pop-to-ebp -3711 c3/return -3712 -3713 # if 'name' starts with a digit, create a new literal var for it -3714 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found -3715 lookup-var-or-literal: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) -3716 # . prologue -3717 55/push-ebp -3718 89/<- %ebp 4/r32/esp -3719 # . save registers -3720 51/push-ecx -3721 56/push-esi -3722 # esi = name -3723 8b/-> *(ebp+8) 6/r32/esi -3724 # if slice-empty?(name) abort -3725 (slice-empty? %esi) # => eax -3726 3d/compare-eax-and 0/imm32/false -3727 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 -3728 # var c/ecx: byte = *name->start -3729 8b/-> *esi 1/r32/ecx -3730 8a/copy-byte *ecx 1/r32/CL -3731 81 4/subop/and %ecx 0xff/imm32 -3732 # if is-decimal-digit?(c) return new var(name) -3733 { -3734 (is-decimal-digit? %ecx) # => eax -3735 81 7/subop/compare %eax 0/imm32/false -3736 74/jump-if-= break/disp8 -3737 (new-literal-integer Heap %esi) # => eax -3738 eb/jump $lookup-var-or-literal:end/disp8 -3739 } -3740 # else if (c == '"') return new var(name) -3741 { -3742 81 7/subop/compare %ecx 0x22/imm32/dquote -3743 75/jump-if-!= break/disp8 -3744 (new-literal-string Heap %esi) # => eax -3745 eb/jump $lookup-var-or-literal:end/disp8 -3746 } -3747 # otherwise return lookup-var(name, vars) -3748 { -3749 (lookup-var %esi *(ebp+0xc)) # => eax -3750 } -3751 $lookup-var-or-literal:end: -3752 # . restore registers -3753 5e/pop-to-esi -3754 59/pop-to-ecx -3755 # . epilogue -3756 89/<- %esp 5/r32/ebp -3757 5d/pop-to-ebp -3758 c3/return -3759 -3760 $lookup-var-or-literal:abort: -3761 (write-buffered Stderr "empty variable!") -3762 (flush Stderr) -3763 # . syscall(exit, 1) -3764 bb/copy-to-ebx 1/imm32 -3765 b8/copy-to-eax 1/imm32/exit -3766 cd/syscall 0x80/imm8 -3767 # never gets here -3768 -3769 # return first 'name' from the top (back) of 'vars' and abort if not found -3770 lookup-var: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) +3080 # (eax..ecx) = "Z$" +3081 b8/copy-to-eax "Z$"/imm32 +3082 8b/-> *eax 1/r32/ecx +3083 8d/copy-address *(eax+ecx+4) 1/r32/ecx +3084 05/add-to-eax 4/imm32 +3085 # var slice/ecx: slice = {eax, ecx} +3086 51/push-ecx +3087 50/push-eax +3088 89/<- %ecx 4/r32/esp +3089 # +3090 (is-identifier? %ecx) +3091 (check-ints-equal %eax 1 "F - test-is-identifier-Z") +3092 # . epilogue +3093 89/<- %esp 5/r32/ebp +3094 5d/pop-to-ebp +3095 c3/return +3096 +3097 test-is-identifier-@: +3098 # character before 'A' is invalid +3099 # . prologue +3100 55/push-ebp +3101 89/<- %ebp 4/r32/esp +3102 # (eax..ecx) = "@a" +3103 b8/copy-to-eax "@a"/imm32 +3104 8b/-> *eax 1/r32/ecx +3105 8d/copy-address *(eax+ecx+4) 1/r32/ecx +3106 05/add-to-eax 4/imm32 +3107 # var slice/ecx: slice = {eax, ecx} +3108 51/push-ecx +3109 50/push-eax +3110 89/<- %ecx 4/r32/esp +3111 # +3112 (is-identifier? %ecx) +3113 (check-ints-equal %eax 0 "F - test-is-identifier-@") +3114 # . epilogue +3115 89/<- %esp 5/r32/ebp +3116 5d/pop-to-ebp +3117 c3/return +3118 +3119 test-is-identifier-square-bracket: +3120 # character after 'Z' is invalid +3121 # . prologue +3122 55/push-ebp +3123 89/<- %ebp 4/r32/esp +3124 # (eax..ecx) = "[a" +3125 b8/copy-to-eax "[a"/imm32 +3126 8b/-> *eax 1/r32/ecx +3127 8d/copy-address *(eax+ecx+4) 1/r32/ecx +3128 05/add-to-eax 4/imm32 +3129 # var slice/ecx: slice = {eax, ecx} +3130 51/push-ecx +3131 50/push-eax +3132 89/<- %ecx 4/r32/esp +3133 # +3134 (is-identifier? %ecx) +3135 (check-ints-equal %eax 0 "F - test-is-identifier-@") +3136 # . epilogue +3137 89/<- %esp 5/r32/ebp +3138 5d/pop-to-ebp +3139 c3/return +3140 +3141 test-is-identifier-backtick: +3142 # character before 'a' is invalid +3143 # . prologue +3144 55/push-ebp +3145 89/<- %ebp 4/r32/esp +3146 # (eax..ecx) = "`a" +3147 b8/copy-to-eax "`a"/imm32 +3148 8b/-> *eax 1/r32/ecx +3149 8d/copy-address *(eax+ecx+4) 1/r32/ecx +3150 05/add-to-eax 4/imm32 +3151 # var slice/ecx: slice = {eax, ecx} +3152 51/push-ecx +3153 50/push-eax +3154 89/<- %ecx 4/r32/esp +3155 # +3156 (is-identifier? %ecx) +3157 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") +3158 # . epilogue +3159 89/<- %esp 5/r32/ebp +3160 5d/pop-to-ebp +3161 c3/return +3162 +3163 test-is-identifier-curly-brace-open: +3164 # character after 'z' is invalid; also used for blocks +3165 # . prologue +3166 55/push-ebp +3167 89/<- %ebp 4/r32/esp +3168 # (eax..ecx) = "{a" +3169 b8/copy-to-eax "{a"/imm32 +3170 8b/-> *eax 1/r32/ecx +3171 8d/copy-address *(eax+ecx+4) 1/r32/ecx +3172 05/add-to-eax 4/imm32 +3173 # var slice/ecx: slice = {eax, ecx} +3174 51/push-ecx +3175 50/push-eax +3176 89/<- %ecx 4/r32/esp +3177 # +3178 (is-identifier? %ecx) +3179 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") +3180 # . epilogue +3181 89/<- %esp 5/r32/ebp +3182 5d/pop-to-ebp +3183 c3/return +3184 +3185 test-is-identifier-curly-brace-close: +3186 # . prologue +3187 55/push-ebp +3188 89/<- %ebp 4/r32/esp +3189 # (eax..ecx) = "}a" +3190 b8/copy-to-eax "}a"/imm32 +3191 8b/-> *eax 1/r32/ecx +3192 8d/copy-address *(eax+ecx+4) 1/r32/ecx +3193 05/add-to-eax 4/imm32 +3194 # var slice/ecx: slice = {eax, ecx} +3195 51/push-ecx +3196 50/push-eax +3197 89/<- %ecx 4/r32/esp +3198 # +3199 (is-identifier? %ecx) +3200 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") +3201 # . epilogue +3202 89/<- %esp 5/r32/ebp +3203 5d/pop-to-ebp +3204 c3/return +3205 +3206 test-is-identifier-hyphen: +3207 # disallow leading '-' since '->' has special meaning +3208 # . prologue +3209 55/push-ebp +3210 89/<- %ebp 4/r32/esp +3211 # (eax..ecx) = "-a" +3212 b8/copy-to-eax "-a"/imm32 +3213 8b/-> *eax 1/r32/ecx +3214 8d/copy-address *(eax+ecx+4) 1/r32/ecx +3215 05/add-to-eax 4/imm32 +3216 # var slice/ecx: slice = {eax, ecx} +3217 51/push-ecx +3218 50/push-eax +3219 89/<- %ecx 4/r32/esp +3220 # +3221 (is-identifier? %ecx) +3222 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") +3223 # . epilogue +3224 89/<- %esp 5/r32/ebp +3225 5d/pop-to-ebp +3226 c3/return +3227 +3228 populate-mu-function-body: # in: (addr buffered-file), out: (handle function), vars: (addr stack (handle var)) +3229 # . prologue +3230 55/push-ebp +3231 89/<- %ebp 4/r32/esp +3232 # . save registers +3233 50/push-eax +3234 56/push-esi +3235 57/push-edi +3236 # esi = in +3237 8b/-> *(ebp+8) 6/r32/esi +3238 # edi = out +3239 8b/-> *(ebp+0xc) 7/r32/edi +3240 # initialize some global state +3241 c7 0/subop/copy *Curr-block-depth 1/imm32 +3242 c7 0/subop/copy *Next-local-stack-offset -4/imm32 +3243 # var eax: (handle block) = parse-mu-block(in, vars, fn) +3244 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax +3245 # out->body = eax +3246 89/<- *(edi+0x10) 0/r32/eax # Function-body +3247 $populate-mu-function-body:end: +3248 # . restore registers +3249 5f/pop-to-edi +3250 5e/pop-to-esi +3251 58/pop-to-eax +3252 # . epilogue +3253 89/<- %esp 5/r32/ebp +3254 5d/pop-to-ebp +3255 c3/return +3256 +3257 == data +3258 +3259 # Global state added to each var record when parsing a function +3260 +3261 Curr-block-depth: # (addr int) +3262 0/imm32 +3263 Next-local-stack-offset: # (addr int) +3264 -4/imm32 +3265 +3266 Next-block-index: # (addr int) +3267 1/imm32 +3268 +3269 == code +3270 +3271 # parses a block, assuming that the leading '{' has already been read by the caller +3272 parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle block) +3273 # pseudocode: +3274 # var line: (stream byte 512) +3275 # var word-slice: slice +3276 # increment *Curr-block-depth +3277 # result/eax = allocate(Heap, Stmt-size) +3278 # result->tag = 0/block +3279 # result->name = some unique name +3280 # while true # line loop +3281 # clear-stream(line) +3282 # read-line-buffered(in, line) +3283 # if (line->write == 0) break # end of file +3284 # word-slice = next-mu-token(line) +3285 # if slice-empty?(word-slice) # end of line +3286 # continue +3287 # else if slice-starts-with?(word-slice, "#") +3288 # continue +3289 # else if slice-equal?(word-slice, "{") +3290 # assert(no-tokens-in(line)) +3291 # block = parse-mu-block(in, vars, fn) +3292 # append-to-block(result, block) +3293 # else if slice-equal?(word-slice, "}") +3294 # break +3295 # else if slice-ends-with?(word-slice, ":") +3296 # # TODO: error-check the rest of 'line' +3297 # --word-slice->end to skip ':' +3298 # named-block = parse-mu-named-block(word-slice, in, vars, fn) +3299 # append-to-block(result, named-block) +3300 # else if slice-equal?(word-slice, "var") +3301 # var-def = parse-mu-var-def(line, vars) +3302 # append-to-block(result, var-def) +3303 # else +3304 # stmt = parse-mu-stmt(line, vars, fn) +3305 # append-to-block(result, stmt) +3306 # decrement *Curr-block-depth +3307 # return result +3308 # +3309 # . prologue +3310 55/push-ebp +3311 89/<- %ebp 4/r32/esp +3312 # . save registers +3313 51/push-ecx +3314 52/push-edx +3315 53/push-ebx +3316 57/push-edi +3317 # var line/ecx: (stream byte 512) +3318 81 5/subop/subtract %esp 0x200/imm32 +3319 68/push 0x200/imm32/length +3320 68/push 0/imm32/read +3321 68/push 0/imm32/write +3322 89/<- %ecx 4/r32/esp +3323 # var word-slice/edx: slice +3324 68/push 0/imm32/end +3325 68/push 0/imm32/start +3326 89/<- %edx 4/r32/esp +3327 # edi = result +3328 (allocate Heap *Stmt-size) # => eax +3329 (zero-out %eax *Stmt-size) +3330 89/<- %edi 0/r32/eax +3331 # set result->tag +3332 c7 0/subop/copy *edi 0/imm32/block # Stmt-tag +3333 # set result->var +3334 (new-block-name *(ebp+0x10)) # => eax +3335 89/<- *(edi+8) 0/r32/eax # Block-var +3336 # push result->var to vars +3337 (push *(ebp+0xc) %eax) +3338 # increment *Curr-block-depth +3339 ff 0/subop/increment *Curr-block-depth +3340 { +3341 $parse-mu-block:line-loop: +3342 # line = read-line-buffered(in) +3343 (clear-stream %ecx) +3344 (read-line-buffered *(ebp+8) %ecx) +3345 #? (write-buffered Stderr "line: ") +3346 #? (write-stream-data Stderr %ecx) +3347 #? (write-buffered Stderr Newline) +3348 #? (flush Stderr) +3349 # if (line->write == 0) break +3350 81 7/subop/compare *ecx 0/imm32 +3351 0f 84/jump-if-= break/disp32 +3352 # word-slice = next-mu-token(line) +3353 (next-mu-token %ecx %edx) +3354 #? (write-buffered Stderr "word: ") +3355 #? (write-slice-buffered Stderr %edx) +3356 #? (write-buffered Stderr Newline) +3357 #? (flush Stderr) +3358 # if slice-empty?(word-slice) continue +3359 (slice-empty? %edx) +3360 3d/compare-eax-and 0/imm32/false +3361 0f 85/jump-if-!= loop/disp32 +3362 # if (slice-starts-with?(word-slice, '#') continue +3363 # . eax = *word-slice->start +3364 8b/-> *edx 0/r32/eax +3365 8a/copy-byte *eax 0/r32/AL +3366 81 4/subop/and %eax 0xff/imm32 +3367 # . if (eax == '#') continue +3368 3d/compare-eax-and 0x23/imm32/hash +3369 0f 84/jump-if-= loop/disp32 +3370 # if slice-equal?(word-slice, "{") +3371 { +3372 $parse-mu-block:check-for-block: +3373 (slice-equal? %edx "{") +3374 3d/compare-eax-and 0/imm32/false +3375 74/jump-if-= break/disp8 +3376 (check-no-tokens-left %ecx) +3377 # parse new block and append +3378 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +3379 (append-to-block Heap %edi %eax) +3380 e9/jump $parse-mu-block:line-loop/disp32 +3381 } +3382 # if slice-equal?(word-slice, "}") break +3383 $parse-mu-block:check-for-end: +3384 (slice-equal? %edx "}") +3385 3d/compare-eax-and 0/imm32/false +3386 0f 85/jump-if-!= break/disp32 +3387 # if slice-ends-with?(word-slice, ":") parse named block and append +3388 { +3389 $parse-mu-block:check-for-named-block: +3390 # . eax = *(word-slice->end-1) +3391 8b/-> *(edx+4) 0/r32/eax +3392 48/decrement-eax +3393 8a/copy-byte *eax 0/r32/AL +3394 81 4/subop/and %eax 0xff/imm32 +3395 # . if (eax != ':') break +3396 3d/compare-eax-and 0x3a/imm32/colon +3397 0f 85/jump-if-!= break/disp32 +3398 # TODO: error-check the rest of 'line' +3399 # +3400 # skip ':' +3401 ff 1/subop/decrement *(edx+4) # Slice-end +3402 # +3403 (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +3404 (append-to-block Heap %edi %eax) +3405 e9/jump $parse-mu-block:line-loop/disp32 +3406 } +3407 # if slice-equal?(word-slice, "var") +3408 { +3409 $parse-mu-block:check-for-var: +3410 (slice-equal? %edx "var") +3411 3d/compare-eax-and 0/imm32/false +3412 74/jump-if-= break/disp8 +3413 # +3414 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax +3415 (append-to-block Heap %edi %eax) +3416 e9/jump $parse-mu-block:line-loop/disp32 +3417 } +3418 $parse-mu-block:regular-stmt: +3419 # otherwise +3420 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +3421 (append-to-block Heap %edi %eax) +3422 e9/jump loop/disp32 +3423 } # end line loop +3424 # decrement *Curr-block-depth +3425 ff 1/subop/decrement *Curr-block-depth +3426 # +3427 (pop *(ebp+0xc)) # => eax +3428 # return result +3429 89/<- %eax 7/r32/edi +3430 $parse-mu-block:end: +3431 # . reclaim locals +3432 81 0/subop/add %esp 0x214/imm32 +3433 # . restore registers +3434 5f/pop-to-edi +3435 5b/pop-to-ebx +3436 5a/pop-to-edx +3437 59/pop-to-ecx +3438 # . epilogue +3439 89/<- %esp 5/r32/ebp +3440 5d/pop-to-ebp +3441 c3/return +3442 +3443 $parse-mu-block:abort: +3444 # error("'{' or '}' should be on its own line, but got '") +3445 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +3446 (rewind-stream %ecx) +3447 (write-stream 2 %ecx) +3448 (write-buffered Stderr "'\n") +3449 (flush Stderr) +3450 # . syscall(exit, 1) +3451 bb/copy-to-ebx 1/imm32 +3452 b8/copy-to-eax 1/imm32/exit +3453 cd/syscall 0x80/imm8 +3454 # never gets here +3455 +3456 new-block-name: # fn: (handle function) -> result/eax: (handle var) +3457 # . prologue +3458 55/push-ebp +3459 89/<- %ebp 4/r32/esp +3460 # . save registers +3461 51/push-ecx +3462 52/push-edx +3463 # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:' +3464 8b/-> *(ebp+8) 0/r32/eax +3465 8b/-> *eax 0/r32/eax # Function-name +3466 8b/-> *eax 0/r32/eax # String-length +3467 05/add-to-eax 0xd/imm32 # 10 + 2 for '$:' +3468 89/<- %ecx 0/r32/eax +3469 # var name/edx: (stream byte n) +3470 29/subtract %esp 1/r32/ecx +3471 ff 6/subop/push %ecx +3472 68/push 0/imm32/read +3473 68/push 0/imm32/write +3474 89/<- %edx 4/r32/esp +3475 (clear-stream %edx) +3476 # eax = fn->name +3477 8b/-> *(ebp+8) 0/r32/eax +3478 8b/-> *eax 0/r32/eax # Function-name +3479 # construct result using Next-block-index (and increment it) +3480 (write %edx "$") +3481 (write %edx %eax) +3482 (write %edx ":") +3483 (print-int32 %edx *Next-block-index) +3484 ff 0/subop/increment *Next-block-index +3485 # var s/eax: slice = {name->data, name->data + name->write} (clobbering edx) +3486 # . eax = name->write +3487 8b/-> *edx 0/r32/eax +3488 # . edx = name->data +3489 8d/copy-address *(edx+0xc) 2/r32/edx +3490 # . eax = name->write + name->data +3491 01/add %eax 2/r32/edx +3492 # . push {edx, eax} +3493 ff 6/subop/push %eax +3494 ff 6/subop/push %edx +3495 89/<- %eax 4/r32/esp +3496 # var final-name/edx: (addr array byte) = slice-to-string(s) +3497 (slice-to-string Heap %eax) # => eax +3498 89/<- %edx 0/r32/eax +3499 # set result->var +3500 # . var type/eax: (handle tree type-id) = literal +3501 (allocate Heap *Tree-size) # => eax +3502 (zero-out %eax *Tree-size) # default type is 'literal' +3503 # . var result/eax: (handle var) = new-var(final-name, type) +3504 (new-var Heap %edx %eax *Curr-block-depth 0 0) # => eax +3505 $new-block-name:end: +3506 # . reclaim locals +3507 81 0/subop/add %ecx 0xc/imm32 # name.{read/write/len} +3508 81 0/subop/add %ecx 8/imm32 # slice +3509 01/add %esp 1/r32/ecx +3510 # . restore registers +3511 5a/pop-to-edx +3512 59/pop-to-ecx +3513 # . epilogue +3514 89/<- %esp 5/r32/ebp +3515 5d/pop-to-ebp +3516 c3/return +3517 +3518 check-no-tokens-left: # line: (addr stream byte) +3519 # . prologue +3520 55/push-ebp +3521 89/<- %ebp 4/r32/esp +3522 # . save registers +3523 50/push-eax +3524 51/push-ecx +3525 # var s/ecx: slice +3526 68/push 0/imm32/end +3527 68/push 0/imm32/start +3528 89/<- %ecx 4/r32/esp +3529 # +3530 (next-mu-token *(ebp+8) %ecx) +3531 # if slice-empty?(s) return +3532 (slice-empty? %ecx) +3533 3d/compare-eax-and 0/imm32/false +3534 75/jump-if-!= $check-no-tokens-left:end/disp8 +3535 # if (slice-starts-with?(s, '#') return +3536 # . eax = *s->start +3537 8b/-> *edx 0/r32/eax +3538 8a/copy-byte *eax 0/r32/AL +3539 81 4/subop/and %eax 0xff/imm32 +3540 # . if (eax == '#') continue +3541 3d/compare-eax-and 0x23/imm32/hash +3542 74/jump-if-= $check-no-tokens-left:end/disp8 +3543 # abort +3544 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +3545 (rewind-stream %ecx) +3546 (write-stream 2 %ecx) +3547 (write-buffered Stderr "'\n") +3548 (flush Stderr) +3549 # . syscall(exit, 1) +3550 bb/copy-to-ebx 1/imm32 +3551 b8/copy-to-eax 1/imm32/exit +3552 cd/syscall 0x80/imm8 +3553 # never gets here +3554 $check-no-tokens-left:end: +3555 # . reclaim locals +3556 81 0/subop/add %esp 8/imm32 +3557 # . restore registers +3558 59/pop-to-ecx +3559 58/pop-to-eax +3560 # . epilogue +3561 89/<- %esp 5/r32/ebp +3562 5d/pop-to-ebp +3563 c3/return +3564 +3565 parse-mu-named-block: # name: (addr slice), in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) +3566 # pseudocode: +3567 # var s: (addr array byte) = slice-to-string(name) +3568 # var v: (handle var) = new-var(s, 0) +3569 # v->block-depth = *Curr-block-depth # containing block depth +3570 # push(vars, v) +3571 # result = parse-mu-block(in, vars, fn) +3572 # pop(vars) +3573 # result->name = s +3574 # return result +3575 # +3576 # . prologue +3577 55/push-ebp +3578 89/<- %ebp 4/r32/esp +3579 # . save registers +3580 51/push-ecx +3581 # var s/ecx: (addr array byte) = slice-to-string(name) +3582 (slice-to-string Heap *(ebp+8)) # => eax +3583 89/<- %ecx 0/r32/eax +3584 # var type/eax: (handle tree type-id) = literal +3585 (allocate Heap *Tree-size) # => eax +3586 (zero-out %eax *Tree-size) # default type is 'literal' +3587 # var v/ecx: (handle var) = new-var(s, type) +3588 (new-var Heap %ecx %eax *Curr-block-depth 0 0) # => eax +3589 89/<- %ecx 0/r32/eax +3590 # push(vars, v) +3591 (push *(ebp+0x10) %ecx) +3592 # eax = result +3593 (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) # => eax +3594 # pop the var +3595 50/push-eax +3596 (pop *(ebp+0x10)) # => eax +3597 58/pop-to-eax +3598 # result->tag = named-block +3599 c7 0/subop/copy *eax 0/imm32/block # Stmt-tag +3600 # result->var = v +3601 89/<- *(eax+8) 1/r32/ecx # Block-var +3602 $parse-mu-named-block:end: +3603 # . restore registers +3604 59/pop-to-ecx +3605 # . epilogue +3606 89/<- %esp 5/r32/ebp +3607 5d/pop-to-ebp +3608 c3/return +3609 +3610 parse-mu-var-def: # line: (addr stream byte), vars: (addr stack (handle var)) -> result/eax: (handle stmt) +3611 # . prologue +3612 55/push-ebp +3613 89/<- %ebp 4/r32/esp +3614 # . save registers +3615 51/push-ecx +3616 52/push-edx +3617 # var word-slice/ecx: slice +3618 68/push 0/imm32/end +3619 68/push 0/imm32/start +3620 89/<- %ecx 4/r32/esp +3621 # var v/edx: (handle var) = parse-var-with-type(line) +3622 (next-mu-token *(ebp+8) %ecx) +3623 (parse-var-with-type %ecx *(ebp+8)) # => eax +3624 89/<- %edx 0/r32/eax +3625 # v->block-depth = *Curr-block-depth +3626 8b/-> *Curr-block-depth 0/r32/eax +3627 89/<- *(edx+8) 0/r32/eax +3628 # +3629 (push *(ebp+0xc) %edx) +3630 # either v has no register and there's no more to this line +3631 8b/-> *(edx+0x10) 0/r32/eax # Var-register +3632 3d/compare-eax-and 0/imm32 +3633 { +3634 75/jump-if-!= break/disp8 +3635 # v->stack-offset = *Next-local-stack-offset +3636 8b/-> *Next-local-stack-offset 0/r32/eax +3637 89/<- *(edx+0xc) 0/r32/eax # Var-stack-offset +3638 # TODO: ensure that there's nothing else on this line +3639 (new-vardef Heap %edx) # => eax +3640 eb/jump $parse-mu-var-def:end/disp8 +3641 } +3642 # or v has a register and there's more to this line +3643 { +3644 74/jump-if-= break/disp8 +3645 # ensure that the next word is '<-' +3646 (next-mu-token *(ebp+8) %ecx) +3647 (slice-equal? %ecx "<-") # => eax +3648 3d/compare-eax-and 0/imm32/false +3649 74/jump-if-= $parse-mu-var-def:abort/disp8 +3650 # +3651 (new-regvardef Heap %edx) # => eax +3652 (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc)) +3653 } +3654 $parse-mu-var-def:end: +3655 # *Next-local-stack-offset -= size-of(v) +3656 50/push-eax +3657 (size-of %edx) # => eax +3658 29/subtract-from *Next-local-stack-offset 0/r32/eax +3659 58/pop-to-eax +3660 # . reclaim locals +3661 81 0/subop/add %esp 8/imm32 +3662 # . restore registers +3663 5a/pop-to-edx +3664 59/pop-to-ecx +3665 # . epilogue +3666 89/<- %esp 5/r32/ebp +3667 5d/pop-to-ebp +3668 c3/return +3669 +3670 $parse-mu-var-def:abort: +3671 (rewind-stream *(ebp+8)) +3672 # error("register variable requires a valid instruction to initialize but got '" line "'\n") +3673 (write-buffered Stderr "register variable requires a valid instruction to initialize but got '") +3674 (flush Stderr) +3675 (write-stream 2 *(ebp+8)) +3676 (write-buffered Stderr "'\n") +3677 (flush Stderr) +3678 # . syscall(exit, 1) +3679 bb/copy-to-ebx 1/imm32 +3680 b8/copy-to-eax 1/imm32/exit +3681 cd/syscall 0x80/imm8 +3682 # never gets here +3683 +3684 test-parse-mu-var-def: +3685 # 'var n: int' +3686 # . prologue +3687 55/push-ebp +3688 89/<- %ebp 4/r32/esp +3689 # setup +3690 (clear-stream _test-input-stream) +3691 (write _test-input-stream "n: int\n") # caller has consumed the 'var' +3692 c7 0/subop/copy *Curr-block-depth 1/imm32 +3693 c7 0/subop/copy *Next-local-stack-offset -4/imm32 +3694 # var vars/ecx: (stack (addr var) 4) +3695 81 5/subop/subtract %esp 0x10/imm32 +3696 68/push 0x10/imm32/length +3697 68/push 0/imm32/top +3698 89/<- %ecx 4/r32/esp +3699 (clear-stack %ecx) +3700 # convert +3701 (parse-mu-var-def _test-input-stream %ecx) # => eax +3702 # check result +3703 (check-ints-equal *eax 2 "F - test-parse-mu-var-def/tag") # Stmt-tag is vardef +3704 8b/-> *(eax+4) 0/r32/eax # Vardef-var +3705 (check-strings-equal *eax "n" "F - test-parse-mu-var-def/var-name") # Var-name +3706 (check-ints-equal *(eax+0x10) 0 "F - test-parse-mu-var-def/var-register") # Var-register +3707 (check-ints-equal *(eax+8) 1 "F - test-parse-mu-reg-var-def/output-block-depth") # Var-block-depth +3708 (check-ints-equal *(eax+0xc) -4 "F - test-parse-mu-reg-var-def/output-stack-offset") # Var-stack-offset +3709 # ensure type is int +3710 8b/-> *(eax+4) 0/r32/eax # Var-type +3711 (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0") # Tree-left +3712 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-var-def/var-type:0") # Tree-right +3713 # globals +3714 (check-ints-equal *Next-local-stack-offset -8 "F - test-parse-mu-reg-var-def/Next-local-stack-offset") +3715 # . epilogue +3716 89/<- %esp 5/r32/ebp +3717 5d/pop-to-ebp +3718 c3/return +3719 +3720 test-parse-mu-reg-var-def: +3721 # 'var n/eax: int <- copy 0' +3722 # . prologue +3723 55/push-ebp +3724 89/<- %ebp 4/r32/esp +3725 # setup +3726 (clear-stream _test-input-stream) +3727 (write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var' +3728 c7 0/subop/copy *Curr-block-depth 1/imm32 +3729 c7 0/subop/copy *Next-local-stack-offset -4/imm32 +3730 # var vars/ecx: (stack (addr var) 4) +3731 81 5/subop/subtract %esp 0x10/imm32 +3732 68/push 0x10/imm32/length +3733 68/push 0/imm32/top +3734 89/<- %ecx 4/r32/esp +3735 (clear-stack %ecx) +3736 # convert +3737 (parse-mu-var-def _test-input-stream %ecx) # => eax +3738 # check result +3739 (check-ints-equal *eax 3 "F - test-parse-mu-reg-var-def/tag") # Stmt-tag is regvardef +3740 8b/-> *(eax+0xc) 0/r32/eax # Regvardef-outputs +3741 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/single-output") # List-next +3742 8b/-> *eax 0/r32/eax # List-value +3743 (check-strings-equal *eax "n" "F - test-parse-mu-reg-var-def/output-name") # Var-name +3744 (check-strings-equal *(eax+0x10) "eax" "F - test-parse-mu-reg-var-def/output-register") # Var-register +3745 (check-ints-equal *(eax+8) 1 "F - test-parse-mu-reg-var-def/output-block-depth") # Var-block-depth +3746 (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-stack-offset") # Var-stack-offset +3747 # ensure type is int +3748 8b/-> *(eax+4) 0/r32/eax # Var-type +3749 (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-left +3750 (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-right +3751 # globals +3752 (check-ints-equal *Next-local-stack-offset -8 "F - test-parse-mu-reg-var-def/Next-local-stack-offset") +3753 # . epilogue +3754 89/<- %esp 5/r32/ebp +3755 5d/pop-to-ebp +3756 c3/return +3757 +3758 parse-mu-stmt: # line: (addr stream byte), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) +3759 # pseudocode: +3760 # var name: slice +3761 # result = allocate(Heap, Stmt-size) +3762 # if stmt-has-outputs?(line) +3763 # while true +3764 # name = next-mu-token(line) +3765 # if (name == '<-') break +3766 # assert(is-identifier?(name)) +3767 # var v: (handle var) = lookup-or-define-var(name, vars, fn) # regular stmts may define vars in fn outputs +3768 # result->outputs = append(result->outputs, v) +3769 # add-operation-and-inputs-to-stmt(result, line, vars) +3770 # 3771 # . prologue 3772 55/push-ebp 3773 89/<- %ebp 4/r32/esp -3774 # var target/eax: (handle array byte) = slice-to-string(name) -3775 (slice-to-string Heap *(ebp+8)) # => eax -3776 # -3777 (lookup-var-helper %eax *(ebp+0xc)) # => eax -3778 # if (result == 0) abort -3779 3d/compare-eax-and 0/imm32 -3780 74/jump-if-= $lookup-var:abort/disp8 -3781 $lookup-var:end: -3782 # . epilogue -3783 89/<- %esp 5/r32/ebp -3784 5d/pop-to-ebp -3785 c3/return -3786 -3787 $lookup-var:abort: -3788 (write-buffered Stderr "unknown variable '") -3789 (write-slice-buffered Stderr *(ebp+8)) -3790 (write-buffered Stderr "'\n") -3791 (flush Stderr) -3792 # . syscall(exit, 1) -3793 bb/copy-to-ebx 1/imm32 -3794 b8/copy-to-eax 1/imm32/exit -3795 cd/syscall 0x80/imm8 -3796 # never gets here -3797 -3798 # return first 'name' from the top (back) of 'vars', and 0/null if not found -3799 lookup-var-helper: # name: (addr array byte), vars: (addr stack (handle var)) -> result/eax: (handle var) -3800 # pseudocode: -3801 # var curr: (addr handle var) = &vars->data[vars->top - 4] -3802 # var min = vars->data -3803 # while curr >= min -3804 # var v: (handle var) = *curr -3805 # if v->name == name -3806 # return v -3807 # return 0 -3808 # -3809 # . prologue -3810 55/push-ebp -3811 89/<- %ebp 4/r32/esp -3812 # . save registers -3813 52/push-edx -3814 53/push-ebx -3815 56/push-esi -3816 # esi = vars -3817 8b/-> *(ebp+0xc) 6/r32/esi -3818 # ebx = vars->top -3819 8b/-> *esi 3/r32/ebx -3820 # if (vars->top > vars->length) abort -3821 3b/compare 0/r32/eax *(esi+4) -3822 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 -3823 # var min/edx: (addr handle var) = vars->data -3824 8d/copy-address *(esi+8) 2/r32/edx -3825 # var curr/ebx: (addr handle var) = &vars->data[vars->top - 4] -3826 81 5/subop/subtract %ebx 4/imm32 -3827 8d/copy-address *(esi+ebx+8) 3/r32/ebx -3828 { -3829 # if (curr < min) return 0 -3830 39/compare %ebx 2/r32/edx -3831 b8/copy-to-eax 0/imm32 -3832 0f 82/jump-if-addr< break/disp32 -3833 # var v/eax: (handle var) = *curr -3834 8b/-> *ebx 0/r32/eax -3835 # if (v->name == name) return v -3836 (string-equal? *eax *(ebp+8)) # Var-name -3837 3d/compare-eax-and 0/imm32/false -3838 8b/-> *ebx 0/r32/eax -3839 75/jump-if-!= break/disp8 -3840 # curr -= 4 -3841 81 5/subop/subtract %ebx 4/imm32 -3842 e9/jump loop/disp32 -3843 } -3844 $lookup-var-helper:end: -3845 # . restore registers -3846 5e/pop-to-esi -3847 5b/pop-to-ebx -3848 5a/pop-to-edx -3849 # . epilogue -3850 89/<- %esp 5/r32/ebp -3851 5d/pop-to-ebp -3852 c3/return -3853 -3854 $lookup-var-helper:error1: -3855 (write-buffered Stderr "malformed stack when looking up '") -3856 (write-slice-buffered Stderr *(ebp+8)) -3857 (write-buffered Stderr "'\n") -3858 (flush Stderr) -3859 # . syscall(exit, 1) -3860 bb/copy-to-ebx 1/imm32 -3861 b8/copy-to-eax 1/imm32/exit -3862 cd/syscall 0x80/imm8 -3863 # never gets here -3864 -3865 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found -3866 lookup-or-define-var: # name: (addr slice), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle var) -3867 # . prologue -3868 55/push-ebp -3869 89/<- %ebp 4/r32/esp -3870 # . save registers -3871 51/push-ecx -3872 # var target/ecx: (handle array byte) = slice-to-string(name) -3873 (slice-to-string Heap *(ebp+8)) # => eax -3874 89/<- %ecx 0/r32/eax -3875 # -3876 (lookup-var-helper %ecx *(ebp+0xc)) # => eax -3877 { -3878 # if (result != 0) return -3879 3d/compare-eax-and 0/imm32 -3880 75/jump-if-!= break/disp8 -3881 # if name is one of fn's outputs, return it -3882 { -3883 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax -3884 3d/compare-eax-and 0/imm32 -3885 # otherwise abort -3886 0f 84/jump-if-!= $lookup-var:abort/disp32 -3887 } -3888 } -3889 $lookup-or-define-var:end: -3890 # . restore registers -3891 59/pop-to-ecx -3892 # . epilogue -3893 89/<- %esp 5/r32/ebp -3894 5d/pop-to-ebp -3895 c3/return -3896 -3897 find-in-function-outputs: # fn: (handle function), name: (handle array byte) -> result/eax: (handle var) -3898 # . prologue -3899 55/push-ebp -3900 89/<- %ebp 4/r32/esp -3901 # . save registers -3902 51/push-ecx -3903 # var curr/ecx: (handle list var) = fn->outputs -3904 8b/-> *(ebp+8) 1/r32/ecx -3905 8b/-> *(ecx+0xc) 1/r32/ecx -3906 # while curr != null -3907 { -3908 81 7/subop/compare %ecx 0/imm32 -3909 74/jump-if-= break/disp8 -3910 # var v: (handle var) = *curr -3911 8b/-> *ecx 0/r32/eax # List-value -3912 # if (curr->name == name) return curr -3913 50/push-eax -3914 (string-equal? *eax *(ebp+0xc)) -3915 3d/compare-eax-and 0/imm32/false -3916 58/pop-to-eax -3917 75/jump-if-!= $find-in-function-outputs:end/disp8 -3918 # curr = curr->next -3919 8b/-> *(ecx+4) 1/r32/ecx # List-next -3920 eb/jump loop/disp8 -3921 } -3922 b8/copy-to-eax 0/imm32 -3923 $find-in-function-outputs:end: -3924 # . restore registers -3925 59/pop-to-ecx -3926 # . epilogue -3927 89/<- %esp 5/r32/ebp -3928 5d/pop-to-ebp -3929 c3/return -3930 -3931 test-parse-mu-stmt: -3932 # . prologue -3933 55/push-ebp -3934 89/<- %ebp 4/r32/esp -3935 # setup -3936 (clear-stream _test-input-stream) -3937 (write _test-input-stream "increment n\n") -3938 # var vars/ecx: (stack (addr var) 4) -3939 81 5/subop/subtract %esp 0x10/imm32 -3940 68/push 0x10/imm32/length -3941 68/push 0/imm32/top -3942 89/<- %ecx 4/r32/esp -3943 (clear-stack %ecx) -3944 # var v/edx: var -3945 81 5/subop/subtract %esp 0x14/imm32 # Var-size -3946 89/<- %edx 4/r32/esp -3947 (zero-out %edx 0x14) # Var-size -3948 # v->name = "n" -3949 c7 0/subop/copy *edx "n"/imm32 # Var-name -3950 # -3951 (push %ecx %edx) -3952 # convert -3953 (parse-mu-stmt _test-input-stream %ecx) # => eax -3954 # check result -3955 (check-ints-equal *eax 1 "F - test-parse-mu-stmt/tag") # Stmt-tag is Stmt1 -3956 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation -3957 # edx: (handle list var) = result->inouts -3958 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts -3959 # ebx: (handle var) = result->inouts->value -3960 8b/-> *edx 3/r32/ebx # List-value -3961 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name -3962 # . epilogue -3963 89/<- %esp 5/r32/ebp -3964 5d/pop-to-ebp -3965 c3/return -3966 -3967 test-parse-mu-stmt-with-comma: -3968 # . prologue -3969 55/push-ebp -3970 89/<- %ebp 4/r32/esp -3971 # setup -3972 (clear-stream _test-input-stream) -3973 (write _test-input-stream "copy-to n, 3\n") -3974 # var vars/ecx: (stack (addr var) 4) -3975 81 5/subop/subtract %esp 0x10/imm32 -3976 68/push 0x10/imm32/length -3977 68/push 0/imm32/top -3978 89/<- %ecx 4/r32/esp -3979 (clear-stack %ecx) -3980 # var v/edx: var -3981 81 5/subop/subtract %esp 0x14/imm32 # Var-size -3982 89/<- %edx 4/r32/esp -3983 (zero-out %edx 0x14) # Var-size -3984 # v->name = "n" -3985 c7 0/subop/copy *edx "n"/imm32 # Var-name -3986 # -3987 (push %ecx %edx) -3988 # convert -3989 (parse-mu-stmt _test-input-stream %ecx) # => eax -3990 # check result -3991 (check-ints-equal *eax 1 "F - test-parse-mu-stmt-with-comma/tag") # Stmt-tag is Stmt1 -3992 (check-strings-equal *(eax+4) "copy-to" "F - test-parse-mu-stmt-with-comma/name") # Stmt1-operation -3993 # edx: (handle list var) = result->inouts -3994 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts -3995 # ebx: (handle var) = result->inouts->value -3996 8b/-> *edx 3/r32/ebx # List-value -3997 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt-with-comma/inout:0") # Var-name -3998 # . epilogue -3999 89/<- %esp 5/r32/ebp -4000 5d/pop-to-ebp -4001 c3/return -4002 -4003 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) -4004 # . prologue -4005 55/push-ebp -4006 89/<- %ebp 4/r32/esp -4007 # . save registers -4008 51/push-ecx -4009 # -4010 (allocate *(ebp+8) *Function-size) # => eax -4011 8b/-> *(ebp+0xc) 1/r32/ecx -4012 89/<- *eax 1/r32/ecx # Function-name -4013 8b/-> *(ebp+0x10) 1/r32/ecx -4014 89/<- *(eax+4) 1/r32/ecx # Function-subx-name -4015 8b/-> *(ebp+0x14) 1/r32/ecx -4016 89/<- *(eax+8) 1/r32/ecx # Function-inouts -4017 8b/-> *(ebp+0x18) 1/r32/ecx -4018 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs -4019 8b/-> *(ebp+0x1c) 1/r32/ecx -4020 89/<- *(eax+0x10) 1/r32/ecx # Function-body -4021 8b/-> *(ebp+0x20) 1/r32/ecx -4022 89/<- *(eax+0x14) 1/r32/ecx # Function-next -4023 $new-function:end: -4024 # . restore registers -4025 59/pop-to-ecx -4026 # . epilogue -4027 89/<- %esp 5/r32/ebp -4028 5d/pop-to-ebp -4029 c3/return -4030 -4031 new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: (addr tree type-id), block: int, stack-offset: int, register: (addr array byte) -> result/eax: (handle var) -4032 # . prologue -4033 55/push-ebp -4034 89/<- %ebp 4/r32/esp -4035 # . save registers -4036 51/push-ecx -4037 # -4038 (allocate *(ebp+8) *Var-size) # => eax -4039 8b/-> *(ebp+0xc) 1/r32/ecx -4040 89/<- *eax 1/r32/ecx # Var-name -4041 8b/-> *(ebp+0x10) 1/r32/ecx -4042 89/<- *(eax+4) 1/r32/ecx # Var-type -4043 8b/-> *(ebp+0x14) 1/r32/ecx -4044 89/<- *(eax+8) 1/r32/ecx # Var-block-depth -4045 8b/-> *(ebp+0x18) 1/r32/ecx -4046 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset -4047 8b/-> *(ebp+0x1c) 1/r32/ecx -4048 89/<- *(eax+0x10) 1/r32/ecx # Var-register -4049 $new-var:end: -4050 # . restore registers -4051 59/pop-to-ecx -4052 # . epilogue -4053 89/<- %esp 5/r32/ebp -4054 5d/pop-to-ebp -4055 c3/return -4056 -4057 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) -4058 # . prologue -4059 55/push-ebp -4060 89/<- %ebp 4/r32/esp -4061 # . save registers -4062 51/push-ecx -4063 # if (!is-hex-int?(name)) abort -4064 (is-hex-int? *(ebp+0xc)) # => eax -4065 3d/compare-eax-and 0/imm32/false -4066 0f 84/jump-if-= $new-literal-integer:abort/disp32 -4067 # var s/ecx: (addr array byte) -4068 (slice-to-string Heap *(ebp+0xc)) # => eax -4069 89/<- %ecx 0/r32/eax -4070 # result/ecx = new var(s) -4071 (allocate *(ebp+8) *Var-size) # => eax -4072 (zero-out %eax *Var-size) -4073 89/<- *eax 1/r32/ecx # Var-name -4074 89/<- %ecx 0/r32/eax -4075 # result->type = new type() -4076 (allocate *(ebp+8) *Tree-size) # => eax -4077 (zero-out %eax *Tree-size) # default type is 'literal' -4078 89/<- *(ecx+4) 0/r32/eax # Var-type -4079 # move result to eax -4080 89/<- %eax 1/r32/ecx -4081 $new-literal-integer:end: -4082 # . restore registers -4083 59/pop-to-ecx -4084 # . epilogue -4085 89/<- %esp 5/r32/ebp -4086 5d/pop-to-ebp -4087 c3/return -4088 -4089 $new-literal-integer:abort: -4090 (write-buffered Stderr "variable cannot begin with a digit '") -4091 (write-slice-buffered Stderr *(ebp+0xc)) -4092 (write-buffered Stderr "'\n") -4093 (flush Stderr) -4094 # . syscall(exit, 1) -4095 bb/copy-to-ebx 1/imm32 -4096 b8/copy-to-eax 1/imm32/exit -4097 cd/syscall 0x80/imm8 -4098 # never gets here -4099 -4100 new-literal-string: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) -4101 # . prologue -4102 55/push-ebp -4103 89/<- %ebp 4/r32/esp -4104 # . save registers -4105 51/push-ecx -4106 # var s/ecx: (addr array byte) -4107 (slice-to-string Heap *(ebp+0xc)) # => eax -4108 89/<- %ecx 0/r32/eax -4109 # result/ecx = new var(s) -4110 (allocate *(ebp+8) *Var-size) # => eax -4111 (zero-out %eax *Var-size) -4112 89/<- *eax 1/r32/ecx # Var-name -4113 89/<- %ecx 0/r32/eax -4114 # result->type = new type() -4115 (allocate *(ebp+8) *Tree-size) # => eax -4116 (zero-out %eax *Tree-size) # default type is 'literal' -4117 89/<- *(ecx+4) 0/r32/eax # Var-type -4118 # move result to eax -4119 89/<- %eax 1/r32/ecx -4120 $new-literal-string:end: -4121 # . restore registers -4122 59/pop-to-ecx -4123 # . epilogue -4124 89/<- %esp 5/r32/ebp -4125 5d/pop-to-ebp -4126 c3/return -4127 -4128 new-label: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) -4129 # . prologue -4130 55/push-ebp -4131 89/<- %ebp 4/r32/esp -4132 # . save registers -4133 51/push-ecx -4134 # var s/ecx: (addr array byte) -4135 (slice-to-string Heap *(ebp+0xc)) # => eax -4136 89/<- %ecx 0/r32/eax -4137 # -4138 (allocate *(ebp+8) *Var-size) # => eax -4139 89/<- *eax 1/r32/ecx # Var-name -4140 89/<- %ecx 0/r32/eax -4141 (allocate *(ebp+8) *Tree-size) # => eax -4142 (zero-out %eax *Tree-size) # labels are literals -4143 89/<- *(ecx+4) 0/r32/eax # Var-type -4144 89/<- %eax 1/r32/ecx -4145 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block-depth -4146 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset -4147 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register -4148 $new-label:end: -4149 # . restore registers -4150 59/pop-to-ecx -4151 # . epilogue -4152 89/<- %esp 5/r32/ebp -4153 5d/pop-to-ebp -4154 c3/return -4155 -4156 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) -4157 # . prologue -4158 55/push-ebp -4159 89/<- %ebp 4/r32/esp -4160 # . save registers -4161 51/push-ecx -4162 # -4163 (allocate *(ebp+8) *Stmt-size) # => eax -4164 (zero-out %eax *Stmt-size) -4165 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag -4166 8b/-> *(ebp+0xc) 1/r32/ecx -4167 89/<- *(eax+4) 1/r32/ecx # Block-statements -4168 $new-block:end: -4169 # . restore registers -4170 59/pop-to-ecx -4171 # . epilogue -4172 89/<- %esp 5/r32/ebp -4173 5d/pop-to-ebp -4174 c3/return -4175 -4176 new-vardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) -4177 # . prologue -4178 55/push-ebp -4179 89/<- %ebp 4/r32/esp -4180 # . save registers -4181 51/push-ecx -4182 # -4183 (allocate *(ebp+8) *Stmt-size) # => eax -4184 (zero-out %eax *Stmt-size) -4185 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag -4186 # result->var = var -4187 8b/-> *(ebp+0xc) 1/r32/ecx -4188 89/<- *(eax+4) 1/r32/ecx # Vardef-var -4189 $new-vardef:end: -4190 # . restore registers -4191 59/pop-to-ecx -4192 # . epilogue -4193 89/<- %esp 5/r32/ebp -4194 5d/pop-to-ebp -4195 c3/return -4196 -4197 new-regvardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) -4198 # . prologue -4199 55/push-ebp -4200 89/<- %ebp 4/r32/esp -4201 # . save registers -4202 51/push-ecx -4203 57/push-edi -4204 # ecx = var -4205 8b/-> *(ebp+0xc) 1/r32/ecx -4206 # edi = result -4207 (allocate *(ebp+8) *Stmt-size) # => eax -4208 89/<- %edi 0/r32/eax -4209 (zero-out %edi *Stmt-size) -4210 # set tag -4211 c7 0/subop/copy *edi 3/imm32/tag/var-in-register # Stmt-tag -4212 # set output -4213 (append-list Heap %ecx *(edi+0xc)) # Regvardef-outputs => eax -4214 89/<- *(edi+0xc) 0/r32/eax # Regvardef-outputs -4215 $new-regvardef:end: -4216 89/<- %eax 7/r32/edi -4217 # . restore registers -4218 5f/pop-to-edi -4219 59/pop-to-ecx -4220 # . epilogue -4221 89/<- %esp 5/r32/ebp -4222 5d/pop-to-ebp -4223 c3/return -4224 -4225 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax: (handle list _type) -4226 # . prologue -4227 55/push-ebp -4228 89/<- %ebp 4/r32/esp -4229 # . save registers -4230 51/push-ecx -4231 # -4232 (allocate *(ebp+8) *List-size) # => eax -4233 8b/-> *(ebp+0xc) 1/r32/ecx -4234 89/<- *eax 1/r32/ecx # List-value -4235 8b/-> *(ebp+0x10) 1/r32/ecx -4236 89/<- *(eax+4) 1/r32/ecx # List-next -4237 $new-list:end: -4238 # . restore registers -4239 59/pop-to-ecx +3774 # . save registers +3775 51/push-ecx +3776 57/push-edi +3777 # var name/ecx: slice +3778 68/push 0/imm32/end +3779 68/push 0/imm32/start +3780 89/<- %ecx 4/r32/esp +3781 # result/edi: (handle stmt) +3782 (allocate Heap *Stmt-size) # => eax +3783 (zero-out %eax *Stmt-size) +3784 89/<- %edi 0/r32/eax +3785 # result->tag = 1/stmt +3786 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag +3787 { +3788 (stmt-has-outputs? *(ebp+8)) +3789 3d/compare-eax-and 0/imm32/false +3790 0f 84/jump-if-= break/disp32 +3791 { +3792 $parse-mu-stmt:read-outputs: +3793 # name = next-mu-token(line) +3794 (next-mu-token *(ebp+8) %ecx) +3795 # if slice-empty?(word-slice) break +3796 (slice-empty? %ecx) +3797 3d/compare-eax-and 0/imm32/false +3798 0f 85/jump-if-!= break/disp32 +3799 # if (name == "<-") break +3800 (slice-equal? %ecx "<-") +3801 3d/compare-eax-and 0/imm32/false +3802 75/jump-if-!= break/disp8 +3803 # assert(is-identifier?(name)) +3804 (is-identifier? %ecx) +3805 3d/compare-eax-and 0/imm32/false +3806 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 +3807 # +3808 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +3809 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax +3810 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs +3811 e9/jump loop/disp32 +3812 } +3813 } +3814 (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc)) +3815 $parse-mu-stmt:end: +3816 # return result +3817 89/<- %eax 7/r32/edi +3818 # . reclaim locals +3819 81 0/subop/add %esp 8/imm32 +3820 # . restore registers +3821 5f/pop-to-edi +3822 59/pop-to-ecx +3823 # . epilogue +3824 89/<- %esp 5/r32/ebp +3825 5d/pop-to-ebp +3826 c3/return +3827 +3828 $parse-mu-stmt:abort: +3829 # error("invalid identifier '" name "'\n") +3830 (write-buffered Stderr "invalid identifier '") +3831 (write-slice-buffered Stderr %ecx) +3832 (write-buffered Stderr "'\n") +3833 (flush Stderr) +3834 # . syscall(exit, 1) +3835 bb/copy-to-ebx 1/imm32 +3836 b8/copy-to-eax 1/imm32/exit +3837 cd/syscall 0x80/imm8 +3838 # never gets here +3839 +3840 add-operation-and-inputs-to-stmt: # stmt: (handle stmt), line: (addr stream byte), vars: (addr stack (handle var)) +3841 # pseudocode: +3842 # stmt->name = slice-to-string(next-mu-token(line)) +3843 # while true +3844 # name = next-mu-token(line) +3845 # v = lookup-var-or-literal(name) +3846 # stmt->inouts = append(stmt->inouts, v) +3847 # +3848 # . prologue +3849 55/push-ebp +3850 89/<- %ebp 4/r32/esp +3851 # . save registers +3852 50/push-eax +3853 51/push-ecx +3854 57/push-edi +3855 # edi = stmt +3856 8b/-> *(ebp+8) 7/r32/edi +3857 # var name/ecx: slice +3858 68/push 0/imm32/end +3859 68/push 0/imm32/start +3860 89/<- %ecx 4/r32/esp +3861 $add-operation-and-inputs-to-stmt:read-operation: +3862 (next-mu-token *(ebp+0xc) %ecx) +3863 (slice-to-string Heap %ecx) # => eax +3864 89/<- *(edi+4) 0/r32/eax # Stmt1-operation or Regvardef-operation +3865 { +3866 $add-operation-and-inputs-to-stmt:read-inouts: +3867 # name = next-mu-token(line) +3868 (next-mu-token *(ebp+0xc) %ecx) +3869 # if slice-empty?(word-slice) break +3870 (slice-empty? %ecx) # => eax +3871 3d/compare-eax-and 0/imm32/false +3872 0f 85/jump-if-!= break/disp32 +3873 # if (name == "<-") abort +3874 (slice-equal? %ecx "<-") +3875 3d/compare-eax-and 0/imm32/false +3876 0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32 +3877 # +3878 (lookup-var-or-literal %ecx *(ebp+0x10)) # => eax +3879 (append-list Heap %eax *(edi+8)) # Stmt1-inouts or Regvardef-inouts => eax +3880 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts or Regvardef-inouts +3881 e9/jump loop/disp32 +3882 } +3883 $add-operation-and-inputs-to-stmt:end: +3884 # . reclaim locals +3885 81 0/subop/add %esp 8/imm32 +3886 # . restore registers +3887 5f/pop-to-edi +3888 59/pop-to-ecx +3889 58/pop-to-eax +3890 # . epilogue +3891 89/<- %esp 5/r32/ebp +3892 5d/pop-to-ebp +3893 c3/return +3894 +3895 $add-operation-and-inputs-to-stmt:abort: +3896 # error("invalid statement '" line "'\n") +3897 (rewind-stream *(ebp+8)) +3898 (write-buffered Stderr "invalid identifier '") +3899 (flush Stderr) +3900 (write-stream 2 *(ebp+8)) +3901 (write-buffered Stderr "'\n") +3902 (flush Stderr) +3903 # . syscall(exit, 1) +3904 bb/copy-to-ebx 1/imm32 +3905 b8/copy-to-eax 1/imm32/exit +3906 cd/syscall 0x80/imm8 +3907 # never gets here +3908 +3909 stmt-has-outputs?: # line: (addr stream byte) -> result/eax: boolean +3910 # . prologue +3911 55/push-ebp +3912 89/<- %ebp 4/r32/esp +3913 # . save registers +3914 51/push-ecx +3915 # var word-slice/ecx: slice +3916 68/push 0/imm32/end +3917 68/push 0/imm32/start +3918 89/<- %ecx 4/r32/esp +3919 # result = false +3920 b8/copy-to-eax 0/imm32/false +3921 (rewind-stream *(ebp+8)) +3922 { +3923 (next-mu-token *(ebp+8) %ecx) +3924 # if slice-empty?(word-slice) break +3925 (slice-empty? %ecx) +3926 3d/compare-eax-and 0/imm32/false +3927 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +3928 0f 85/jump-if-!= break/disp32 +3929 # if slice-starts-with?(word-slice, '#') break +3930 # . eax = *word-slice->start +3931 8b/-> *ecx 0/r32/eax +3932 8a/copy-byte *eax 0/r32/AL +3933 81 4/subop/and %eax 0xff/imm32 +3934 # . if (eax == '#') break +3935 3d/compare-eax-and 0x23/imm32/hash +3936 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +3937 0f 84/jump-if-= break/disp32 +3938 # if slice-equal?(word-slice, '<-') return true +3939 (slice-equal? %ecx "<-") +3940 3d/compare-eax-and 0/imm32/false +3941 74/jump-if-= loop/disp8 +3942 b8/copy-to-eax 1/imm32/true +3943 } +3944 $stmt-has-outputs:end: +3945 (rewind-stream *(ebp+8)) +3946 # . reclaim locals +3947 81 0/subop/add %esp 8/imm32 +3948 # . restore registers +3949 59/pop-to-ecx +3950 # . epilogue +3951 89/<- %esp 5/r32/ebp +3952 5d/pop-to-ebp +3953 c3/return +3954 +3955 # if 'name' starts with a digit, create a new literal var for it +3956 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found +3957 lookup-var-or-literal: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) +3958 # . prologue +3959 55/push-ebp +3960 89/<- %ebp 4/r32/esp +3961 # . save registers +3962 51/push-ecx +3963 56/push-esi +3964 # esi = name +3965 8b/-> *(ebp+8) 6/r32/esi +3966 # if slice-empty?(name) abort +3967 (slice-empty? %esi) # => eax +3968 3d/compare-eax-and 0/imm32/false +3969 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 +3970 # var c/ecx: byte = *name->start +3971 8b/-> *esi 1/r32/ecx +3972 8a/copy-byte *ecx 1/r32/CL +3973 81 4/subop/and %ecx 0xff/imm32 +3974 # if is-decimal-digit?(c) return new var(name) +3975 { +3976 (is-decimal-digit? %ecx) # => eax +3977 81 7/subop/compare %eax 0/imm32/false +3978 74/jump-if-= break/disp8 +3979 (new-literal-integer Heap %esi) # => eax +3980 eb/jump $lookup-var-or-literal:end/disp8 +3981 } +3982 # else if (c == '"') return new var(name) +3983 { +3984 81 7/subop/compare %ecx 0x22/imm32/dquote +3985 75/jump-if-!= break/disp8 +3986 (new-literal-string Heap %esi) # => eax +3987 eb/jump $lookup-var-or-literal:end/disp8 +3988 } +3989 # otherwise return lookup-var(name, vars) +3990 { +3991 (lookup-var %esi *(ebp+0xc)) # => eax +3992 } +3993 $lookup-var-or-literal:end: +3994 # . restore registers +3995 5e/pop-to-esi +3996 59/pop-to-ecx +3997 # . epilogue +3998 89/<- %esp 5/r32/ebp +3999 5d/pop-to-ebp +4000 c3/return +4001 +4002 $lookup-var-or-literal:abort: +4003 (write-buffered Stderr "empty variable!") +4004 (flush Stderr) +4005 # . syscall(exit, 1) +4006 bb/copy-to-ebx 1/imm32 +4007 b8/copy-to-eax 1/imm32/exit +4008 cd/syscall 0x80/imm8 +4009 # never gets here +4010 +4011 # return first 'name' from the top (back) of 'vars' and abort if not found +4012 lookup-var: # name: (addr slice), vars: (addr stack (handle var)) -> result/eax: (handle var) +4013 # . prologue +4014 55/push-ebp +4015 89/<- %ebp 4/r32/esp +4016 # var target/eax: (handle array byte) = slice-to-string(name) +4017 (slice-to-string Heap *(ebp+8)) # => eax +4018 # +4019 (lookup-var-helper %eax *(ebp+0xc)) # => eax +4020 # if (result == 0) abort +4021 3d/compare-eax-and 0/imm32 +4022 74/jump-if-= $lookup-var:abort/disp8 +4023 $lookup-var:end: +4024 # . epilogue +4025 89/<- %esp 5/r32/ebp +4026 5d/pop-to-ebp +4027 c3/return +4028 +4029 $lookup-var:abort: +4030 (write-buffered Stderr "unknown variable '") +4031 (write-slice-buffered Stderr *(ebp+8)) +4032 (write-buffered Stderr "'\n") +4033 (flush Stderr) +4034 # . syscall(exit, 1) +4035 bb/copy-to-ebx 1/imm32 +4036 b8/copy-to-eax 1/imm32/exit +4037 cd/syscall 0x80/imm8 +4038 # never gets here +4039 +4040 # return first 'name' from the top (back) of 'vars', and 0/null if not found +4041 lookup-var-helper: # name: (addr array byte), vars: (addr stack (handle var)) -> result/eax: (handle var) +4042 # pseudocode: +4043 # var curr: (addr handle var) = &vars->data[vars->top - 4] +4044 # var min = vars->data +4045 # while curr >= min +4046 # var v: (handle var) = *curr +4047 # if v->name == name +4048 # return v +4049 # return 0 +4050 # +4051 # . prologue +4052 55/push-ebp +4053 89/<- %ebp 4/r32/esp +4054 # . save registers +4055 52/push-edx +4056 53/push-ebx +4057 56/push-esi +4058 # esi = vars +4059 8b/-> *(ebp+0xc) 6/r32/esi +4060 # ebx = vars->top +4061 8b/-> *esi 3/r32/ebx +4062 # if (vars->top > vars->length) abort +4063 3b/compare 0/r32/eax *(esi+4) +4064 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 +4065 # var min/edx: (addr handle var) = vars->data +4066 8d/copy-address *(esi+8) 2/r32/edx +4067 # var curr/ebx: (addr handle var) = &vars->data[vars->top - 4] +4068 81 5/subop/subtract %ebx 4/imm32 +4069 8d/copy-address *(esi+ebx+8) 3/r32/ebx +4070 { +4071 # if (curr < min) return 0 +4072 39/compare %ebx 2/r32/edx +4073 b8/copy-to-eax 0/imm32 +4074 0f 82/jump-if-addr< break/disp32 +4075 # var v/eax: (handle var) = *curr +4076 8b/-> *ebx 0/r32/eax +4077 # if (v->name == name) return v +4078 (string-equal? *eax *(ebp+8)) # Var-name +4079 3d/compare-eax-and 0/imm32/false +4080 8b/-> *ebx 0/r32/eax +4081 75/jump-if-!= break/disp8 +4082 # curr -= 4 +4083 81 5/subop/subtract %ebx 4/imm32 +4084 e9/jump loop/disp32 +4085 } +4086 $lookup-var-helper:end: +4087 # . restore registers +4088 5e/pop-to-esi +4089 5b/pop-to-ebx +4090 5a/pop-to-edx +4091 # . epilogue +4092 89/<- %esp 5/r32/ebp +4093 5d/pop-to-ebp +4094 c3/return +4095 +4096 $lookup-var-helper:error1: +4097 (write-buffered Stderr "malformed stack when looking up '") +4098 (write-slice-buffered Stderr *(ebp+8)) +4099 (write-buffered Stderr "'\n") +4100 (flush Stderr) +4101 # . syscall(exit, 1) +4102 bb/copy-to-ebx 1/imm32 +4103 b8/copy-to-eax 1/imm32/exit +4104 cd/syscall 0x80/imm8 +4105 # never gets here +4106 +4107 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found +4108 lookup-or-define-var: # name: (addr slice), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle var) +4109 # . prologue +4110 55/push-ebp +4111 89/<- %ebp 4/r32/esp +4112 # . save registers +4113 51/push-ecx +4114 # var target/ecx: (handle array byte) = slice-to-string(name) +4115 (slice-to-string Heap *(ebp+8)) # => eax +4116 89/<- %ecx 0/r32/eax +4117 # +4118 (lookup-var-helper %ecx *(ebp+0xc)) # => eax +4119 { +4120 # if (result != 0) return +4121 3d/compare-eax-and 0/imm32 +4122 75/jump-if-!= break/disp8 +4123 # if name is one of fn's outputs, return it +4124 { +4125 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax +4126 3d/compare-eax-and 0/imm32 +4127 # otherwise abort +4128 0f 84/jump-if-!= $lookup-var:abort/disp32 +4129 } +4130 } +4131 $lookup-or-define-var:end: +4132 # . restore registers +4133 59/pop-to-ecx +4134 # . epilogue +4135 89/<- %esp 5/r32/ebp +4136 5d/pop-to-ebp +4137 c3/return +4138 +4139 find-in-function-outputs: # fn: (handle function), name: (handle array byte) -> result/eax: (handle var) +4140 # . prologue +4141 55/push-ebp +4142 89/<- %ebp 4/r32/esp +4143 # . save registers +4144 51/push-ecx +4145 # var curr/ecx: (handle list var) = fn->outputs +4146 8b/-> *(ebp+8) 1/r32/ecx +4147 8b/-> *(ecx+0xc) 1/r32/ecx +4148 # while curr != null +4149 { +4150 81 7/subop/compare %ecx 0/imm32 +4151 74/jump-if-= break/disp8 +4152 # var v: (handle var) = *curr +4153 8b/-> *ecx 0/r32/eax # List-value +4154 # if (curr->name == name) return curr +4155 50/push-eax +4156 (string-equal? *eax *(ebp+0xc)) +4157 3d/compare-eax-and 0/imm32/false +4158 58/pop-to-eax +4159 75/jump-if-!= $find-in-function-outputs:end/disp8 +4160 # curr = curr->next +4161 8b/-> *(ecx+4) 1/r32/ecx # List-next +4162 eb/jump loop/disp8 +4163 } +4164 b8/copy-to-eax 0/imm32 +4165 $find-in-function-outputs:end: +4166 # . restore registers +4167 59/pop-to-ecx +4168 # . epilogue +4169 89/<- %esp 5/r32/ebp +4170 5d/pop-to-ebp +4171 c3/return +4172 +4173 test-parse-mu-stmt: +4174 # . prologue +4175 55/push-ebp +4176 89/<- %ebp 4/r32/esp +4177 # setup +4178 (clear-stream _test-input-stream) +4179 (write _test-input-stream "increment n\n") +4180 # var vars/ecx: (stack (addr var) 4) +4181 81 5/subop/subtract %esp 0x10/imm32 +4182 68/push 0x10/imm32/length +4183 68/push 0/imm32/top +4184 89/<- %ecx 4/r32/esp +4185 (clear-stack %ecx) +4186 # var v/edx: var +4187 81 5/subop/subtract %esp 0x14/imm32 # Var-size +4188 89/<- %edx 4/r32/esp +4189 (zero-out %edx 0x14) # Var-size +4190 # v->name = "n" +4191 c7 0/subop/copy *edx "n"/imm32 # Var-name +4192 # +4193 (push %ecx %edx) +4194 # convert +4195 (parse-mu-stmt _test-input-stream %ecx) # => eax +4196 # check result +4197 (check-ints-equal *eax 1 "F - test-parse-mu-stmt/tag") # Stmt-tag is Stmt1 +4198 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation +4199 # edx: (handle list var) = result->inouts +4200 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts +4201 # ebx: (handle var) = result->inouts->value +4202 8b/-> *edx 3/r32/ebx # List-value +4203 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name +4204 # . epilogue +4205 89/<- %esp 5/r32/ebp +4206 5d/pop-to-ebp +4207 c3/return +4208 +4209 test-parse-mu-stmt-with-comma: +4210 # . prologue +4211 55/push-ebp +4212 89/<- %ebp 4/r32/esp +4213 # setup +4214 (clear-stream _test-input-stream) +4215 (write _test-input-stream "copy-to n, 3\n") +4216 # var vars/ecx: (stack (addr var) 4) +4217 81 5/subop/subtract %esp 0x10/imm32 +4218 68/push 0x10/imm32/length +4219 68/push 0/imm32/top +4220 89/<- %ecx 4/r32/esp +4221 (clear-stack %ecx) +4222 # var v/edx: var +4223 81 5/subop/subtract %esp 0x14/imm32 # Var-size +4224 89/<- %edx 4/r32/esp +4225 (zero-out %edx 0x14) # Var-size +4226 # v->name = "n" +4227 c7 0/subop/copy *edx "n"/imm32 # Var-name +4228 # +4229 (push %ecx %edx) +4230 # convert +4231 (parse-mu-stmt _test-input-stream %ecx) # => eax +4232 # check result +4233 (check-ints-equal *eax 1 "F - test-parse-mu-stmt-with-comma/tag") # Stmt-tag is Stmt1 +4234 (check-strings-equal *(eax+4) "copy-to" "F - test-parse-mu-stmt-with-comma/name") # Stmt1-operation +4235 # edx: (handle list var) = result->inouts +4236 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts +4237 # ebx: (handle var) = result->inouts->value +4238 8b/-> *edx 3/r32/ebx # List-value +4239 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt-with-comma/inout:0") # Var-name 4240 # . epilogue 4241 89/<- %esp 5/r32/ebp 4242 5d/pop-to-ebp 4243 c3/return 4244 -4245 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax: (handle list _type) +4245 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) 4246 # . prologue 4247 55/push-ebp 4248 89/<- %ebp 4/r32/esp 4249 # . save registers 4250 51/push-ecx 4251 # -4252 (allocate *(ebp+8) *List-size) # => eax +4252 (allocate *(ebp+8) *Function-size) # => eax 4253 8b/-> *(ebp+0xc) 1/r32/ecx -4254 89/<- *eax 1/r32/ecx # List-value -4255 # if (list == null) return result -4256 81 7/subop/compare *(ebp+0x10) 0/imm32 -4257 74/jump-if-= $new-list:end/disp8 -4258 # otherwise append -4259 # var curr/ecx = list -4260 8b/-> *(ebp+0x10) 1/r32/ecx -4261 # while (curr->next != null) curr = curr->next -4262 { -4263 81 7/subop/compare *(ecx+4) 0/imm32 # List-next -4264 74/jump-if-= break/disp8 -4265 # curr = curr->next -4266 8b/-> *(ecx+4) 1/r32/ecx -4267 eb/jump loop/disp8 -4268 } -4269 # curr->next = result -4270 89/<- *(ecx+4) 0/r32/eax -4271 # return list -4272 8b/-> *(ebp+0x10) 0/r32/eax -4273 $append-list:end: -4274 # . restore registers -4275 59/pop-to-ecx -4276 # . epilogue -4277 89/<- %esp 5/r32/ebp -4278 5d/pop-to-ebp -4279 c3/return -4280 -4281 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) -4282 # . prologue -4283 55/push-ebp -4284 89/<- %ebp 4/r32/esp -4285 # . save registers -4286 56/push-esi -4287 # esi = block -4288 8b/-> *(ebp+0xc) 6/r32/esi -4289 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements -4290 89/<- *(esi+4) 0/r32/eax # Block-statements -4291 $append-to-block:end: +4254 89/<- *eax 1/r32/ecx # Function-name +4255 8b/-> *(ebp+0x10) 1/r32/ecx +4256 89/<- *(eax+4) 1/r32/ecx # Function-subx-name +4257 8b/-> *(ebp+0x14) 1/r32/ecx +4258 89/<- *(eax+8) 1/r32/ecx # Function-inouts +4259 8b/-> *(ebp+0x18) 1/r32/ecx +4260 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs +4261 8b/-> *(ebp+0x1c) 1/r32/ecx +4262 89/<- *(eax+0x10) 1/r32/ecx # Function-body +4263 8b/-> *(ebp+0x20) 1/r32/ecx +4264 89/<- *(eax+0x14) 1/r32/ecx # Function-next +4265 $new-function:end: +4266 # . restore registers +4267 59/pop-to-ecx +4268 # . epilogue +4269 89/<- %esp 5/r32/ebp +4270 5d/pop-to-ebp +4271 c3/return +4272 +4273 new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: (addr tree type-id), block: int, stack-offset: int, register: (addr array byte) -> result/eax: (handle var) +4274 # . prologue +4275 55/push-ebp +4276 89/<- %ebp 4/r32/esp +4277 # . save registers +4278 51/push-ecx +4279 # +4280 (allocate *(ebp+8) *Var-size) # => eax +4281 8b/-> *(ebp+0xc) 1/r32/ecx +4282 89/<- *eax 1/r32/ecx # Var-name +4283 8b/-> *(ebp+0x10) 1/r32/ecx +4284 89/<- *(eax+4) 1/r32/ecx # Var-type +4285 8b/-> *(ebp+0x14) 1/r32/ecx +4286 89/<- *(eax+8) 1/r32/ecx # Var-block-depth +4287 8b/-> *(ebp+0x18) 1/r32/ecx +4288 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset +4289 8b/-> *(ebp+0x1c) 1/r32/ecx +4290 89/<- *(eax+0x10) 1/r32/ecx # Var-register +4291 $new-var:end: 4292 # . restore registers -4293 5e/pop-to-esi +4293 59/pop-to-ecx 4294 # . epilogue 4295 89/<- %esp 5/r32/ebp 4296 5d/pop-to-ebp 4297 c3/return 4298 -4299 ####################################################### -4300 # Type-checking -4301 ####################################################### -4302 -4303 check-mu-types: -4304 # . prologue -4305 55/push-ebp -4306 89/<- %ebp 4/r32/esp -4307 # -4308 $check-mu-types:end: -4309 # . epilogue -4310 89/<- %esp 5/r32/ebp -4311 5d/pop-to-ebp -4312 c3/return -4313 -4314 size-of: # v: (addr var) -> result/eax: int -4315 # . prologue -4316 55/push-ebp -4317 89/<- %ebp 4/r32/esp -4318 # if v is a literal, return 0 -4319 8b/-> *(ebp+8) 0/r32/eax -4320 8b/-> *(eax+4) 0/r32/eax # Var-type -4321 81 7/subop/compare *eax 0/imm32 # Tree-left -4322 b8/copy-to-eax 0/imm32 -4323 74/jump-if-= $size-of:end/disp8 -4324 # hard-coded since we only support 'int' types for now -4325 b8/copy-to-eax 4/imm32 -4326 $size-of:end: -4327 # . epilogue -4328 89/<- %esp 5/r32/ebp -4329 5d/pop-to-ebp -4330 c3/return -4331 -4332 type-equal?: # a: (handle tree type-id), b: (handle tree type-id) -> result/eax: boolean -4333 # . prologue -4334 55/push-ebp -4335 89/<- %ebp 4/r32/esp -4336 # . save registers -4337 51/push-ecx -4338 52/push-edx -4339 # ecx = a -4340 8b/-> *(ebp+8) 1/r32/ecx -4341 # edx = b -4342 8b/-> *(ebp+0xc) 2/r32/edx -4343 # if (a == b) return true -4344 8b/-> %ecx 0/r32/eax # Var-type -4345 39/compare %edx 0/r32/eax # Var-type -4346 b8/copy-to-eax 1/imm32/true -4347 74/jump-if-= $type-equal?:end/disp8 -4348 # if (a < MAX_TYPE_ID) return false -4349 81 7/subop/compare %ecx 0x10000/imm32 -4350 b8/copy-to-eax 0/imm32/false -4351 72/jump-if-addr< $type-equal?:end/disp8 -4352 # if (b < MAX_TYPE_ID) return false -4353 81 7/subop/compare %edx 0x10000/imm32 -4354 b8/copy-to-eax 0/imm32/false -4355 72/jump-if-addr< $type-equal?:end/disp8 -4356 # if (!type-equal?(a->left, b->left)) return false -4357 (type-equal? *ecx *edx) # Tree-left, Tree-left => eax -4358 3d/compare-eax-and 0/imm32/false -4359 74/jump-if-= $type-equal?:end/disp8 -4360 # return type-equal?(a->right, b->right) -4361 (type-equal? *(ecx+4) *(edx+4)) # Tree-right, Tree-right => eax -4362 $type-equal?:end: +4299 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) +4300 # . prologue +4301 55/push-ebp +4302 89/<- %ebp 4/r32/esp +4303 # . save registers +4304 51/push-ecx +4305 # if (!is-hex-int?(name)) abort +4306 (is-hex-int? *(ebp+0xc)) # => eax +4307 3d/compare-eax-and 0/imm32/false +4308 0f 84/jump-if-= $new-literal-integer:abort/disp32 +4309 # var s/ecx: (addr array byte) +4310 (slice-to-string Heap *(ebp+0xc)) # => eax +4311 89/<- %ecx 0/r32/eax +4312 # result/ecx = new var(s) +4313 (allocate *(ebp+8) *Var-size) # => eax +4314 (zero-out %eax *Var-size) +4315 89/<- *eax 1/r32/ecx # Var-name +4316 89/<- %ecx 0/r32/eax +4317 # result->type = new type() +4318 (allocate *(ebp+8) *Tree-size) # => eax +4319 (zero-out %eax *Tree-size) # default type is 'literal' +4320 89/<- *(ecx+4) 0/r32/eax # Var-type +4321 # move result to eax +4322 89/<- %eax 1/r32/ecx +4323 $new-literal-integer:end: +4324 # . restore registers +4325 59/pop-to-ecx +4326 # . epilogue +4327 89/<- %esp 5/r32/ebp +4328 5d/pop-to-ebp +4329 c3/return +4330 +4331 $new-literal-integer:abort: +4332 (write-buffered Stderr "variable cannot begin with a digit '") +4333 (write-slice-buffered Stderr *(ebp+0xc)) +4334 (write-buffered Stderr "'\n") +4335 (flush Stderr) +4336 # . syscall(exit, 1) +4337 bb/copy-to-ebx 1/imm32 +4338 b8/copy-to-eax 1/imm32/exit +4339 cd/syscall 0x80/imm8 +4340 # never gets here +4341 +4342 new-literal-string: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) +4343 # . prologue +4344 55/push-ebp +4345 89/<- %ebp 4/r32/esp +4346 # . save registers +4347 51/push-ecx +4348 # var s/ecx: (addr array byte) +4349 (slice-to-string Heap *(ebp+0xc)) # => eax +4350 89/<- %ecx 0/r32/eax +4351 # result/ecx = new var(s) +4352 (allocate *(ebp+8) *Var-size) # => eax +4353 (zero-out %eax *Var-size) +4354 89/<- *eax 1/r32/ecx # Var-name +4355 89/<- %ecx 0/r32/eax +4356 # result->type = new type() +4357 (allocate *(ebp+8) *Tree-size) # => eax +4358 (zero-out %eax *Tree-size) # default type is 'literal' +4359 89/<- *(ecx+4) 0/r32/eax # Var-type +4360 # move result to eax +4361 89/<- %eax 1/r32/ecx +4362 $new-literal-string:end: 4363 # . restore registers -4364 5a/pop-to-edx -4365 59/pop-to-ecx -4366 # . epilogue -4367 89/<- %esp 5/r32/ebp -4368 5d/pop-to-ebp -4369 c3/return -4370 -4371 == data -4372 -4373 # not yet used, but it will be -4374 Type-size: # (stream int) -4375 0x18/imm32/write -4376 0/imm32/read -4377 0x100/imm32/length -4378 # data -4379 4/imm32 # literal -4380 4/imm32 # int -4381 4/imm32 # addr -4382 0/imm32 # array (logic elsewhere) -4383 8/imm32 # handle (fat pointer) -4384 4/imm32 # bool -4385 0/imm32 -4386 0/imm32 -4387 # 0x20 -4388 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -4389 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -4390 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -4391 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -4392 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -4393 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -4394 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -4395 -4396 == code +4364 59/pop-to-ecx +4365 # . epilogue +4366 89/<- %esp 5/r32/ebp +4367 5d/pop-to-ebp +4368 c3/return +4369 +4370 new-label: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) +4371 # . prologue +4372 55/push-ebp +4373 89/<- %ebp 4/r32/esp +4374 # . save registers +4375 51/push-ecx +4376 # var s/ecx: (addr array byte) +4377 (slice-to-string Heap *(ebp+0xc)) # => eax +4378 89/<- %ecx 0/r32/eax +4379 # +4380 (allocate *(ebp+8) *Var-size) # => eax +4381 89/<- *eax 1/r32/ecx # Var-name +4382 89/<- %ecx 0/r32/eax +4383 (allocate *(ebp+8) *Tree-size) # => eax +4384 (zero-out %eax *Tree-size) # labels are literals +4385 89/<- *(ecx+4) 0/r32/eax # Var-type +4386 89/<- %eax 1/r32/ecx +4387 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block-depth +4388 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset +4389 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register +4390 $new-label:end: +4391 # . restore registers +4392 59/pop-to-ecx +4393 # . epilogue +4394 89/<- %esp 5/r32/ebp +4395 5d/pop-to-ebp +4396 c3/return 4397 -4398 ####################################################### -4399 # Code-generation -4400 ####################################################### -4401 -4402 emit-subx: # out: (addr buffered-file) -4403 # . prologue -4404 55/push-ebp -4405 89/<- %ebp 4/r32/esp -4406 # . save registers -4407 50/push-eax -4408 51/push-ecx -4409 57/push-edi -4410 # edi = out -4411 8b/-> *(ebp+8) 7/r32/edi -4412 # var curr/ecx: (handle function) = *Program -4413 8b/-> *Program 1/r32/ecx -4414 { -4415 # if (curr == null) break -4416 81 7/subop/compare %ecx 0/imm32 -4417 0f 84/jump-if-= break/disp32 -4418 (emit-subx-function %edi %ecx) -4419 # curr = curr->next -4420 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -4421 e9/jump loop/disp32 -4422 } -4423 $emit-subx:end: -4424 # . restore registers -4425 5f/pop-to-edi -4426 59/pop-to-ecx -4427 58/pop-to-eax -4428 # . epilogue -4429 89/<- %esp 5/r32/ebp -4430 5d/pop-to-ebp -4431 c3/return -4432 -4433 emit-subx-function: # out: (addr buffered-file), f: (handle function) -4434 # . prologue -4435 55/push-ebp -4436 89/<- %ebp 4/r32/esp -4437 # . save registers -4438 50/push-eax -4439 51/push-ecx -4440 52/push-edx -4441 57/push-edi -4442 # edi = out -4443 8b/-> *(ebp+8) 7/r32/edi -4444 # ecx = f -4445 8b/-> *(ebp+0xc) 1/r32/ecx -4446 # var vars/edx: (stack (addr var) 256) -4447 81 5/subop/subtract %esp 0x400/imm32 -4448 68/push 0x400/imm32/length -4449 68/push 0/imm32/top -4450 89/<- %edx 4/r32/esp -4451 # -4452 (write-buffered %edi *ecx) -4453 (write-buffered %edi ":\n") -4454 # Important: each block's depth during code-generation should be identical -4455 # to what it was during parsing. -4456 c7 0/subop/copy *Curr-block-depth 1/imm32 -4457 (emit-subx-prologue %edi) -4458 (emit-subx-block %edi *(ecx+0x10) %edx) # Function-body -4459 (emit-subx-epilogue %edi) -4460 $emit-subx-function:end: -4461 # . reclaim locals -4462 81 0/subop/add %esp 408/imm32 -4463 # . restore registers -4464 5f/pop-to-edi -4465 5a/pop-to-edx -4466 59/pop-to-ecx -4467 58/pop-to-eax -4468 # . epilogue -4469 89/<- %esp 5/r32/ebp -4470 5d/pop-to-ebp -4471 c3/return -4472 -4473 emit-subx-stmt-list: # out: (addr buffered-file), stmts: (handle list stmt), vars: (addr stack (handle var)) -4474 # . prologue -4475 55/push-ebp -4476 89/<- %ebp 4/r32/esp -4477 # . save registers -4478 50/push-eax -4479 51/push-ecx -4480 52/push-edx -4481 53/push-ebx -4482 56/push-esi -4483 # esi = stmts -4484 8b/-> *(ebp+0xc) 6/r32/esi -4485 # var var-seen?/edx: boolean <- copy false -4486 ba/copy-to-edx 0/imm32/false -4487 # -4488 { -4489 $emit-subx-stmt-list:loop: -4490 81 7/subop/compare %esi 0/imm32 -4491 0f 84/jump-if-= break/disp32 -4492 # var curr-stmt/ecx = stmts->value -4493 8b/-> *esi 1/r32/ecx # List-value -4494 { -4495 $emit-subx-stmt-list:check-for-block: -4496 81 7/subop/compare *ecx 0/imm32/block # Stmt-tag -4497 75/jump-if-!= break/disp8 -4498 $emit-subx-stmt-list:block: -4499 (emit-subx-block *(ebp+8) %ecx *(ebp+0x10)) -4500 } -4501 { -4502 $emit-subx-stmt-list:check-for-stmt: -4503 81 7/subop/compare *ecx 1/imm32/stmt1 # Stmt-tag -4504 0f 85/jump-if-!= break/disp32 -4505 $emit-subx-stmt-list:stmt1: -4506 { -4507 (is-mu-branch? %ecx) # => eax -4508 3d/compare-eax-and 0/imm32/false -4509 0f 84/jump-if-= break/disp32 -4510 $emit-subx-stmt-list:branch-stmt: -4511 # if !var-seen? break -4512 81 7/subop/compare %edx 0/imm32/false -4513 0f 84/jump-if-= break/disp32 -4514 $emit-subx-stmt-list:branch-stmt-and-var-seen: -4515 +-- 26 lines: # unconditional loops ----------------------------------------------------------------------------------------------------------------------------------------------------- -4541 +-- 78 lines: # conditional branches ---------------------------------------------------------------------------------------------------------------------------------------------------- -4619 } -4620 $emit-subx-stmt-list:1-to-1: -4621 (emit-subx-statement *(ebp+8) %ecx Primitives *Program) -4622 } -4623 { -4624 $emit-subx-stmt-list:check-for-vardef: -4625 81 7/subop/compare *ecx 2/imm32/vardef # Stmt-tag -4626 75/jump-if-!= break/disp8 -4627 $emit-subx-stmt-list:vardef: -4628 (emit-subx-var-def *(ebp+8) %ecx) -4629 (push *(ebp+0x10) *(ecx+4)) # Vardef-var -4630 # var-seen? = true -4631 ba/copy-to-edx 1/imm32/true -4632 } -4633 { -4634 $emit-subx-stmt-list:check-for-regvardef: -4635 81 7/subop/compare *ecx 3/imm32/regvardef # Stmt-tag -4636 0f 85/jump-if-!= break/disp32 -4637 $emit-subx-stmt-list:regvardef: -4638 # TODO: ensure that there's exactly one output -4639 # var output/eax: (handle var) = curr-stmt->outputs->value -4640 8b/-> *(ecx+0xc) 0/r32/eax -4641 8b/-> *eax 0/r32/eax -4642 # ensure that output is in a register -4643 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -4644 0f 84/jump-if-= $emit-subx-stmt-list:abort-regvardef-without-register/disp32 -4645 # emit spill -4646 (emit-indent *(ebp+8) *Curr-block-depth) -4647 (write-buffered *(ebp+8) "ff 6/subop/push %") -4648 (write-buffered *(ebp+8) *(eax+0x10)) -4649 (write-buffered *(ebp+8) Newline) -4650 # register variable definition -4651 (push *(ebp+0x10) %eax) -4652 # emit the instruction as usual -4653 (emit-subx-statement *(ebp+8) %ecx Primitives *Program) -4654 # var-seen? = true -4655 ba/copy-to-edx 1/imm32/true -4656 } -4657 $emit-subx-stmt-list:continue: -4658 # TODO: raise an error on unrecognized Stmt-tag -4659 8b/-> *(esi+4) 6/r32/esi # List-next -4660 e9/jump loop/disp32 -4661 } -4662 $emit-subx-stmt-list:cleanup: -4663 (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth) -4664 (clean-up-blocks *(ebp+0x10) *Curr-block-depth) -4665 $emit-subx-stmt-list:end: +4398 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) +4399 # . prologue +4400 55/push-ebp +4401 89/<- %ebp 4/r32/esp +4402 # . save registers +4403 51/push-ecx +4404 # +4405 (allocate *(ebp+8) *Stmt-size) # => eax +4406 (zero-out %eax *Stmt-size) +4407 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag +4408 8b/-> *(ebp+0xc) 1/r32/ecx +4409 89/<- *(eax+4) 1/r32/ecx # Block-statements +4410 $new-block:end: +4411 # . restore registers +4412 59/pop-to-ecx +4413 # . epilogue +4414 89/<- %esp 5/r32/ebp +4415 5d/pop-to-ebp +4416 c3/return +4417 +4418 new-vardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) +4419 # . prologue +4420 55/push-ebp +4421 89/<- %ebp 4/r32/esp +4422 # . save registers +4423 51/push-ecx +4424 # +4425 (allocate *(ebp+8) *Stmt-size) # => eax +4426 (zero-out %eax *Stmt-size) +4427 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag +4428 # result->var = var +4429 8b/-> *(ebp+0xc) 1/r32/ecx +4430 89/<- *(eax+4) 1/r32/ecx # Vardef-var +4431 $new-vardef:end: +4432 # . restore registers +4433 59/pop-to-ecx +4434 # . epilogue +4435 89/<- %esp 5/r32/ebp +4436 5d/pop-to-ebp +4437 c3/return +4438 +4439 new-regvardef: # ad: (addr allocation-descriptor), var: (handle var) -> result/eax: (handle statement) +4440 # . prologue +4441 55/push-ebp +4442 89/<- %ebp 4/r32/esp +4443 # . save registers +4444 51/push-ecx +4445 57/push-edi +4446 # ecx = var +4447 8b/-> *(ebp+0xc) 1/r32/ecx +4448 # edi = result +4449 (allocate *(ebp+8) *Stmt-size) # => eax +4450 89/<- %edi 0/r32/eax +4451 (zero-out %edi *Stmt-size) +4452 # set tag +4453 c7 0/subop/copy *edi 3/imm32/tag/var-in-register # Stmt-tag +4454 # set output +4455 (append-list Heap %ecx *(edi+0xc)) # Regvardef-outputs => eax +4456 89/<- *(edi+0xc) 0/r32/eax # Regvardef-outputs +4457 $new-regvardef:end: +4458 89/<- %eax 7/r32/edi +4459 # . restore registers +4460 5f/pop-to-edi +4461 59/pop-to-ecx +4462 # . epilogue +4463 89/<- %esp 5/r32/ebp +4464 5d/pop-to-ebp +4465 c3/return +4466 +4467 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax: (handle list _type) +4468 # . prologue +4469 55/push-ebp +4470 89/<- %ebp 4/r32/esp +4471 # . save registers +4472 51/push-ecx +4473 # +4474 (allocate *(ebp+8) *List-size) # => eax +4475 8b/-> *(ebp+0xc) 1/r32/ecx +4476 89/<- *eax 1/r32/ecx # List-value +4477 8b/-> *(ebp+0x10) 1/r32/ecx +4478 89/<- *(eax+4) 1/r32/ecx # List-next +4479 $new-list:end: +4480 # . restore registers +4481 59/pop-to-ecx +4482 # . epilogue +4483 89/<- %esp 5/r32/ebp +4484 5d/pop-to-ebp +4485 c3/return +4486 +4487 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax: (handle list _type) +4488 # . prologue +4489 55/push-ebp +4490 89/<- %ebp 4/r32/esp +4491 # . save registers +4492 51/push-ecx +4493 # +4494 (allocate *(ebp+8) *List-size) # => eax +4495 8b/-> *(ebp+0xc) 1/r32/ecx +4496 89/<- *eax 1/r32/ecx # List-value +4497 # if (list == null) return result +4498 81 7/subop/compare *(ebp+0x10) 0/imm32 +4499 74/jump-if-= $new-list:end/disp8 +4500 # otherwise append +4501 # var curr/ecx = list +4502 8b/-> *(ebp+0x10) 1/r32/ecx +4503 # while (curr->next != null) curr = curr->next +4504 { +4505 81 7/subop/compare *(ecx+4) 0/imm32 # List-next +4506 74/jump-if-= break/disp8 +4507 # curr = curr->next +4508 8b/-> *(ecx+4) 1/r32/ecx +4509 eb/jump loop/disp8 +4510 } +4511 # curr->next = result +4512 89/<- *(ecx+4) 0/r32/eax +4513 # return list +4514 8b/-> *(ebp+0x10) 0/r32/eax +4515 $append-list:end: +4516 # . restore registers +4517 59/pop-to-ecx +4518 # . epilogue +4519 89/<- %esp 5/r32/ebp +4520 5d/pop-to-ebp +4521 c3/return +4522 +4523 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) +4524 # . prologue +4525 55/push-ebp +4526 89/<- %ebp 4/r32/esp +4527 # . save registers +4528 56/push-esi +4529 # esi = block +4530 8b/-> *(ebp+0xc) 6/r32/esi +4531 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements +4532 89/<- *(esi+4) 0/r32/eax # Block-statements +4533 $append-to-block:end: +4534 # . restore registers +4535 5e/pop-to-esi +4536 # . epilogue +4537 89/<- %esp 5/r32/ebp +4538 5d/pop-to-ebp +4539 c3/return +4540 +4541 ####################################################### +4542 # Type-checking +4543 ####################################################### +4544 +4545 check-mu-types: +4546 # . prologue +4547 55/push-ebp +4548 89/<- %ebp 4/r32/esp +4549 # +4550 $check-mu-types:end: +4551 # . epilogue +4552 89/<- %esp 5/r32/ebp +4553 5d/pop-to-ebp +4554 c3/return +4555 +4556 size-of: # v: (addr var) -> result/eax: int +4557 # . prologue +4558 55/push-ebp +4559 89/<- %ebp 4/r32/esp +4560 # if v is a literal, return 0 +4561 8b/-> *(ebp+8) 0/r32/eax +4562 8b/-> *(eax+4) 0/r32/eax # Var-type +4563 81 7/subop/compare *eax 0/imm32 # Tree-left +4564 b8/copy-to-eax 0/imm32 +4565 74/jump-if-= $size-of:end/disp8 +4566 # hard-coded since we only support 'int' types for now +4567 b8/copy-to-eax 4/imm32 +4568 $size-of:end: +4569 # . epilogue +4570 89/<- %esp 5/r32/ebp +4571 5d/pop-to-ebp +4572 c3/return +4573 +4574 type-equal?: # a: (handle tree type-id), b: (handle tree type-id) -> result/eax: boolean +4575 # . prologue +4576 55/push-ebp +4577 89/<- %ebp 4/r32/esp +4578 # . save registers +4579 51/push-ecx +4580 52/push-edx +4581 # ecx = a +4582 8b/-> *(ebp+8) 1/r32/ecx +4583 # edx = b +4584 8b/-> *(ebp+0xc) 2/r32/edx +4585 # if (a == b) return true +4586 8b/-> %ecx 0/r32/eax # Var-type +4587 39/compare %edx 0/r32/eax # Var-type +4588 b8/copy-to-eax 1/imm32/true +4589 74/jump-if-= $type-equal?:end/disp8 +4590 # if (a < MAX_TYPE_ID) return false +4591 81 7/subop/compare %ecx 0x10000/imm32 +4592 b8/copy-to-eax 0/imm32/false +4593 72/jump-if-addr< $type-equal?:end/disp8 +4594 # if (b < MAX_TYPE_ID) return false +4595 81 7/subop/compare %edx 0x10000/imm32 +4596 b8/copy-to-eax 0/imm32/false +4597 72/jump-if-addr< $type-equal?:end/disp8 +4598 # if (!type-equal?(a->left, b->left)) return false +4599 (type-equal? *ecx *edx) # Tree-left, Tree-left => eax +4600 3d/compare-eax-and 0/imm32/false +4601 74/jump-if-= $type-equal?:end/disp8 +4602 # return type-equal?(a->right, b->right) +4603 (type-equal? *(ecx+4) *(edx+4)) # Tree-right, Tree-right => eax +4604 $type-equal?:end: +4605 # . restore registers +4606 5a/pop-to-edx +4607 59/pop-to-ecx +4608 # . epilogue +4609 89/<- %esp 5/r32/ebp +4610 5d/pop-to-ebp +4611 c3/return +4612 +4613 == data +4614 +4615 # not yet used, but it will be +4616 Type-size: # (stream int) +4617 0x18/imm32/write +4618 0/imm32/read +4619 0x100/imm32/length +4620 # data +4621 4/imm32 # literal +4622 4/imm32 # int +4623 4/imm32 # addr +4624 0/imm32 # array (logic elsewhere) +4625 8/imm32 # handle (fat pointer) +4626 4/imm32 # bool +4627 0/imm32 +4628 0/imm32 +4629 # 0x20 +4630 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +4631 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +4632 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +4633 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +4634 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +4635 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +4636 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +4637 +4638 == code +4639 +4640 ####################################################### +4641 # Code-generation +4642 ####################################################### +4643 +4644 emit-subx: # out: (addr buffered-file) +4645 # . prologue +4646 55/push-ebp +4647 89/<- %ebp 4/r32/esp +4648 # . save registers +4649 50/push-eax +4650 51/push-ecx +4651 57/push-edi +4652 # edi = out +4653 8b/-> *(ebp+8) 7/r32/edi +4654 # var curr/ecx: (handle function) = *Program +4655 8b/-> *Program 1/r32/ecx +4656 { +4657 # if (curr == null) break +4658 81 7/subop/compare %ecx 0/imm32 +4659 0f 84/jump-if-= break/disp32 +4660 (emit-subx-function %edi %ecx) +4661 # curr = curr->next +4662 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +4663 e9/jump loop/disp32 +4664 } +4665 $emit-subx:end: 4666 # . restore registers -4667 5e/pop-to-esi -4668 5b/pop-to-ebx -4669 5a/pop-to-edx -4670 59/pop-to-ecx -4671 58/pop-to-eax -4672 # . epilogue -4673 89/<- %esp 5/r32/ebp -4674 5d/pop-to-ebp -4675 c3/return -4676 -4677 $emit-subx-stmt-list:abort-regvardef-without-register: -4678 # error("var '" var->name "' initialized from an instruction must live in a register\n") -4679 (write-buffered Stderr "var '") -4680 (write-buffered Stderr *eax) # Var-name -4681 (write-buffered Stderr "' initialized from an instruction must live in a register\n") -4682 (flush Stderr) -4683 # . syscall(exit, 1) -4684 bb/copy-to-ebx 1/imm32 -4685 b8/copy-to-eax 1/imm32/exit -4686 cd/syscall 0x80/imm8 -4687 # never gets here -4688 -4689 is-mu-branch?: # stmt: (addr stmt1) -> result/eax: boolean -4690 # . prologue -4691 55/push-ebp -4692 89/<- %ebp 4/r32/esp -4693 # . save registers -4694 51/push-ecx -4695 # ecx = stmt -4696 8b/-> *(ebp+8) 1/r32/ecx -4697 # if (stmt->operation starts with "loop") return true -4698 (string-starts-with? *(ecx+4) "loop") # Stmt1-operation => eax -4699 3d/compare-eax-and 0/imm32/false -4700 75/jump-if-not-equal $is-mu-branch?:end/disp8 -4701 # otherwise return (stmt->operation starts with "break") -4702 (string-starts-with? *(ecx+4) "break") # Stmt1-operation => eax -4703 $is-mu-branch?:end: -4704 # . restore registers -4705 59/pop-to-ecx -4706 # . epilogue -4707 89/<- %esp 5/r32/ebp -4708 5d/pop-to-ebp -4709 c3/return -4710 -4711 emit-reverse-break: # out: (addr buffered-file), stmt: (addr stmt1) -4712 # . prologue -4713 55/push-ebp -4714 89/<- %ebp 4/r32/esp -4715 # . save registers -4716 50/push-eax -4717 # eax = stmt -4718 8b/-> *(ebp+0xc) 0/r32/eax -4719 # -4720 (get Reverse-branch *(eax+4) 8 "reverse-branch: ") # Stmt1-operation => eax: (addr addr array byte) -4721 (emit-indent *(ebp+8) *Curr-block-depth) -4722 (write-buffered *(ebp+8) *eax) -4723 (write-buffered *(ebp+8) " break/disp32\n") -4724 $emit-reverse-break:end: -4725 # . restore registers -4726 58/pop-to-eax -4727 # . epilogue -4728 89/<- %esp 5/r32/ebp -4729 5d/pop-to-ebp -4730 c3/return -4731 -4732 == data -4733 -4734 Reverse-branch: # (table string string) -4735 # a table is a stream -4736 0xa0/imm32/write -4737 0/imm32/read -4738 0xa0/imm32/length -4739 # data -4740 "break-if-="/imm32 "0f 85/jump-if-!="/imm32 -4741 "loop-if-="/imm32 "0f 85/jump-if-!="/imm32 -4742 "break-if-!="/imm32 "0f 84/jump-if-="/imm32 -4743 "loop-if-!="/imm32 "0f 84/jump-if-="/imm32 -4744 "break-if-<"/imm32 "0f 8d/jump-if->="/imm32 -4745 "loop-if-<"/imm32 "0f 8d/jump-if->="/imm32 -4746 "break-if->"/imm32 "0f 8e/jump-if-<="/imm32 -4747 "loop-if->"/imm32 "0f 8e/jump-if-<="/imm32 -4748 "break-if-<="/imm32 "0f 87/jump-if->"/imm32 -4749 "loop-if-<="/imm32 "0f 87/jump-if->"/imm32 -4750 "break-if->="/imm32 "0f 8c/jump-if-<"/imm32 -4751 "loop-if->="/imm32 "0f 8c/jump-if-<"/imm32 -4752 "break-if-addr<"/imm32 "0f 83/jump-if-addr>="/imm32 -4753 "loop-if-addr<"/imm32 "0f 83/jump-if-addr>="/imm32 -4754 "break-if-addr>"/imm32 "0f 86/jump-if-addr<="/imm32 -4755 "loop-if-addr>"/imm32 "0f 86/jump-if-addr<="/imm32 -4756 "break-if-addr<="/imm32 "0f 87/jump-if-addr>"/imm32 -4757 "loop-if-addr<="/imm32 "0f 87/jump-if-addr>"/imm32 -4758 "break-if-addr>="/imm32 "0f 82/jump-if-addr<"/imm32 -4759 "loop-if-addr>="/imm32 "0f 82/jump-if-addr<"/imm32 -4760 -4761 == code -4762 -4763 emit-unconditional-jump-to-depth: # out: (addr buffered-file), vars: (addr stack (handle var)), depth: int, label-suffix: (addr array byte) -4764 # . prologue -4765 55/push-ebp -4766 89/<- %ebp 4/r32/esp -4767 # . save registers -4768 50/push-eax -4769 51/push-ecx -4770 52/push-edx -4771 53/push-ebx -4772 # ecx = vars -4773 8b/-> *(ebp+0xc) 1/r32/ecx -4774 # var eax: int = vars->top -4775 8b/-> *ecx 0/r32/eax -4776 # var min/ecx: (address (handle var)) = vars->data -4777 81 0/subop/add %ecx 8/imm32 -4778 # var curr/eax: (address (handle var)) = &vars->data[vars->top - 4] -4779 81 5/subop/subtract %eax 4/imm32 -4780 8d/copy-address *(ecx+eax) 0/r32/eax -4781 # edx = depth -4782 8b/-> *(ebp+0x10) 2/r32/edx -4783 { -4784 $emit-unconditional-jump-to-depth:loop: -4785 # if (curr < min) break -4786 39/compare %eax 1/r32/ecx -4787 0f 82/jump-if-addr< break/disp32 -4788 # var v/ebx: (handle var) = *curr -4789 8b/-> *eax 3/r32/ebx -4790 # if (v->block-depth < until-block-depth) break -4791 39/compare *(ebx+8) 2/r32/edx # Var-block-depth -4792 0f 8c/jump-if-< break/disp32 -4793 { -4794 $emit-unconditional-jump-to-depth:check: -4795 # if v->block-depth != until-block-depth, continue -4796 39/compare *(ebx+8) 2/r32/edx # Var-block-depth -4797 0f 85/jump-if-!= break/disp32 -4798 $emit-unconditional-jump-to-depth:depth-found: -4799 # if v is not a literal, continue -4800 # . var eax: int = size-of(v) -4801 50/push-eax -4802 (size-of %ebx) # => eax -4803 # . if (eax != 0) continue -4804 3d/compare-eax-and 0/imm32 -4805 58/pop-to-eax -4806 # -4807 0f 85/jump-if-!= break/disp32 -4808 $emit-unconditional-jump-to-depth:label-found: -4809 # emit unconditional jump, then return -4810 (emit-indent *(ebp+8) *Curr-block-depth) -4811 (write-buffered *(ebp+8) "e9/jump ") -4812 (write-buffered *(ebp+8) *ebx) # Var-name -4813 (write-buffered *(ebp+8) ":") -4814 (write-buffered *(ebp+8) *(ebp+0x14)) -4815 (write-buffered *(ebp+8) "/disp32\n") -4816 eb/jump $emit-unconditional-jump-to-depth:end/disp8 -4817 } -4818 # curr -= 4 -4819 2d/subtract-from-eax 4/imm32 -4820 e9/jump loop/disp32 -4821 } -4822 # TODO: error if no label at 'depth' was found -4823 $emit-unconditional-jump-to-depth:end: -4824 # . restore registers -4825 5b/pop-to-ebx -4826 5a/pop-to-edx -4827 59/pop-to-ecx -4828 58/pop-to-eax -4829 # . epilogue -4830 89/<- %esp 5/r32/ebp -4831 5d/pop-to-ebp -4832 c3/return -4833 -4834 # emit clean-up code for 'vars' until some block depth -4835 # doesn't actually modify 'vars' so we need traverse manually inside the stack -4836 emit-cleanup-code-until-depth: # out: (addr buffered-file), vars: (addr stack (handle var)), until-block-depth: int -4837 # . prologue -4838 55/push-ebp -4839 89/<- %ebp 4/r32/esp -4840 # . save registers -4841 50/push-eax -4842 51/push-ecx -4843 52/push-edx -4844 53/push-ebx -4845 # ecx = vars -4846 8b/-> *(ebp+0xc) 1/r32/ecx -4847 # var eax: int = vars->top -4848 8b/-> *ecx 0/r32/eax -4849 # var min/ecx: (address (handle var)) = vars->data -4850 81 0/subop/add %ecx 8/imm32 -4851 # var curr/eax: (address (handle var)) = &vars->data[vars->top - 4] -4852 81 5/subop/subtract %eax 4/imm32 -4853 8d/copy-address *(ecx+eax) 0/r32/eax -4854 # edx = until-block-depth -4855 8b/-> *(ebp+0x10) 2/r32/edx -4856 { -4857 $emit-cleanup-code-until-depth:loop: -4858 # if (curr < min) break -4859 39/compare %eax 1/r32/ecx -4860 0f 82/jump-if-addr< break/disp32 -4861 # var v/ebx: (handle var) = *curr -4862 8b/-> *eax 3/r32/ebx -4863 # if (v->block-depth < until-block-depth) break -4864 39/compare *(ebx+8) 2/r32/edx # Var-block-depth -4865 0f 8c/jump-if-< break/disp32 -4866 # if v is in a register -4867 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +4667 5f/pop-to-edi +4668 59/pop-to-ecx +4669 58/pop-to-eax +4670 # . epilogue +4671 89/<- %esp 5/r32/ebp +4672 5d/pop-to-ebp +4673 c3/return +4674 +4675 emit-subx-function: # out: (addr buffered-file), f: (handle function) +4676 # . prologue +4677 55/push-ebp +4678 89/<- %ebp 4/r32/esp +4679 # . save registers +4680 50/push-eax +4681 51/push-ecx +4682 52/push-edx +4683 57/push-edi +4684 # edi = out +4685 8b/-> *(ebp+8) 7/r32/edi +4686 # ecx = f +4687 8b/-> *(ebp+0xc) 1/r32/ecx +4688 # var vars/edx: (stack (addr var) 256) +4689 81 5/subop/subtract %esp 0x400/imm32 +4690 68/push 0x400/imm32/length +4691 68/push 0/imm32/top +4692 89/<- %edx 4/r32/esp +4693 # +4694 (write-buffered %edi *ecx) +4695 (write-buffered %edi ":\n") +4696 # Important: each block's depth during code-generation should be identical +4697 # to what it was during parsing. +4698 c7 0/subop/copy *Curr-block-depth 1/imm32 +4699 (emit-subx-prologue %edi) +4700 (emit-subx-block %edi *(ecx+0x10) %edx) # Function-body +4701 (emit-subx-epilogue %edi) +4702 $emit-subx-function:end: +4703 # . reclaim locals +4704 81 0/subop/add %esp 408/imm32 +4705 # . restore registers +4706 5f/pop-to-edi +4707 5a/pop-to-edx +4708 59/pop-to-ecx +4709 58/pop-to-eax +4710 # . epilogue +4711 89/<- %esp 5/r32/ebp +4712 5d/pop-to-ebp +4713 c3/return +4714 +4715 emit-subx-stmt-list: # out: (addr buffered-file), stmts: (handle list stmt), vars: (addr stack (handle var)) +4716 # . prologue +4717 55/push-ebp +4718 89/<- %ebp 4/r32/esp +4719 # . save registers +4720 50/push-eax +4721 51/push-ecx +4722 52/push-edx +4723 53/push-ebx +4724 56/push-esi +4725 # esi = stmts +4726 8b/-> *(ebp+0xc) 6/r32/esi +4727 # var var-seen?/edx: boolean <- copy false +4728 ba/copy-to-edx 0/imm32/false +4729 # +4730 { +4731 $emit-subx-stmt-list:loop: +4732 81 7/subop/compare %esi 0/imm32 +4733 0f 84/jump-if-= break/disp32 +4734 # var curr-stmt/ecx = stmts->value +4735 8b/-> *esi 1/r32/ecx # List-value +4736 { +4737 $emit-subx-stmt-list:check-for-block: +4738 81 7/subop/compare *ecx 0/imm32/block # Stmt-tag +4739 75/jump-if-!= break/disp8 +4740 $emit-subx-stmt-list:block: +4741 (emit-subx-block *(ebp+8) %ecx *(ebp+0x10)) +4742 } +4743 { +4744 $emit-subx-stmt-list:check-for-stmt: +4745 81 7/subop/compare *ecx 1/imm32/stmt1 # Stmt-tag +4746 0f 85/jump-if-!= break/disp32 +4747 $emit-subx-stmt-list:stmt1: +4748 { +4749 (is-mu-branch? %ecx) # => eax +4750 3d/compare-eax-and 0/imm32/false +4751 0f 84/jump-if-= break/disp32 +4752 $emit-subx-stmt-list:branch-stmt: +4753 # if !var-seen? break +4754 81 7/subop/compare %edx 0/imm32/false +4755 0f 84/jump-if-= break/disp32 +4756 $emit-subx-stmt-list:branch-stmt-and-var-seen: +4757 +-- 26 lines: # unconditional loops ----------------------------------------------------------------------------------------------------------------------------------------------------- +4783 +-- 15 lines: # unconditional breaks ---------------------------------------------------------------------------------------------------------------------------------------------------- +4798 +-- 37 lines: # simple conditional branches without a target ---------------------------------------------------------------------------------------------------------------------------- +4835 +-- 19 lines: # conditional branches with an explicit target ---------------------------------------------------------------------------------------------------------------------------- +4854 } +4855 $emit-subx-stmt-list:1-to-1: +4856 (emit-subx-statement *(ebp+8) %ecx Primitives *Program) +4857 } +4858 { +4859 $emit-subx-stmt-list:check-for-vardef: +4860 81 7/subop/compare *ecx 2/imm32/vardef # Stmt-tag +4861 75/jump-if-!= break/disp8 +4862 $emit-subx-stmt-list:vardef: +4863 (emit-subx-var-def *(ebp+8) %ecx) +4864 (push *(ebp+0x10) *(ecx+4)) # Vardef-var +4865 # var-seen? = true +4866 ba/copy-to-edx 1/imm32/true +4867 } 4868 { -4869 74/jump-if-= break/disp8 -4870 $emit-cleanup-code-until-depth:reclaim-var-in-register: -4871 (emit-indent *(ebp+8) *Curr-block-depth) -4872 (write-buffered *(ebp+8) "8f 0/subop/pop %") -4873 (write-buffered *(ebp+8) *(ebx+0x10)) -4874 (write-buffered *(ebp+8) Newline) -4875 } -4876 # otherwise v is on the stack -4877 { -4878 75/jump-if-!= break/disp8 -4879 $emit-cleanup-code-until-depth:reclaim-var-on-stack: -4880 50/push-eax -4881 (size-of %ebx) # => eax -4882 # don't emit code for labels -4883 3d/compare-eax-and 0/imm32 -4884 74/jump-if-= break/disp8 -4885 # -4886 (emit-indent *(ebp+8) *Curr-block-depth) -4887 (write-buffered *(ebp+8) "81 0/subop/add %esp ") -4888 (print-int32-buffered *(ebp+8) %eax) -4889 (write-buffered *(ebp+8) "/imm32\n") -4890 58/pop-to-eax +4869 $emit-subx-stmt-list:check-for-regvardef: +4870 81 7/subop/compare *ecx 3/imm32/regvardef # Stmt-tag +4871 0f 85/jump-if-!= break/disp32 +4872 $emit-subx-stmt-list:regvardef: +4873 # TODO: ensure that there's exactly one output +4874 # var output/eax: (handle var) = curr-stmt->outputs->value +4875 8b/-> *(ecx+0xc) 0/r32/eax +4876 8b/-> *eax 0/r32/eax +4877 # ensure that output is in a register +4878 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +4879 0f 84/jump-if-= $emit-subx-stmt-list:abort-regvardef-without-register/disp32 +4880 # emit spill +4881 (emit-indent *(ebp+8) *Curr-block-depth) +4882 (write-buffered *(ebp+8) "ff 6/subop/push %") +4883 (write-buffered *(ebp+8) *(eax+0x10)) +4884 (write-buffered *(ebp+8) Newline) +4885 # register variable definition +4886 (push *(ebp+0x10) %eax) +4887 # emit the instruction as usual +4888 (emit-subx-statement *(ebp+8) %ecx Primitives *Program) +4889 # var-seen? = true +4890 ba/copy-to-edx 1/imm32/true 4891 } -4892 # curr -= 4 -4893 2d/subtract-from-eax 4/imm32 -4894 e9/jump loop/disp32 -4895 } -4896 $emit-cleanup-code-until-depth:end: -4897 # . restore registers -4898 5b/pop-to-ebx -4899 5a/pop-to-edx -4900 59/pop-to-ecx -4901 58/pop-to-eax -4902 # . epilogue -4903 89/<- %esp 5/r32/ebp -4904 5d/pop-to-ebp -4905 c3/return -4906 -4907 # emit clean-up code for 'vars' until a given label is encountered -4908 # doesn't actually modify 'vars' so we need traverse manually inside the stack -4909 emit-cleanup-code-until-target: # out: (addr buffered-file), vars: (addr stack (handle var)), until-block-label: (addr array byte) -4910 # . prologue -4911 55/push-ebp -4912 89/<- %ebp 4/r32/esp -4913 # . save registers -4914 50/push-eax -4915 51/push-ecx -4916 52/push-edx -4917 53/push-ebx -4918 # ecx = vars -4919 8b/-> *(ebp+0xc) 1/r32/ecx -4920 # var eax: int = vars->top -4921 8b/-> *ecx 0/r32/eax -4922 # var min/ecx: (address (handle var)) = vars->data -4923 81 0/subop/add %ecx 8/imm32 -4924 # var curr/edx: (address (handle var)) = &vars->data[vars->top - 4] -4925 81 5/subop/subtract %eax 4/imm32 -4926 8d/copy-address *(ecx+eax) 2/r32/edx -4927 { -4928 $emit-cleanup-code-until-target:loop: -4929 # if (curr < min) break -4930 39/compare %edx 1/r32/ecx -4931 0f 82/jump-if-addr< break/disp32 -4932 # var v/ebx: (handle var) = *curr -4933 8b/-> *edx 3/r32/ebx -4934 # if (v->name == until-block-label) break -4935 (string-equal? *ebx *(ebp+0x10)) # => eax -4936 3d/compare-eax-and 0/imm32/false -4937 0f 85/jump-if-!= break/disp32 -4938 # if v is in a register -4939 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register -4940 { -4941 74/jump-if-= break/disp8 -4942 $emit-cleanup-code-until-target:reclaim-var-in-register: -4943 (emit-indent *(ebp+8) *Curr-block-depth) -4944 (write-buffered *(ebp+8) "8f 0/subop/pop %") -4945 (write-buffered *(ebp+8) *(ebx+0x10)) -4946 (write-buffered *(ebp+8) Newline) -4947 } -4948 # otherwise v is on the stack -4949 { -4950 75/jump-if-!= break/disp8 -4951 $emit-cleanup-code-until-target:reclaim-var-on-stack: -4952 (size-of %ebx) # => eax -4953 # don't emit code for labels -4954 3d/compare-eax-and 0/imm32 -4955 74/jump-if-= break/disp8 -4956 # -4957 (emit-indent *(ebp+8) *Curr-block-depth) -4958 (write-buffered *(ebp+8) "81 0/subop/add %esp ") -4959 (print-int32-buffered *(ebp+8) %eax) -4960 (write-buffered *(ebp+8) "/imm32\n") -4961 } -4962 # curr -= 4 -4963 81 5/subop/subtract %edx 4/imm32 -4964 e9/jump loop/disp32 -4965 } -4966 $emit-cleanup-code-until-target:end: -4967 # . restore registers -4968 5b/pop-to-ebx -4969 5a/pop-to-edx -4970 59/pop-to-ecx -4971 58/pop-to-eax -4972 # . epilogue -4973 89/<- %esp 5/r32/ebp -4974 5d/pop-to-ebp -4975 c3/return -4976 -4977 # clean up global state for 'vars' until some block depth -4978 clean-up-blocks: # vars: (addr stack (handle var)), until-block-depth: int -4979 # . prologue -4980 55/push-ebp -4981 89/<- %ebp 4/r32/esp -4982 # . save registers -4983 50/push-eax -4984 51/push-ecx -4985 56/push-esi -4986 # esi = vars -4987 8b/-> *(ebp+8) 6/r32/esi -4988 # ecx = until-block-depth -4989 8b/-> *(ebp+0xc) 1/r32/ecx -4990 { -4991 $clean-up-blocks:reclaim-loop: -4992 # if (vars->top <= 0) break -4993 81 7/subop/compare *esi 0/imm32 # Stack-top -4994 7e/jump-if-<= break/disp8 -4995 # var v/eax: (handle var) = top(vars) -4996 (top %esi) # => eax -4997 # if (v->block-depth < until-block-depth) break -4998 39/compare *(eax+8) 1/r32/ecx # Var-block-depth -4999 7c/jump-if-< break/disp8 -5000 # if v is on the stack, update Next-local-stack-offset -5001 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -5002 { -5003 75/jump-if-!= break/disp8 -5004 $clean-up-blocks:reclaim-var-on-stack: -5005 (size-of %eax) # => eax -5006 01/add *Next-local-stack-offset 0/r32/eax -5007 } -5008 (pop %esi) -5009 e9/jump loop/disp32 -5010 } -5011 $clean-up-blocks:end: -5012 # . restore registers -5013 5e/pop-to-esi -5014 59/pop-to-ecx -5015 58/pop-to-eax -5016 # . epilogue -5017 89/<- %esp 5/r32/ebp -5018 5d/pop-to-ebp -5019 c3/return -5020 -5021 emit-subx-var-def: # out: (addr buffered-file), stmt: (handle statement) -5022 # . prologue -5023 55/push-ebp -5024 89/<- %ebp 4/r32/esp -5025 # . save registers -5026 50/push-eax -5027 51/push-ecx -5028 # eax = stmt -5029 8b/-> *(ebp+0xc) 0/r32/eax -5030 # var n/eax: int = size-of(stmt->var) -5031 (size-of *(eax+4)) # Vardef-var => eax -5032 # while n > 0 -5033 { -5034 3d/compare-eax-with 0/imm32 -5035 7e/jump-if-<= break/disp8 -5036 (emit-indent *(ebp+8) *Curr-block-depth) -5037 (write-buffered *(ebp+8) "68/push 0/imm32\n") -5038 # n -= 4 -5039 2d/subtract-from-eax 4/imm32 -5040 # -5041 eb/jump loop/disp8 -5042 } -5043 $emit-subx-var-def:end: -5044 # . restore registers -5045 59/pop-to-ecx -5046 58/pop-to-eax -5047 # . epilogue -5048 89/<- %esp 5/r32/ebp -5049 5d/pop-to-ebp -5050 c3/return -5051 -5052 emit-subx-statement: # out: (addr buffered-file), stmt: (handle statement), primitives: (handle primitive), functions: (handle function) -5053 # . prologue -5054 55/push-ebp -5055 89/<- %ebp 4/r32/esp -5056 # . save registers -5057 50/push-eax -5058 51/push-ecx -5059 # if stmt matches a primitive, emit it +4892 $emit-subx-stmt-list:continue: +4893 # TODO: raise an error on unrecognized Stmt-tag +4894 8b/-> *(esi+4) 6/r32/esi # List-next +4895 e9/jump loop/disp32 +4896 } +4897 $emit-subx-stmt-list:emit-cleanup: +4898 (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth) +4899 $emit-subx-stmt-list:cleanup: +4900 (clean-up-blocks *(ebp+0x10) *Curr-block-depth) +4901 $emit-subx-stmt-list:end: +4902 # . restore registers +4903 5e/pop-to-esi +4904 5b/pop-to-ebx +4905 5a/pop-to-edx +4906 59/pop-to-ecx +4907 58/pop-to-eax +4908 # . epilogue +4909 89/<- %esp 5/r32/ebp +4910 5d/pop-to-ebp +4911 c3/return +4912 +4913 $emit-subx-stmt-list:abort-regvardef-without-register: +4914 # error("var '" var->name "' initialized from an instruction must live in a register\n") +4915 (write-buffered Stderr "var '") +4916 (write-buffered Stderr *eax) # Var-name +4917 (write-buffered Stderr "' initialized from an instruction must live in a register\n") +4918 (flush Stderr) +4919 # . syscall(exit, 1) +4920 bb/copy-to-ebx 1/imm32 +4921 b8/copy-to-eax 1/imm32/exit +4922 cd/syscall 0x80/imm8 +4923 # never gets here +4924 +4925 emit-subx-cleanup-and-unconditional-nonlocal-branch: # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack (handle var)) +4926 # . prologue +4927 55/push-ebp +4928 89/<- %ebp 4/r32/esp +4929 # . save registers +4930 50/push-eax +4931 51/push-ecx +4932 52/push-edx +4933 # ecx = stmt +4934 8b/-> *(ebp+0xc) 1/r32/ecx +4935 # var target/edx: (addr array byte) = curr-stmt->inouts->value->name +4936 8b/-> *(ecx+8) 2/r32/edx # Stmt1-inouts +4937 8b/-> *edx 2/r32/edx # List-value +4938 8b/-> *edx 2/r32/edx # Var-name +4939 # clean up until target block +4940 (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %edx) +4941 # emit jump to target block +4942 (emit-indent *(ebp+8) *Curr-block-depth) +4943 (write-buffered *(ebp+8) "e9/jump ") +4944 (write-buffered *(ebp+8) %edx) +4945 (string-starts-with? *(ecx+4) "break") +4946 3d/compare-eax-and 0/imm32/false +4947 { +4948 74/jump-if-= break/disp8 +4949 (write-buffered *(ebp+8) ":break/disp32\n") +4950 } +4951 3d/compare-eax-and 0/imm32/false # just in case the function call modified flags +4952 { +4953 75/jump-if-!= break/disp8 +4954 (write-buffered *(ebp+8) ":loop/disp32\n") +4955 } +4956 $emit-subx-cleanup-and-unconditional-nonlocal-branch:end: +4957 # . restore registers +4958 5a/pop-to-edx +4959 59/pop-to-ecx +4960 58/pop-to-eax +4961 # . epilogue +4962 89/<- %esp 5/r32/ebp +4963 5d/pop-to-ebp +4964 c3/return +4965 +4966 is-mu-branch?: # stmt: (addr stmt1) -> result/eax: boolean +4967 # . prologue +4968 55/push-ebp +4969 89/<- %ebp 4/r32/esp +4970 # . save registers +4971 51/push-ecx +4972 # ecx = stmt +4973 8b/-> *(ebp+8) 1/r32/ecx +4974 # if (stmt->operation starts with "loop") return true +4975 (string-starts-with? *(ecx+4) "loop") # Stmt1-operation => eax +4976 3d/compare-eax-and 0/imm32/false +4977 75/jump-if-not-equal $is-mu-branch?:end/disp8 +4978 # otherwise return (stmt->operation starts with "break") +4979 (string-starts-with? *(ecx+4) "break") # Stmt1-operation => eax +4980 $is-mu-branch?:end: +4981 # . restore registers +4982 59/pop-to-ecx +4983 # . epilogue +4984 89/<- %esp 5/r32/ebp +4985 5d/pop-to-ebp +4986 c3/return +4987 +4988 emit-reverse-break: # out: (addr buffered-file), stmt: (addr stmt1) +4989 # . prologue +4990 55/push-ebp +4991 89/<- %ebp 4/r32/esp +4992 # . save registers +4993 50/push-eax +4994 # eax = stmt +4995 8b/-> *(ebp+0xc) 0/r32/eax +4996 # +4997 (get Reverse-branch *(eax+4) 8 "reverse-branch: ") # Stmt1-operation => eax: (addr addr array byte) +4998 (emit-indent *(ebp+8) *Curr-block-depth) +4999 (write-buffered *(ebp+8) *eax) +5000 (write-buffered *(ebp+8) " break/disp32\n") +5001 $emit-reverse-break:end: +5002 # . restore registers +5003 58/pop-to-eax +5004 # . epilogue +5005 89/<- %esp 5/r32/ebp +5006 5d/pop-to-ebp +5007 c3/return +5008 +5009 == data +5010 +5011 Reverse-branch: # (table string string) +5012 # a table is a stream +5013 0xa0/imm32/write +5014 0/imm32/read +5015 0xa0/imm32/length +5016 # data +5017 "break-if-="/imm32 "0f 85/jump-if-!="/imm32 +5018 "loop-if-="/imm32 "0f 85/jump-if-!="/imm32 +5019 "break-if-!="/imm32 "0f 84/jump-if-="/imm32 +5020 "loop-if-!="/imm32 "0f 84/jump-if-="/imm32 +5021 "break-if-<"/imm32 "0f 8d/jump-if->="/imm32 +5022 "loop-if-<"/imm32 "0f 8d/jump-if->="/imm32 +5023 "break-if->"/imm32 "0f 8e/jump-if-<="/imm32 +5024 "loop-if->"/imm32 "0f 8e/jump-if-<="/imm32 +5025 "break-if-<="/imm32 "0f 87/jump-if->"/imm32 +5026 "loop-if-<="/imm32 "0f 87/jump-if->"/imm32 +5027 "break-if->="/imm32 "0f 8c/jump-if-<"/imm32 +5028 "loop-if->="/imm32 "0f 8c/jump-if-<"/imm32 +5029 "break-if-addr<"/imm32 "0f 83/jump-if-addr>="/imm32 +5030 "loop-if-addr<"/imm32 "0f 83/jump-if-addr>="/imm32 +5031 "break-if-addr>"/imm32 "0f 86/jump-if-addr<="/imm32 +5032 "loop-if-addr>"/imm32 "0f 86/jump-if-addr<="/imm32 +5033 "break-if-addr<="/imm32 "0f 87/jump-if-addr>"/imm32 +5034 "loop-if-addr<="/imm32 "0f 87/jump-if-addr>"/imm32 +5035 "break-if-addr>="/imm32 "0f 82/jump-if-addr<"/imm32 +5036 "loop-if-addr>="/imm32 "0f 82/jump-if-addr<"/imm32 +5037 +5038 == code +5039 +5040 emit-unconditional-jump-to-depth: # out: (addr buffered-file), vars: (addr stack (handle var)), depth: int, label-suffix: (addr array byte) +5041 # . prologue +5042 55/push-ebp +5043 89/<- %ebp 4/r32/esp +5044 # . save registers +5045 50/push-eax +5046 51/push-ecx +5047 52/push-edx +5048 53/push-ebx +5049 # ecx = vars +5050 8b/-> *(ebp+0xc) 1/r32/ecx +5051 # var eax: int = vars->top +5052 8b/-> *ecx 0/r32/eax +5053 # var min/ecx: (address (handle var)) = vars->data +5054 81 0/subop/add %ecx 8/imm32 +5055 # var curr/eax: (address (handle var)) = &vars->data[vars->top - 4] +5056 81 5/subop/subtract %eax 4/imm32 +5057 8d/copy-address *(ecx+eax) 0/r32/eax +5058 # edx = depth +5059 8b/-> *(ebp+0x10) 2/r32/edx 5060 { -5061 $emit-subx-statement:check-for-primitive: -5062 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax -5063 3d/compare-eax-and 0/imm32 -5064 74/jump-if-= break/disp8 -5065 $emit-subx-statement:primitive: -5066 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -5067 e9/jump $emit-subx-statement:end/disp32 -5068 } -5069 # else if stmt matches a function, emit a call to it -5070 { -5071 $emit-subx-statement:check-for-call: -5072 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax -5073 3d/compare-eax-and 0/imm32 -5074 74/jump-if-= break/disp8 -5075 $emit-subx-statement:call: -5076 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -5077 e9/jump $emit-subx-statement:end/disp32 -5078 } -5079 # else assume it's a SubX function (TODO: how to type-check?!) -5080 (emit-hailmary-call *(ebp+8) *(ebp+0xc)) -5081 $emit-subx-statement:end: -5082 # . restore registers -5083 59/pop-to-ecx -5084 58/pop-to-eax -5085 # . epilogue -5086 89/<- %esp 5/r32/ebp -5087 5d/pop-to-ebp -5088 c3/return -5089 -5090 $emit-subx-statement:abort: -5091 # error("couldn't translate '" stmt "'\n") -5092 (write-buffered Stderr "couldn't translate an instruction with operation '") -5093 8b/-> *(ebp+0xc) 0/r32/eax -5094 (write-buffered Stderr *(eax+4)) # Stmt1-operation -5095 (write-buffered Stderr "'\n") -5096 (flush Stderr) -5097 # . syscall(exit, 1) -5098 bb/copy-to-ebx 1/imm32 -5099 b8/copy-to-eax 1/imm32/exit -5100 cd/syscall 0x80/imm8 -5101 # never gets here -5102 -5103 emit-subx-block: # out: (addr buffered-file), block: (handle block), vars: (addr stack (handle var)) -5104 # . prologue -5105 55/push-ebp -5106 89/<- %ebp 4/r32/esp -5107 # . save registers -5108 50/push-eax -5109 51/push-ecx -5110 56/push-esi -5111 # esi = block -5112 8b/-> *(ebp+0xc) 6/r32/esi -5113 # var stmts/eax: (handle list statement) = block->statements -5114 8b/-> *(esi+4) 0/r32/eax # Block-statements -5115 # -5116 { -5117 $emit-subx-block:check-empty: -5118 81 7/subop/compare %eax 0/imm32 -5119 0f 84/jump-if-= break/disp32 -5120 (emit-indent *(ebp+8) *Curr-block-depth) -5121 (write-buffered *(ebp+8) "{\n") -5122 # var v/ecx: (addr array byte) = block->var->name -5123 8b/-> *(esi+8) 1/r32/ecx # Block-var -5124 (write-buffered *(ebp+8) *ecx) # Var-name -5125 (write-buffered *(ebp+8) ":loop:\n") -5126 ff 0/subop/increment *Curr-block-depth -5127 (push *(ebp+0x10) %ecx) -5128 (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10)) -5129 (pop *(ebp+0x10)) # => eax -5130 ff 1/subop/decrement *Curr-block-depth -5131 (emit-indent *(ebp+8) *Curr-block-depth) -5132 (write-buffered *(ebp+8) "}\n") -5133 (write-buffered *(ebp+8) *ecx) # Var-name -5134 (write-buffered *(ebp+8) ":break:\n") -5135 } -5136 $emit-subx-block:end: -5137 # . restore registers -5138 5e/pop-to-esi -5139 59/pop-to-ecx -5140 58/pop-to-eax -5141 # . epilogue -5142 89/<- %esp 5/r32/ebp -5143 5d/pop-to-ebp -5144 c3/return -5145 -5146 # Primitives supported -5147 # For each operation, put variants with hard-coded registers before flexible ones. -5148 == data -5149 Primitives: -5150 # - increment/decrement -5151 _Primitive-inc-eax: -5152 # var/eax <- increment => 40/increment-eax -5153 "increment"/imm32/name -5154 0/imm32/no-inouts -5155 Single-int-var-in-eax/imm32/outputs -5156 "40/increment-eax"/imm32/subx-name -5157 0/imm32/no-rm32 -5158 0/imm32/no-r32 -5159 0/imm32/no-imm32 -5160 0/imm32/no-disp32 -5161 0/imm32/output-is-write-only -5162 _Primitive-inc-ecx/imm32/next -5163 _Primitive-inc-ecx: -5164 # var/ecx <- increment => 41/increment-ecx -5165 "increment"/imm32/name -5166 0/imm32/no-inouts -5167 Single-int-var-in-ecx/imm32/outputs -5168 "41/increment-ecx"/imm32/subx-name -5169 0/imm32/no-rm32 -5170 0/imm32/no-r32 -5171 0/imm32/no-imm32 -5172 0/imm32/no-disp32 -5173 0/imm32/output-is-write-only -5174 _Primitive-inc-edx/imm32/next -5175 _Primitive-inc-edx: -5176 # var/edx <- increment => 42/increment-edx -5177 "increment"/imm32/name -5178 0/imm32/no-inouts -5179 Single-int-var-in-edx/imm32/outputs -5180 "42/increment-edx"/imm32/subx-name -5181 0/imm32/no-rm32 -5182 0/imm32/no-r32 -5183 0/imm32/no-imm32 -5184 0/imm32/no-disp32 -5185 0/imm32/output-is-write-only -5186 _Primitive-inc-ebx/imm32/next -5187 _Primitive-inc-ebx: -5188 # var/ebx <- increment => 43/increment-ebx -5189 "increment"/imm32/name -5190 0/imm32/no-inouts -5191 Single-int-var-in-ebx/imm32/outputs -5192 "43/increment-ebx"/imm32/subx-name -5193 0/imm32/no-rm32 -5194 0/imm32/no-r32 -5195 0/imm32/no-imm32 -5196 0/imm32/no-disp32 -5197 0/imm32/output-is-write-only -5198 _Primitive-inc-esi/imm32/next -5199 _Primitive-inc-esi: -5200 # var/esi <- increment => 46/increment-esi -5201 "increment"/imm32/name -5202 0/imm32/no-inouts -5203 Single-int-var-in-esi/imm32/outputs -5204 "46/increment-esi"/imm32/subx-name -5205 0/imm32/no-rm32 -5206 0/imm32/no-r32 -5207 0/imm32/no-imm32 -5208 0/imm32/no-disp32 -5209 0/imm32/output-is-write-only -5210 _Primitive-inc-edi/imm32/next -5211 _Primitive-inc-edi: -5212 # var/edi <- increment => 47/increment-edi -5213 "increment"/imm32/name -5214 0/imm32/no-inouts -5215 Single-int-var-in-edi/imm32/outputs -5216 "47/increment-edi"/imm32/subx-name -5217 0/imm32/no-rm32 -5218 0/imm32/no-r32 -5219 0/imm32/no-imm32 -5220 0/imm32/no-disp32 -5221 0/imm32/output-is-write-only -5222 _Primitive-dec-eax/imm32/next -5223 _Primitive-dec-eax: -5224 # var/eax <- decrement => 48/decrement-eax -5225 "decrement"/imm32/name -5226 0/imm32/no-inouts -5227 Single-int-var-in-eax/imm32/outputs -5228 "48/decrement-eax"/imm32/subx-name -5229 0/imm32/no-rm32 -5230 0/imm32/no-r32 -5231 0/imm32/no-imm32 -5232 0/imm32/no-disp32 -5233 0/imm32/output-is-write-only -5234 _Primitive-dec-ecx/imm32/next -5235 _Primitive-dec-ecx: -5236 # var/ecx <- decrement => 49/decrement-ecx -5237 "decrement"/imm32/name -5238 0/imm32/no-inouts -5239 Single-int-var-in-ecx/imm32/outputs -5240 "49/decrement-ecx"/imm32/subx-name -5241 0/imm32/no-rm32 -5242 0/imm32/no-r32 -5243 0/imm32/no-imm32 -5244 0/imm32/no-disp32 -5245 0/imm32/output-is-write-only -5246 _Primitive-dec-edx/imm32/next -5247 _Primitive-dec-edx: -5248 # var/edx <- decrement => 4a/decrement-edx -5249 "decrement"/imm32/name -5250 0/imm32/no-inouts -5251 Single-int-var-in-edx/imm32/outputs -5252 "4a/decrement-edx"/imm32/subx-name -5253 0/imm32/no-rm32 -5254 0/imm32/no-r32 -5255 0/imm32/no-imm32 -5256 0/imm32/no-disp32 -5257 0/imm32/output-is-write-only -5258 _Primitive-dec-ebx/imm32/next -5259 _Primitive-dec-ebx: -5260 # var/ebx <- decrement => 4b/decrement-ebx -5261 "decrement"/imm32/name -5262 0/imm32/no-inouts -5263 Single-int-var-in-ebx/imm32/outputs -5264 "4b/decrement-ebx"/imm32/subx-name -5265 0/imm32/no-rm32 -5266 0/imm32/no-r32 -5267 0/imm32/no-imm32 -5268 0/imm32/no-disp32 -5269 0/imm32/output-is-write-only -5270 _Primitive-dec-esi/imm32/next -5271 _Primitive-dec-esi: -5272 # var/esi <- decrement => 4e/decrement-esi -5273 "decrement"/imm32/name -5274 0/imm32/no-inouts -5275 Single-int-var-in-esi/imm32/outputs -5276 "4e/decrement-esi"/imm32/subx-name -5277 0/imm32/no-rm32 -5278 0/imm32/no-r32 -5279 0/imm32/no-imm32 -5280 0/imm32/no-disp32 -5281 0/imm32/output-is-write-only -5282 _Primitive-dec-edi/imm32/next -5283 _Primitive-dec-edi: -5284 # var/edi <- decrement => 4f/decrement-edi -5285 "decrement"/imm32/name -5286 0/imm32/no-inouts -5287 Single-int-var-in-edi/imm32/outputs -5288 "4f/decrement-edi"/imm32/subx-name -5289 0/imm32/no-rm32 -5290 0/imm32/no-r32 -5291 0/imm32/no-imm32 -5292 0/imm32/no-disp32 -5293 0/imm32/output-is-write-only -5294 _Primitive-inc-mem/imm32/next -5295 _Primitive-inc-mem: -5296 # increment var => ff 0/subop/increment *(ebp+__) -5297 "increment"/imm32/name -5298 Single-int-var-on-stack/imm32/inouts -5299 0/imm32/no-outputs -5300 "ff 0/subop/increment"/imm32/subx-name -5301 1/imm32/rm32-is-first-inout -5302 0/imm32/no-r32 -5303 0/imm32/no-imm32 -5304 0/imm32/no-disp32 -5305 0/imm32/output-is-write-only -5306 _Primitive-inc-reg/imm32/next -5307 _Primitive-inc-reg: -5308 # var/reg <- increment => ff 0/subop/increment %__ -5309 "increment"/imm32/name -5310 0/imm32/no-inouts -5311 Single-int-var-in-some-register/imm32/outputs -5312 "ff 0/subop/increment"/imm32/subx-name -5313 3/imm32/rm32-is-first-output -5314 0/imm32/no-r32 -5315 0/imm32/no-imm32 -5316 0/imm32/no-disp32 -5317 0/imm32/output-is-write-only -5318 _Primitive-dec-mem/imm32/next -5319 _Primitive-dec-mem: -5320 # decrement var => ff 1/subop/decrement *(ebp+__) -5321 "decrement"/imm32/name -5322 Single-int-var-on-stack/imm32/inouts -5323 0/imm32/no-outputs -5324 "ff 1/subop/decrement"/imm32/subx-name -5325 1/imm32/rm32-is-first-inout -5326 0/imm32/no-r32 -5327 0/imm32/no-imm32 -5328 0/imm32/no-disp32 -5329 0/imm32/output-is-write-only -5330 _Primitive-dec-reg/imm32/next -5331 _Primitive-dec-reg: -5332 # var/reg <- decrement => ff 1/subop/decrement %__ -5333 "decrement"/imm32/name -5334 0/imm32/no-inouts -5335 Single-int-var-in-some-register/imm32/outputs -5336 "ff 1/subop/decrement"/imm32/subx-name -5337 3/imm32/rm32-is-first-output -5338 0/imm32/no-r32 -5339 0/imm32/no-imm32 -5340 0/imm32/no-disp32 -5341 0/imm32/output-is-write-only -5342 _Primitive-add-to-eax/imm32/next -5343 # - add -5344 _Primitive-add-to-eax: -5345 # var/eax <- add lit => 05/add-to-eax lit/imm32 -5346 "add"/imm32/name -5347 Single-lit-var/imm32/inouts -5348 Single-int-var-in-eax/imm32/outputs -5349 "05/add-to-eax"/imm32/subx-name -5350 0/imm32/no-rm32 -5351 0/imm32/no-r32 -5352 1/imm32/imm32-is-first-inout -5353 0/imm32/no-disp32 -5354 0/imm32/output-is-write-only -5355 _Primitive-add-reg-to-reg/imm32/next -5356 _Primitive-add-reg-to-reg: -5357 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 -5358 "add"/imm32/name -5359 Single-int-var-in-some-register/imm32/inouts -5360 Single-int-var-in-some-register/imm32/outputs -5361 "01/add-to"/imm32/subx-name -5362 3/imm32/rm32-is-first-output -5363 1/imm32/r32-is-first-inout -5364 0/imm32/no-imm32 -5365 0/imm32/no-disp32 -5366 0/imm32/output-is-write-only -5367 _Primitive-add-reg-to-mem/imm32/next -5368 _Primitive-add-reg-to-mem: -5369 # add-to var1 var2/reg => 01/add-to var1 var2/r32 -5370 "add-to"/imm32/name -5371 Two-args-int-stack-int-reg/imm32/inouts -5372 0/imm32/outputs -5373 "01/add-to"/imm32/subx-name -5374 1/imm32/rm32-is-first-inout -5375 2/imm32/r32-is-second-inout -5376 0/imm32/no-imm32 -5377 0/imm32/no-disp32 -5378 0/imm32/output-is-write-only -5379 _Primitive-add-mem-to-reg/imm32/next -5380 _Primitive-add-mem-to-reg: -5381 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 -5382 "add"/imm32/name -5383 Single-int-var-on-stack/imm32/inouts -5384 Single-int-var-in-some-register/imm32/outputs -5385 "03/add"/imm32/subx-name -5386 1/imm32/rm32-is-first-inout -5387 3/imm32/r32-is-first-output -5388 0/imm32/no-imm32 -5389 0/imm32/no-disp32 -5390 0/imm32/output-is-write-only -5391 _Primitive-add-lit-to-reg/imm32/next -5392 _Primitive-add-lit-to-reg: -5393 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 -5394 "add"/imm32/name -5395 Single-lit-var/imm32/inouts -5396 Single-int-var-in-some-register/imm32/outputs -5397 "81 0/subop/add"/imm32/subx-name -5398 3/imm32/rm32-is-first-output -5399 0/imm32/no-r32 -5400 1/imm32/imm32-is-first-inout -5401 0/imm32/no-disp32 -5402 0/imm32/output-is-write-only -5403 _Primitive-add-lit-to-mem/imm32/next -5404 _Primitive-add-lit-to-mem: -5405 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 -5406 "add-to"/imm32/name -5407 Int-var-and-literal/imm32/inouts -5408 0/imm32/outputs -5409 "81 0/subop/add"/imm32/subx-name -5410 1/imm32/rm32-is-first-inout -5411 0/imm32/no-r32 -5412 2/imm32/imm32-is-second-inout -5413 0/imm32/no-disp32 -5414 0/imm32/output-is-write-only -5415 _Primitive-subtract-from-eax/imm32/next -5416 # - subtract -5417 _Primitive-subtract-from-eax: -5418 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 -5419 "subtract"/imm32/name -5420 Single-lit-var/imm32/inouts -5421 Single-int-var-in-eax/imm32/outputs -5422 "2d/subtract-from-eax"/imm32/subx-name -5423 0/imm32/no-rm32 -5424 0/imm32/no-r32 -5425 1/imm32/imm32-is-first-inout -5426 0/imm32/no-disp32 -5427 0/imm32/output-is-write-only -5428 _Primitive-subtract-reg-from-reg/imm32/next -5429 _Primitive-subtract-reg-from-reg: -5430 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 -5431 "subtract"/imm32/name -5432 Single-int-var-in-some-register/imm32/inouts -5433 Single-int-var-in-some-register/imm32/outputs -5434 "29/subtract-from"/imm32/subx-name -5435 3/imm32/rm32-is-first-output -5436 1/imm32/r32-is-first-inout -5437 0/imm32/no-imm32 -5438 0/imm32/no-disp32 -5439 0/imm32/output-is-write-only -5440 _Primitive-subtract-reg-from-mem/imm32/next -5441 _Primitive-subtract-reg-from-mem: -5442 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 -5443 "subtract-from"/imm32/name -5444 Two-args-int-stack-int-reg/imm32/inouts -5445 0/imm32/outputs -5446 "29/subtract-from"/imm32/subx-name -5447 1/imm32/rm32-is-first-inout -5448 2/imm32/r32-is-second-inout -5449 0/imm32/no-imm32 -5450 0/imm32/no-disp32 -5451 0/imm32/output-is-write-only -5452 _Primitive-subtract-mem-from-reg/imm32/next -5453 _Primitive-subtract-mem-from-reg: -5454 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 -5455 "subtract"/imm32/name -5456 Single-int-var-on-stack/imm32/inouts -5457 Single-int-var-in-some-register/imm32/outputs -5458 "2b/subtract"/imm32/subx-name -5459 1/imm32/rm32-is-first-inout -5460 3/imm32/r32-is-first-output -5461 0/imm32/no-imm32 -5462 0/imm32/no-disp32 -5463 0/imm32/output-is-write-only -5464 _Primitive-subtract-lit-from-reg/imm32/next -5465 _Primitive-subtract-lit-from-reg: -5466 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 -5467 "subtract"/imm32/name -5468 Single-lit-var/imm32/inouts -5469 Single-int-var-in-some-register/imm32/outputs -5470 "81 5/subop/subtract"/imm32/subx-name -5471 3/imm32/rm32-is-first-output -5472 0/imm32/no-r32 -5473 1/imm32/imm32-is-first-inout -5474 0/imm32/no-disp32 -5475 0/imm32/output-is-write-only -5476 _Primitive-subtract-lit-from-mem/imm32/next -5477 _Primitive-subtract-lit-from-mem: -5478 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 -5479 "subtract-from"/imm32/name -5480 Int-var-and-literal/imm32/inouts -5481 0/imm32/outputs -5482 "81 5/subop/subtract"/imm32/subx-name -5483 1/imm32/rm32-is-first-inout -5484 0/imm32/no-r32 -5485 2/imm32/imm32-is-first-inout -5486 0/imm32/no-disp32 -5487 0/imm32/output-is-write-only -5488 _Primitive-and-with-eax/imm32/next -5489 # - and -5490 _Primitive-and-with-eax: -5491 # var/eax <- and lit => 25/and-with-eax lit/imm32 -5492 "and"/imm32/name -5493 Single-lit-var/imm32/inouts -5494 Single-int-var-in-eax/imm32/outputs -5495 "25/and-with-eax"/imm32/subx-name -5496 0/imm32/no-rm32 -5497 0/imm32/no-r32 -5498 1/imm32/imm32-is-first-inout -5499 0/imm32/no-disp32 -5500 0/imm32/output-is-write-only -5501 _Primitive-and-reg-with-reg/imm32/next -5502 _Primitive-and-reg-with-reg: -5503 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 -5504 "and"/imm32/name -5505 Single-int-var-in-some-register/imm32/inouts -5506 Single-int-var-in-some-register/imm32/outputs -5507 "21/and-with"/imm32/subx-name -5508 3/imm32/rm32-is-first-output -5509 1/imm32/r32-is-first-inout -5510 0/imm32/no-imm32 -5511 0/imm32/no-disp32 -5512 0/imm32/output-is-write-only -5513 _Primitive-and-reg-with-mem/imm32/next -5514 _Primitive-and-reg-with-mem: -5515 # and-with var1 var2/reg => 21/and-with var1 var2/r32 -5516 "and-with"/imm32/name -5517 Two-args-int-stack-int-reg/imm32/inouts -5518 0/imm32/outputs -5519 "21/and-with"/imm32/subx-name -5520 1/imm32/rm32-is-first-inout -5521 2/imm32/r32-is-second-inout -5522 0/imm32/no-imm32 -5523 0/imm32/no-disp32 -5524 0/imm32/output-is-write-only -5525 _Primitive-and-mem-with-reg/imm32/next -5526 _Primitive-and-mem-with-reg: -5527 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 -5528 "and"/imm32/name -5529 Single-int-var-on-stack/imm32/inouts -5530 Single-int-var-in-some-register/imm32/outputs -5531 "23/and"/imm32/subx-name -5532 1/imm32/rm32-is-first-inout -5533 3/imm32/r32-is-first-output -5534 0/imm32/no-imm32 -5535 0/imm32/no-disp32 -5536 0/imm32/output-is-write-only -5537 _Primitive-and-lit-with-reg/imm32/next -5538 _Primitive-and-lit-with-reg: -5539 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 -5540 "and"/imm32/name -5541 Single-lit-var/imm32/inouts -5542 Single-int-var-in-some-register/imm32/outputs -5543 "81 4/subop/and"/imm32/subx-name -5544 3/imm32/rm32-is-first-output -5545 0/imm32/no-r32 -5546 1/imm32/imm32-is-first-inout -5547 0/imm32/no-disp32 -5548 0/imm32/output-is-write-only -5549 _Primitive-and-lit-with-mem/imm32/next -5550 _Primitive-and-lit-with-mem: -5551 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 -5552 "and-with"/imm32/name -5553 Int-var-and-literal/imm32/inouts -5554 0/imm32/outputs -5555 "81 4/subop/and"/imm32/subx-name -5556 1/imm32/rm32-is-first-inout -5557 0/imm32/no-r32 -5558 2/imm32/imm32-is-first-inout -5559 0/imm32/no-disp32 -5560 0/imm32/output-is-write-only -5561 _Primitive-or-with-eax/imm32/next -5562 # - or -5563 _Primitive-or-with-eax: -5564 # var/eax <- or lit => 0d/or-with-eax lit/imm32 -5565 "or"/imm32/name -5566 Single-lit-var/imm32/inouts -5567 Single-int-var-in-eax/imm32/outputs -5568 "0d/or-with-eax"/imm32/subx-name +5061 $emit-unconditional-jump-to-depth:loop: +5062 # if (curr < min) break +5063 39/compare %eax 1/r32/ecx +5064 0f 82/jump-if-addr< break/disp32 +5065 # var v/ebx: (handle var) = *curr +5066 8b/-> *eax 3/r32/ebx +5067 # if (v->block-depth < until-block-depth) break +5068 39/compare *(ebx+8) 2/r32/edx # Var-block-depth +5069 0f 8c/jump-if-< break/disp32 +5070 { +5071 $emit-unconditional-jump-to-depth:check: +5072 # if v->block-depth != until-block-depth, continue +5073 39/compare *(ebx+8) 2/r32/edx # Var-block-depth +5074 0f 85/jump-if-!= break/disp32 +5075 $emit-unconditional-jump-to-depth:depth-found: +5076 # if v is not a literal, continue +5077 # . var eax: int = size-of(v) +5078 50/push-eax +5079 (size-of %ebx) # => eax +5080 # . if (eax != 0) continue +5081 3d/compare-eax-and 0/imm32 +5082 58/pop-to-eax +5083 # +5084 0f 85/jump-if-!= break/disp32 +5085 $emit-unconditional-jump-to-depth:label-found: +5086 # emit unconditional jump, then return +5087 (emit-indent *(ebp+8) *Curr-block-depth) +5088 (write-buffered *(ebp+8) "e9/jump ") +5089 (write-buffered *(ebp+8) *ebx) # Var-name +5090 (write-buffered *(ebp+8) ":") +5091 (write-buffered *(ebp+8) *(ebp+0x14)) +5092 (write-buffered *(ebp+8) "/disp32\n") +5093 eb/jump $emit-unconditional-jump-to-depth:end/disp8 +5094 } +5095 # curr -= 4 +5096 2d/subtract-from-eax 4/imm32 +5097 e9/jump loop/disp32 +5098 } +5099 # TODO: error if no label at 'depth' was found +5100 $emit-unconditional-jump-to-depth:end: +5101 # . restore registers +5102 5b/pop-to-ebx +5103 5a/pop-to-edx +5104 59/pop-to-ecx +5105 58/pop-to-eax +5106 # . epilogue +5107 89/<- %esp 5/r32/ebp +5108 5d/pop-to-ebp +5109 c3/return +5110 +5111 # emit clean-up code for 'vars' until some block depth +5112 # doesn't actually modify 'vars' so we need traverse manually inside the stack +5113 emit-cleanup-code-until-depth: # out: (addr buffered-file), vars: (addr stack (handle var)), until-block-depth: int +5114 # . prologue +5115 55/push-ebp +5116 89/<- %ebp 4/r32/esp +5117 # . save registers +5118 50/push-eax +5119 51/push-ecx +5120 52/push-edx +5121 53/push-ebx +5122 # ecx = vars +5123 8b/-> *(ebp+0xc) 1/r32/ecx +5124 # var eax: int = vars->top +5125 8b/-> *ecx 0/r32/eax +5126 # var min/ecx: (address (handle var)) = vars->data +5127 81 0/subop/add %ecx 8/imm32 +5128 # var curr/eax: (address (handle var)) = &vars->data[vars->top - 4] +5129 81 5/subop/subtract %eax 4/imm32 +5130 8d/copy-address *(ecx+eax) 0/r32/eax +5131 # edx = until-block-depth +5132 8b/-> *(ebp+0x10) 2/r32/edx +5133 { +5134 $emit-cleanup-code-until-depth:loop: +5135 # if (curr < min) break +5136 39/compare %eax 1/r32/ecx +5137 0f 82/jump-if-addr< break/disp32 +5138 # var v/ebx: (handle var) = *curr +5139 8b/-> *eax 3/r32/ebx +5140 # if (v->block-depth < until-block-depth) break +5141 39/compare *(ebx+8) 2/r32/edx # Var-block-depth +5142 0f 8c/jump-if-< break/disp32 +5143 # if v is in a register +5144 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +5145 { +5146 74/jump-if-= break/disp8 +5147 $emit-cleanup-code-until-depth:reclaim-var-in-register: +5148 (emit-indent *(ebp+8) *Curr-block-depth) +5149 (write-buffered *(ebp+8) "8f 0/subop/pop %") +5150 (write-buffered *(ebp+8) *(ebx+0x10)) +5151 (write-buffered *(ebp+8) Newline) +5152 } +5153 # otherwise v is on the stack +5154 { +5155 75/jump-if-!= break/disp8 +5156 $emit-cleanup-code-until-depth:reclaim-var-on-stack: +5157 50/push-eax +5158 (size-of %ebx) # => eax +5159 # don't emit code for labels +5160 3d/compare-eax-and 0/imm32 +5161 74/jump-if-= break/disp8 +5162 # +5163 (emit-indent *(ebp+8) *Curr-block-depth) +5164 (write-buffered *(ebp+8) "81 0/subop/add %esp ") +5165 (print-int32-buffered *(ebp+8) %eax) +5166 (write-buffered *(ebp+8) "/imm32\n") +5167 58/pop-to-eax +5168 } +5169 # curr -= 4 +5170 2d/subtract-from-eax 4/imm32 +5171 e9/jump loop/disp32 +5172 } +5173 $emit-cleanup-code-until-depth:end: +5174 # . restore registers +5175 5b/pop-to-ebx +5176 5a/pop-to-edx +5177 59/pop-to-ecx +5178 58/pop-to-eax +5179 # . epilogue +5180 89/<- %esp 5/r32/ebp +5181 5d/pop-to-ebp +5182 c3/return +5183 +5184 # emit clean-up code for 'vars' until a given label is encountered +5185 # doesn't actually modify 'vars' so we need traverse manually inside the stack +5186 emit-cleanup-code-until-target: # out: (addr buffered-file), vars: (addr stack (handle var)), until-block-label: (addr array byte) +5187 # . prologue +5188 55/push-ebp +5189 89/<- %ebp 4/r32/esp +5190 # . save registers +5191 50/push-eax +5192 51/push-ecx +5193 52/push-edx +5194 53/push-ebx +5195 # ecx = vars +5196 8b/-> *(ebp+0xc) 1/r32/ecx +5197 # var eax: int = vars->top +5198 8b/-> *ecx 0/r32/eax +5199 # var min/ecx: (address (handle var)) = vars->data +5200 81 0/subop/add %ecx 8/imm32 +5201 # var curr/edx: (address (handle var)) = &vars->data[vars->top - 4] +5202 81 5/subop/subtract %eax 4/imm32 +5203 8d/copy-address *(ecx+eax) 2/r32/edx +5204 { +5205 $emit-cleanup-code-until-target:loop: +5206 # if (curr < min) break +5207 39/compare %edx 1/r32/ecx +5208 0f 82/jump-if-addr< break/disp32 +5209 # var v/ebx: (handle var) = *curr +5210 8b/-> *edx 3/r32/ebx +5211 # if (v->name == until-block-label) break +5212 (string-equal? *ebx *(ebp+0x10)) # => eax +5213 3d/compare-eax-and 0/imm32/false +5214 0f 85/jump-if-!= break/disp32 +5215 # if v is in a register +5216 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register +5217 { +5218 74/jump-if-= break/disp8 +5219 $emit-cleanup-code-until-target:reclaim-var-in-register: +5220 (emit-indent *(ebp+8) *Curr-block-depth) +5221 (write-buffered *(ebp+8) "8f 0/subop/pop %") +5222 (write-buffered *(ebp+8) *(ebx+0x10)) +5223 (write-buffered *(ebp+8) Newline) +5224 } +5225 # otherwise v is on the stack +5226 { +5227 75/jump-if-!= break/disp8 +5228 $emit-cleanup-code-until-target:reclaim-var-on-stack: +5229 (size-of %ebx) # => eax +5230 # don't emit code for labels +5231 3d/compare-eax-and 0/imm32 +5232 74/jump-if-= break/disp8 +5233 # +5234 (emit-indent *(ebp+8) *Curr-block-depth) +5235 (write-buffered *(ebp+8) "81 0/subop/add %esp ") +5236 (print-int32-buffered *(ebp+8) %eax) +5237 (write-buffered *(ebp+8) "/imm32\n") +5238 } +5239 # curr -= 4 +5240 81 5/subop/subtract %edx 4/imm32 +5241 e9/jump loop/disp32 +5242 } +5243 $emit-cleanup-code-until-target:end: +5244 # . restore registers +5245 5b/pop-to-ebx +5246 5a/pop-to-edx +5247 59/pop-to-ecx +5248 58/pop-to-eax +5249 # . epilogue +5250 89/<- %esp 5/r32/ebp +5251 5d/pop-to-ebp +5252 c3/return +5253 +5254 # clean up global state for 'vars' until some block depth +5255 clean-up-blocks: # vars: (addr stack (handle var)), until-block-depth: int +5256 # . prologue +5257 55/push-ebp +5258 89/<- %ebp 4/r32/esp +5259 # . save registers +5260 50/push-eax +5261 51/push-ecx +5262 56/push-esi +5263 # esi = vars +5264 8b/-> *(ebp+8) 6/r32/esi +5265 # ecx = until-block-depth +5266 8b/-> *(ebp+0xc) 1/r32/ecx +5267 { +5268 $clean-up-blocks:reclaim-loop: +5269 # if (vars->top <= 0) break +5270 81 7/subop/compare *esi 0/imm32 # Stack-top +5271 7e/jump-if-<= break/disp8 +5272 # var v/eax: (handle var) = top(vars) +5273 (top %esi) # => eax +5274 # if (v->block-depth < until-block-depth) break +5275 39/compare *(eax+8) 1/r32/ecx # Var-block-depth +5276 7c/jump-if-< break/disp8 +5277 # if v is on the stack, update Next-local-stack-offset +5278 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +5279 { +5280 75/jump-if-!= break/disp8 +5281 $clean-up-blocks:reclaim-var-on-stack: +5282 (size-of %eax) # => eax +5283 01/add *Next-local-stack-offset 0/r32/eax +5284 } +5285 (pop %esi) +5286 e9/jump loop/disp32 +5287 } +5288 $clean-up-blocks:end: +5289 # . restore registers +5290 5e/pop-to-esi +5291 59/pop-to-ecx +5292 58/pop-to-eax +5293 # . epilogue +5294 89/<- %esp 5/r32/ebp +5295 5d/pop-to-ebp +5296 c3/return +5297 +5298 emit-subx-var-def: # out: (addr buffered-file), stmt: (handle statement) +5299 # . prologue +5300 55/push-ebp +5301 89/<- %ebp 4/r32/esp +5302 # . save registers +5303 50/push-eax +5304 51/push-ecx +5305 # eax = stmt +5306 8b/-> *(ebp+0xc) 0/r32/eax +5307 # var n/eax: int = size-of(stmt->var) +5308 (size-of *(eax+4)) # Vardef-var => eax +5309 # while n > 0 +5310 { +5311 3d/compare-eax-with 0/imm32 +5312 7e/jump-if-<= break/disp8 +5313 (emit-indent *(ebp+8) *Curr-block-depth) +5314 (write-buffered *(ebp+8) "68/push 0/imm32\n") +5315 # n -= 4 +5316 2d/subtract-from-eax 4/imm32 +5317 # +5318 eb/jump loop/disp8 +5319 } +5320 $emit-subx-var-def:end: +5321 # . restore registers +5322 59/pop-to-ecx +5323 58/pop-to-eax +5324 # . epilogue +5325 89/<- %esp 5/r32/ebp +5326 5d/pop-to-ebp +5327 c3/return +5328 +5329 emit-subx-statement: # out: (addr buffered-file), stmt: (handle statement), primitives: (handle primitive), functions: (handle function) +5330 # . prologue +5331 55/push-ebp +5332 89/<- %ebp 4/r32/esp +5333 # . save registers +5334 50/push-eax +5335 51/push-ecx +5336 # handle some special cases +5337 # ecx = stmt +5338 8b/-> *(ebp+0xc) 1/r32/ecx +5339 +-- 24 lines: # array length ------------------------------------------------------------------------------------------------------------------------------------------------------------ +5363 # if stmt matches a primitive, emit it +5364 { +5365 $emit-subx-statement:check-for-primitive: +5366 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax +5367 3d/compare-eax-and 0/imm32 +5368 74/jump-if-= break/disp8 +5369 $emit-subx-statement:primitive: +5370 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +5371 e9/jump $emit-subx-statement:end/disp32 +5372 } +5373 # else if stmt matches a function, emit a call to it +5374 { +5375 $emit-subx-statement:check-for-call: +5376 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax +5377 3d/compare-eax-and 0/imm32 +5378 74/jump-if-= break/disp8 +5379 $emit-subx-statement:call: +5380 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +5381 e9/jump $emit-subx-statement:end/disp32 +5382 } +5383 # else assume it's a SubX function (TODO: how to type-check?!) +5384 (emit-hailmary-call *(ebp+8) *(ebp+0xc)) +5385 $emit-subx-statement:end: +5386 # . restore registers +5387 59/pop-to-ecx +5388 58/pop-to-eax +5389 # . epilogue +5390 89/<- %esp 5/r32/ebp +5391 5d/pop-to-ebp +5392 c3/return +5393 +5394 $emit-subx-statement:abort: +5395 # error("couldn't translate '" stmt "'\n") +5396 (write-buffered Stderr "couldn't translate an instruction with operation '") +5397 8b/-> *(ebp+0xc) 0/r32/eax +5398 (write-buffered Stderr *(eax+4)) # Stmt1-operation +5399 (write-buffered Stderr "'\n") +5400 (flush Stderr) +5401 # . syscall(exit, 1) +5402 bb/copy-to-ebx 1/imm32 +5403 b8/copy-to-eax 1/imm32/exit +5404 cd/syscall 0x80/imm8 +5405 # never gets here +5406 +5407 emit-subx-block: # out: (addr buffered-file), block: (handle block), vars: (addr stack (handle var)) +5408 # . prologue +5409 55/push-ebp +5410 89/<- %ebp 4/r32/esp +5411 # . save registers +5412 50/push-eax +5413 51/push-ecx +5414 56/push-esi +5415 # esi = block +5416 8b/-> *(ebp+0xc) 6/r32/esi +5417 # var stmts/eax: (handle list statement) = block->statements +5418 8b/-> *(esi+4) 0/r32/eax # Block-statements +5419 # +5420 { +5421 $emit-subx-block:check-empty: +5422 81 7/subop/compare %eax 0/imm32 +5423 0f 84/jump-if-= break/disp32 +5424 (emit-indent *(ebp+8) *Curr-block-depth) +5425 (write-buffered *(ebp+8) "{\n") +5426 # var v/ecx: (addr array byte) = block->var->name +5427 8b/-> *(esi+8) 1/r32/ecx # Block-var +5428 (write-buffered *(ebp+8) *ecx) # Var-name +5429 (write-buffered *(ebp+8) ":loop:\n") +5430 ff 0/subop/increment *Curr-block-depth +5431 (push *(ebp+0x10) %ecx) +5432 (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10)) +5433 (pop *(ebp+0x10)) # => eax +5434 ff 1/subop/decrement *Curr-block-depth +5435 (emit-indent *(ebp+8) *Curr-block-depth) +5436 (write-buffered *(ebp+8) "}\n") +5437 (write-buffered *(ebp+8) *ecx) # Var-name +5438 (write-buffered *(ebp+8) ":break:\n") +5439 } +5440 $emit-subx-block:end: +5441 # . restore registers +5442 5e/pop-to-esi +5443 59/pop-to-ecx +5444 58/pop-to-eax +5445 # . epilogue +5446 89/<- %esp 5/r32/ebp +5447 5d/pop-to-ebp +5448 c3/return +5449 +5450 # Primitives supported +5451 # For each operation, put variants with hard-coded registers before flexible ones. +5452 == data +5453 Primitives: +5454 # - increment/decrement +5455 _Primitive-inc-eax: +5456 # var/eax <- increment => 40/increment-eax +5457 "increment"/imm32/name +5458 0/imm32/no-inouts +5459 Single-int-var-in-eax/imm32/outputs +5460 "40/increment-eax"/imm32/subx-name +5461 0/imm32/no-rm32 +5462 0/imm32/no-r32 +5463 0/imm32/no-imm32 +5464 0/imm32/no-disp32 +5465 0/imm32/output-is-write-only +5466 _Primitive-inc-ecx/imm32/next +5467 _Primitive-inc-ecx: +5468 # var/ecx <- increment => 41/increment-ecx +5469 "increment"/imm32/name +5470 0/imm32/no-inouts +5471 Single-int-var-in-ecx/imm32/outputs +5472 "41/increment-ecx"/imm32/subx-name +5473 0/imm32/no-rm32 +5474 0/imm32/no-r32 +5475 0/imm32/no-imm32 +5476 0/imm32/no-disp32 +5477 0/imm32/output-is-write-only +5478 _Primitive-inc-edx/imm32/next +5479 _Primitive-inc-edx: +5480 # var/edx <- increment => 42/increment-edx +5481 "increment"/imm32/name +5482 0/imm32/no-inouts +5483 Single-int-var-in-edx/imm32/outputs +5484 "42/increment-edx"/imm32/subx-name +5485 0/imm32/no-rm32 +5486 0/imm32/no-r32 +5487 0/imm32/no-imm32 +5488 0/imm32/no-disp32 +5489 0/imm32/output-is-write-only +5490 _Primitive-inc-ebx/imm32/next +5491 _Primitive-inc-ebx: +5492 # var/ebx <- increment => 43/increment-ebx +5493 "increment"/imm32/name +5494 0/imm32/no-inouts +5495 Single-int-var-in-ebx/imm32/outputs +5496 "43/increment-ebx"/imm32/subx-name +5497 0/imm32/no-rm32 +5498 0/imm32/no-r32 +5499 0/imm32/no-imm32 +5500 0/imm32/no-disp32 +5501 0/imm32/output-is-write-only +5502 _Primitive-inc-esi/imm32/next +5503 _Primitive-inc-esi: +5504 # var/esi <- increment => 46/increment-esi +5505 "increment"/imm32/name +5506 0/imm32/no-inouts +5507 Single-int-var-in-esi/imm32/outputs +5508 "46/increment-esi"/imm32/subx-name +5509 0/imm32/no-rm32 +5510 0/imm32/no-r32 +5511 0/imm32/no-imm32 +5512 0/imm32/no-disp32 +5513 0/imm32/output-is-write-only +5514 _Primitive-inc-edi/imm32/next +5515 _Primitive-inc-edi: +5516 # var/edi <- increment => 47/increment-edi +5517 "increment"/imm32/name +5518 0/imm32/no-inouts +5519 Single-int-var-in-edi/imm32/outputs +5520 "47/increment-edi"/imm32/subx-name +5521 0/imm32/no-rm32 +5522 0/imm32/no-r32 +5523 0/imm32/no-imm32 +5524 0/imm32/no-disp32 +5525 0/imm32/output-is-write-only +5526 _Primitive-dec-eax/imm32/next +5527 _Primitive-dec-eax: +5528 # var/eax <- decrement => 48/decrement-eax +5529 "decrement"/imm32/name +5530 0/imm32/no-inouts +5531 Single-int-var-in-eax/imm32/outputs +5532 "48/decrement-eax"/imm32/subx-name +5533 0/imm32/no-rm32 +5534 0/imm32/no-r32 +5535 0/imm32/no-imm32 +5536 0/imm32/no-disp32 +5537 0/imm32/output-is-write-only +5538 _Primitive-dec-ecx/imm32/next +5539 _Primitive-dec-ecx: +5540 # var/ecx <- decrement => 49/decrement-ecx +5541 "decrement"/imm32/name +5542 0/imm32/no-inouts +5543 Single-int-var-in-ecx/imm32/outputs +5544 "49/decrement-ecx"/imm32/subx-name +5545 0/imm32/no-rm32 +5546 0/imm32/no-r32 +5547 0/imm32/no-imm32 +5548 0/imm32/no-disp32 +5549 0/imm32/output-is-write-only +5550 _Primitive-dec-edx/imm32/next +5551 _Primitive-dec-edx: +5552 # var/edx <- decrement => 4a/decrement-edx +5553 "decrement"/imm32/name +5554 0/imm32/no-inouts +5555 Single-int-var-in-edx/imm32/outputs +5556 "4a/decrement-edx"/imm32/subx-name +5557 0/imm32/no-rm32 +5558 0/imm32/no-r32 +5559 0/imm32/no-imm32 +5560 0/imm32/no-disp32 +5561 0/imm32/output-is-write-only +5562 _Primitive-dec-ebx/imm32/next +5563 _Primitive-dec-ebx: +5564 # var/ebx <- decrement => 4b/decrement-ebx +5565 "decrement"/imm32/name +5566 0/imm32/no-inouts +5567 Single-int-var-in-ebx/imm32/outputs +5568 "4b/decrement-ebx"/imm32/subx-name 5569 0/imm32/no-rm32 5570 0/imm32/no-r32 -5571 1/imm32/imm32-is-first-inout +5571 0/imm32/no-imm32 5572 0/imm32/no-disp32 5573 0/imm32/output-is-write-only -5574 _Primitive-or-reg-with-reg/imm32/next -5575 _Primitive-or-reg-with-reg: -5576 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 -5577 "or"/imm32/name -5578 Single-int-var-in-some-register/imm32/inouts -5579 Single-int-var-in-some-register/imm32/outputs -5580 "09/or-with"/imm32/subx-name -5581 3/imm32/rm32-is-first-output -5582 1/imm32/r32-is-first-inout +5574 _Primitive-dec-esi/imm32/next +5575 _Primitive-dec-esi: +5576 # var/esi <- decrement => 4e/decrement-esi +5577 "decrement"/imm32/name +5578 0/imm32/no-inouts +5579 Single-int-var-in-esi/imm32/outputs +5580 "4e/decrement-esi"/imm32/subx-name +5581 0/imm32/no-rm32 +5582 0/imm32/no-r32 5583 0/imm32/no-imm32 5584 0/imm32/no-disp32 5585 0/imm32/output-is-write-only -5586 _Primitive-or-reg-with-mem/imm32/next -5587 _Primitive-or-reg-with-mem: -5588 # or-with var1 var2/reg => 09/or-with var1 var2/r32 -5589 "or-with"/imm32/name -5590 Two-args-int-stack-int-reg/imm32/inouts -5591 0/imm32/outputs -5592 "09/or-with"/imm32/subx-name -5593 1/imm32/rm32-is-first-inout -5594 2/imm32/r32-is-second-inout +5586 _Primitive-dec-edi/imm32/next +5587 _Primitive-dec-edi: +5588 # var/edi <- decrement => 4f/decrement-edi +5589 "decrement"/imm32/name +5590 0/imm32/no-inouts +5591 Single-int-var-in-edi/imm32/outputs +5592 "4f/decrement-edi"/imm32/subx-name +5593 0/imm32/no-rm32 +5594 0/imm32/no-r32 5595 0/imm32/no-imm32 5596 0/imm32/no-disp32 5597 0/imm32/output-is-write-only -5598 _Primitive-or-mem-with-reg/imm32/next -5599 _Primitive-or-mem-with-reg: -5600 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 -5601 "or"/imm32/name -5602 Single-int-var-on-stack/imm32/inouts -5603 Single-int-var-in-some-register/imm32/outputs -5604 "0b/or"/imm32/subx-name +5598 _Primitive-inc-mem/imm32/next +5599 _Primitive-inc-mem: +5600 # increment var => ff 0/subop/increment *(ebp+__) +5601 "increment"/imm32/name +5602 Single-int-var-on-stack/imm32/inouts +5603 0/imm32/no-outputs +5604 "ff 0/subop/increment"/imm32/subx-name 5605 1/imm32/rm32-is-first-inout -5606 3/imm32/r32-is-first-output +5606 0/imm32/no-r32 5607 0/imm32/no-imm32 5608 0/imm32/no-disp32 5609 0/imm32/output-is-write-only -5610 _Primitive-or-lit-with-reg/imm32/next -5611 _Primitive-or-lit-with-reg: -5612 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 -5613 "or"/imm32/name -5614 Single-lit-var/imm32/inouts -5615 Single-int-var-in-some-register/imm32/outputs -5616 "81 1/subop/or"/imm32/subx-name +5610 _Primitive-inc-reg/imm32/next +5611 _Primitive-inc-reg: +5612 # var/reg <- increment => ff 0/subop/increment %__ +5613 "increment"/imm32/name +5614 0/imm32/no-inouts +5615 Single-int-var-in-some-register/imm32/outputs +5616 "ff 0/subop/increment"/imm32/subx-name 5617 3/imm32/rm32-is-first-output 5618 0/imm32/no-r32 -5619 1/imm32/imm32-is-first-inout +5619 0/imm32/no-imm32 5620 0/imm32/no-disp32 5621 0/imm32/output-is-write-only -5622 _Primitive-or-lit-with-mem/imm32/next -5623 _Primitive-or-lit-with-mem: -5624 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 -5625 "or-with"/imm32/name -5626 Int-var-and-literal/imm32/inouts -5627 0/imm32/outputs -5628 "81 1/subop/or"/imm32/subx-name +5622 _Primitive-dec-mem/imm32/next +5623 _Primitive-dec-mem: +5624 # decrement var => ff 1/subop/decrement *(ebp+__) +5625 "decrement"/imm32/name +5626 Single-int-var-on-stack/imm32/inouts +5627 0/imm32/no-outputs +5628 "ff 1/subop/decrement"/imm32/subx-name 5629 1/imm32/rm32-is-first-inout 5630 0/imm32/no-r32 -5631 2/imm32/imm32-is-second-inout +5631 0/imm32/no-imm32 5632 0/imm32/no-disp32 5633 0/imm32/output-is-write-only -5634 _Primitive-xor-with-eax/imm32/next -5635 # - xor -5636 _Primitive-xor-with-eax: -5637 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 -5638 "xor"/imm32/name -5639 Single-lit-var/imm32/inouts -5640 Single-int-var-in-eax/imm32/outputs -5641 "35/xor-with-eax"/imm32/subx-name -5642 0/imm32/no-rm32 -5643 0/imm32/no-r32 -5644 1/imm32/imm32-is-first-inout -5645 0/imm32/no-disp32 -5646 0/imm32/output-is-write-only -5647 _Primitive-xor-reg-with-reg/imm32/next -5648 _Primitive-xor-reg-with-reg: -5649 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 -5650 "xor"/imm32/name -5651 Single-int-var-in-some-register/imm32/inouts -5652 Single-int-var-in-some-register/imm32/outputs -5653 "31/xor-with"/imm32/subx-name -5654 3/imm32/rm32-is-first-output -5655 1/imm32/r32-is-first-inout -5656 0/imm32/no-imm32 +5634 _Primitive-dec-reg/imm32/next +5635 _Primitive-dec-reg: +5636 # var/reg <- decrement => ff 1/subop/decrement %__ +5637 "decrement"/imm32/name +5638 0/imm32/no-inouts +5639 Single-int-var-in-some-register/imm32/outputs +5640 "ff 1/subop/decrement"/imm32/subx-name +5641 3/imm32/rm32-is-first-output +5642 0/imm32/no-r32 +5643 0/imm32/no-imm32 +5644 0/imm32/no-disp32 +5645 0/imm32/output-is-write-only +5646 _Primitive-add-to-eax/imm32/next +5647 # - add +5648 _Primitive-add-to-eax: +5649 # var/eax <- add lit => 05/add-to-eax lit/imm32 +5650 "add"/imm32/name +5651 Single-lit-var/imm32/inouts +5652 Single-int-var-in-eax/imm32/outputs +5653 "05/add-to-eax"/imm32/subx-name +5654 0/imm32/no-rm32 +5655 0/imm32/no-r32 +5656 1/imm32/imm32-is-first-inout 5657 0/imm32/no-disp32 5658 0/imm32/output-is-write-only -5659 _Primitive-xor-reg-with-mem/imm32/next -5660 _Primitive-xor-reg-with-mem: -5661 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 -5662 "xor-with"/imm32/name -5663 Two-args-int-stack-int-reg/imm32/inouts -5664 0/imm32/outputs -5665 "31/xor-with"/imm32/subx-name -5666 1/imm32/rm32-is-first-inout -5667 2/imm32/r32-is-second-inout +5659 _Primitive-add-reg-to-reg/imm32/next +5660 _Primitive-add-reg-to-reg: +5661 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 +5662 "add"/imm32/name +5663 Single-int-var-in-some-register/imm32/inouts +5664 Single-int-var-in-some-register/imm32/outputs +5665 "01/add-to"/imm32/subx-name +5666 3/imm32/rm32-is-first-output +5667 1/imm32/r32-is-first-inout 5668 0/imm32/no-imm32 5669 0/imm32/no-disp32 5670 0/imm32/output-is-write-only -5671 _Primitive-xor-mem-with-reg/imm32/next -5672 _Primitive-xor-mem-with-reg: -5673 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 -5674 "xor"/imm32/name -5675 Single-int-var-on-stack/imm32/inouts -5676 Single-int-var-in-some-register/imm32/outputs -5677 "33/xor"/imm32/subx-name +5671 _Primitive-add-reg-to-mem/imm32/next +5672 _Primitive-add-reg-to-mem: +5673 # add-to var1 var2/reg => 01/add-to var1 var2/r32 +5674 "add-to"/imm32/name +5675 Two-args-int-stack-int-reg/imm32/inouts +5676 0/imm32/outputs +5677 "01/add-to"/imm32/subx-name 5678 1/imm32/rm32-is-first-inout -5679 3/imm32/r32-is-first-output +5679 2/imm32/r32-is-second-inout 5680 0/imm32/no-imm32 5681 0/imm32/no-disp32 5682 0/imm32/output-is-write-only -5683 _Primitive-xor-lit-with-reg/imm32/next -5684 _Primitive-xor-lit-with-reg: -5685 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 -5686 "xor"/imm32/name -5687 Single-lit-var/imm32/inouts -5688 Single-int-var-in-some-register/imm32/outputs -5689 "81 6/subop/xor"/imm32/subx-name -5690 3/imm32/rm32-is-first-output -5691 0/imm32/no-r32 -5692 1/imm32/imm32-is-first-inout +5683 _Primitive-add-mem-to-reg/imm32/next +5684 _Primitive-add-mem-to-reg: +5685 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 +5686 "add"/imm32/name +5687 Single-int-var-on-stack/imm32/inouts +5688 Single-int-var-in-some-register/imm32/outputs +5689 "03/add"/imm32/subx-name +5690 1/imm32/rm32-is-first-inout +5691 3/imm32/r32-is-first-output +5692 0/imm32/no-imm32 5693 0/imm32/no-disp32 5694 0/imm32/output-is-write-only -5695 _Primitive-xor-lit-with-mem/imm32/next -5696 _Primitive-xor-lit-with-mem: -5697 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 -5698 "xor-with"/imm32/name -5699 Int-var-and-literal/imm32/inouts -5700 0/imm32/outputs -5701 "81 6/subop/xor"/imm32/subx-name -5702 1/imm32/rm32-is-first-inout +5695 _Primitive-add-lit-to-reg/imm32/next +5696 _Primitive-add-lit-to-reg: +5697 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 +5698 "add"/imm32/name +5699 Single-lit-var/imm32/inouts +5700 Single-int-var-in-some-register/imm32/outputs +5701 "81 0/subop/add"/imm32/subx-name +5702 3/imm32/rm32-is-first-output 5703 0/imm32/no-r32 -5704 2/imm32/imm32-is-first-inout +5704 1/imm32/imm32-is-first-inout 5705 0/imm32/no-disp32 5706 0/imm32/output-is-write-only -5707 _Primitive-copy-to-eax/imm32/next -5708 # - copy -5709 _Primitive-copy-to-eax: -5710 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 -5711 "copy"/imm32/name -5712 Single-lit-var/imm32/inouts -5713 Single-int-var-in-eax/imm32/outputs -5714 "b8/copy-to-eax"/imm32/subx-name -5715 0/imm32/no-rm32 -5716 0/imm32/no-r32 -5717 1/imm32/imm32-is-first-inout -5718 0/imm32/no-disp32 -5719 1/imm32/output-is-write-only -5720 _Primitive-copy-to-ecx/imm32/next -5721 _Primitive-copy-to-ecx: -5722 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 -5723 "copy"/imm32/name -5724 Single-lit-var/imm32/inouts -5725 Single-int-var-in-ecx/imm32/outputs -5726 "b9/copy-to-ecx"/imm32/subx-name +5707 _Primitive-add-lit-to-mem/imm32/next +5708 _Primitive-add-lit-to-mem: +5709 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 +5710 "add-to"/imm32/name +5711 Int-var-and-literal/imm32/inouts +5712 0/imm32/outputs +5713 "81 0/subop/add"/imm32/subx-name +5714 1/imm32/rm32-is-first-inout +5715 0/imm32/no-r32 +5716 2/imm32/imm32-is-second-inout +5717 0/imm32/no-disp32 +5718 0/imm32/output-is-write-only +5719 _Primitive-subtract-from-eax/imm32/next +5720 # - subtract +5721 _Primitive-subtract-from-eax: +5722 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 +5723 "subtract"/imm32/name +5724 Single-lit-var/imm32/inouts +5725 Single-int-var-in-eax/imm32/outputs +5726 "2d/subtract-from-eax"/imm32/subx-name 5727 0/imm32/no-rm32 5728 0/imm32/no-r32 5729 1/imm32/imm32-is-first-inout 5730 0/imm32/no-disp32 -5731 1/imm32/output-is-write-only -5732 _Primitive-copy-to-edx/imm32/next -5733 _Primitive-copy-to-edx: -5734 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 -5735 "copy"/imm32/name -5736 Single-lit-var/imm32/inouts -5737 Single-int-var-in-edx/imm32/outputs -5738 "ba/copy-to-edx"/imm32/subx-name -5739 0/imm32/no-rm32 -5740 0/imm32/no-r32 -5741 1/imm32/imm32-is-first-inout +5731 0/imm32/output-is-write-only +5732 _Primitive-subtract-reg-from-reg/imm32/next +5733 _Primitive-subtract-reg-from-reg: +5734 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 +5735 "subtract"/imm32/name +5736 Single-int-var-in-some-register/imm32/inouts +5737 Single-int-var-in-some-register/imm32/outputs +5738 "29/subtract-from"/imm32/subx-name +5739 3/imm32/rm32-is-first-output +5740 1/imm32/r32-is-first-inout +5741 0/imm32/no-imm32 5742 0/imm32/no-disp32 -5743 1/imm32/output-is-write-only -5744 _Primitive-copy-to-ebx/imm32/next -5745 _Primitive-copy-to-ebx: -5746 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 -5747 "copy"/imm32/name -5748 Single-lit-var/imm32/inouts -5749 Single-int-var-in-ebx/imm32/outputs -5750 "bb/copy-to-ebx"/imm32/subx-name -5751 0/imm32/no-rm32 -5752 0/imm32/no-r32 -5753 1/imm32/imm32-is-first-inout +5743 0/imm32/output-is-write-only +5744 _Primitive-subtract-reg-from-mem/imm32/next +5745 _Primitive-subtract-reg-from-mem: +5746 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 +5747 "subtract-from"/imm32/name +5748 Two-args-int-stack-int-reg/imm32/inouts +5749 0/imm32/outputs +5750 "29/subtract-from"/imm32/subx-name +5751 1/imm32/rm32-is-first-inout +5752 2/imm32/r32-is-second-inout +5753 0/imm32/no-imm32 5754 0/imm32/no-disp32 -5755 1/imm32/output-is-write-only -5756 _Primitive-copy-to-esi/imm32/next -5757 _Primitive-copy-to-esi: -5758 # var/esi <- copy lit => be/copy-to-esi lit/imm32 -5759 "copy"/imm32/name -5760 Single-lit-var/imm32/inouts -5761 Single-int-var-in-esi/imm32/outputs -5762 "be/copy-to-esi"/imm32/subx-name -5763 0/imm32/no-rm32 -5764 0/imm32/no-r32 -5765 1/imm32/imm32-is-first-inout +5755 0/imm32/output-is-write-only +5756 _Primitive-subtract-mem-from-reg/imm32/next +5757 _Primitive-subtract-mem-from-reg: +5758 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 +5759 "subtract"/imm32/name +5760 Single-int-var-on-stack/imm32/inouts +5761 Single-int-var-in-some-register/imm32/outputs +5762 "2b/subtract"/imm32/subx-name +5763 1/imm32/rm32-is-first-inout +5764 3/imm32/r32-is-first-output +5765 0/imm32/no-imm32 5766 0/imm32/no-disp32 -5767 1/imm32/output-is-write-only -5768 _Primitive-copy-to-edi/imm32/next -5769 _Primitive-copy-to-edi: -5770 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 -5771 "copy"/imm32/name -5772 Single-lit-var/imm32/inouts -5773 Single-int-var-in-edi/imm32/outputs -5774 "bf/copy-to-edi"/imm32/subx-name -5775 0/imm32/no-rm32 +5767 0/imm32/output-is-write-only +5768 _Primitive-subtract-lit-from-reg/imm32/next +5769 _Primitive-subtract-lit-from-reg: +5770 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 +5771 "subtract"/imm32/name +5772 Single-lit-var/imm32/inouts +5773 Single-int-var-in-some-register/imm32/outputs +5774 "81 5/subop/subtract"/imm32/subx-name +5775 3/imm32/rm32-is-first-output 5776 0/imm32/no-r32 5777 1/imm32/imm32-is-first-inout 5778 0/imm32/no-disp32 -5779 1/imm32/output-is-write-only -5780 _Primitive-copy-reg-to-reg/imm32/next -5781 _Primitive-copy-reg-to-reg: -5782 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 -5783 "copy"/imm32/name -5784 Single-int-var-in-some-register/imm32/inouts -5785 Single-int-var-in-some-register/imm32/outputs -5786 "89/copy-to"/imm32/subx-name -5787 3/imm32/rm32-is-first-output -5788 1/imm32/r32-is-first-inout -5789 0/imm32/no-imm32 +5779 0/imm32/output-is-write-only +5780 _Primitive-subtract-lit-from-mem/imm32/next +5781 _Primitive-subtract-lit-from-mem: +5782 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 +5783 "subtract-from"/imm32/name +5784 Int-var-and-literal/imm32/inouts +5785 0/imm32/outputs +5786 "81 5/subop/subtract"/imm32/subx-name +5787 1/imm32/rm32-is-first-inout +5788 0/imm32/no-r32 +5789 2/imm32/imm32-is-first-inout 5790 0/imm32/no-disp32 -5791 1/imm32/output-is-write-only -5792 _Primitive-copy-reg-to-mem/imm32/next -5793 _Primitive-copy-reg-to-mem: -5794 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 -5795 "copy-to"/imm32/name -5796 Two-args-int-stack-int-reg/imm32/inouts -5797 0/imm32/outputs -5798 "89/copy-to"/imm32/subx-name -5799 1/imm32/rm32-is-first-inout -5800 2/imm32/r32-is-second-inout -5801 0/imm32/no-imm32 -5802 0/imm32/no-disp32 -5803 1/imm32/output-is-write-only -5804 _Primitive-copy-mem-to-reg/imm32/next -5805 _Primitive-copy-mem-to-reg: -5806 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 -5807 "copy"/imm32/name -5808 Single-int-var-on-stack/imm32/inouts -5809 Single-int-var-in-some-register/imm32/outputs -5810 "8b/copy-from"/imm32/subx-name -5811 1/imm32/rm32-is-first-inout -5812 3/imm32/r32-is-first-output -5813 0/imm32/no-imm32 -5814 0/imm32/no-disp32 -5815 1/imm32/output-is-write-only -5816 _Primitive-copy-lit-to-reg/imm32/next -5817 _Primitive-copy-lit-to-reg: -5818 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 -5819 "copy"/imm32/name -5820 Single-lit-var/imm32/inouts -5821 Single-int-var-in-some-register/imm32/outputs -5822 "c7 0/subop/copy"/imm32/subx-name -5823 3/imm32/rm32-is-first-output -5824 0/imm32/no-r32 -5825 1/imm32/imm32-is-first-inout -5826 0/imm32/no-disp32 -5827 1/imm32/output-is-write-only -5828 _Primitive-copy-lit-to-mem/imm32/next -5829 _Primitive-copy-lit-to-mem: -5830 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 -5831 "copy-to"/imm32/name -5832 Int-var-and-literal/imm32/inouts -5833 0/imm32/outputs -5834 "c7 0/subop/copy"/imm32/subx-name -5835 1/imm32/rm32-is-first-inout -5836 0/imm32/no-r32 -5837 2/imm32/imm32-is-first-inout -5838 0/imm32/no-disp32 -5839 1/imm32/output-is-write-only -5840 _Primitive-compare-mem-with-reg/imm32/next -5841 # - compare -5842 _Primitive-compare-mem-with-reg: -5843 # compare var1 var2/reg => 39/compare-> var1/rm32 var2/r32 -5844 "compare"/imm32/name -5845 Two-args-int-stack-int-reg/imm32/inouts -5846 0/imm32/outputs -5847 "39/compare->"/imm32/subx-name -5848 1/imm32/rm32-is-first-inout -5849 2/imm32/r32-is-second-inout -5850 0/imm32/no-imm32 +5791 0/imm32/output-is-write-only +5792 _Primitive-and-with-eax/imm32/next +5793 # - and +5794 _Primitive-and-with-eax: +5795 # var/eax <- and lit => 25/and-with-eax lit/imm32 +5796 "and"/imm32/name +5797 Single-lit-var/imm32/inouts +5798 Single-int-var-in-eax/imm32/outputs +5799 "25/and-with-eax"/imm32/subx-name +5800 0/imm32/no-rm32 +5801 0/imm32/no-r32 +5802 1/imm32/imm32-is-first-inout +5803 0/imm32/no-disp32 +5804 0/imm32/output-is-write-only +5805 _Primitive-and-reg-with-reg/imm32/next +5806 _Primitive-and-reg-with-reg: +5807 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 +5808 "and"/imm32/name +5809 Single-int-var-in-some-register/imm32/inouts +5810 Single-int-var-in-some-register/imm32/outputs +5811 "21/and-with"/imm32/subx-name +5812 3/imm32/rm32-is-first-output +5813 1/imm32/r32-is-first-inout +5814 0/imm32/no-imm32 +5815 0/imm32/no-disp32 +5816 0/imm32/output-is-write-only +5817 _Primitive-and-reg-with-mem/imm32/next +5818 _Primitive-and-reg-with-mem: +5819 # and-with var1 var2/reg => 21/and-with var1 var2/r32 +5820 "and-with"/imm32/name +5821 Two-args-int-stack-int-reg/imm32/inouts +5822 0/imm32/outputs +5823 "21/and-with"/imm32/subx-name +5824 1/imm32/rm32-is-first-inout +5825 2/imm32/r32-is-second-inout +5826 0/imm32/no-imm32 +5827 0/imm32/no-disp32 +5828 0/imm32/output-is-write-only +5829 _Primitive-and-mem-with-reg/imm32/next +5830 _Primitive-and-mem-with-reg: +5831 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 +5832 "and"/imm32/name +5833 Single-int-var-on-stack/imm32/inouts +5834 Single-int-var-in-some-register/imm32/outputs +5835 "23/and"/imm32/subx-name +5836 1/imm32/rm32-is-first-inout +5837 3/imm32/r32-is-first-output +5838 0/imm32/no-imm32 +5839 0/imm32/no-disp32 +5840 0/imm32/output-is-write-only +5841 _Primitive-and-lit-with-reg/imm32/next +5842 _Primitive-and-lit-with-reg: +5843 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 +5844 "and"/imm32/name +5845 Single-lit-var/imm32/inouts +5846 Single-int-var-in-some-register/imm32/outputs +5847 "81 4/subop/and"/imm32/subx-name +5848 3/imm32/rm32-is-first-output +5849 0/imm32/no-r32 +5850 1/imm32/imm32-is-first-inout 5851 0/imm32/no-disp32 5852 0/imm32/output-is-write-only -5853 _Primitive-compare-reg-with-mem/imm32/next -5854 _Primitive-compare-reg-with-mem: -5855 # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32 -5856 "compare"/imm32/name -5857 Two-args-int-reg-int-stack/imm32/inouts +5853 _Primitive-and-lit-with-mem/imm32/next +5854 _Primitive-and-lit-with-mem: +5855 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 +5856 "and-with"/imm32/name +5857 Int-var-and-literal/imm32/inouts 5858 0/imm32/outputs -5859 "3b/compare<-"/imm32/subx-name -5860 2/imm32/rm32-is-second-inout -5861 1/imm32/r32-is-first-inout -5862 0/imm32/no-imm32 +5859 "81 4/subop/and"/imm32/subx-name +5860 1/imm32/rm32-is-first-inout +5861 0/imm32/no-r32 +5862 2/imm32/imm32-is-first-inout 5863 0/imm32/no-disp32 5864 0/imm32/output-is-write-only -5865 _Primitive-compare-eax-with-literal/imm32/next -5866 _Primitive-compare-eax-with-literal: -5867 # compare var1/eax n => 3d/compare-eax-with n/imm32 -5868 "compare"/imm32/name -5869 Two-args-int-eax-int-literal/imm32/inouts -5870 0/imm32/outputs -5871 "3d/compare-eax-with"/imm32/subx-name -5872 0/imm32/no-rm32 -5873 0/imm32/no-r32 -5874 2/imm32/imm32-is-second-inout -5875 0/imm32/no-disp32 -5876 0/imm32/output-is-write-only -5877 _Primitive-compare-regmem-with-literal/imm32/next -5878 _Primitive-compare-regmem-with-literal: -5879 # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32 -5880 "compare"/imm32/name -5881 Int-var-and-literal/imm32/inouts -5882 0/imm32/outputs -5883 "81 7/subop/compare"/imm32/subx-name -5884 1/imm32/rm32-is-first-inout -5885 0/imm32/no-r32 -5886 2/imm32/imm32-is-second-inout -5887 0/imm32/no-disp32 -5888 0/imm32/output-is-write-only -5889 _Primitive-multiply-reg-by-mem/imm32/next -5890 # - multiply -5891 _Primitive-multiply-reg-by-mem: -5892 # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32 -5893 "multiply"/imm32/name -5894 Single-int-var-on-stack/imm32/inouts -5895 Single-int-var-in-some-register/imm32/outputs -5896 "0f af/multiply"/imm32/subx-name +5865 _Primitive-or-with-eax/imm32/next +5866 # - or +5867 _Primitive-or-with-eax: +5868 # var/eax <- or lit => 0d/or-with-eax lit/imm32 +5869 "or"/imm32/name +5870 Single-lit-var/imm32/inouts +5871 Single-int-var-in-eax/imm32/outputs +5872 "0d/or-with-eax"/imm32/subx-name +5873 0/imm32/no-rm32 +5874 0/imm32/no-r32 +5875 1/imm32/imm32-is-first-inout +5876 0/imm32/no-disp32 +5877 0/imm32/output-is-write-only +5878 _Primitive-or-reg-with-reg/imm32/next +5879 _Primitive-or-reg-with-reg: +5880 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 +5881 "or"/imm32/name +5882 Single-int-var-in-some-register/imm32/inouts +5883 Single-int-var-in-some-register/imm32/outputs +5884 "09/or-with"/imm32/subx-name +5885 3/imm32/rm32-is-first-output +5886 1/imm32/r32-is-first-inout +5887 0/imm32/no-imm32 +5888 0/imm32/no-disp32 +5889 0/imm32/output-is-write-only +5890 _Primitive-or-reg-with-mem/imm32/next +5891 _Primitive-or-reg-with-mem: +5892 # or-with var1 var2/reg => 09/or-with var1 var2/r32 +5893 "or-with"/imm32/name +5894 Two-args-int-stack-int-reg/imm32/inouts +5895 0/imm32/outputs +5896 "09/or-with"/imm32/subx-name 5897 1/imm32/rm32-is-first-inout -5898 3/imm32/r32-is-first-output +5898 2/imm32/r32-is-second-inout 5899 0/imm32/no-imm32 5900 0/imm32/no-disp32 5901 0/imm32/output-is-write-only -5902 _Primitive-break-if-addr</imm32/next -5903 # - branches -5904 _Primitive-break-if-addr<: -5905 "break-if-addr<"/imm32/name -5906 0/imm32/inouts -5907 0/imm32/outputs -5908 "0f 82/jump-if-addr< break/disp32"/imm32/subx-name -5909 0/imm32/no-rm32 -5910 0/imm32/no-r32 +5902 _Primitive-or-mem-with-reg/imm32/next +5903 _Primitive-or-mem-with-reg: +5904 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 +5905 "or"/imm32/name +5906 Single-int-var-on-stack/imm32/inouts +5907 Single-int-var-in-some-register/imm32/outputs +5908 "0b/or"/imm32/subx-name +5909 1/imm32/rm32-is-first-inout +5910 3/imm32/r32-is-first-output 5911 0/imm32/no-imm32 5912 0/imm32/no-disp32 -5913 0/imm32/no-output -5914 _Primitive-break-if-addr>=/imm32/next -5915 _Primitive-break-if-addr>=: -5916 "break-if-addr>="/imm32/name -5917 0/imm32/inouts -5918 0/imm32/outputs -5919 "0f 83/jump-if-addr>= break/disp32"/imm32/subx-name -5920 0/imm32/no-rm32 -5921 0/imm32/no-r32 -5922 0/imm32/no-imm32 -5923 0/imm32/no-disp32 -5924 0/imm32/no-output -5925 _Primitive-break-if-=/imm32/next -5926 _Primitive-break-if-=: -5927 "break-if-="/imm32/name -5928 0/imm32/inouts -5929 0/imm32/outputs -5930 "0f 84/jump-if-= break/disp32"/imm32/subx-name -5931 0/imm32/no-rm32 -5932 0/imm32/no-r32 -5933 0/imm32/no-imm32 -5934 0/imm32/no-disp32 -5935 0/imm32/no-output -5936 _Primitive-break-if-!=/imm32/next -5937 _Primitive-break-if-!=: -5938 "break-if-!="/imm32/name -5939 0/imm32/inouts -5940 0/imm32/outputs -5941 "0f 85/jump-if-!= break/disp32"/imm32/subx-name -5942 0/imm32/no-rm32 -5943 0/imm32/no-r32 -5944 0/imm32/no-imm32 -5945 0/imm32/no-disp32 -5946 0/imm32/no-output -5947 _Primitive-break-if-addr<=/imm32/next -5948 _Primitive-break-if-addr<=: -5949 "break-if-addr<="/imm32/name -5950 0/imm32/inouts -5951 0/imm32/outputs -5952 "0f 86/jump-if-addr<= break/disp32"/imm32/subx-name -5953 0/imm32/no-rm32 -5954 0/imm32/no-r32 -5955 0/imm32/no-imm32 -5956 0/imm32/no-disp32 -5957 0/imm32/no-output -5958 _Primitive-break-if-addr>/imm32/next -5959 _Primitive-break-if-addr>: -5960 "break-if-addr>"/imm32/name -5961 0/imm32/inouts -5962 0/imm32/outputs -5963 "0f 87/jump-if-addr> break/disp32"/imm32/subx-name -5964 0/imm32/no-rm32 -5965 0/imm32/no-r32 -5966 0/imm32/no-imm32 -5967 0/imm32/no-disp32 -5968 0/imm32/no-output -5969 _Primitive-break-if-</imm32/next -5970 _Primitive-break-if-<: -5971 "break-if-<"/imm32/name -5972 0/imm32/inouts -5973 0/imm32/outputs -5974 "0f 8c/jump-if-< break/disp32"/imm32/subx-name -5975 0/imm32/no-rm32 -5976 0/imm32/no-r32 -5977 0/imm32/no-imm32 -5978 0/imm32/no-disp32 -5979 0/imm32/no-output -5980 _Primitive-break-if->=/imm32/next -5981 _Primitive-break-if->=: -5982 "break-if->="/imm32/name -5983 0/imm32/inouts -5984 0/imm32/outputs -5985 "0f 8d/jump-if->= break/disp32"/imm32/subx-name -5986 0/imm32/no-rm32 -5987 0/imm32/no-r32 -5988 0/imm32/no-imm32 -5989 0/imm32/no-disp32 -5990 0/imm32/no-output -5991 _Primitive-break-if-<=/imm32/next -5992 _Primitive-break-if-<=: -5993 "break-if-<="/imm32/name -5994 0/imm32/inouts -5995 0/imm32/outputs -5996 "0f 8e/jump-if-<= break/disp32"/imm32/subx-name -5997 0/imm32/no-rm32 -5998 0/imm32/no-r32 -5999 0/imm32/no-imm32 -6000 0/imm32/no-disp32 -6001 0/imm32/no-output -6002 _Primitive-break-if->/imm32/next -6003 _Primitive-break-if->: -6004 "break-if->"/imm32/name -6005 0/imm32/inouts -6006 0/imm32/outputs -6007 "0f 8f/jump-if-> break/disp32"/imm32/subx-name -6008 0/imm32/no-rm32 -6009 0/imm32/no-r32 -6010 0/imm32/no-imm32 -6011 0/imm32/no-disp32 -6012 0/imm32/no-output -6013 _Primitive-loop-if-addr</imm32/next -6014 _Primitive-loop-if-addr<: -6015 "loop-if-addr<"/imm32/name -6016 0/imm32/inouts -6017 0/imm32/outputs -6018 "0f 82/jump-if-addr< loop/disp32"/imm32/subx-name +5913 0/imm32/output-is-write-only +5914 _Primitive-or-lit-with-reg/imm32/next +5915 _Primitive-or-lit-with-reg: +5916 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 +5917 "or"/imm32/name +5918 Single-lit-var/imm32/inouts +5919 Single-int-var-in-some-register/imm32/outputs +5920 "81 1/subop/or"/imm32/subx-name +5921 3/imm32/rm32-is-first-output +5922 0/imm32/no-r32 +5923 1/imm32/imm32-is-first-inout +5924 0/imm32/no-disp32 +5925 0/imm32/output-is-write-only +5926 _Primitive-or-lit-with-mem/imm32/next +5927 _Primitive-or-lit-with-mem: +5928 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 +5929 "or-with"/imm32/name +5930 Int-var-and-literal/imm32/inouts +5931 0/imm32/outputs +5932 "81 1/subop/or"/imm32/subx-name +5933 1/imm32/rm32-is-first-inout +5934 0/imm32/no-r32 +5935 2/imm32/imm32-is-second-inout +5936 0/imm32/no-disp32 +5937 0/imm32/output-is-write-only +5938 _Primitive-xor-with-eax/imm32/next +5939 # - xor +5940 _Primitive-xor-with-eax: +5941 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 +5942 "xor"/imm32/name +5943 Single-lit-var/imm32/inouts +5944 Single-int-var-in-eax/imm32/outputs +5945 "35/xor-with-eax"/imm32/subx-name +5946 0/imm32/no-rm32 +5947 0/imm32/no-r32 +5948 1/imm32/imm32-is-first-inout +5949 0/imm32/no-disp32 +5950 0/imm32/output-is-write-only +5951 _Primitive-xor-reg-with-reg/imm32/next +5952 _Primitive-xor-reg-with-reg: +5953 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 +5954 "xor"/imm32/name +5955 Single-int-var-in-some-register/imm32/inouts +5956 Single-int-var-in-some-register/imm32/outputs +5957 "31/xor-with"/imm32/subx-name +5958 3/imm32/rm32-is-first-output +5959 1/imm32/r32-is-first-inout +5960 0/imm32/no-imm32 +5961 0/imm32/no-disp32 +5962 0/imm32/output-is-write-only +5963 _Primitive-xor-reg-with-mem/imm32/next +5964 _Primitive-xor-reg-with-mem: +5965 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 +5966 "xor-with"/imm32/name +5967 Two-args-int-stack-int-reg/imm32/inouts +5968 0/imm32/outputs +5969 "31/xor-with"/imm32/subx-name +5970 1/imm32/rm32-is-first-inout +5971 2/imm32/r32-is-second-inout +5972 0/imm32/no-imm32 +5973 0/imm32/no-disp32 +5974 0/imm32/output-is-write-only +5975 _Primitive-xor-mem-with-reg/imm32/next +5976 _Primitive-xor-mem-with-reg: +5977 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 +5978 "xor"/imm32/name +5979 Single-int-var-on-stack/imm32/inouts +5980 Single-int-var-in-some-register/imm32/outputs +5981 "33/xor"/imm32/subx-name +5982 1/imm32/rm32-is-first-inout +5983 3/imm32/r32-is-first-output +5984 0/imm32/no-imm32 +5985 0/imm32/no-disp32 +5986 0/imm32/output-is-write-only +5987 _Primitive-xor-lit-with-reg/imm32/next +5988 _Primitive-xor-lit-with-reg: +5989 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 +5990 "xor"/imm32/name +5991 Single-lit-var/imm32/inouts +5992 Single-int-var-in-some-register/imm32/outputs +5993 "81 6/subop/xor"/imm32/subx-name +5994 3/imm32/rm32-is-first-output +5995 0/imm32/no-r32 +5996 1/imm32/imm32-is-first-inout +5997 0/imm32/no-disp32 +5998 0/imm32/output-is-write-only +5999 _Primitive-xor-lit-with-mem/imm32/next +6000 _Primitive-xor-lit-with-mem: +6001 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 +6002 "xor-with"/imm32/name +6003 Int-var-and-literal/imm32/inouts +6004 0/imm32/outputs +6005 "81 6/subop/xor"/imm32/subx-name +6006 1/imm32/rm32-is-first-inout +6007 0/imm32/no-r32 +6008 2/imm32/imm32-is-first-inout +6009 0/imm32/no-disp32 +6010 0/imm32/output-is-write-only +6011 _Primitive-copy-to-eax/imm32/next +6012 # - copy +6013 _Primitive-copy-to-eax: +6014 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 +6015 "copy"/imm32/name +6016 Single-lit-var/imm32/inouts +6017 Single-int-var-in-eax/imm32/outputs +6018 "b8/copy-to-eax"/imm32/subx-name 6019 0/imm32/no-rm32 6020 0/imm32/no-r32 -6021 0/imm32/no-imm32 +6021 1/imm32/imm32-is-first-inout 6022 0/imm32/no-disp32 -6023 0/imm32/no-output -6024 _Primitive-loop-if-addr>=/imm32/next -6025 _Primitive-loop-if-addr>=: -6026 "loop-if-addr>="/imm32/name -6027 0/imm32/inouts -6028 0/imm32/outputs -6029 "0f 83/jump-if-addr>= loop/disp32"/imm32/subx-name -6030 0/imm32/no-rm32 -6031 0/imm32/no-r32 -6032 0/imm32/no-imm32 -6033 0/imm32/no-disp32 -6034 0/imm32/no-output -6035 _Primitive-loop-if-=/imm32/next -6036 _Primitive-loop-if-=: -6037 "loop-if-="/imm32/name -6038 0/imm32/inouts -6039 0/imm32/outputs -6040 "0f 84/jump-if-= loop/disp32"/imm32/subx-name -6041 0/imm32/no-rm32 -6042 0/imm32/no-r32 -6043 0/imm32/no-imm32 -6044 0/imm32/no-disp32 -6045 0/imm32/no-output -6046 _Primitive-loop-if-!=/imm32/next -6047 _Primitive-loop-if-!=: -6048 "loop-if-!="/imm32/name -6049 0/imm32/inouts -6050 0/imm32/outputs -6051 "0f 85/jump-if-!= loop/disp32"/imm32/subx-name -6052 0/imm32/no-rm32 -6053 0/imm32/no-r32 -6054 0/imm32/no-imm32 -6055 0/imm32/no-disp32 -6056 0/imm32/no-output -6057 _Primitive-loop-if-addr<=/imm32/next -6058 _Primitive-loop-if-addr<=: -6059 "loop-if-addr<="/imm32/name -6060 0/imm32/inouts -6061 0/imm32/outputs -6062 "0f 86/jump-if-addr<= loop/disp32"/imm32/subx-name -6063 0/imm32/no-rm32 -6064 0/imm32/no-r32 -6065 0/imm32/no-imm32 -6066 0/imm32/no-disp32 -6067 0/imm32/no-output -6068 _Primitive-loop-if-addr>/imm32/next -6069 _Primitive-loop-if-addr>: -6070 "loop-if-addr>"/imm32/name -6071 0/imm32/inouts -6072 0/imm32/outputs -6073 "0f 87/jump-if-addr> loop/disp32"/imm32/subx-name -6074 0/imm32/no-rm32 -6075 0/imm32/no-r32 -6076 0/imm32/no-imm32 -6077 0/imm32/no-disp32 -6078 0/imm32/no-output -6079 _Primitive-loop-if-</imm32/next -6080 _Primitive-loop-if-<: -6081 "loop-if-<"/imm32/name -6082 0/imm32/inouts -6083 0/imm32/outputs -6084 "0f 8c/jump-if-< loop/disp32"/imm32/subx-name -6085 0/imm32/no-rm32 -6086 0/imm32/no-r32 -6087 0/imm32/no-imm32 -6088 0/imm32/no-disp32 -6089 0/imm32/no-output -6090 _Primitive-loop-if->=/imm32/next -6091 _Primitive-loop-if->=: -6092 "loop-if->="/imm32/name -6093 0/imm32/inouts -6094 0/imm32/outputs -6095 "0f 8d/jump-if->= loop/disp32"/imm32/subx-name -6096 0/imm32/no-rm32 -6097 0/imm32/no-r32 -6098 0/imm32/no-imm32 -6099 0/imm32/no-disp32 -6100 0/imm32/no-output -6101 _Primitive-loop-if-<=/imm32/next -6102 _Primitive-loop-if-<=: -6103 "loop-if-<="/imm32/name -6104 0/imm32/inouts -6105 0/imm32/outputs -6106 "0f 8e/jump-if-<= loop/disp32"/imm32/subx-name -6107 0/imm32/no-rm32 -6108 0/imm32/no-r32 -6109 0/imm32/no-imm32 -6110 0/imm32/no-disp32 -6111 0/imm32/no-output -6112 _Primitive-loop-if->/imm32/next -6113 _Primitive-loop-if->: -6114 "loop-if->"/imm32/name -6115 0/imm32/inouts -6116 0/imm32/outputs -6117 "0f 8f/jump-if-> loop/disp32"/imm32/subx-name -6118 0/imm32/no-rm32 -6119 0/imm32/no-r32 -6120 0/imm32/no-imm32 -6121 0/imm32/no-disp32 -6122 0/imm32/no-output -6123 _Primitive-loop/imm32/next # we probably don't need an unconditional break -6124 _Primitive-loop: -6125 "loop"/imm32/name -6126 0/imm32/inouts -6127 0/imm32/outputs -6128 "e9/jump loop/disp32"/imm32/subx-name -6129 0/imm32/no-rm32 -6130 0/imm32/no-r32 -6131 0/imm32/no-imm32 -6132 0/imm32/no-disp32 -6133 0/imm32/no-output -6134 _Primitive-break-if-addr<-named/imm32/next -6135 # - branches to named blocks -6136 _Primitive-break-if-addr<-named: -6137 "break-if-addr<"/imm32/name -6138 Single-lit-var/imm32/inouts -6139 0/imm32/outputs -6140 "0f 82/jump-if-addr<"/imm32/subx-name -6141 0/imm32/no-rm32 -6142 0/imm32/no-r32 -6143 0/imm32/no-imm32 -6144 1/imm32/disp32-is-first-inout -6145 0/imm32/no-output -6146 _Primitive-break-if-addr>=-named/imm32/next -6147 _Primitive-break-if-addr>=-named: -6148 "break-if-addr>="/imm32/name -6149 Single-lit-var/imm32/inouts +6023 1/imm32/output-is-write-only +6024 _Primitive-copy-to-ecx/imm32/next +6025 _Primitive-copy-to-ecx: +6026 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 +6027 "copy"/imm32/name +6028 Single-lit-var/imm32/inouts +6029 Single-int-var-in-ecx/imm32/outputs +6030 "b9/copy-to-ecx"/imm32/subx-name +6031 0/imm32/no-rm32 +6032 0/imm32/no-r32 +6033 1/imm32/imm32-is-first-inout +6034 0/imm32/no-disp32 +6035 1/imm32/output-is-write-only +6036 _Primitive-copy-to-edx/imm32/next +6037 _Primitive-copy-to-edx: +6038 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 +6039 "copy"/imm32/name +6040 Single-lit-var/imm32/inouts +6041 Single-int-var-in-edx/imm32/outputs +6042 "ba/copy-to-edx"/imm32/subx-name +6043 0/imm32/no-rm32 +6044 0/imm32/no-r32 +6045 1/imm32/imm32-is-first-inout +6046 0/imm32/no-disp32 +6047 1/imm32/output-is-write-only +6048 _Primitive-copy-to-ebx/imm32/next +6049 _Primitive-copy-to-ebx: +6050 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 +6051 "copy"/imm32/name +6052 Single-lit-var/imm32/inouts +6053 Single-int-var-in-ebx/imm32/outputs +6054 "bb/copy-to-ebx"/imm32/subx-name +6055 0/imm32/no-rm32 +6056 0/imm32/no-r32 +6057 1/imm32/imm32-is-first-inout +6058 0/imm32/no-disp32 +6059 1/imm32/output-is-write-only +6060 _Primitive-copy-to-esi/imm32/next +6061 _Primitive-copy-to-esi: +6062 # var/esi <- copy lit => be/copy-to-esi lit/imm32 +6063 "copy"/imm32/name +6064 Single-lit-var/imm32/inouts +6065 Single-int-var-in-esi/imm32/outputs +6066 "be/copy-to-esi"/imm32/subx-name +6067 0/imm32/no-rm32 +6068 0/imm32/no-r32 +6069 1/imm32/imm32-is-first-inout +6070 0/imm32/no-disp32 +6071 1/imm32/output-is-write-only +6072 _Primitive-copy-to-edi/imm32/next +6073 _Primitive-copy-to-edi: +6074 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 +6075 "copy"/imm32/name +6076 Single-lit-var/imm32/inouts +6077 Single-int-var-in-edi/imm32/outputs +6078 "bf/copy-to-edi"/imm32/subx-name +6079 0/imm32/no-rm32 +6080 0/imm32/no-r32 +6081 1/imm32/imm32-is-first-inout +6082 0/imm32/no-disp32 +6083 1/imm32/output-is-write-only +6084 _Primitive-copy-reg-to-reg/imm32/next +6085 _Primitive-copy-reg-to-reg: +6086 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 +6087 "copy"/imm32/name +6088 Single-int-var-in-some-register/imm32/inouts +6089 Single-int-var-in-some-register/imm32/outputs +6090 "89/copy-to"/imm32/subx-name +6091 3/imm32/rm32-is-first-output +6092 1/imm32/r32-is-first-inout +6093 0/imm32/no-imm32 +6094 0/imm32/no-disp32 +6095 1/imm32/output-is-write-only +6096 _Primitive-copy-reg-to-mem/imm32/next +6097 _Primitive-copy-reg-to-mem: +6098 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 +6099 "copy-to"/imm32/name +6100 Two-args-int-stack-int-reg/imm32/inouts +6101 0/imm32/outputs +6102 "89/copy-to"/imm32/subx-name +6103 1/imm32/rm32-is-first-inout +6104 2/imm32/r32-is-second-inout +6105 0/imm32/no-imm32 +6106 0/imm32/no-disp32 +6107 1/imm32/output-is-write-only +6108 _Primitive-copy-mem-to-reg/imm32/next +6109 _Primitive-copy-mem-to-reg: +6110 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 +6111 "copy"/imm32/name +6112 Single-int-var-on-stack/imm32/inouts +6113 Single-int-var-in-some-register/imm32/outputs +6114 "8b/copy-from"/imm32/subx-name +6115 1/imm32/rm32-is-first-inout +6116 3/imm32/r32-is-first-output +6117 0/imm32/no-imm32 +6118 0/imm32/no-disp32 +6119 1/imm32/output-is-write-only +6120 _Primitive-copy-lit-to-reg/imm32/next +6121 _Primitive-copy-lit-to-reg: +6122 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 +6123 "copy"/imm32/name +6124 Single-lit-var/imm32/inouts +6125 Single-int-var-in-some-register/imm32/outputs +6126 "c7 0/subop/copy"/imm32/subx-name +6127 3/imm32/rm32-is-first-output +6128 0/imm32/no-r32 +6129 1/imm32/imm32-is-first-inout +6130 0/imm32/no-disp32 +6131 1/imm32/output-is-write-only +6132 _Primitive-copy-lit-to-mem/imm32/next +6133 _Primitive-copy-lit-to-mem: +6134 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 +6135 "copy-to"/imm32/name +6136 Int-var-and-literal/imm32/inouts +6137 0/imm32/outputs +6138 "c7 0/subop/copy"/imm32/subx-name +6139 1/imm32/rm32-is-first-inout +6140 0/imm32/no-r32 +6141 2/imm32/imm32-is-first-inout +6142 0/imm32/no-disp32 +6143 1/imm32/output-is-write-only +6144 _Primitive-compare-mem-with-reg/imm32/next +6145 # - compare +6146 _Primitive-compare-mem-with-reg: +6147 # compare var1 var2/reg => 39/compare-> var1/rm32 var2/r32 +6148 "compare"/imm32/name +6149 Two-args-int-stack-int-reg/imm32/inouts 6150 0/imm32/outputs -6151 "0f 83/jump-if-addr>="/imm32/subx-name -6152 0/imm32/no-rm32 -6153 0/imm32/no-r32 +6151 "39/compare->"/imm32/subx-name +6152 1/imm32/rm32-is-first-inout +6153 2/imm32/r32-is-second-inout 6154 0/imm32/no-imm32 -6155 1/imm32/disp32-is-first-inout -6156 0/imm32/no-output -6157 _Primitive-break-if-=-named/imm32/next -6158 _Primitive-break-if-=-named: -6159 "break-if-="/imm32/name -6160 Single-lit-var/imm32/inouts -6161 0/imm32/outputs -6162 "0f 84/jump-if-="/imm32/subx-name -6163 0/imm32/no-rm32 -6164 0/imm32/no-r32 -6165 0/imm32/no-imm32 -6166 1/imm32/disp32-is-first-inout -6167 0/imm32/no-output -6168 _Primitive-break-if-!=-named/imm32/next -6169 _Primitive-break-if-!=-named: -6170 "break-if-!="/imm32/name -6171 Single-lit-var/imm32/inouts -6172 0/imm32/outputs -6173 "0f 85/jump-if-!="/imm32/subx-name -6174 0/imm32/no-rm32 -6175 0/imm32/no-r32 -6176 0/imm32/no-imm32 -6177 1/imm32/disp32-is-first-inout -6178 0/imm32/no-output -6179 _Primitive-break-if-addr<=-named/imm32/next -6180 _Primitive-break-if-addr<=-named: -6181 "break-if-addr<="/imm32/name -6182 Single-lit-var/imm32/inouts -6183 0/imm32/outputs -6184 "0f 86/jump-if-addr<="/imm32/subx-name -6185 0/imm32/no-rm32 -6186 0/imm32/no-r32 -6187 0/imm32/no-imm32 -6188 1/imm32/disp32-is-first-inout -6189 0/imm32/no-output -6190 _Primitive-break-if-addr>-named/imm32/next -6191 _Primitive-break-if-addr>-named: -6192 "break-if-addr>"/imm32/name -6193 Single-lit-var/imm32/inouts -6194 0/imm32/outputs -6195 "0f 87/jump-if-addr>"/imm32/subx-name -6196 0/imm32/no-rm32 -6197 0/imm32/no-r32 -6198 0/imm32/no-imm32 -6199 1/imm32/disp32-is-first-inout -6200 0/imm32/no-output -6201 _Primitive-break-if-<-named/imm32/next -6202 _Primitive-break-if-<-named: -6203 "break-if-<"/imm32/name -6204 Single-lit-var/imm32/inouts -6205 0/imm32/outputs -6206 "0f 8c/jump-if-<"/imm32/subx-name -6207 0/imm32/no-rm32 -6208 0/imm32/no-r32 -6209 0/imm32/no-imm32 -6210 1/imm32/disp32-is-first-inout -6211 0/imm32/no-output -6212 _Primitive-break-if->=-named/imm32/next -6213 _Primitive-break-if->=-named: -6214 "break-if->="/imm32/name -6215 Single-lit-var/imm32/inouts -6216 0/imm32/outputs -6217 "0f 8d/jump-if->="/imm32/subx-name -6218 0/imm32/no-rm32 -6219 0/imm32/no-r32 -6220 0/imm32/no-imm32 -6221 1/imm32/disp32-is-first-inout -6222 0/imm32/no-output -6223 _Primitive-break-if-<=-named/imm32/next -6224 _Primitive-break-if-<=-named: -6225 "break-if-<="/imm32/name -6226 Single-lit-var/imm32/inouts -6227 0/imm32/outputs -6228 "0f 8e/jump-if-<="/imm32/subx-name -6229 0/imm32/no-rm32 -6230 0/imm32/no-r32 -6231 0/imm32/no-imm32 -6232 1/imm32/disp32-is-first-inout -6233 0/imm32/no-output -6234 _Primitive-break-if->-named/imm32/next -6235 _Primitive-break-if->-named: -6236 "break-if->"/imm32/name -6237 Single-lit-var/imm32/inouts -6238 0/imm32/outputs -6239 "0f 8f/jump-if->"/imm32/subx-name -6240 0/imm32/no-rm32 -6241 0/imm32/no-r32 -6242 0/imm32/no-imm32 -6243 1/imm32/disp32-is-first-inout -6244 0/imm32/no-output -6245 _Primitive-loop-if-addr<-named/imm32/next -6246 _Primitive-loop-if-addr<-named: -6247 "loop-if-addr<"/imm32/name -6248 Single-lit-var/imm32/inouts -6249 0/imm32/outputs -6250 "0f 82/jump-if-addr<"/imm32/subx-name -6251 0/imm32/no-rm32 -6252 0/imm32/no-r32 -6253 0/imm32/no-imm32 -6254 1/imm32/disp32-is-first-inout -6255 0/imm32/no-output -6256 _Primitive-loop-if-addr>=-named/imm32/next -6257 _Primitive-loop-if-addr>=-named: -6258 "loop-if-addr>="/imm32/name -6259 Single-lit-var/imm32/inouts -6260 0/imm32/outputs -6261 "0f 83/jump-if-addr>="/imm32/subx-name -6262 0/imm32/no-rm32 -6263 0/imm32/no-r32 -6264 0/imm32/no-imm32 -6265 1/imm32/disp32-is-first-inout -6266 0/imm32/no-output -6267 _Primitive-loop-if-=-named/imm32/next -6268 _Primitive-loop-if-=-named: -6269 "loop-if-="/imm32/name -6270 Single-lit-var/imm32/inouts -6271 0/imm32/outputs -6272 "0f 84/jump-if-="/imm32/subx-name -6273 0/imm32/no-rm32 -6274 0/imm32/no-r32 -6275 0/imm32/no-imm32 -6276 1/imm32/disp32-is-first-inout -6277 0/imm32/no-output -6278 _Primitive-loop-if-!=-named/imm32/next -6279 _Primitive-loop-if-!=-named: -6280 "loop-if-!="/imm32/name -6281 Single-lit-var/imm32/inouts -6282 0/imm32/outputs -6283 "0f 85/jump-if-!="/imm32/subx-name -6284 0/imm32/no-rm32 -6285 0/imm32/no-r32 -6286 0/imm32/no-imm32 -6287 1/imm32/disp32-is-first-inout -6288 0/imm32/no-output -6289 _Primitive-loop-if-addr<=-named/imm32/next -6290 _Primitive-loop-if-addr<=-named: -6291 "loop-if-addr<="/imm32/name -6292 Single-lit-var/imm32/inouts -6293 0/imm32/outputs -6294 "0f 86/jump-if-addr<="/imm32/subx-name -6295 0/imm32/no-rm32 -6296 0/imm32/no-r32 -6297 0/imm32/no-imm32 -6298 1/imm32/disp32-is-first-inout -6299 0/imm32/no-output -6300 _Primitive-loop-if-addr>-named/imm32/next -6301 _Primitive-loop-if-addr>-named: -6302 "loop-if-addr>"/imm32/name -6303 Single-lit-var/imm32/inouts -6304 0/imm32/outputs -6305 "0f 87/jump-if-addr>"/imm32/subx-name -6306 0/imm32/no-rm32 -6307 0/imm32/no-r32 -6308 0/imm32/no-imm32 -6309 1/imm32/disp32-is-first-inout -6310 0/imm32/no-output -6311 _Primitive-loop-if-<-named/imm32/next -6312 _Primitive-loop-if-<-named: -6313 "loop-if-<"/imm32/name -6314 Single-lit-var/imm32/inouts -6315 0/imm32/outputs -6316 "0f 8c/jump-if-<"/imm32/subx-name -6317 0/imm32/no-rm32 -6318 0/imm32/no-r32 -6319 0/imm32/no-imm32 -6320 1/imm32/disp32-is-first-inout -6321 0/imm32/no-output -6322 _Primitive-loop-if->=-named/imm32/next -6323 _Primitive-loop-if->=-named: -6324 "loop-if->="/imm32/name -6325 Single-lit-var/imm32/inouts -6326 0/imm32/outputs -6327 "0f 8d/jump-if->="/imm32/subx-name -6328 0/imm32/no-rm32 -6329 0/imm32/no-r32 -6330 0/imm32/no-imm32 -6331 1/imm32/disp32-is-first-inout -6332 0/imm32/no-output -6333 _Primitive-loop-if-<=-named/imm32/next -6334 _Primitive-loop-if-<=-named: -6335 "loop-if-<="/imm32/name -6336 Single-lit-var/imm32/inouts -6337 0/imm32/outputs -6338 "0f 8e/jump-if-<="/imm32/subx-name -6339 0/imm32/no-rm32 -6340 0/imm32/no-r32 -6341 0/imm32/no-imm32 -6342 1/imm32/disp32-is-first-inout -6343 0/imm32/no-output -6344 _Primitive-loop-if->-named/imm32/next -6345 _Primitive-loop-if->-named: -6346 "loop-if->"/imm32/name -6347 Single-lit-var/imm32/inouts -6348 0/imm32/outputs -6349 "0f 8f/jump-if->"/imm32/subx-name -6350 0/imm32/no-rm32 -6351 0/imm32/no-r32 -6352 0/imm32/no-imm32 -6353 1/imm32/disp32-is-first-inout -6354 0/imm32/no-output -6355 _Primitive-loop-named/imm32/next # we probably don't need an unconditional break -6356 _Primitive-loop-named: -6357 "loop"/imm32/name -6358 Single-lit-var/imm32/inouts -6359 0/imm32/outputs -6360 "e9/jump"/imm32/subx-name -6361 0/imm32/no-rm32 -6362 0/imm32/no-r32 -6363 0/imm32/no-imm32 -6364 1/imm32/disp32-is-first-inout -6365 0/imm32/no-output -6366 0/imm32/next -6367 -6368 Single-int-var-on-stack: -6369 Int-var-on-stack/imm32 -6370 0/imm32/next -6371 -6372 Int-var-on-stack: -6373 "arg1"/imm32/name -6374 Type-int/imm32 -6375 1/imm32/some-block-depth -6376 1/imm32/some-stack-offset -6377 0/imm32/no-register -6378 -6379 Two-args-int-stack-int-reg: -6380 Int-var-on-stack/imm32 -6381 Single-int-var-in-some-register/imm32/next -6382 -6383 Two-args-int-reg-int-stack: -6384 Int-var-in-some-register/imm32 -6385 Single-int-var-on-stack/imm32/next -6386 -6387 Two-args-int-eax-int-literal: -6388 Int-var-in-eax/imm32 -6389 Single-lit-var/imm32/next -6390 -6391 Int-var-and-literal: -6392 Int-var-on-stack/imm32 -6393 Single-lit-var/imm32/next -6394 -6395 Single-int-var-in-some-register: -6396 Int-var-in-some-register/imm32 -6397 0/imm32/next -6398 -6399 Int-var-in-some-register: -6400 "arg1"/imm32/name -6401 Type-int/imm32 -6402 1/imm32/some-block-depth -6403 0/imm32/no-stack-offset -6404 "*"/imm32/register -6405 -6406 Single-int-var-in-eax: -6407 Int-var-in-eax/imm32 -6408 0/imm32/next -6409 -6410 Int-var-in-eax: -6411 "arg1"/imm32/name -6412 Type-int/imm32 -6413 1/imm32/some-block-depth -6414 0/imm32/no-stack-offset -6415 "eax"/imm32/register -6416 -6417 Single-int-var-in-ecx: -6418 Int-var-in-ecx/imm32 -6419 0/imm32/next -6420 -6421 Int-var-in-ecx: -6422 "arg1"/imm32/name -6423 Type-int/imm32 -6424 1/imm32/some-block-depth -6425 0/imm32/no-stack-offset -6426 "ecx"/imm32/register -6427 -6428 Single-int-var-in-edx: -6429 Int-var-in-edx/imm32 -6430 0/imm32/next -6431 -6432 Int-var-in-edx: -6433 "arg1"/imm32/name -6434 Type-int/imm32 -6435 1/imm32/some-block-depth -6436 0/imm32/no-stack-offset -6437 "edx"/imm32/register -6438 -6439 Single-int-var-in-ebx: -6440 Int-var-in-ebx/imm32 -6441 0/imm32/next -6442 -6443 Int-var-in-ebx: -6444 "arg1"/imm32/name -6445 Type-int/imm32 -6446 1/imm32/some-block-depth -6447 0/imm32/no-stack-offset -6448 "ebx"/imm32/register -6449 -6450 Single-int-var-in-esi: -6451 Int-var-in-esi/imm32 -6452 0/imm32/next -6453 -6454 Int-var-in-esi: -6455 "arg1"/imm32/name -6456 Type-int/imm32 -6457 1/imm32/some-block-depth -6458 0/imm32/no-stack-offset -6459 "esi"/imm32/register -6460 -6461 Single-int-var-in-edi: -6462 Int-var-in-edi/imm32 -6463 0/imm32/next -6464 -6465 Int-var-in-edi: -6466 "arg1"/imm32/name -6467 Type-int/imm32 -6468 1/imm32/some-block-depth -6469 0/imm32/no-stack-offset -6470 "edi"/imm32/register -6471 -6472 Single-lit-var: -6473 Lit-var/imm32 -6474 0/imm32/next -6475 -6476 Lit-var: -6477 "literal"/imm32/name -6478 Type-literal/imm32 -6479 1/imm32/some-block-depth -6480 0/imm32/no-stack-offset -6481 0/imm32/no-register -6482 -6483 Type-int: -6484 1/imm32/left/int -6485 0/imm32/right/null -6486 -6487 Type-literal: -6488 0/imm32/left/literal -6489 0/imm32/right/null -6490 -6491 == code -6492 emit-subx-primitive: # out: (addr buffered-file), stmt: (handle statement), primitive: (handle function) -6493 # . prologue -6494 55/push-ebp -6495 89/<- %ebp 4/r32/esp -6496 # . save registers -6497 50/push-eax -6498 51/push-ecx -6499 # ecx = primitive -6500 8b/-> *(ebp+0x10) 1/r32/ecx -6501 # emit primitive name -6502 (emit-indent *(ebp+8) *Curr-block-depth) -6503 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name -6504 # emit rm32 if necessary -6505 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt -6506 # emit r32 if necessary -6507 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt -6508 # emit imm32 if necessary -6509 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt -6510 # emit disp32 if necessary -6511 (emit-subx-disp32 *(ebp+8) *(ecx+0x1c) *(ebp+0xc)) # out, Primitive-subx-disp32, stmt -6512 (write-buffered *(ebp+8) Newline) -6513 $emit-subx-primitive:end: -6514 # . restore registers -6515 59/pop-to-ecx -6516 58/pop-to-eax -6517 # . epilogue -6518 89/<- %esp 5/r32/ebp -6519 5d/pop-to-ebp -6520 c3/return -6521 -6522 emit-subx-rm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) -6523 # . prologue -6524 55/push-ebp -6525 89/<- %ebp 4/r32/esp -6526 # . save registers -6527 50/push-eax -6528 # if (l == 0) return -6529 81 7/subop/compare *(ebp+0xc) 0/imm32 -6530 74/jump-if-= $emit-subx-rm32:end/disp8 -6531 # -6532 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -6533 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var -6534 $emit-subx-rm32:end: -6535 # . restore registers -6536 58/pop-to-eax -6537 # . epilogue -6538 89/<- %esp 5/r32/ebp -6539 5d/pop-to-ebp -6540 c3/return -6541 -6542 get-stmt-operand-from-arg-location: # stmt: (handle statement), l: arg-location -> var/eax: (handle variable) -6543 # . prologue -6544 55/push-ebp -6545 89/<- %ebp 4/r32/esp -6546 # . save registers -6547 51/push-ecx -6548 # eax = l -6549 8b/-> *(ebp+0xc) 0/r32/eax -6550 # ecx = stmt -6551 8b/-> *(ebp+8) 1/r32/ecx -6552 # if (l == 1) return stmt->inouts->var -6553 { -6554 3d/compare-eax-and 1/imm32 -6555 75/jump-if-!= break/disp8 -6556 $get-stmt-operand-from-arg-location:1: -6557 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -6558 8b/-> *eax 0/r32/eax # Operand-var -6559 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -6560 } -6561 # if (l == 2) return stmt->inouts->next->var -6562 { -6563 3d/compare-eax-and 2/imm32 -6564 75/jump-if-!= break/disp8 -6565 $get-stmt-operand-from-arg-location:2: -6566 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -6567 8b/-> *(eax+4) 0/r32/eax # Operand-next -6568 8b/-> *eax 0/r32/eax # Operand-var -6569 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -6570 } -6571 # if (l == 3) return stmt->outputs -6572 { -6573 3d/compare-eax-and 3/imm32 -6574 75/jump-if-!= break/disp8 -6575 $get-stmt-operand-from-arg-location:3: -6576 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs -6577 8b/-> *eax 0/r32/eax # Operand-var -6578 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -6579 } -6580 # abort -6581 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 -6582 $get-stmt-operand-from-arg-location:end: -6583 # . restore registers -6584 59/pop-to-ecx -6585 # . epilogue -6586 89/<- %esp 5/r32/ebp -6587 5d/pop-to-ebp -6588 c3/return -6589 -6590 $get-stmt-operand-from-arg-location:abort: -6591 # error("invalid arg-location " eax) -6592 (write-buffered Stderr "invalid arg-location ") -6593 (print-int32-buffered Stderr %eax) -6594 (write-buffered Stderr Newline) -6595 (flush Stderr) -6596 # . syscall(exit, 1) -6597 bb/copy-to-ebx 1/imm32 -6598 b8/copy-to-eax 1/imm32/exit -6599 cd/syscall 0x80/imm8 -6600 # never gets here -6601 -6602 emit-subx-r32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) -6603 # . prologue -6604 55/push-ebp -6605 89/<- %ebp 4/r32/esp -6606 # . save registers -6607 50/push-eax -6608 51/push-ecx -6609 # if (location == 0) return -6610 81 7/subop/compare *(ebp+0xc) 0/imm32 -6611 0f 84/jump-if-= $emit-subx-r32:end/disp32 -6612 # -6613 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -6614 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax: (addr register-index) -6615 (write-buffered *(ebp+8) Space) -6616 (print-int32-buffered *(ebp+8) *eax) -6617 (write-buffered *(ebp+8) "/r32") -6618 $emit-subx-r32:end: -6619 # . restore registers -6620 59/pop-to-ecx -6621 58/pop-to-eax -6622 # . epilogue -6623 89/<- %esp 5/r32/ebp -6624 5d/pop-to-ebp -6625 c3/return -6626 -6627 emit-subx-imm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) -6628 # . prologue -6629 55/push-ebp -6630 89/<- %ebp 4/r32/esp -6631 # . save registers -6632 50/push-eax -6633 51/push-ecx -6634 # if (location == 0) return -6635 81 7/subop/compare *(ebp+0xc) 0/imm32 -6636 74/jump-if-= $emit-subx-imm32:end/disp8 -6637 # -6638 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -6639 (write-buffered *(ebp+8) Space) -6640 (write-buffered *(ebp+8) *eax) # Var-name -6641 (write-buffered *(ebp+8) "/imm32") -6642 $emit-subx-imm32:end: -6643 # . restore registers -6644 59/pop-to-ecx -6645 58/pop-to-eax -6646 # . epilogue -6647 89/<- %esp 5/r32/ebp -6648 5d/pop-to-ebp -6649 c3/return -6650 -6651 emit-subx-disp32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) -6652 # . prologue -6653 55/push-ebp -6654 89/<- %ebp 4/r32/esp -6655 # . save registers -6656 50/push-eax -6657 51/push-ecx -6658 # if (location == 0) return -6659 81 7/subop/compare *(ebp+0xc) 0/imm32 -6660 0f 84/jump-if-= $emit-subx-disp32:end/disp32 -6661 # -6662 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -6663 (write-buffered *(ebp+8) Space) -6664 (write-buffered *(ebp+8) *eax) # Var-name -6665 # hack: if instruction operation starts with "break", emit ":break" -6666 # var name/ecx: (addr array byte) = stmt->operation -6667 8b/-> *(ebp+0x10) 0/r32/eax -6668 8b/-> *(eax+4) 1/r32/ecx -6669 { -6670 (string-starts-with? %ecx "break") # => eax -6671 3d/compare-eax-and 0/imm32/false -6672 74/jump-if-= break/disp8 -6673 (write-buffered *(ebp+8) ":break") -6674 } -6675 # hack: if instruction operation starts with "loop", emit ":loop" -6676 { -6677 (string-starts-with? %ecx "loop") # => eax -6678 3d/compare-eax-and 0/imm32/false -6679 74/jump-if-= break/disp8 -6680 (write-buffered *(ebp+8) ":loop") -6681 } -6682 (write-buffered *(ebp+8) "/disp32") -6683 $emit-subx-disp32:end: -6684 # . restore registers -6685 59/pop-to-ecx -6686 58/pop-to-eax -6687 # . epilogue -6688 89/<- %esp 5/r32/ebp -6689 5d/pop-to-ebp -6690 c3/return -6691 -6692 emit-subx-call: # out: (addr buffered-file), stmt: (handle statement), callee: (handle function) -6693 # . prologue -6694 55/push-ebp -6695 89/<- %ebp 4/r32/esp -6696 # . save registers -6697 51/push-ecx -6698 # -6699 (emit-indent *(ebp+8) *Curr-block-depth) -6700 (write-buffered *(ebp+8) "(") -6701 # - emit function name -6702 8b/-> *(ebp+0x10) 1/r32/ecx -6703 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name -6704 # - emit arguments -6705 # var curr/ecx: (handle list var) = stmt->inouts -6706 8b/-> *(ebp+0xc) 1/r32/ecx -6707 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts -6708 { -6709 # if (curr == null) break -6710 81 7/subop/compare %ecx 0/imm32 -6711 74/jump-if-= break/disp8 -6712 # -6713 (emit-subx-call-operand *(ebp+8) *ecx) -6714 # curr = curr->next -6715 8b/-> *(ecx+4) 1/r32/ecx -6716 eb/jump loop/disp8 -6717 } -6718 # -6719 (write-buffered *(ebp+8) ")\n") -6720 $emit-subx-call:end: -6721 # . restore registers -6722 59/pop-to-ecx -6723 # . epilogue -6724 89/<- %esp 5/r32/ebp -6725 5d/pop-to-ebp -6726 c3/return -6727 -6728 # like a function call, except we have no idea what function it is -6729 # we hope it's defined in SubX and that the types are ok -6730 emit-hailmary-call: # out: (addr buffered-file), stmt: (handle statement) -6731 # . prologue -6732 55/push-ebp -6733 89/<- %ebp 4/r32/esp -6734 # . save registers -6735 51/push-ecx -6736 # -6737 (emit-indent *(ebp+8) *Curr-block-depth) -6738 (write-buffered *(ebp+8) "(") -6739 # ecx = stmt -6740 8b/-> *(ebp+0xc) 1/r32/ecx -6741 # - emit function name -6742 (write-buffered *(ebp+8) *(ecx+4)) # Stmt1-operation -6743 # - emit arguments -6744 # var curr/ecx: (handle list var) = stmt->inouts -6745 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts -6746 { -6747 # if (curr == null) break -6748 81 7/subop/compare %ecx 0/imm32 -6749 74/jump-if-= break/disp8 -6750 # -6751 (emit-subx-call-operand *(ebp+8) *ecx) -6752 # curr = curr->next -6753 8b/-> *(ecx+4) 1/r32/ecx -6754 eb/jump loop/disp8 -6755 } -6756 # -6757 (write-buffered *(ebp+8) ")\n") -6758 $emit-hailmary-call:end: -6759 # . restore registers -6760 59/pop-to-ecx -6761 # . epilogue -6762 89/<- %esp 5/r32/ebp -6763 5d/pop-to-ebp -6764 c3/return -6765 -6766 emit-subx-call-operand: # out: (addr buffered-file), operand: (handle variable) -6767 # shares code with emit-subx-var-as-rm32 -6768 # . prologue -6769 55/push-ebp -6770 89/<- %ebp 4/r32/esp -6771 # . save registers -6772 50/push-eax -6773 # eax = operand -6774 8b/-> *(ebp+0xc) 0/r32/eax -6775 # if (operand->register) emit "%__" -6776 { -6777 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -6778 74/jump-if-= break/disp8 -6779 $emit-subx-call-operand:register: -6780 (write-buffered *(ebp+8) " %") -6781 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -6782 e9/jump $emit-subx-call-operand:end/disp32 -6783 } -6784 # else if (operand->stack-offset) emit "*(ebp+__)" -6785 { -6786 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -6787 74/jump-if-= break/disp8 -6788 $emit-subx-call-operand:stack: -6789 (write-buffered *(ebp+8) Space) -6790 (write-buffered *(ebp+8) "*(ebp+") -6791 8b/-> *(ebp+0xc) 0/r32/eax -6792 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -6793 (write-buffered *(ebp+8) ")") -6794 e9/jump $emit-subx-call-operand:end/disp32 -6795 } -6796 # else if (operand->type == literal) emit "__" -6797 { -6798 50/push-eax -6799 8b/-> *(eax+4) 0/r32/eax # Var-type -6800 81 7/subop/compare *eax 0/imm32 # Tree-left -6801 58/pop-to-eax -6802 75/jump-if-!= break/disp8 -6803 $emit-subx-call-operand:literal: -6804 (write-buffered *(ebp+8) Space) -6805 (write-buffered *(ebp+8) *eax) -6806 } -6807 $emit-subx-call-operand:end: -6808 # . restore registers -6809 58/pop-to-eax -6810 # . epilogue -6811 89/<- %esp 5/r32/ebp -6812 5d/pop-to-ebp -6813 c3/return -6814 -6815 emit-subx-var-as-rm32: # out: (addr buffered-file), operand: (handle variable) -6816 # . prologue -6817 55/push-ebp -6818 89/<- %ebp 4/r32/esp -6819 # . save registers -6820 50/push-eax -6821 # eax = operand -6822 8b/-> *(ebp+0xc) 0/r32/eax -6823 # if (operand->register) emit "%__" -6824 { -6825 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -6826 74/jump-if-= break/disp8 -6827 $emit-subx-var-as-rm32:register: -6828 (write-buffered *(ebp+8) " %") -6829 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -6830 } -6831 # else if (operand->stack-offset) emit "*(ebp+__)" -6832 { -6833 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -6834 74/jump-if-= break/disp8 -6835 $emit-subx-var-as-rm32:stack: -6836 (write-buffered *(ebp+8) Space) -6837 (write-buffered *(ebp+8) "*(ebp+") -6838 8b/-> *(ebp+0xc) 0/r32/eax -6839 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -6840 (write-buffered *(ebp+8) ")") -6841 } -6842 $emit-subx-var-as-rm32:end: -6843 # . restore registers -6844 58/pop-to-eax -6845 # . epilogue -6846 89/<- %esp 5/r32/ebp -6847 5d/pop-to-ebp -6848 c3/return -6849 -6850 find-matching-function: # functions: (addr function), stmt: (handle statement) -> result/eax: (handle function) -6851 # . prologue -6852 55/push-ebp -6853 89/<- %ebp 4/r32/esp -6854 # . save registers -6855 51/push-ecx -6856 # var curr/ecx: (handle function) = functions -6857 8b/-> *(ebp+8) 1/r32/ecx -6858 { -6859 # if (curr == null) break -6860 81 7/subop/compare %ecx 0/imm32 -6861 74/jump-if-= break/disp8 -6862 # if match(stmt, curr) return curr -6863 { -6864 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax -6865 3d/compare-eax-and 0/imm32/false -6866 74/jump-if-= break/disp8 -6867 89/<- %eax 1/r32/ecx -6868 eb/jump $find-matching-function:end/disp8 -6869 } -6870 # curr = curr->next -6871 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -6872 eb/jump loop/disp8 -6873 } -6874 # return null -6875 b8/copy-to-eax 0/imm32 -6876 $find-matching-function:end: -6877 # . restore registers -6878 59/pop-to-ecx -6879 # . epilogue -6880 89/<- %esp 5/r32/ebp -6881 5d/pop-to-ebp -6882 c3/return -6883 -6884 find-matching-primitive: # primitives: (handle primitive), stmt: (handle statement) -> result/eax: (handle primitive) -6885 # . prologue -6886 55/push-ebp -6887 89/<- %ebp 4/r32/esp -6888 # . save registers -6889 51/push-ecx -6890 # var curr/ecx: (handle primitive) = primitives -6891 8b/-> *(ebp+8) 1/r32/ecx -6892 { -6893 $find-matching-primitive:loop: -6894 # if (curr == null) break -6895 81 7/subop/compare %ecx 0/imm32 -6896 0f 84/jump-if-= break/disp32 -6897 #? (write-buffered Stderr "prim: ") -6898 #? (write-buffered Stderr *ecx) # Primitive-name -6899 #? (write-buffered Stderr " => ") -6900 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name -6901 #? (write-buffered Stderr Newline) -6902 #? (flush Stderr) -6903 # if match(curr, stmt) return curr -6904 { -6905 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax -6906 3d/compare-eax-and 0/imm32/false -6907 74/jump-if-= break/disp8 -6908 89/<- %eax 1/r32/ecx -6909 eb/jump $find-matching-primitive:end/disp8 -6910 } -6911 $find-matching-primitive:next-primitive: -6912 # curr = curr->next -6913 8b/-> *(ecx+0x24) 1/r32/ecx # Primitive-next -6914 e9/jump loop/disp32 -6915 } -6916 # return null -6917 b8/copy-to-eax 0/imm32 -6918 $find-matching-primitive:end: -6919 # . restore registers -6920 59/pop-to-ecx -6921 # . epilogue -6922 89/<- %esp 5/r32/ebp -6923 5d/pop-to-ebp -6924 c3/return -6925 -6926 mu-stmt-matches-function?: # stmt: (handle statement), function: (handle function) -> result/eax: boolean -6927 # . prologue -6928 55/push-ebp -6929 89/<- %ebp 4/r32/esp -6930 # . save registers -6931 51/push-ecx -6932 # return function->name == stmt->operation -6933 8b/-> *(ebp+8) 1/r32/ecx -6934 8b/-> *(ebp+0xc) 0/r32/eax -6935 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax -6936 $mu-stmt-matches-function?:end: -6937 # . restore registers -6938 59/pop-to-ecx -6939 # . epilogue -6940 89/<- %esp 5/r32/ebp -6941 5d/pop-to-ebp -6942 c3/return -6943 -6944 mu-stmt-matches-primitive?: # stmt: (handle statement), primitive: (handle primitive) -> result/eax: boolean -6945 # A mu stmt matches a primitive if the name matches, all the inout vars -6946 # match, and all the output vars match. -6947 # Vars match if types match and registers match. -6948 # In addition, a stmt output matches a primitive's output if types match -6949 # and the primitive has a wildcard register. -6950 # . prologue -6951 55/push-ebp -6952 89/<- %ebp 4/r32/esp -6953 # . save registers -6954 51/push-ecx -6955 52/push-edx -6956 53/push-ebx -6957 56/push-esi -6958 57/push-edi -6959 # ecx = stmt -6960 8b/-> *(ebp+8) 1/r32/ecx -6961 # edx = primitive -6962 8b/-> *(ebp+0xc) 2/r32/edx -6963 { -6964 $mu-stmt-matches-primitive?:check-name: -6965 # if (primitive->name != stmt->operation) return false -6966 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax -6967 3d/compare-eax-and 0/imm32/false -6968 75/jump-if-!= break/disp8 -6969 b8/copy-to-eax 0/imm32 -6970 e9/jump $mu-stmt-matches-primitive?:end/disp32 -6971 } -6972 $mu-stmt-matches-primitive?:check-inouts: -6973 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) -6974 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts -6975 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts -6976 { -6977 # if (curr == 0 && curr2 == 0) move on to check outputs -6978 { -6979 81 7/subop/compare %esi 0/imm32 -6980 75/jump-if-!= break/disp8 -6981 $mu-stmt-matches-primitive?:stmt-inout-is-null: -6982 { -6983 81 7/subop/compare %edi 0/imm32 -6984 75/jump-if-!= break/disp8 -6985 # -6986 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 -6987 } -6988 # return false -6989 b8/copy-to-eax 0/imm32/false -6990 e9/jump $mu-stmt-matches-primitive?:end/disp32 -6991 } -6992 # if (curr2 == 0) return false -6993 { -6994 81 7/subop/compare %edi 0/imm32 -6995 75/jump-if-!= break/disp8 -6996 $mu-stmt-matches-primitive?:prim-inout-is-null: -6997 b8/copy-to-eax 0/imm32/false -6998 e9/jump $mu-stmt-matches-primitive?:end/disp32 -6999 } -7000 # if (curr != curr2) return false -7001 { -7002 (operand-matches-primitive? *esi *edi) # => eax -7003 3d/compare-eax-and 0/imm32/false -7004 75/jump-if-!= break/disp8 -7005 b8/copy-to-eax 0/imm32/false -7006 e9/jump $mu-stmt-matches-primitive?:end/disp32 -7007 } -7008 # curr=curr->next -7009 8b/-> *(esi+4) 6/r32/esi # Operand-next -7010 # curr2=curr2->next -7011 8b/-> *(edi+4) 7/r32/edi # Operand-next -7012 eb/jump loop/disp8 -7013 } -7014 $mu-stmt-matches-primitive?:check-outputs: -7015 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) -7016 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs -7017 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs -7018 { -7019 # if (curr == 0) return (curr2 == 0) -7020 { -7021 $mu-stmt-matches-primitive?:check-output: -7022 81 7/subop/compare %esi 0/imm32 -7023 75/jump-if-!= break/disp8 -7024 { -7025 81 7/subop/compare %edi 0/imm32 -7026 75/jump-if-!= break/disp8 -7027 # return true -7028 b8/copy-to-eax 1/imm32 -7029 e9/jump $mu-stmt-matches-primitive?:end/disp32 -7030 } -7031 # return false -7032 b8/copy-to-eax 0/imm32 -7033 e9/jump $mu-stmt-matches-primitive?:end/disp32 -7034 } -7035 # if (curr2 == 0) return false -7036 { -7037 81 7/subop/compare %edi 0/imm32 -7038 75/jump-if-!= break/disp8 -7039 b8/copy-to-eax 0/imm32 -7040 e9/jump $mu-stmt-matches-primitive?:end/disp32 -7041 } -7042 # if (curr != curr2) return false -7043 { -7044 (operand-matches-primitive? *esi *edi) # List-value List-value => eax -7045 3d/compare-eax-and 0/imm32/false -7046 75/jump-if-!= break/disp8 -7047 b8/copy-to-eax 0/imm32 -7048 e9/jump $mu-stmt-matches-primitive?:end/disp32 -7049 } -7050 # curr=curr->next -7051 8b/-> *(esi+4) 6/r32/esi # Operand-next -7052 # curr2=curr2->next -7053 8b/-> *(edi+4) 7/r32/edi # Operand-next -7054 eb/jump loop/disp8 -7055 } -7056 $mu-stmt-matches-primitive?:return-true: -7057 b8/copy-to-eax 1/imm32 -7058 $mu-stmt-matches-primitive?:end: -7059 # . restore registers -7060 5f/pop-to-edi -7061 5e/pop-to-esi -7062 5b/pop-to-ebx -7063 5a/pop-to-edx -7064 59/pop-to-ecx -7065 # . epilogue -7066 89/<- %esp 5/r32/ebp -7067 5d/pop-to-ebp -7068 c3/return -7069 -7070 operand-matches-primitive?: # var: (handle var), prim-var: (handle var) -> result/eax: boolean -7071 # . prologue -7072 55/push-ebp -7073 89/<- %ebp 4/r32/esp -7074 # . save registers -7075 56/push-esi -7076 57/push-edi -7077 # esi = var -7078 8b/-> *(ebp+8) 6/r32/esi -7079 # edi = prim-var -7080 8b/-> *(ebp+0xc) 7/r32/edi -7081 # if (var->type != prim-var->type) return false -7082 (type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax -7083 3d/compare-eax-and 0/imm32/false -7084 b8/copy-to-eax 0/imm32/false -7085 74/jump-if-= $operand-matches-primitive?:end/disp8 -7086 # return false if var->register doesn't match prim-var->register -7087 { -7088 # if addresses are equal, don't return here -7089 8b/-> *(esi+0x10) 0/r32/eax -7090 39/compare *(edi+0x10) 0/r32/eax -7091 74/jump-if-= break/disp8 -7092 # if either address is 0, return false -7093 3d/compare-eax-and 0/imm32 -7094 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -7095 81 7/subop/compare *(edi+0x10) 0/imm32 -7096 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -7097 # if prim-var->register is "*", return true -7098 (string-equal? *(edi+0x10) "*") # Var-register -7099 3d/compare-eax-and 0/imm32/false -7100 b8/copy-to-eax 1/imm32/true -7101 75/jump-if-!= $operand-matches-primitive?:end/disp8 -7102 # if string contents don't match, return false -7103 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register -7104 3d/compare-eax-and 0/imm32/false -7105 b8/copy-to-eax 0/imm32/false -7106 74/jump-if-= $operand-matches-primitive?:end/disp8 -7107 } -7108 # return true -7109 b8/copy-to-eax 1/imm32/true -7110 $operand-matches-primitive?:end: -7111 # . restore registers -7112 5f/pop-to-edi -7113 5e/pop-to-esi -7114 # . epilogue -7115 89/<- %esp 5/r32/ebp -7116 5d/pop-to-ebp -7117 c3/return -7118 -7119 subx-type-equal?: # a: (handle tree type-id), b: (handle tree type-id) -> result/eax: boolean -7120 # . prologue -7121 55/push-ebp -7122 89/<- %ebp 4/r32/esp -7123 # . save registers -7124 51/push-ecx -7125 # var alit/ecx: boolean = is-literal-type?(a) -7126 (is-literal-type? *(ebp+8)) # => eax -7127 89/<- %ecx 0/r32/eax -7128 # var blit/eax: boolean = is-literal-type?(b) -7129 (is-literal-type? *(ebp+0xc)) # => eax -7130 # return alit == blit -7131 39/compare %eax 1/r32/ecx -7132 74/jump-if-= $subx-type-equal?:true/disp8 -7133 $subx-type-equal?:false: -7134 b8/copy-to-eax 0/imm32/false -7135 eb/jump $subx-type-equal?:end/disp8 -7136 $subx-type-equal?:true: -7137 b8/copy-to-eax 1/imm32/true -7138 $subx-type-equal?:end: -7139 # . restore registers -7140 59/pop-to-ecx -7141 # . epilogue -7142 89/<- %esp 5/r32/ebp -7143 5d/pop-to-ebp -7144 c3/return -7145 -7146 is-literal-type?: # a: (handle tree type-id) -> result/eax: boolean -7147 # . prologue -7148 55/push-ebp -7149 89/<- %ebp 4/r32/esp -7150 # -7151 8b/-> *(ebp+8) 0/r32/eax -7152 8b/-> *eax 0/r32/eax # Atom-value -7153 $is-literal-type?:end: -7154 # . epilogue -7155 89/<- %esp 5/r32/ebp -7156 5d/pop-to-ebp -7157 c3/return -7158 -7159 test-emit-subx-statement-primitive: -7160 # Primitive operation on a variable on the stack. -7161 # increment foo -7162 # => -7163 # ff 0/subop/increment *(ebp-8) -7164 # -7165 # There's a variable on the var stack as follows: -7166 # name: 'foo' -7167 # type: int -7168 # stack-offset: -8 -7169 # -7170 # There's a primitive with this info: -7171 # name: 'increment' -7172 # inouts: int/mem -7173 # value: 'ff 0/subop/increment' -7174 # -7175 # There's nothing in functions. -7176 # +6155 0/imm32/no-disp32 +6156 0/imm32/output-is-write-only +6157 _Primitive-compare-reg-with-mem/imm32/next +6158 _Primitive-compare-reg-with-mem: +6159 # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32 +6160 "compare"/imm32/name +6161 Two-args-int-reg-int-stack/imm32/inouts +6162 0/imm32/outputs +6163 "3b/compare<-"/imm32/subx-name +6164 2/imm32/rm32-is-second-inout +6165 1/imm32/r32-is-first-inout +6166 0/imm32/no-imm32 +6167 0/imm32/no-disp32 +6168 0/imm32/output-is-write-only +6169 _Primitive-compare-eax-with-literal/imm32/next +6170 _Primitive-compare-eax-with-literal: +6171 # compare var1/eax n => 3d/compare-eax-with n/imm32 +6172 "compare"/imm32/name +6173 Two-args-int-eax-int-literal/imm32/inouts +6174 0/imm32/outputs +6175 "3d/compare-eax-with"/imm32/subx-name +6176 0/imm32/no-rm32 +6177 0/imm32/no-r32 +6178 2/imm32/imm32-is-second-inout +6179 0/imm32/no-disp32 +6180 0/imm32/output-is-write-only +6181 _Primitive-compare-regmem-with-literal/imm32/next +6182 _Primitive-compare-regmem-with-literal: +6183 # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32 +6184 "compare"/imm32/name +6185 Int-var-and-literal/imm32/inouts +6186 0/imm32/outputs +6187 "81 7/subop/compare"/imm32/subx-name +6188 1/imm32/rm32-is-first-inout +6189 0/imm32/no-r32 +6190 2/imm32/imm32-is-second-inout +6191 0/imm32/no-disp32 +6192 0/imm32/output-is-write-only +6193 _Primitive-multiply-reg-by-mem/imm32/next +6194 # - multiply +6195 _Primitive-multiply-reg-by-mem: +6196 # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32 +6197 "multiply"/imm32/name +6198 Single-int-var-on-stack/imm32/inouts +6199 Single-int-var-in-some-register/imm32/outputs +6200 "0f af/multiply"/imm32/subx-name +6201 1/imm32/rm32-is-first-inout +6202 3/imm32/r32-is-first-output +6203 0/imm32/no-imm32 +6204 0/imm32/no-disp32 +6205 0/imm32/output-is-write-only +6206 _Primitive-break-if-addr</imm32/next +6207 # - branches +6208 _Primitive-break-if-addr<: +6209 "break-if-addr<"/imm32/name +6210 0/imm32/inouts +6211 0/imm32/outputs +6212 "0f 82/jump-if-addr< break/disp32"/imm32/subx-name +6213 0/imm32/no-rm32 +6214 0/imm32/no-r32 +6215 0/imm32/no-imm32 +6216 0/imm32/no-disp32 +6217 0/imm32/no-output +6218 _Primitive-break-if-addr>=/imm32/next +6219 _Primitive-break-if-addr>=: +6220 "break-if-addr>="/imm32/name +6221 0/imm32/inouts +6222 0/imm32/outputs +6223 "0f 83/jump-if-addr>= break/disp32"/imm32/subx-name +6224 0/imm32/no-rm32 +6225 0/imm32/no-r32 +6226 0/imm32/no-imm32 +6227 0/imm32/no-disp32 +6228 0/imm32/no-output +6229 _Primitive-break-if-=/imm32/next +6230 _Primitive-break-if-=: +6231 "break-if-="/imm32/name +6232 0/imm32/inouts +6233 0/imm32/outputs +6234 "0f 84/jump-if-= break/disp32"/imm32/subx-name +6235 0/imm32/no-rm32 +6236 0/imm32/no-r32 +6237 0/imm32/no-imm32 +6238 0/imm32/no-disp32 +6239 0/imm32/no-output +6240 _Primitive-break-if-!=/imm32/next +6241 _Primitive-break-if-!=: +6242 "break-if-!="/imm32/name +6243 0/imm32/inouts +6244 0/imm32/outputs +6245 "0f 85/jump-if-!= break/disp32"/imm32/subx-name +6246 0/imm32/no-rm32 +6247 0/imm32/no-r32 +6248 0/imm32/no-imm32 +6249 0/imm32/no-disp32 +6250 0/imm32/no-output +6251 _Primitive-break-if-addr<=/imm32/next +6252 _Primitive-break-if-addr<=: +6253 "break-if-addr<="/imm32/name +6254 0/imm32/inouts +6255 0/imm32/outputs +6256 "0f 86/jump-if-addr<= break/disp32"/imm32/subx-name +6257 0/imm32/no-rm32 +6258 0/imm32/no-r32 +6259 0/imm32/no-imm32 +6260 0/imm32/no-disp32 +6261 0/imm32/no-output +6262 _Primitive-break-if-addr>/imm32/next +6263 _Primitive-break-if-addr>: +6264 "break-if-addr>"/imm32/name +6265 0/imm32/inouts +6266 0/imm32/outputs +6267 "0f 87/jump-if-addr> break/disp32"/imm32/subx-name +6268 0/imm32/no-rm32 +6269 0/imm32/no-r32 +6270 0/imm32/no-imm32 +6271 0/imm32/no-disp32 +6272 0/imm32/no-output +6273 _Primitive-break-if-</imm32/next +6274 _Primitive-break-if-<: +6275 "break-if-<"/imm32/name +6276 0/imm32/inouts +6277 0/imm32/outputs +6278 "0f 8c/jump-if-< break/disp32"/imm32/subx-name +6279 0/imm32/no-rm32 +6280 0/imm32/no-r32 +6281 0/imm32/no-imm32 +6282 0/imm32/no-disp32 +6283 0/imm32/no-output +6284 _Primitive-break-if->=/imm32/next +6285 _Primitive-break-if->=: +6286 "break-if->="/imm32/name +6287 0/imm32/inouts +6288 0/imm32/outputs +6289 "0f 8d/jump-if->= break/disp32"/imm32/subx-name +6290 0/imm32/no-rm32 +6291 0/imm32/no-r32 +6292 0/imm32/no-imm32 +6293 0/imm32/no-disp32 +6294 0/imm32/no-output +6295 _Primitive-break-if-<=/imm32/next +6296 _Primitive-break-if-<=: +6297 "break-if-<="/imm32/name +6298 0/imm32/inouts +6299 0/imm32/outputs +6300 "0f 8e/jump-if-<= break/disp32"/imm32/subx-name +6301 0/imm32/no-rm32 +6302 0/imm32/no-r32 +6303 0/imm32/no-imm32 +6304 0/imm32/no-disp32 +6305 0/imm32/no-output +6306 _Primitive-break-if->/imm32/next +6307 _Primitive-break-if->: +6308 "break-if->"/imm32/name +6309 0/imm32/inouts +6310 0/imm32/outputs +6311 "0f 8f/jump-if-> break/disp32"/imm32/subx-name +6312 0/imm32/no-rm32 +6313 0/imm32/no-r32 +6314 0/imm32/no-imm32 +6315 0/imm32/no-disp32 +6316 0/imm32/no-output +6317 _Primitive-break/imm32/next +6318 _Primitive-break: +6319 "break"/imm32/name +6320 0/imm32/inouts +6321 0/imm32/outputs +6322 "e9/jump break/disp32"/imm32/subx-name +6323 0/imm32/no-rm32 +6324 0/imm32/no-r32 +6325 0/imm32/no-imm32 +6326 0/imm32/no-disp32 +6327 0/imm32/no-output +6328 _Primitive-loop-if-addr</imm32/next +6329 _Primitive-loop-if-addr<: +6330 "loop-if-addr<"/imm32/name +6331 0/imm32/inouts +6332 0/imm32/outputs +6333 "0f 82/jump-if-addr< loop/disp32"/imm32/subx-name +6334 0/imm32/no-rm32 +6335 0/imm32/no-r32 +6336 0/imm32/no-imm32 +6337 0/imm32/no-disp32 +6338 0/imm32/no-output +6339 _Primitive-loop-if-addr>=/imm32/next +6340 _Primitive-loop-if-addr>=: +6341 "loop-if-addr>="/imm32/name +6342 0/imm32/inouts +6343 0/imm32/outputs +6344 "0f 83/jump-if-addr>= loop/disp32"/imm32/subx-name +6345 0/imm32/no-rm32 +6346 0/imm32/no-r32 +6347 0/imm32/no-imm32 +6348 0/imm32/no-disp32 +6349 0/imm32/no-output +6350 _Primitive-loop-if-=/imm32/next +6351 _Primitive-loop-if-=: +6352 "loop-if-="/imm32/name +6353 0/imm32/inouts +6354 0/imm32/outputs +6355 "0f 84/jump-if-= loop/disp32"/imm32/subx-name +6356 0/imm32/no-rm32 +6357 0/imm32/no-r32 +6358 0/imm32/no-imm32 +6359 0/imm32/no-disp32 +6360 0/imm32/no-output +6361 _Primitive-loop-if-!=/imm32/next +6362 _Primitive-loop-if-!=: +6363 "loop-if-!="/imm32/name +6364 0/imm32/inouts +6365 0/imm32/outputs +6366 "0f 85/jump-if-!= loop/disp32"/imm32/subx-name +6367 0/imm32/no-rm32 +6368 0/imm32/no-r32 +6369 0/imm32/no-imm32 +6370 0/imm32/no-disp32 +6371 0/imm32/no-output +6372 _Primitive-loop-if-addr<=/imm32/next +6373 _Primitive-loop-if-addr<=: +6374 "loop-if-addr<="/imm32/name +6375 0/imm32/inouts +6376 0/imm32/outputs +6377 "0f 86/jump-if-addr<= loop/disp32"/imm32/subx-name +6378 0/imm32/no-rm32 +6379 0/imm32/no-r32 +6380 0/imm32/no-imm32 +6381 0/imm32/no-disp32 +6382 0/imm32/no-output +6383 _Primitive-loop-if-addr>/imm32/next +6384 _Primitive-loop-if-addr>: +6385 "loop-if-addr>"/imm32/name +6386 0/imm32/inouts +6387 0/imm32/outputs +6388 "0f 87/jump-if-addr> loop/disp32"/imm32/subx-name +6389 0/imm32/no-rm32 +6390 0/imm32/no-r32 +6391 0/imm32/no-imm32 +6392 0/imm32/no-disp32 +6393 0/imm32/no-output +6394 _Primitive-loop-if-</imm32/next +6395 _Primitive-loop-if-<: +6396 "loop-if-<"/imm32/name +6397 0/imm32/inouts +6398 0/imm32/outputs +6399 "0f 8c/jump-if-< loop/disp32"/imm32/subx-name +6400 0/imm32/no-rm32 +6401 0/imm32/no-r32 +6402 0/imm32/no-imm32 +6403 0/imm32/no-disp32 +6404 0/imm32/no-output +6405 _Primitive-loop-if->=/imm32/next +6406 _Primitive-loop-if->=: +6407 "loop-if->="/imm32/name +6408 0/imm32/inouts +6409 0/imm32/outputs +6410 "0f 8d/jump-if->= loop/disp32"/imm32/subx-name +6411 0/imm32/no-rm32 +6412 0/imm32/no-r32 +6413 0/imm32/no-imm32 +6414 0/imm32/no-disp32 +6415 0/imm32/no-output +6416 _Primitive-loop-if-<=/imm32/next +6417 _Primitive-loop-if-<=: +6418 "loop-if-<="/imm32/name +6419 0/imm32/inouts +6420 0/imm32/outputs +6421 "0f 8e/jump-if-<= loop/disp32"/imm32/subx-name +6422 0/imm32/no-rm32 +6423 0/imm32/no-r32 +6424 0/imm32/no-imm32 +6425 0/imm32/no-disp32 +6426 0/imm32/no-output +6427 _Primitive-loop-if->/imm32/next +6428 _Primitive-loop-if->: +6429 "loop-if->"/imm32/name +6430 0/imm32/inouts +6431 0/imm32/outputs +6432 "0f 8f/jump-if-> loop/disp32"/imm32/subx-name +6433 0/imm32/no-rm32 +6434 0/imm32/no-r32 +6435 0/imm32/no-imm32 +6436 0/imm32/no-disp32 +6437 0/imm32/no-output +6438 _Primitive-loop/imm32/next # we probably don't need an unconditional break +6439 _Primitive-loop: +6440 "loop"/imm32/name +6441 0/imm32/inouts +6442 0/imm32/outputs +6443 "e9/jump loop/disp32"/imm32/subx-name +6444 0/imm32/no-rm32 +6445 0/imm32/no-r32 +6446 0/imm32/no-imm32 +6447 0/imm32/no-disp32 +6448 0/imm32/no-output +6449 _Primitive-break-if-addr<-named/imm32/next +6450 # - branches to named blocks +6451 _Primitive-break-if-addr<-named: +6452 "break-if-addr<"/imm32/name +6453 Single-lit-var/imm32/inouts +6454 0/imm32/outputs +6455 "0f 82/jump-if-addr<"/imm32/subx-name +6456 0/imm32/no-rm32 +6457 0/imm32/no-r32 +6458 0/imm32/no-imm32 +6459 1/imm32/disp32-is-first-inout +6460 0/imm32/no-output +6461 _Primitive-break-if-addr>=-named/imm32/next +6462 _Primitive-break-if-addr>=-named: +6463 "break-if-addr>="/imm32/name +6464 Single-lit-var/imm32/inouts +6465 0/imm32/outputs +6466 "0f 83/jump-if-addr>="/imm32/subx-name +6467 0/imm32/no-rm32 +6468 0/imm32/no-r32 +6469 0/imm32/no-imm32 +6470 1/imm32/disp32-is-first-inout +6471 0/imm32/no-output +6472 _Primitive-break-if-=-named/imm32/next +6473 _Primitive-break-if-=-named: +6474 "break-if-="/imm32/name +6475 Single-lit-var/imm32/inouts +6476 0/imm32/outputs +6477 "0f 84/jump-if-="/imm32/subx-name +6478 0/imm32/no-rm32 +6479 0/imm32/no-r32 +6480 0/imm32/no-imm32 +6481 1/imm32/disp32-is-first-inout +6482 0/imm32/no-output +6483 _Primitive-break-if-!=-named/imm32/next +6484 _Primitive-break-if-!=-named: +6485 "break-if-!="/imm32/name +6486 Single-lit-var/imm32/inouts +6487 0/imm32/outputs +6488 "0f 85/jump-if-!="/imm32/subx-name +6489 0/imm32/no-rm32 +6490 0/imm32/no-r32 +6491 0/imm32/no-imm32 +6492 1/imm32/disp32-is-first-inout +6493 0/imm32/no-output +6494 _Primitive-break-if-addr<=-named/imm32/next +6495 _Primitive-break-if-addr<=-named: +6496 "break-if-addr<="/imm32/name +6497 Single-lit-var/imm32/inouts +6498 0/imm32/outputs +6499 "0f 86/jump-if-addr<="/imm32/subx-name +6500 0/imm32/no-rm32 +6501 0/imm32/no-r32 +6502 0/imm32/no-imm32 +6503 1/imm32/disp32-is-first-inout +6504 0/imm32/no-output +6505 _Primitive-break-if-addr>-named/imm32/next +6506 _Primitive-break-if-addr>-named: +6507 "break-if-addr>"/imm32/name +6508 Single-lit-var/imm32/inouts +6509 0/imm32/outputs +6510 "0f 87/jump-if-addr>"/imm32/subx-name +6511 0/imm32/no-rm32 +6512 0/imm32/no-r32 +6513 0/imm32/no-imm32 +6514 1/imm32/disp32-is-first-inout +6515 0/imm32/no-output +6516 _Primitive-break-if-<-named/imm32/next +6517 _Primitive-break-if-<-named: +6518 "break-if-<"/imm32/name +6519 Single-lit-var/imm32/inouts +6520 0/imm32/outputs +6521 "0f 8c/jump-if-<"/imm32/subx-name +6522 0/imm32/no-rm32 +6523 0/imm32/no-r32 +6524 0/imm32/no-imm32 +6525 1/imm32/disp32-is-first-inout +6526 0/imm32/no-output +6527 _Primitive-break-if->=-named/imm32/next +6528 _Primitive-break-if->=-named: +6529 "break-if->="/imm32/name +6530 Single-lit-var/imm32/inouts +6531 0/imm32/outputs +6532 "0f 8d/jump-if->="/imm32/subx-name +6533 0/imm32/no-rm32 +6534 0/imm32/no-r32 +6535 0/imm32/no-imm32 +6536 1/imm32/disp32-is-first-inout +6537 0/imm32/no-output +6538 _Primitive-break-if-<=-named/imm32/next +6539 _Primitive-break-if-<=-named: +6540 "break-if-<="/imm32/name +6541 Single-lit-var/imm32/inouts +6542 0/imm32/outputs +6543 "0f 8e/jump-if-<="/imm32/subx-name +6544 0/imm32/no-rm32 +6545 0/imm32/no-r32 +6546 0/imm32/no-imm32 +6547 1/imm32/disp32-is-first-inout +6548 0/imm32/no-output +6549 _Primitive-break-if->-named/imm32/next +6550 _Primitive-break-if->-named: +6551 "break-if->"/imm32/name +6552 Single-lit-var/imm32/inouts +6553 0/imm32/outputs +6554 "0f 8f/jump-if->"/imm32/subx-name +6555 0/imm32/no-rm32 +6556 0/imm32/no-r32 +6557 0/imm32/no-imm32 +6558 1/imm32/disp32-is-first-inout +6559 0/imm32/no-output +6560 _Primitive-break-named/imm32/next +6561 _Primitive-break-named: +6562 "break"/imm32/name +6563 Single-lit-var/imm32/inouts +6564 0/imm32/outputs +6565 "e9/jump"/imm32/subx-name +6566 0/imm32/no-rm32 +6567 0/imm32/no-r32 +6568 0/imm32/no-imm32 +6569 1/imm32/disp32-is-first-inout +6570 0/imm32/no-output +6571 _Primitive-loop-if-addr<-named/imm32/next +6572 _Primitive-loop-if-addr<-named: +6573 "loop-if-addr<"/imm32/name +6574 Single-lit-var/imm32/inouts +6575 0/imm32/outputs +6576 "0f 82/jump-if-addr<"/imm32/subx-name +6577 0/imm32/no-rm32 +6578 0/imm32/no-r32 +6579 0/imm32/no-imm32 +6580 1/imm32/disp32-is-first-inout +6581 0/imm32/no-output +6582 _Primitive-loop-if-addr>=-named/imm32/next +6583 _Primitive-loop-if-addr>=-named: +6584 "loop-if-addr>="/imm32/name +6585 Single-lit-var/imm32/inouts +6586 0/imm32/outputs +6587 "0f 83/jump-if-addr>="/imm32/subx-name +6588 0/imm32/no-rm32 +6589 0/imm32/no-r32 +6590 0/imm32/no-imm32 +6591 1/imm32/disp32-is-first-inout +6592 0/imm32/no-output +6593 _Primitive-loop-if-=-named/imm32/next +6594 _Primitive-loop-if-=-named: +6595 "loop-if-="/imm32/name +6596 Single-lit-var/imm32/inouts +6597 0/imm32/outputs +6598 "0f 84/jump-if-="/imm32/subx-name +6599 0/imm32/no-rm32 +6600 0/imm32/no-r32 +6601 0/imm32/no-imm32 +6602 1/imm32/disp32-is-first-inout +6603 0/imm32/no-output +6604 _Primitive-loop-if-!=-named/imm32/next +6605 _Primitive-loop-if-!=-named: +6606 "loop-if-!="/imm32/name +6607 Single-lit-var/imm32/inouts +6608 0/imm32/outputs +6609 "0f 85/jump-if-!="/imm32/subx-name +6610 0/imm32/no-rm32 +6611 0/imm32/no-r32 +6612 0/imm32/no-imm32 +6613 1/imm32/disp32-is-first-inout +6614 0/imm32/no-output +6615 _Primitive-loop-if-addr<=-named/imm32/next +6616 _Primitive-loop-if-addr<=-named: +6617 "loop-if-addr<="/imm32/name +6618 Single-lit-var/imm32/inouts +6619 0/imm32/outputs +6620 "0f 86/jump-if-addr<="/imm32/subx-name +6621 0/imm32/no-rm32 +6622 0/imm32/no-r32 +6623 0/imm32/no-imm32 +6624 1/imm32/disp32-is-first-inout +6625 0/imm32/no-output +6626 _Primitive-loop-if-addr>-named/imm32/next +6627 _Primitive-loop-if-addr>-named: +6628 "loop-if-addr>"/imm32/name +6629 Single-lit-var/imm32/inouts +6630 0/imm32/outputs +6631 "0f 87/jump-if-addr>"/imm32/subx-name +6632 0/imm32/no-rm32 +6633 0/imm32/no-r32 +6634 0/imm32/no-imm32 +6635 1/imm32/disp32-is-first-inout +6636 0/imm32/no-output +6637 _Primitive-loop-if-<-named/imm32/next +6638 _Primitive-loop-if-<-named: +6639 "loop-if-<"/imm32/name +6640 Single-lit-var/imm32/inouts +6641 0/imm32/outputs +6642 "0f 8c/jump-if-<"/imm32/subx-name +6643 0/imm32/no-rm32 +6644 0/imm32/no-r32 +6645 0/imm32/no-imm32 +6646 1/imm32/disp32-is-first-inout +6647 0/imm32/no-output +6648 _Primitive-loop-if->=-named/imm32/next +6649 _Primitive-loop-if->=-named: +6650 "loop-if->="/imm32/name +6651 Single-lit-var/imm32/inouts +6652 0/imm32/outputs +6653 "0f 8d/jump-if->="/imm32/subx-name +6654 0/imm32/no-rm32 +6655 0/imm32/no-r32 +6656 0/imm32/no-imm32 +6657 1/imm32/disp32-is-first-inout +6658 0/imm32/no-output +6659 _Primitive-loop-if-<=-named/imm32/next +6660 _Primitive-loop-if-<=-named: +6661 "loop-if-<="/imm32/name +6662 Single-lit-var/imm32/inouts +6663 0/imm32/outputs +6664 "0f 8e/jump-if-<="/imm32/subx-name +6665 0/imm32/no-rm32 +6666 0/imm32/no-r32 +6667 0/imm32/no-imm32 +6668 1/imm32/disp32-is-first-inout +6669 0/imm32/no-output +6670 _Primitive-loop-if->-named/imm32/next +6671 _Primitive-loop-if->-named: +6672 "loop-if->"/imm32/name +6673 Single-lit-var/imm32/inouts +6674 0/imm32/outputs +6675 "0f 8f/jump-if->"/imm32/subx-name +6676 0/imm32/no-rm32 +6677 0/imm32/no-r32 +6678 0/imm32/no-imm32 +6679 1/imm32/disp32-is-first-inout +6680 0/imm32/no-output +6681 _Primitive-loop-named/imm32/next # we probably don't need an unconditional break +6682 _Primitive-loop-named: +6683 "loop"/imm32/name +6684 Single-lit-var/imm32/inouts +6685 0/imm32/outputs +6686 "e9/jump"/imm32/subx-name +6687 0/imm32/no-rm32 +6688 0/imm32/no-r32 +6689 0/imm32/no-imm32 +6690 1/imm32/disp32-is-first-inout +6691 0/imm32/no-output +6692 0/imm32/next +6693 +6694 Single-int-var-on-stack: +6695 Int-var-on-stack/imm32 +6696 0/imm32/next +6697 +6698 Int-var-on-stack: +6699 "arg1"/imm32/name +6700 Type-int/imm32 +6701 1/imm32/some-block-depth +6702 1/imm32/some-stack-offset +6703 0/imm32/no-register +6704 +6705 Two-args-int-stack-int-reg: +6706 Int-var-on-stack/imm32 +6707 Single-int-var-in-some-register/imm32/next +6708 +6709 Two-args-int-reg-int-stack: +6710 Int-var-in-some-register/imm32 +6711 Single-int-var-on-stack/imm32/next +6712 +6713 Two-args-int-eax-int-literal: +6714 Int-var-in-eax/imm32 +6715 Single-lit-var/imm32/next +6716 +6717 Int-var-and-literal: +6718 Int-var-on-stack/imm32 +6719 Single-lit-var/imm32/next +6720 +6721 Single-int-var-in-some-register: +6722 Int-var-in-some-register/imm32 +6723 0/imm32/next +6724 +6725 Int-var-in-some-register: +6726 "arg1"/imm32/name +6727 Type-int/imm32 +6728 1/imm32/some-block-depth +6729 0/imm32/no-stack-offset +6730 "*"/imm32/register +6731 +6732 Single-int-var-in-eax: +6733 Int-var-in-eax/imm32 +6734 0/imm32/next +6735 +6736 Int-var-in-eax: +6737 "arg1"/imm32/name +6738 Type-int/imm32 +6739 1/imm32/some-block-depth +6740 0/imm32/no-stack-offset +6741 "eax"/imm32/register +6742 +6743 Single-int-var-in-ecx: +6744 Int-var-in-ecx/imm32 +6745 0/imm32/next +6746 +6747 Int-var-in-ecx: +6748 "arg1"/imm32/name +6749 Type-int/imm32 +6750 1/imm32/some-block-depth +6751 0/imm32/no-stack-offset +6752 "ecx"/imm32/register +6753 +6754 Single-int-var-in-edx: +6755 Int-var-in-edx/imm32 +6756 0/imm32/next +6757 +6758 Int-var-in-edx: +6759 "arg1"/imm32/name +6760 Type-int/imm32 +6761 1/imm32/some-block-depth +6762 0/imm32/no-stack-offset +6763 "edx"/imm32/register +6764 +6765 Single-int-var-in-ebx: +6766 Int-var-in-ebx/imm32 +6767 0/imm32/next +6768 +6769 Int-var-in-ebx: +6770 "arg1"/imm32/name +6771 Type-int/imm32 +6772 1/imm32/some-block-depth +6773 0/imm32/no-stack-offset +6774 "ebx"/imm32/register +6775 +6776 Single-int-var-in-esi: +6777 Int-var-in-esi/imm32 +6778 0/imm32/next +6779 +6780 Int-var-in-esi: +6781 "arg1"/imm32/name +6782 Type-int/imm32 +6783 1/imm32/some-block-depth +6784 0/imm32/no-stack-offset +6785 "esi"/imm32/register +6786 +6787 Single-int-var-in-edi: +6788 Int-var-in-edi/imm32 +6789 0/imm32/next +6790 +6791 Int-var-in-edi: +6792 "arg1"/imm32/name +6793 Type-int/imm32 +6794 1/imm32/some-block-depth +6795 0/imm32/no-stack-offset +6796 "edi"/imm32/register +6797 +6798 Single-lit-var: +6799 Lit-var/imm32 +6800 0/imm32/next +6801 +6802 Lit-var: +6803 "literal"/imm32/name +6804 Type-literal/imm32 +6805 1/imm32/some-block-depth +6806 0/imm32/no-stack-offset +6807 0/imm32/no-register +6808 +6809 Type-int: +6810 1/imm32/left/int +6811 0/imm32/right/null +6812 +6813 Type-literal: +6814 0/imm32/left/literal +6815 0/imm32/right/null +6816 +6817 == code +6818 emit-subx-primitive: # out: (addr buffered-file), stmt: (handle statement), primitive: (handle function) +6819 # . prologue +6820 55/push-ebp +6821 89/<- %ebp 4/r32/esp +6822 # . save registers +6823 50/push-eax +6824 51/push-ecx +6825 # ecx = primitive +6826 8b/-> *(ebp+0x10) 1/r32/ecx +6827 # emit primitive name +6828 (emit-indent *(ebp+8) *Curr-block-depth) +6829 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name +6830 # emit rm32 if necessary +6831 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt +6832 # emit r32 if necessary +6833 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt +6834 # emit imm32 if necessary +6835 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt +6836 # emit disp32 if necessary +6837 (emit-subx-disp32 *(ebp+8) *(ecx+0x1c) *(ebp+0xc)) # out, Primitive-subx-disp32, stmt +6838 (write-buffered *(ebp+8) Newline) +6839 $emit-subx-primitive:end: +6840 # . restore registers +6841 59/pop-to-ecx +6842 58/pop-to-eax +6843 # . epilogue +6844 89/<- %esp 5/r32/ebp +6845 5d/pop-to-ebp +6846 c3/return +6847 +6848 emit-subx-rm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) +6849 # . prologue +6850 55/push-ebp +6851 89/<- %ebp 4/r32/esp +6852 # . save registers +6853 50/push-eax +6854 # if (l == 0) return +6855 81 7/subop/compare *(ebp+0xc) 0/imm32 +6856 74/jump-if-= $emit-subx-rm32:end/disp8 +6857 # +6858 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +6859 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var +6860 $emit-subx-rm32:end: +6861 # . restore registers +6862 58/pop-to-eax +6863 # . epilogue +6864 89/<- %esp 5/r32/ebp +6865 5d/pop-to-ebp +6866 c3/return +6867 +6868 get-stmt-operand-from-arg-location: # stmt: (handle statement), l: arg-location -> var/eax: (handle variable) +6869 # . prologue +6870 55/push-ebp +6871 89/<- %ebp 4/r32/esp +6872 # . save registers +6873 51/push-ecx +6874 # eax = l +6875 8b/-> *(ebp+0xc) 0/r32/eax +6876 # ecx = stmt +6877 8b/-> *(ebp+8) 1/r32/ecx +6878 # if (l == 1) return stmt->inouts->var +6879 { +6880 3d/compare-eax-and 1/imm32 +6881 75/jump-if-!= break/disp8 +6882 $get-stmt-operand-from-arg-location:1: +6883 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +6884 8b/-> *eax 0/r32/eax # Operand-var +6885 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +6886 } +6887 # if (l == 2) return stmt->inouts->next->var +6888 { +6889 3d/compare-eax-and 2/imm32 +6890 75/jump-if-!= break/disp8 +6891 $get-stmt-operand-from-arg-location:2: +6892 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +6893 8b/-> *(eax+4) 0/r32/eax # Operand-next +6894 8b/-> *eax 0/r32/eax # Operand-var +6895 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +6896 } +6897 # if (l == 3) return stmt->outputs +6898 { +6899 3d/compare-eax-and 3/imm32 +6900 75/jump-if-!= break/disp8 +6901 $get-stmt-operand-from-arg-location:3: +6902 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs +6903 8b/-> *eax 0/r32/eax # Operand-var +6904 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +6905 } +6906 # abort +6907 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 +6908 $get-stmt-operand-from-arg-location:end: +6909 # . restore registers +6910 59/pop-to-ecx +6911 # . epilogue +6912 89/<- %esp 5/r32/ebp +6913 5d/pop-to-ebp +6914 c3/return +6915 +6916 $get-stmt-operand-from-arg-location:abort: +6917 # error("invalid arg-location " eax) +6918 (write-buffered Stderr "invalid arg-location ") +6919 (print-int32-buffered Stderr %eax) +6920 (write-buffered Stderr Newline) +6921 (flush Stderr) +6922 # . syscall(exit, 1) +6923 bb/copy-to-ebx 1/imm32 +6924 b8/copy-to-eax 1/imm32/exit +6925 cd/syscall 0x80/imm8 +6926 # never gets here +6927 +6928 emit-subx-r32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) +6929 # . prologue +6930 55/push-ebp +6931 89/<- %ebp 4/r32/esp +6932 # . save registers +6933 50/push-eax +6934 51/push-ecx +6935 # if (location == 0) return +6936 81 7/subop/compare *(ebp+0xc) 0/imm32 +6937 0f 84/jump-if-= $emit-subx-r32:end/disp32 +6938 # +6939 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +6940 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax: (addr register-index) +6941 (write-buffered *(ebp+8) Space) +6942 (print-int32-buffered *(ebp+8) *eax) +6943 (write-buffered *(ebp+8) "/r32") +6944 $emit-subx-r32:end: +6945 # . restore registers +6946 59/pop-to-ecx +6947 58/pop-to-eax +6948 # . epilogue +6949 89/<- %esp 5/r32/ebp +6950 5d/pop-to-ebp +6951 c3/return +6952 +6953 emit-subx-imm32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) +6954 # . prologue +6955 55/push-ebp +6956 89/<- %ebp 4/r32/esp +6957 # . save registers +6958 50/push-eax +6959 51/push-ecx +6960 # if (location == 0) return +6961 81 7/subop/compare *(ebp+0xc) 0/imm32 +6962 74/jump-if-= $emit-subx-imm32:end/disp8 +6963 # +6964 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +6965 (write-buffered *(ebp+8) Space) +6966 (write-buffered *(ebp+8) *eax) # Var-name +6967 (write-buffered *(ebp+8) "/imm32") +6968 $emit-subx-imm32:end: +6969 # . restore registers +6970 59/pop-to-ecx +6971 58/pop-to-eax +6972 # . epilogue +6973 89/<- %esp 5/r32/ebp +6974 5d/pop-to-ebp +6975 c3/return +6976 +6977 emit-subx-disp32: # out: (addr buffered-file), l: arg-location, stmt: (handle statement) +6978 # . prologue +6979 55/push-ebp +6980 89/<- %ebp 4/r32/esp +6981 # . save registers +6982 50/push-eax +6983 51/push-ecx +6984 # if (location == 0) return +6985 81 7/subop/compare *(ebp+0xc) 0/imm32 +6986 0f 84/jump-if-= $emit-subx-disp32:end/disp32 +6987 # +6988 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +6989 (write-buffered *(ebp+8) Space) +6990 (write-buffered *(ebp+8) *eax) # Var-name +6991 # hack: if instruction operation starts with "break", emit ":break" +6992 # var name/ecx: (addr array byte) = stmt->operation +6993 8b/-> *(ebp+0x10) 0/r32/eax +6994 8b/-> *(eax+4) 1/r32/ecx +6995 { +6996 (string-starts-with? %ecx "break") # => eax +6997 3d/compare-eax-and 0/imm32/false +6998 74/jump-if-= break/disp8 +6999 (write-buffered *(ebp+8) ":break") +7000 } +7001 # hack: if instruction operation starts with "loop", emit ":loop" +7002 { +7003 (string-starts-with? %ecx "loop") # => eax +7004 3d/compare-eax-and 0/imm32/false +7005 74/jump-if-= break/disp8 +7006 (write-buffered *(ebp+8) ":loop") +7007 } +7008 (write-buffered *(ebp+8) "/disp32") +7009 $emit-subx-disp32:end: +7010 # . restore registers +7011 59/pop-to-ecx +7012 58/pop-to-eax +7013 # . epilogue +7014 89/<- %esp 5/r32/ebp +7015 5d/pop-to-ebp +7016 c3/return +7017 +7018 emit-subx-call: # out: (addr buffered-file), stmt: (handle statement), callee: (handle function) +7019 # . prologue +7020 55/push-ebp +7021 89/<- %ebp 4/r32/esp +7022 # . save registers +7023 51/push-ecx +7024 # +7025 (emit-indent *(ebp+8) *Curr-block-depth) +7026 (write-buffered *(ebp+8) "(") +7027 # - emit function name +7028 8b/-> *(ebp+0x10) 1/r32/ecx +7029 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name +7030 # - emit arguments +7031 # var curr/ecx: (handle list var) = stmt->inouts +7032 8b/-> *(ebp+0xc) 1/r32/ecx +7033 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts +7034 { +7035 # if (curr == null) break +7036 81 7/subop/compare %ecx 0/imm32 +7037 74/jump-if-= break/disp8 +7038 # +7039 (emit-subx-call-operand *(ebp+8) *ecx) +7040 # curr = curr->next +7041 8b/-> *(ecx+4) 1/r32/ecx +7042 eb/jump loop/disp8 +7043 } +7044 # +7045 (write-buffered *(ebp+8) ")\n") +7046 $emit-subx-call:end: +7047 # . restore registers +7048 59/pop-to-ecx +7049 # . epilogue +7050 89/<- %esp 5/r32/ebp +7051 5d/pop-to-ebp +7052 c3/return +7053 +7054 # like a function call, except we have no idea what function it is +7055 # we hope it's defined in SubX and that the types are ok +7056 emit-hailmary-call: # out: (addr buffered-file), stmt: (handle statement) +7057 # . prologue +7058 55/push-ebp +7059 89/<- %ebp 4/r32/esp +7060 # . save registers +7061 51/push-ecx +7062 # +7063 (emit-indent *(ebp+8) *Curr-block-depth) +7064 (write-buffered *(ebp+8) "(") +7065 # ecx = stmt +7066 8b/-> *(ebp+0xc) 1/r32/ecx +7067 # - emit function name +7068 (write-buffered *(ebp+8) *(ecx+4)) # Stmt1-operation +7069 # - emit arguments +7070 # var curr/ecx: (handle list var) = stmt->inouts +7071 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts +7072 { +7073 # if (curr == null) break +7074 81 7/subop/compare %ecx 0/imm32 +7075 74/jump-if-= break/disp8 +7076 # +7077 (emit-subx-call-operand *(ebp+8) *ecx) +7078 # curr = curr->next +7079 8b/-> *(ecx+4) 1/r32/ecx +7080 eb/jump loop/disp8 +7081 } +7082 # +7083 (write-buffered *(ebp+8) ")\n") +7084 $emit-hailmary-call:end: +7085 # . restore registers +7086 59/pop-to-ecx +7087 # . epilogue +7088 89/<- %esp 5/r32/ebp +7089 5d/pop-to-ebp +7090 c3/return +7091 +7092 emit-subx-call-operand: # out: (addr buffered-file), operand: (handle variable) +7093 # shares code with emit-subx-var-as-rm32 +7094 # . prologue +7095 55/push-ebp +7096 89/<- %ebp 4/r32/esp +7097 # . save registers +7098 50/push-eax +7099 # eax = operand +7100 8b/-> *(ebp+0xc) 0/r32/eax +7101 # if (operand->register) emit "%__" +7102 { +7103 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +7104 74/jump-if-= break/disp8 +7105 $emit-subx-call-operand:register: +7106 (write-buffered *(ebp+8) " %") +7107 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +7108 e9/jump $emit-subx-call-operand:end/disp32 +7109 } +7110 # else if (operand->stack-offset) emit "*(ebp+__)" +7111 { +7112 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +7113 74/jump-if-= break/disp8 +7114 $emit-subx-call-operand:stack: +7115 (write-buffered *(ebp+8) Space) +7116 (write-buffered *(ebp+8) "*(ebp+") +7117 8b/-> *(ebp+0xc) 0/r32/eax +7118 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +7119 (write-buffered *(ebp+8) ")") +7120 e9/jump $emit-subx-call-operand:end/disp32 +7121 } +7122 # else if (operand->type == literal) emit "__" +7123 { +7124 50/push-eax +7125 8b/-> *(eax+4) 0/r32/eax # Var-type +7126 81 7/subop/compare *eax 0/imm32 # Tree-left +7127 58/pop-to-eax +7128 75/jump-if-!= break/disp8 +7129 $emit-subx-call-operand:literal: +7130 (write-buffered *(ebp+8) Space) +7131 (write-buffered *(ebp+8) *eax) +7132 } +7133 $emit-subx-call-operand:end: +7134 # . restore registers +7135 58/pop-to-eax +7136 # . epilogue +7137 89/<- %esp 5/r32/ebp +7138 5d/pop-to-ebp +7139 c3/return +7140 +7141 emit-subx-var-as-rm32: # out: (addr buffered-file), operand: (handle variable) +7142 # . prologue +7143 55/push-ebp +7144 89/<- %ebp 4/r32/esp +7145 # . save registers +7146 50/push-eax +7147 # eax = operand +7148 8b/-> *(ebp+0xc) 0/r32/eax +7149 # if (operand->register) emit "%__" +7150 { +7151 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +7152 74/jump-if-= break/disp8 +7153 $emit-subx-var-as-rm32:register: +7154 (write-buffered *(ebp+8) " %") +7155 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +7156 } +7157 # else if (operand->stack-offset) emit "*(ebp+__)" +7158 { +7159 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +7160 74/jump-if-= break/disp8 +7161 $emit-subx-var-as-rm32:stack: +7162 (write-buffered *(ebp+8) Space) +7163 (write-buffered *(ebp+8) "*(ebp+") +7164 8b/-> *(ebp+0xc) 0/r32/eax +7165 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +7166 (write-buffered *(ebp+8) ")") +7167 } +7168 $emit-subx-var-as-rm32:end: +7169 # . restore registers +7170 58/pop-to-eax +7171 # . epilogue +7172 89/<- %esp 5/r32/ebp +7173 5d/pop-to-ebp +7174 c3/return +7175 +7176 find-matching-function: # functions: (addr function), stmt: (handle statement) -> result/eax: (handle function) 7177 # . prologue 7178 55/push-ebp 7179 89/<- %ebp 4/r32/esp -7180 # setup -7181 (clear-stream _test-output-stream) -7182 (clear-stream $_test-output-buffered-file->buffer) -7183 # var type/ecx: (handle tree type-id) = int -7184 68/push 0/imm32/right/null -7185 68/push 1/imm32/left/int -7186 89/<- %ecx 4/r32/esp -7187 # var var-foo/ecx: var -7188 68/push 0/imm32/no-register -7189 68/push -8/imm32/stack-offset -7190 68/push 1/imm32/block-depth -7191 51/push-ecx -7192 68/push "foo"/imm32 -7193 89/<- %ecx 4/r32/esp -7194 # var operand/ebx: (list var) -7195 68/push 0/imm32/next -7196 51/push-ecx/var-foo -7197 89/<- %ebx 4/r32/esp -7198 # var stmt/esi: statement -7199 68/push 0/imm32/next -7200 68/push 0/imm32/outputs -7201 53/push-ebx/operands -7202 68/push "increment"/imm32/operation -7203 68/push 1/imm32 -7204 89/<- %esi 4/r32/esp -7205 # var primitives/ebx: primitive -7206 68/push 0/imm32/next -7207 68/push 0/imm32/output-is-write-only -7208 68/push 0/imm32/no-disp32 -7209 68/push 0/imm32/no-imm32 -7210 68/push 0/imm32/no-r32 -7211 68/push 1/imm32/rm32-is-first-inout -7212 68/push "ff 0/subop/increment"/imm32/subx-name -7213 68/push 0/imm32/outputs -7214 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call -7215 68/push "increment"/imm32/name -7216 89/<- %ebx 4/r32/esp -7217 # convert -7218 c7 0/subop/copy *Curr-block-depth 0/imm32 -7219 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -7220 (flush _test-output-buffered-file) -7221 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -7227 # check output -7228 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") -7229 # . epilogue -7230 89/<- %esp 5/r32/ebp -7231 5d/pop-to-ebp -7232 c3/return -7233 -7234 test-emit-subx-statement-primitive-register: -7235 # Primitive operation on a variable in a register. -7236 # foo <- increment -7237 # => -7238 # ff 0/subop/increment %eax # sub-optimal, but should suffice -7239 # -7240 # There's a variable on the var stack as follows: -7241 # name: 'foo' -7242 # type: int -7243 # register: 'eax' -7244 # -7245 # There's a primitive with this info: -7246 # name: 'increment' -7247 # out: int/reg -7248 # value: 'ff 0/subop/increment' -7249 # -7250 # There's nothing in functions. -7251 # -7252 # . prologue -7253 55/push-ebp -7254 89/<- %ebp 4/r32/esp -7255 # setup -7256 (clear-stream _test-output-stream) -7257 (clear-stream $_test-output-buffered-file->buffer) -7258 # var type/ecx: (handle tree type-id) = int -7259 68/push 0/imm32/right/null -7260 68/push 1/imm32/left/int -7261 89/<- %ecx 4/r32/esp -7262 # var var-foo/ecx: var in eax -7263 68/push "eax"/imm32/register -7264 68/push 0/imm32/no-stack-offset -7265 68/push 1/imm32/block-depth -7266 51/push-ecx -7267 68/push "foo"/imm32 -7268 89/<- %ecx 4/r32/esp -7269 # var operand/ebx: (list var) -7270 68/push 0/imm32/next -7271 51/push-ecx/var-foo -7272 89/<- %ebx 4/r32/esp -7273 # var stmt/esi: statement -7274 68/push 0/imm32/next -7275 53/push-ebx/outputs -7276 68/push 0/imm32/inouts -7277 68/push "increment"/imm32/operation -7278 68/push 1/imm32 -7279 89/<- %esi 4/r32/esp -7280 # var formal-var/ebx: var in any register -7281 68/push Any-register/imm32 -7282 68/push 0/imm32/no-stack-offset -7283 68/push 1/imm32/block-depth -7284 ff 6/subop/push *(ecx+4) # Var-type -7285 68/push "dummy"/imm32 -7286 89/<- %ebx 4/r32/esp -7287 # var operand/ebx: (list var) -7288 68/push 0/imm32/next -7289 53/push-ebx/formal-var -7290 89/<- %ebx 4/r32/esp -7291 # var primitives/ebx: primitive -7292 68/push 0/imm32/next -7293 68/push 0/imm32/output-is-write-only -7294 68/push 0/imm32/no-disp32 -7295 68/push 0/imm32/no-imm32 -7296 68/push 0/imm32/no-r32 -7297 68/push 3/imm32/rm32-in-first-output -7298 68/push "ff 0/subop/increment"/imm32/subx-name -7299 53/push-ebx/outputs -7300 68/push 0/imm32/inouts -7301 68/push "increment"/imm32/name -7302 89/<- %ebx 4/r32/esp -7303 # convert -7304 c7 0/subop/copy *Curr-block-depth 0/imm32 -7305 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -7306 (flush _test-output-buffered-file) -7307 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -7313 # check output -7314 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") -7315 # . epilogue -7316 89/<- %esp 5/r32/ebp -7317 5d/pop-to-ebp -7318 c3/return -7319 -7320 test-emit-subx-statement-select-primitive: -7321 # Select the right primitive between overloads. -7322 # foo <- increment -7323 # => -7324 # ff 0/subop/increment %eax # sub-optimal, but should suffice -7325 # -7326 # There's a variable on the var stack as follows: -7327 # name: 'foo' -7328 # type: int -7329 # register: 'eax' -7330 # -7331 # There's two primitives, as follows: -7332 # - name: 'increment' -7333 # out: int/reg -7334 # value: 'ff 0/subop/increment' -7335 # - name: 'increment' -7336 # inout: int/mem -7337 # value: 'ff 0/subop/increment' -7338 # -7339 # There's nothing in functions. -7340 # -7341 # . prologue -7342 55/push-ebp -7343 89/<- %ebp 4/r32/esp -7344 # setup -7345 (clear-stream _test-output-stream) -7346 (clear-stream $_test-output-buffered-file->buffer) -7347 # var type/ecx: (handle tree type-id) = int -7348 68/push 0/imm32/right/null -7349 68/push 1/imm32/left/int -7350 89/<- %ecx 4/r32/esp -7351 # var var-foo/ecx: var in eax -7352 68/push "eax"/imm32/register -7353 68/push 0/imm32/no-stack-offset -7354 68/push 1/imm32/block-depth -7355 51/push-ecx -7356 68/push "foo"/imm32 -7357 89/<- %ecx 4/r32/esp -7358 # var real-outputs/edi: (list var) -7359 68/push 0/imm32/next -7360 51/push-ecx/var-foo -7361 89/<- %edi 4/r32/esp -7362 # var stmt/esi: statement -7363 68/push 0/imm32/next -7364 57/push-edi/outputs -7365 68/push 0/imm32/inouts -7366 68/push "increment"/imm32/operation -7367 68/push 1/imm32 -7368 89/<- %esi 4/r32/esp -7369 # var formal-var/ebx: var in any register -7370 68/push Any-register/imm32 -7371 68/push 0/imm32/no-stack-offset -7372 68/push 1/imm32/block-depth -7373 ff 6/subop/push *(ecx+4) # Var-type -7374 68/push "dummy"/imm32 -7375 89/<- %ebx 4/r32/esp -7376 # var formal-outputs/ebx: (list var) = {formal-var, 0} -7377 68/push 0/imm32/next -7378 53/push-ebx/formal-var -7379 89/<- %ebx 4/r32/esp -7380 # var primitive1/ebx: primitive -7381 68/push 0/imm32/next -7382 68/push 0/imm32/output-is-write-only -7383 68/push 0/imm32/no-disp32 -7384 68/push 0/imm32/no-imm32 -7385 68/push 0/imm32/no-r32 -7386 68/push 3/imm32/rm32-in-first-output -7387 68/push "ff 0/subop/increment"/imm32/subx-name -7388 53/push-ebx/outputs/formal-outputs -7389 68/push 0/imm32/inouts -7390 68/push "increment"/imm32/name -7391 89/<- %ebx 4/r32/esp -7392 # var primitives/ebx: primitive -7393 53/push-ebx/next -7394 68/push 0/imm32/output-is-write-only -7395 68/push 0/imm32/no-disp32 -7396 68/push 0/imm32/no-imm32 -7397 68/push 0/imm32/no-r32 -7398 68/push 1/imm32/rm32-is-first-inout -7399 68/push "ff 0/subop/increment"/imm32/subx-name -7400 68/push 0/imm32/outputs -7401 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -7402 68/push "increment"/imm32/name -7403 89/<- %ebx 4/r32/esp -7404 # convert -7405 c7 0/subop/copy *Curr-block-depth 0/imm32 -7406 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -7407 (flush _test-output-buffered-file) -7408 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -7414 # check output -7415 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") -7416 # . epilogue -7417 89/<- %esp 5/r32/ebp -7418 5d/pop-to-ebp -7419 c3/return -7420 -7421 test-emit-subx-statement-select-primitive-2: -7422 # Select the right primitive between overloads. -7423 # foo <- increment -7424 # => -7425 # ff 0/subop/increment %eax # sub-optimal, but should suffice -7426 # -7427 # There's a variable on the var stack as follows: -7428 # name: 'foo' -7429 # type: int -7430 # register: 'eax' -7431 # -7432 # There's two primitives, as follows: -7433 # - name: 'increment' -7434 # out: int/reg -7435 # value: 'ff 0/subop/increment' -7436 # - name: 'increment' -7437 # inout: int/mem -7438 # value: 'ff 0/subop/increment' -7439 # -7440 # There's nothing in functions. -7441 # -7442 # . prologue -7443 55/push-ebp -7444 89/<- %ebp 4/r32/esp -7445 # setup -7446 (clear-stream _test-output-stream) -7447 (clear-stream $_test-output-buffered-file->buffer) -7448 # var type/ecx: (handle tree type-id) = int -7449 68/push 0/imm32/right/null -7450 68/push 1/imm32/left/int -7451 89/<- %ecx 4/r32/esp -7452 # var var-foo/ecx: var in eax -7453 68/push "eax"/imm32/register -7454 68/push 0/imm32/no-stack-offset -7455 68/push 1/imm32/block-depth -7456 51/push-ecx -7457 68/push "foo"/imm32 -7458 89/<- %ecx 4/r32/esp -7459 # var inouts/edi: (list var) -7460 68/push 0/imm32/next -7461 51/push-ecx/var-foo -7462 89/<- %edi 4/r32/esp -7463 # var stmt/esi: statement -7464 68/push 0/imm32/next -7465 68/push 0/imm32/outputs -7466 57/push-edi/inouts -7467 68/push "increment"/imm32/operation -7468 68/push 1/imm32 -7469 89/<- %esi 4/r32/esp -7470 # var formal-var/ebx: var in any register -7471 68/push Any-register/imm32 -7472 68/push 0/imm32/no-stack-offset -7473 68/push 1/imm32/block-depth -7474 ff 6/subop/push *(ecx+4) # Var-type -7475 68/push "dummy"/imm32 -7476 89/<- %ebx 4/r32/esp -7477 # var operand/ebx: (list var) -7478 68/push 0/imm32/next -7479 53/push-ebx/formal-var -7480 89/<- %ebx 4/r32/esp -7481 # var primitive1/ebx: primitive -7482 68/push 0/imm32/next -7483 68/push 0/imm32/output-is-write-only -7484 68/push 0/imm32/no-disp32 -7485 68/push 0/imm32/no-imm32 -7486 68/push 0/imm32/no-r32 -7487 68/push 3/imm32/rm32-in-first-output -7488 68/push "ff 0/subop/increment"/imm32/subx-name -7489 53/push-ebx/outputs/formal-outputs -7490 68/push 0/imm32/inouts -7491 68/push "increment"/imm32/name -7492 89/<- %ebx 4/r32/esp -7493 # var primitives/ebx: primitive -7494 53/push-ebx/next -7495 68/push 0/imm32/output-is-write-only -7496 68/push 0/imm32/no-disp32 -7497 68/push 0/imm32/no-imm32 -7498 68/push 0/imm32/no-r32 -7499 68/push 1/imm32/rm32-is-first-inout -7500 68/push "ff 0/subop/increment"/imm32/subx-name -7501 68/push 0/imm32/outputs -7502 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -7503 68/push "increment"/imm32/name -7504 89/<- %ebx 4/r32/esp -7505 # convert -7506 c7 0/subop/copy *Curr-block-depth 0/imm32 -7507 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -7508 (flush _test-output-buffered-file) -7509 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -7515 # check output -7516 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") -7517 # . epilogue -7518 89/<- %esp 5/r32/ebp -7519 5d/pop-to-ebp -7520 c3/return -7521 -7522 test-increment-register: -7523 # Select the right register between overloads. -7524 # foo <- increment -7525 # => -7526 # 50/increment-eax -7527 # -7528 # There's a variable on the var stack as follows: -7529 # name: 'foo' -7530 # type: int -7531 # register: 'eax' -7532 # -7533 # Primitives are the global definitions. -7534 # -7535 # There are no functions defined. -7536 # -7537 # . prologue -7538 55/push-ebp -7539 89/<- %ebp 4/r32/esp -7540 # setup -7541 (clear-stream _test-output-stream) -7542 (clear-stream $_test-output-buffered-file->buffer) -7543 # var type/ecx: (handle tree type-id) = int -7544 68/push 0/imm32/right/null -7545 68/push 1/imm32/left/int -7546 89/<- %ecx 4/r32/esp -7547 # var var-foo/ecx: var in eax -7548 68/push "eax"/imm32/register -7549 68/push 0/imm32/no-stack-offset -7550 68/push 1/imm32/block-depth -7551 51/push-ecx -7552 68/push "foo"/imm32 -7553 89/<- %ecx 4/r32/esp -7554 # var real-outputs/edi: (list var) -7555 68/push 0/imm32/next -7556 51/push-ecx/var-foo -7557 89/<- %edi 4/r32/esp -7558 # var stmt/esi: statement -7559 68/push 0/imm32/next -7560 57/push-edi/outputs -7561 68/push 0/imm32/inouts -7562 68/push "increment"/imm32/operation -7563 68/push 1/imm32/regular-statement -7564 89/<- %esi 4/r32/esp -7565 # convert -7566 c7 0/subop/copy *Curr-block-depth 0/imm32 -7567 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -7568 (flush _test-output-buffered-file) -7569 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -7575 # check output -7576 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") -7577 # . epilogue -7578 89/<- %esp 5/r32/ebp -7579 5d/pop-to-ebp -7580 c3/return -7581 -7582 test-increment-var: -7583 # Select the right primitive between overloads. -7584 # foo <- increment -7585 # => -7586 # ff 0/subop/increment %eax # sub-optimal, but should suffice -7587 # -7588 # There's a variable on the var stack as follows: -7589 # name: 'foo' -7590 # type: int -7591 # register: 'eax' -7592 # -7593 # Primitives are the global definitions. -7594 # -7595 # There are no functions defined. -7596 # -7597 # . prologue -7598 55/push-ebp -7599 89/<- %ebp 4/r32/esp -7600 # setup -7601 (clear-stream _test-output-stream) -7602 (clear-stream $_test-output-buffered-file->buffer) -7603 # var type/ecx: (handle tree type-id) = int -7604 68/push 0/imm32/right/null -7605 68/push 1/imm32/left/int -7606 89/<- %ecx 4/r32/esp -7607 # var var-foo/ecx: var in eax -7608 68/push "eax"/imm32/register -7609 68/push 0/imm32/no-stack-offset -7610 68/push 1/imm32/block-depth -7611 51/push-ecx -7612 68/push "foo"/imm32 -7613 89/<- %ecx 4/r32/esp -7614 # var inouts/edi: (list var) -7615 68/push 0/imm32/next -7616 51/push-ecx/var-foo -7617 89/<- %edi 4/r32/esp -7618 # var stmt/esi: statement -7619 68/push 0/imm32/next -7620 68/push 0/imm32/outputs -7621 57/push-edi/inouts -7622 68/push "increment"/imm32/operation -7623 68/push 1/imm32 -7624 89/<- %esi 4/r32/esp -7625 # convert -7626 c7 0/subop/copy *Curr-block-depth 0/imm32 -7627 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -7628 (flush _test-output-buffered-file) -7629 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -7635 # check output -7636 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") -7637 # . epilogue -7638 89/<- %esp 5/r32/ebp -7639 5d/pop-to-ebp -7640 c3/return -7641 -7642 test-add-reg-to-reg: -7643 # var1/reg <- add var2/reg -7644 # => -7645 # 01/add %var1 var2 -7646 # -7647 # . prologue -7648 55/push-ebp -7649 89/<- %ebp 4/r32/esp -7650 # setup -7651 (clear-stream _test-output-stream) -7652 (clear-stream $_test-output-buffered-file->buffer) -7653 # var type/ecx: (handle tree type-id) = int -7654 68/push 0/imm32/right/null -7655 68/push 1/imm32/left/int -7656 89/<- %ecx 4/r32/esp -7657 # var var-var1/ecx: var in eax -7658 68/push "eax"/imm32/register -7659 68/push 0/imm32/no-stack-offset -7660 68/push 1/imm32/block-depth -7661 51/push-ecx -7662 68/push "var1"/imm32 -7663 89/<- %ecx 4/r32/esp -7664 # var var-var2/edx: var in ecx -7665 68/push "ecx"/imm32/register -7666 68/push 0/imm32/no-stack-offset -7667 68/push 1/imm32/block-depth -7668 ff 6/subop/push *(ecx+4) # Var-type -7669 68/push "var2"/imm32 -7670 89/<- %edx 4/r32/esp -7671 # var inouts/esi: (list var2) -7672 68/push 0/imm32/next -7673 52/push-edx/var-var2 -7674 89/<- %esi 4/r32/esp -7675 # var outputs/edi: (list var1) -7676 68/push 0/imm32/next -7677 51/push-ecx/var-var1 -7678 89/<- %edi 4/r32/esp -7679 # var stmt/esi: statement -7680 68/push 0/imm32/next -7681 57/push-edi/outputs -7682 56/push-esi/inouts -7683 68/push "add"/imm32/operation -7684 68/push 1/imm32 -7685 89/<- %esi 4/r32/esp -7686 # convert -7687 c7 0/subop/copy *Curr-block-depth 0/imm32 -7688 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -7689 (flush _test-output-buffered-file) -7690 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -7696 # check output -7697 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") -7698 # . epilogue -7699 89/<- %esp 5/r32/ebp -7700 5d/pop-to-ebp -7701 c3/return -7702 -7703 test-add-reg-to-mem: -7704 # add-to var1 var2/reg -7705 # => -7706 # 01/add *(ebp+__) var2 -7707 # -7708 # . prologue -7709 55/push-ebp -7710 89/<- %ebp 4/r32/esp -7711 # setup -7712 (clear-stream _test-output-stream) -7713 (clear-stream $_test-output-buffered-file->buffer) -7714 # var type/ecx: (handle tree type-id) = int -7715 68/push 0/imm32/right/null -7716 68/push 1/imm32/left/int -7717 89/<- %ecx 4/r32/esp -7718 # var var-var1/ecx: var -7719 68/push 0/imm32/no-register -7720 68/push 8/imm32/stack-offset -7721 68/push 1/imm32/block-depth -7722 51/push-ecx -7723 68/push "var1"/imm32 -7724 89/<- %ecx 4/r32/esp -7725 # var var-var2/edx: var in ecx -7726 68/push "ecx"/imm32/register -7727 68/push 0/imm32/no-stack-offset -7728 68/push 1/imm32/block-depth -7729 ff 6/subop/push *(ecx+4) # Var-type -7730 68/push "var2"/imm32 -7731 89/<- %edx 4/r32/esp -7732 # var inouts/esi: (list var2) -7733 68/push 0/imm32/next -7734 52/push-edx/var-var2 -7735 89/<- %esi 4/r32/esp -7736 # var inouts = (list var1 var2) -7737 56/push-esi/next -7738 51/push-ecx/var-var1 -7739 89/<- %esi 4/r32/esp -7740 # var stmt/esi: statement -7741 68/push 0/imm32/next -7742 68/push 0/imm32/outputs -7743 56/push-esi/inouts -7744 68/push "add-to"/imm32/operation -7745 68/push 1/imm32 -7746 89/<- %esi 4/r32/esp -7747 # convert -7748 c7 0/subop/copy *Curr-block-depth 0/imm32 -7749 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -7750 (flush _test-output-buffered-file) -7751 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -7757 # check output -7758 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") -7759 # . epilogue -7760 89/<- %esp 5/r32/ebp -7761 5d/pop-to-ebp -7762 c3/return -7763 -7764 test-add-mem-to-reg: -7765 # var1/reg <- add var2 -7766 # => -7767 # 03/add *(ebp+__) var1 +7180 # . save registers +7181 51/push-ecx +7182 # var curr/ecx: (handle function) = functions +7183 8b/-> *(ebp+8) 1/r32/ecx +7184 { +7185 # if (curr == null) break +7186 81 7/subop/compare %ecx 0/imm32 +7187 74/jump-if-= break/disp8 +7188 # if match(stmt, curr) return curr +7189 { +7190 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax +7191 3d/compare-eax-and 0/imm32/false +7192 74/jump-if-= break/disp8 +7193 89/<- %eax 1/r32/ecx +7194 eb/jump $find-matching-function:end/disp8 +7195 } +7196 # curr = curr->next +7197 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +7198 eb/jump loop/disp8 +7199 } +7200 # return null +7201 b8/copy-to-eax 0/imm32 +7202 $find-matching-function:end: +7203 # . restore registers +7204 59/pop-to-ecx +7205 # . epilogue +7206 89/<- %esp 5/r32/ebp +7207 5d/pop-to-ebp +7208 c3/return +7209 +7210 find-matching-primitive: # primitives: (handle primitive), stmt: (handle statement) -> result/eax: (handle primitive) +7211 # . prologue +7212 55/push-ebp +7213 89/<- %ebp 4/r32/esp +7214 # . save registers +7215 51/push-ecx +7216 # var curr/ecx: (handle primitive) = primitives +7217 8b/-> *(ebp+8) 1/r32/ecx +7218 { +7219 $find-matching-primitive:loop: +7220 # if (curr == null) break +7221 81 7/subop/compare %ecx 0/imm32 +7222 0f 84/jump-if-= break/disp32 +7223 #? (write-buffered Stderr "prim: ") +7224 #? (write-buffered Stderr *ecx) # Primitive-name +7225 #? (write-buffered Stderr " => ") +7226 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name +7227 #? (write-buffered Stderr Newline) +7228 #? (flush Stderr) +7229 # if match(curr, stmt) return curr +7230 { +7231 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax +7232 3d/compare-eax-and 0/imm32/false +7233 74/jump-if-= break/disp8 +7234 89/<- %eax 1/r32/ecx +7235 eb/jump $find-matching-primitive:end/disp8 +7236 } +7237 $find-matching-primitive:next-primitive: +7238 # curr = curr->next +7239 8b/-> *(ecx+0x24) 1/r32/ecx # Primitive-next +7240 e9/jump loop/disp32 +7241 } +7242 # return null +7243 b8/copy-to-eax 0/imm32 +7244 $find-matching-primitive:end: +7245 # . restore registers +7246 59/pop-to-ecx +7247 # . epilogue +7248 89/<- %esp 5/r32/ebp +7249 5d/pop-to-ebp +7250 c3/return +7251 +7252 mu-stmt-matches-function?: # stmt: (handle statement), function: (handle function) -> result/eax: boolean +7253 # . prologue +7254 55/push-ebp +7255 89/<- %ebp 4/r32/esp +7256 # . save registers +7257 51/push-ecx +7258 # return function->name == stmt->operation +7259 8b/-> *(ebp+8) 1/r32/ecx +7260 8b/-> *(ebp+0xc) 0/r32/eax +7261 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax +7262 $mu-stmt-matches-function?:end: +7263 # . restore registers +7264 59/pop-to-ecx +7265 # . epilogue +7266 89/<- %esp 5/r32/ebp +7267 5d/pop-to-ebp +7268 c3/return +7269 +7270 mu-stmt-matches-primitive?: # stmt: (handle statement), primitive: (handle primitive) -> result/eax: boolean +7271 # A mu stmt matches a primitive if the name matches, all the inout vars +7272 # match, and all the output vars match. +7273 # Vars match if types match and registers match. +7274 # In addition, a stmt output matches a primitive's output if types match +7275 # and the primitive has a wildcard register. +7276 # . prologue +7277 55/push-ebp +7278 89/<- %ebp 4/r32/esp +7279 # . save registers +7280 51/push-ecx +7281 52/push-edx +7282 53/push-ebx +7283 56/push-esi +7284 57/push-edi +7285 # ecx = stmt +7286 8b/-> *(ebp+8) 1/r32/ecx +7287 # edx = primitive +7288 8b/-> *(ebp+0xc) 2/r32/edx +7289 { +7290 $mu-stmt-matches-primitive?:check-name: +7291 # if (primitive->name != stmt->operation) return false +7292 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax +7293 3d/compare-eax-and 0/imm32/false +7294 75/jump-if-!= break/disp8 +7295 b8/copy-to-eax 0/imm32 +7296 e9/jump $mu-stmt-matches-primitive?:end/disp32 +7297 } +7298 $mu-stmt-matches-primitive?:check-inouts: +7299 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) +7300 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts +7301 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts +7302 { +7303 # if (curr == 0 && curr2 == 0) move on to check outputs +7304 { +7305 81 7/subop/compare %esi 0/imm32 +7306 75/jump-if-!= break/disp8 +7307 $mu-stmt-matches-primitive?:stmt-inout-is-null: +7308 { +7309 81 7/subop/compare %edi 0/imm32 +7310 75/jump-if-!= break/disp8 +7311 # +7312 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 +7313 } +7314 # return false +7315 b8/copy-to-eax 0/imm32/false +7316 e9/jump $mu-stmt-matches-primitive?:end/disp32 +7317 } +7318 # if (curr2 == 0) return false +7319 { +7320 81 7/subop/compare %edi 0/imm32 +7321 75/jump-if-!= break/disp8 +7322 $mu-stmt-matches-primitive?:prim-inout-is-null: +7323 b8/copy-to-eax 0/imm32/false +7324 e9/jump $mu-stmt-matches-primitive?:end/disp32 +7325 } +7326 # if (curr != curr2) return false +7327 { +7328 (operand-matches-primitive? *esi *edi) # => eax +7329 3d/compare-eax-and 0/imm32/false +7330 75/jump-if-!= break/disp8 +7331 b8/copy-to-eax 0/imm32/false +7332 e9/jump $mu-stmt-matches-primitive?:end/disp32 +7333 } +7334 # curr=curr->next +7335 8b/-> *(esi+4) 6/r32/esi # Operand-next +7336 # curr2=curr2->next +7337 8b/-> *(edi+4) 7/r32/edi # Operand-next +7338 eb/jump loop/disp8 +7339 } +7340 $mu-stmt-matches-primitive?:check-outputs: +7341 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) +7342 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs +7343 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs +7344 { +7345 # if (curr == 0) return (curr2 == 0) +7346 { +7347 $mu-stmt-matches-primitive?:check-output: +7348 81 7/subop/compare %esi 0/imm32 +7349 75/jump-if-!= break/disp8 +7350 { +7351 81 7/subop/compare %edi 0/imm32 +7352 75/jump-if-!= break/disp8 +7353 # return true +7354 b8/copy-to-eax 1/imm32 +7355 e9/jump $mu-stmt-matches-primitive?:end/disp32 +7356 } +7357 # return false +7358 b8/copy-to-eax 0/imm32 +7359 e9/jump $mu-stmt-matches-primitive?:end/disp32 +7360 } +7361 # if (curr2 == 0) return false +7362 { +7363 81 7/subop/compare %edi 0/imm32 +7364 75/jump-if-!= break/disp8 +7365 b8/copy-to-eax 0/imm32 +7366 e9/jump $mu-stmt-matches-primitive?:end/disp32 +7367 } +7368 # if (curr != curr2) return false +7369 { +7370 (operand-matches-primitive? *esi *edi) # List-value List-value => eax +7371 3d/compare-eax-and 0/imm32/false +7372 75/jump-if-!= break/disp8 +7373 b8/copy-to-eax 0/imm32 +7374 e9/jump $mu-stmt-matches-primitive?:end/disp32 +7375 } +7376 # curr=curr->next +7377 8b/-> *(esi+4) 6/r32/esi # Operand-next +7378 # curr2=curr2->next +7379 8b/-> *(edi+4) 7/r32/edi # Operand-next +7380 eb/jump loop/disp8 +7381 } +7382 $mu-stmt-matches-primitive?:return-true: +7383 b8/copy-to-eax 1/imm32 +7384 $mu-stmt-matches-primitive?:end: +7385 # . restore registers +7386 5f/pop-to-edi +7387 5e/pop-to-esi +7388 5b/pop-to-ebx +7389 5a/pop-to-edx +7390 59/pop-to-ecx +7391 # . epilogue +7392 89/<- %esp 5/r32/ebp +7393 5d/pop-to-ebp +7394 c3/return +7395 +7396 operand-matches-primitive?: # var: (handle var), prim-var: (handle var) -> result/eax: boolean +7397 # . prologue +7398 55/push-ebp +7399 89/<- %ebp 4/r32/esp +7400 # . save registers +7401 56/push-esi +7402 57/push-edi +7403 # esi = var +7404 8b/-> *(ebp+8) 6/r32/esi +7405 # edi = prim-var +7406 8b/-> *(ebp+0xc) 7/r32/edi +7407 # if (var->type != prim-var->type) return false +7408 (subx-type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax +7409 3d/compare-eax-and 0/imm32/false +7410 b8/copy-to-eax 0/imm32/false +7411 74/jump-if-= $operand-matches-primitive?:end/disp8 +7412 # return false if var->register doesn't match prim-var->register +7413 { +7414 # if addresses are equal, don't return here +7415 8b/-> *(esi+0x10) 0/r32/eax +7416 39/compare *(edi+0x10) 0/r32/eax +7417 74/jump-if-= break/disp8 +7418 # if either address is 0, return false +7419 3d/compare-eax-and 0/imm32 +7420 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +7421 81 7/subop/compare *(edi+0x10) 0/imm32 +7422 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +7423 # if prim-var->register is "*", return true +7424 (string-equal? *(edi+0x10) "*") # Var-register +7425 3d/compare-eax-and 0/imm32/false +7426 b8/copy-to-eax 1/imm32/true +7427 75/jump-if-!= $operand-matches-primitive?:end/disp8 +7428 # if string contents don't match, return false +7429 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register +7430 3d/compare-eax-and 0/imm32/false +7431 b8/copy-to-eax 0/imm32/false +7432 74/jump-if-= $operand-matches-primitive?:end/disp8 +7433 } +7434 # return true +7435 b8/copy-to-eax 1/imm32/true +7436 $operand-matches-primitive?:end: +7437 # . restore registers +7438 5f/pop-to-edi +7439 5e/pop-to-esi +7440 # . epilogue +7441 89/<- %esp 5/r32/ebp +7442 5d/pop-to-ebp +7443 c3/return +7444 +7445 subx-type-equal?: # a: (handle tree type-id), b: (handle tree type-id) -> result/eax: boolean +7446 # . prologue +7447 55/push-ebp +7448 89/<- %ebp 4/r32/esp +7449 # . save registers +7450 51/push-ecx +7451 # var alit/ecx: boolean = is-literal-type?(a) +7452 (is-literal-type? *(ebp+8)) # => eax +7453 89/<- %ecx 0/r32/eax +7454 # var blit/eax: boolean = is-literal-type?(b) +7455 (is-literal-type? *(ebp+0xc)) # => eax +7456 # return alit == blit +7457 39/compare %eax 1/r32/ecx +7458 74/jump-if-= $subx-type-equal?:true/disp8 +7459 $subx-type-equal?:false: +7460 b8/copy-to-eax 0/imm32/false +7461 eb/jump $subx-type-equal?:end/disp8 +7462 $subx-type-equal?:true: +7463 b8/copy-to-eax 1/imm32/true +7464 $subx-type-equal?:end: +7465 # . restore registers +7466 59/pop-to-ecx +7467 # . epilogue +7468 89/<- %esp 5/r32/ebp +7469 5d/pop-to-ebp +7470 c3/return +7471 +7472 is-literal-type?: # a: (handle tree type-id) -> result/eax: boolean +7473 # . prologue +7474 55/push-ebp +7475 89/<- %ebp 4/r32/esp +7476 # +7477 8b/-> *(ebp+8) 0/r32/eax +7478 8b/-> *eax 0/r32/eax # Atom-value +7479 3d/compare-eax-and 0/imm32/false +7480 74/jump-if-equal $is-literal-type?:end/disp8 +7481 b8/copy-to-eax 1/imm32/true +7482 $is-literal-type?:end: +7483 # . epilogue +7484 89/<- %esp 5/r32/ebp +7485 5d/pop-to-ebp +7486 c3/return +7487 +7488 test-emit-subx-statement-primitive: +7489 # Primitive operation on a variable on the stack. +7490 # increment foo +7491 # => +7492 # ff 0/subop/increment *(ebp-8) +7493 # +7494 # There's a variable on the var stack as follows: +7495 # name: 'foo' +7496 # type: int +7497 # stack-offset: -8 +7498 # +7499 # There's a primitive with this info: +7500 # name: 'increment' +7501 # inouts: int/mem +7502 # value: 'ff 0/subop/increment' +7503 # +7504 # There's nothing in functions. +7505 # +7506 # . prologue +7507 55/push-ebp +7508 89/<- %ebp 4/r32/esp +7509 # setup +7510 (clear-stream _test-output-stream) +7511 (clear-stream $_test-output-buffered-file->buffer) +7512 # var type/ecx: (handle tree type-id) = int +7513 68/push 0/imm32/right/null +7514 68/push 1/imm32/left/int +7515 89/<- %ecx 4/r32/esp +7516 # var var-foo/ecx: var +7517 68/push 0/imm32/no-register +7518 68/push -8/imm32/stack-offset +7519 68/push 1/imm32/block-depth +7520 51/push-ecx +7521 68/push "foo"/imm32 +7522 89/<- %ecx 4/r32/esp +7523 # var operand/ebx: (list var) +7524 68/push 0/imm32/next +7525 51/push-ecx/var-foo +7526 89/<- %ebx 4/r32/esp +7527 # var stmt/esi: statement +7528 68/push 0/imm32/next +7529 68/push 0/imm32/outputs +7530 53/push-ebx/operands +7531 68/push "increment"/imm32/operation +7532 68/push 1/imm32 +7533 89/<- %esi 4/r32/esp +7534 # var primitives/ebx: primitive +7535 68/push 0/imm32/next +7536 68/push 0/imm32/output-is-write-only +7537 68/push 0/imm32/no-disp32 +7538 68/push 0/imm32/no-imm32 +7539 68/push 0/imm32/no-r32 +7540 68/push 1/imm32/rm32-is-first-inout +7541 68/push "ff 0/subop/increment"/imm32/subx-name +7542 68/push 0/imm32/outputs +7543 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call +7544 68/push "increment"/imm32/name +7545 89/<- %ebx 4/r32/esp +7546 # convert +7547 c7 0/subop/copy *Curr-block-depth 0/imm32 +7548 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +7549 (flush _test-output-buffered-file) +7550 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +7556 # check output +7557 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") +7558 # . epilogue +7559 89/<- %esp 5/r32/ebp +7560 5d/pop-to-ebp +7561 c3/return +7562 +7563 test-emit-subx-statement-primitive-register: +7564 # Primitive operation on a variable in a register. +7565 # foo <- increment +7566 # => +7567 # ff 0/subop/increment %eax # sub-optimal, but should suffice +7568 # +7569 # There's a variable on the var stack as follows: +7570 # name: 'foo' +7571 # type: int +7572 # register: 'eax' +7573 # +7574 # There's a primitive with this info: +7575 # name: 'increment' +7576 # out: int/reg +7577 # value: 'ff 0/subop/increment' +7578 # +7579 # There's nothing in functions. +7580 # +7581 # . prologue +7582 55/push-ebp +7583 89/<- %ebp 4/r32/esp +7584 # setup +7585 (clear-stream _test-output-stream) +7586 (clear-stream $_test-output-buffered-file->buffer) +7587 # var type/ecx: (handle tree type-id) = int +7588 68/push 0/imm32/right/null +7589 68/push 1/imm32/left/int +7590 89/<- %ecx 4/r32/esp +7591 # var var-foo/ecx: var in eax +7592 68/push "eax"/imm32/register +7593 68/push 0/imm32/no-stack-offset +7594 68/push 1/imm32/block-depth +7595 51/push-ecx +7596 68/push "foo"/imm32 +7597 89/<- %ecx 4/r32/esp +7598 # var operand/ebx: (list var) +7599 68/push 0/imm32/next +7600 51/push-ecx/var-foo +7601 89/<- %ebx 4/r32/esp +7602 # var stmt/esi: statement +7603 68/push 0/imm32/next +7604 53/push-ebx/outputs +7605 68/push 0/imm32/inouts +7606 68/push "increment"/imm32/operation +7607 68/push 1/imm32 +7608 89/<- %esi 4/r32/esp +7609 # var formal-var/ebx: var in any register +7610 68/push Any-register/imm32 +7611 68/push 0/imm32/no-stack-offset +7612 68/push 1/imm32/block-depth +7613 ff 6/subop/push *(ecx+4) # Var-type +7614 68/push "dummy"/imm32 +7615 89/<- %ebx 4/r32/esp +7616 # var operand/ebx: (list var) +7617 68/push 0/imm32/next +7618 53/push-ebx/formal-var +7619 89/<- %ebx 4/r32/esp +7620 # var primitives/ebx: primitive +7621 68/push 0/imm32/next +7622 68/push 0/imm32/output-is-write-only +7623 68/push 0/imm32/no-disp32 +7624 68/push 0/imm32/no-imm32 +7625 68/push 0/imm32/no-r32 +7626 68/push 3/imm32/rm32-in-first-output +7627 68/push "ff 0/subop/increment"/imm32/subx-name +7628 53/push-ebx/outputs +7629 68/push 0/imm32/inouts +7630 68/push "increment"/imm32/name +7631 89/<- %ebx 4/r32/esp +7632 # convert +7633 c7 0/subop/copy *Curr-block-depth 0/imm32 +7634 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +7635 (flush _test-output-buffered-file) +7636 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +7642 # check output +7643 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") +7644 # . epilogue +7645 89/<- %esp 5/r32/ebp +7646 5d/pop-to-ebp +7647 c3/return +7648 +7649 test-emit-subx-statement-select-primitive: +7650 # Select the right primitive between overloads. +7651 # foo <- increment +7652 # => +7653 # ff 0/subop/increment %eax # sub-optimal, but should suffice +7654 # +7655 # There's a variable on the var stack as follows: +7656 # name: 'foo' +7657 # type: int +7658 # register: 'eax' +7659 # +7660 # There's two primitives, as follows: +7661 # - name: 'increment' +7662 # out: int/reg +7663 # value: 'ff 0/subop/increment' +7664 # - name: 'increment' +7665 # inout: int/mem +7666 # value: 'ff 0/subop/increment' +7667 # +7668 # There's nothing in functions. +7669 # +7670 # . prologue +7671 55/push-ebp +7672 89/<- %ebp 4/r32/esp +7673 # setup +7674 (clear-stream _test-output-stream) +7675 (clear-stream $_test-output-buffered-file->buffer) +7676 # var type/ecx: (handle tree type-id) = int +7677 68/push 0/imm32/right/null +7678 68/push 1/imm32/left/int +7679 89/<- %ecx 4/r32/esp +7680 # var var-foo/ecx: var in eax +7681 68/push "eax"/imm32/register +7682 68/push 0/imm32/no-stack-offset +7683 68/push 1/imm32/block-depth +7684 51/push-ecx +7685 68/push "foo"/imm32 +7686 89/<- %ecx 4/r32/esp +7687 # var real-outputs/edi: (list var) +7688 68/push 0/imm32/next +7689 51/push-ecx/var-foo +7690 89/<- %edi 4/r32/esp +7691 # var stmt/esi: statement +7692 68/push 0/imm32/next +7693 57/push-edi/outputs +7694 68/push 0/imm32/inouts +7695 68/push "increment"/imm32/operation +7696 68/push 1/imm32 +7697 89/<- %esi 4/r32/esp +7698 # var formal-var/ebx: var in any register +7699 68/push Any-register/imm32 +7700 68/push 0/imm32/no-stack-offset +7701 68/push 1/imm32/block-depth +7702 ff 6/subop/push *(ecx+4) # Var-type +7703 68/push "dummy"/imm32 +7704 89/<- %ebx 4/r32/esp +7705 # var formal-outputs/ebx: (list var) = {formal-var, 0} +7706 68/push 0/imm32/next +7707 53/push-ebx/formal-var +7708 89/<- %ebx 4/r32/esp +7709 # var primitive1/ebx: primitive +7710 68/push 0/imm32/next +7711 68/push 0/imm32/output-is-write-only +7712 68/push 0/imm32/no-disp32 +7713 68/push 0/imm32/no-imm32 +7714 68/push 0/imm32/no-r32 +7715 68/push 3/imm32/rm32-in-first-output +7716 68/push "ff 0/subop/increment"/imm32/subx-name +7717 53/push-ebx/outputs/formal-outputs +7718 68/push 0/imm32/inouts +7719 68/push "increment"/imm32/name +7720 89/<- %ebx 4/r32/esp +7721 # var primitives/ebx: primitive +7722 53/push-ebx/next +7723 68/push 0/imm32/output-is-write-only +7724 68/push 0/imm32/no-disp32 +7725 68/push 0/imm32/no-imm32 +7726 68/push 0/imm32/no-r32 +7727 68/push 1/imm32/rm32-is-first-inout +7728 68/push "ff 0/subop/increment"/imm32/subx-name +7729 68/push 0/imm32/outputs +7730 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +7731 68/push "increment"/imm32/name +7732 89/<- %ebx 4/r32/esp +7733 # convert +7734 c7 0/subop/copy *Curr-block-depth 0/imm32 +7735 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +7736 (flush _test-output-buffered-file) +7737 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +7743 # check output +7744 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") +7745 # . epilogue +7746 89/<- %esp 5/r32/ebp +7747 5d/pop-to-ebp +7748 c3/return +7749 +7750 test-emit-subx-statement-select-primitive-2: +7751 # Select the right primitive between overloads. +7752 # foo <- increment +7753 # => +7754 # ff 0/subop/increment %eax # sub-optimal, but should suffice +7755 # +7756 # There's a variable on the var stack as follows: +7757 # name: 'foo' +7758 # type: int +7759 # register: 'eax' +7760 # +7761 # There's two primitives, as follows: +7762 # - name: 'increment' +7763 # out: int/reg +7764 # value: 'ff 0/subop/increment' +7765 # - name: 'increment' +7766 # inout: int/mem +7767 # value: 'ff 0/subop/increment' 7768 # -7769 # . prologue -7770 55/push-ebp -7771 89/<- %ebp 4/r32/esp -7772 # setup -7773 (clear-stream _test-output-stream) -7774 (clear-stream $_test-output-buffered-file->buffer) -7775 # var type/ecx: (handle tree type-id) = int -7776 68/push 0/imm32/right/null -7777 68/push 1/imm32/left/int -7778 89/<- %ecx 4/r32/esp -7779 # var var-var1/ecx: var in eax -7780 68/push "eax"/imm32/register -7781 68/push 0/imm32/no-stack-offset -7782 68/push 1/imm32/block-depth -7783 51/push-ecx -7784 68/push "var1"/imm32 -7785 89/<- %ecx 4/r32/esp -7786 # var var-var2/edx: var -7787 68/push 0/imm32/no-register -7788 68/push 8/imm32/stack-offset -7789 68/push 1/imm32/block-depth -7790 ff 6/subop/push *(ecx+4) # Var-type -7791 68/push "var2"/imm32 -7792 89/<- %edx 4/r32/esp -7793 # var inouts/esi: (list var2) -7794 68/push 0/imm32/next -7795 52/push-edx/var-var2 -7796 89/<- %esi 4/r32/esp -7797 # var outputs/edi: (list var1) -7798 68/push 0/imm32/next -7799 51/push-ecx/var-var1 -7800 89/<- %edi 4/r32/esp -7801 # var stmt/esi: statement -7802 68/push 0/imm32/next -7803 57/push-edi/outputs -7804 56/push-esi/inouts -7805 68/push "add"/imm32/operation -7806 68/push 1/imm32 -7807 89/<- %esi 4/r32/esp -7808 # convert -7809 c7 0/subop/copy *Curr-block-depth 0/imm32 -7810 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -7811 (flush _test-output-buffered-file) -7812 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -7818 # check output -7819 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") -7820 # . epilogue -7821 89/<- %esp 5/r32/ebp -7822 5d/pop-to-ebp -7823 c3/return -7824 -7825 test-add-literal-to-eax: -7826 # var1/eax <- add 0x34 -7827 # => -7828 # 05/add-to-eax 0x34/imm32 -7829 # -7830 # . prologue -7831 55/push-ebp -7832 89/<- %ebp 4/r32/esp -7833 # setup -7834 (clear-stream _test-output-stream) -7835 (clear-stream $_test-output-buffered-file->buffer) -7836 # var type/ecx: (handle tree type-id) = int -7837 68/push 0/imm32/right/null -7838 68/push 1/imm32/left/int -7839 89/<- %ecx 4/r32/esp -7840 # var var-var1/ecx: var in eax -7841 68/push "eax"/imm32/register -7842 68/push 0/imm32/no-stack-offset -7843 68/push 1/imm32/block-depth -7844 51/push-ecx -7845 68/push "var1"/imm32 -7846 89/<- %ecx 4/r32/esp -7847 # var type/edx: (handle tree type-id) = literal -7848 68/push 0/imm32/right/null -7849 68/push 0/imm32/left/literal -7850 89/<- %edx 4/r32/esp -7851 # var var-var2/edx: var literal -7852 68/push 0/imm32/no-register -7853 68/push 0/imm32/no-stack-offset -7854 68/push 1/imm32/block-depth -7855 52/push-edx -7856 68/push "0x34"/imm32 -7857 89/<- %edx 4/r32/esp -7858 # var inouts/esi: (list var2) -7859 68/push 0/imm32/next -7860 52/push-edx/var-var2 -7861 89/<- %esi 4/r32/esp -7862 # var outputs/edi: (list var1) -7863 68/push 0/imm32/next -7864 51/push-ecx/var-var1 -7865 89/<- %edi 4/r32/esp -7866 # var stmt/esi: statement -7867 68/push 0/imm32/next -7868 57/push-edi/outputs -7869 56/push-esi/inouts -7870 68/push "add"/imm32/operation -7871 68/push 1/imm32 -7872 89/<- %esi 4/r32/esp -7873 # convert -7874 c7 0/subop/copy *Curr-block-depth 0/imm32 -7875 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -7876 (flush _test-output-buffered-file) -7877 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -7883 # check output -7884 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") -7885 # . epilogue -7886 89/<- %esp 5/r32/ebp -7887 5d/pop-to-ebp -7888 c3/return -7889 -7890 test-add-literal-to-reg: -7891 # var1/ecx <- add 0x34 -7892 # => -7893 # 81 0/subop/add %ecx 0x34/imm32 -7894 # -7895 # . prologue -7896 55/push-ebp -7897 89/<- %ebp 4/r32/esp -7898 # setup -7899 (clear-stream _test-output-stream) -7900 (clear-stream $_test-output-buffered-file->buffer) -7901 # var type/ecx: (handle tree type-id) = int -7902 68/push 0/imm32/right/null -7903 68/push 1/imm32/left/int -7904 89/<- %ecx 4/r32/esp -7905 # var var-var1/ecx: var in ecx -7906 68/push "ecx"/imm32/register -7907 68/push 0/imm32/no-stack-offset -7908 68/push 1/imm32/block-depth -7909 51/push-ecx -7910 68/push "var1"/imm32 -7911 89/<- %ecx 4/r32/esp -7912 # var type/edx: (handle tree type-id) = literal -7913 68/push 0/imm32/right/null -7914 68/push 0/imm32/left/literal -7915 89/<- %edx 4/r32/esp -7916 # var var-var2/edx: var literal -7917 68/push 0/imm32/no-register -7918 68/push 0/imm32/no-stack-offset -7919 68/push 1/imm32/block-depth -7920 52/push-edx -7921 68/push "0x34"/imm32 -7922 89/<- %edx 4/r32/esp -7923 # var inouts/esi: (list var2) -7924 68/push 0/imm32/next -7925 52/push-edx/var-var2 -7926 89/<- %esi 4/r32/esp -7927 # var outputs/edi: (list var1) -7928 68/push 0/imm32/next -7929 51/push-ecx/var-var1 -7930 89/<- %edi 4/r32/esp -7931 # var stmt/esi: statement -7932 68/push 0/imm32/next -7933 57/push-edi/outputs -7934 56/push-esi/inouts -7935 68/push "add"/imm32/operation -7936 68/push 1/imm32 -7937 89/<- %esi 4/r32/esp -7938 # convert -7939 c7 0/subop/copy *Curr-block-depth 0/imm32 -7940 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -7941 (flush _test-output-buffered-file) -7942 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -7948 # check output -7949 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") -7950 # . epilogue -7951 89/<- %esp 5/r32/ebp -7952 5d/pop-to-ebp -7953 c3/return -7954 -7955 test-add-literal-to-mem: -7956 # add-to var1, 0x34 -7957 # => -7958 # 81 0/subop/add %eax 0x34/imm32 -7959 # -7960 # . prologue -7961 55/push-ebp -7962 89/<- %ebp 4/r32/esp -7963 # setup -7964 (clear-stream _test-output-stream) -7965 (clear-stream $_test-output-buffered-file->buffer) -7966 # var type/ecx: (handle tree type-id) = int -7967 68/push 0/imm32/right/null -7968 68/push 1/imm32/left/int -7969 89/<- %ecx 4/r32/esp -7970 # var var-var1/ecx: var -7971 68/push 0/imm32/no-register -7972 68/push 8/imm32/stack-offset -7973 68/push 1/imm32/block-depth -7974 51/push-ecx -7975 68/push "var1"/imm32 -7976 89/<- %ecx 4/r32/esp -7977 # var type/edx: (handle tree type-id) = literal -7978 68/push 0/imm32/right/null -7979 68/push 0/imm32/left/literal -7980 89/<- %edx 4/r32/esp -7981 # var var-var2/edx: var literal -7982 68/push 0/imm32/no-register -7983 68/push 0/imm32/no-stack-offset -7984 68/push 1/imm32/block-depth -7985 52/push-edx -7986 68/push "0x34"/imm32 -7987 89/<- %edx 4/r32/esp -7988 # var inouts/esi: (list var2) -7989 68/push 0/imm32/next -7990 52/push-edx/var-var2 -7991 89/<- %esi 4/r32/esp -7992 # var inouts = (list var1 inouts) -7993 56/push-esi/next -7994 51/push-ecx/var-var1 -7995 89/<- %esi 4/r32/esp -7996 # var stmt/esi: statement -7997 68/push 0/imm32/next -7998 68/push 0/imm32/outputs -7999 56/push-esi/inouts -8000 68/push "add-to"/imm32/operation -8001 68/push 1/imm32 -8002 89/<- %esi 4/r32/esp -8003 # convert -8004 c7 0/subop/copy *Curr-block-depth 0/imm32 -8005 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -8006 (flush _test-output-buffered-file) -8007 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -8013 # check output -8014 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") -8015 # . epilogue -8016 89/<- %esp 5/r32/ebp -8017 5d/pop-to-ebp -8018 c3/return -8019 -8020 test-compare-mem-with-reg: -8021 # compare var1, var2/eax -8022 # => -8023 # 39/compare *(ebp+___) 0/r32/eax -8024 # -8025 # . prologue -8026 55/push-ebp -8027 89/<- %ebp 4/r32/esp -8028 # setup -8029 (clear-stream _test-output-stream) -8030 (clear-stream $_test-output-buffered-file->buffer) -8031 # var type/ecx: (handle tree type-id) = int -8032 68/push 0/imm32/right/null -8033 68/push 1/imm32/left/int -8034 89/<- %ecx 4/r32/esp -8035 # var var-var2/ecx: var in eax -8036 68/push "eax"/imm32/register -8037 68/push 0/imm32/no-stack-offset -8038 68/push 1/imm32/block-depth -8039 51/push-ecx -8040 68/push "var2"/imm32 -8041 89/<- %ecx 4/r32/esp -8042 # var var-var1/edx: var -8043 68/push 0/imm32/no-register -8044 68/push 8/imm32/stack-offset -8045 68/push 1/imm32/block-depth -8046 ff 6/subop/push *(ecx+4) # Var-type -8047 68/push "var1"/imm32 -8048 89/<- %edx 4/r32/esp -8049 # var inouts/esi: (list var1 var2) -8050 68/push 0/imm32/next -8051 51/push-ecx/var-var2 -8052 89/<- %esi 4/r32/esp -8053 56/push-esi -8054 52/push-edx/var-var1 -8055 89/<- %esi 4/r32/esp -8056 # var stmt/esi: statement -8057 68/push 0/imm32/next -8058 68/push 0/imm32/outputs -8059 56/push-esi/inouts -8060 68/push "compare"/imm32/operation -8061 68/push 1/imm32 -8062 89/<- %esi 4/r32/esp -8063 # convert -8064 c7 0/subop/copy *Curr-block-depth 0/imm32 -8065 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -8066 (flush _test-output-buffered-file) -8067 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -8073 # check output -8074 (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg") -8075 # . epilogue -8076 89/<- %esp 5/r32/ebp -8077 5d/pop-to-ebp -8078 c3/return -8079 -8080 test-compare-reg-with-mem: -8081 # compare var1/eax, var2 -8082 # => -8083 # 3b/compare *(ebp+___) 0/r32/eax -8084 # -8085 # . prologue -8086 55/push-ebp -8087 89/<- %ebp 4/r32/esp -8088 # setup -8089 (clear-stream _test-output-stream) -8090 (clear-stream $_test-output-buffered-file->buffer) -8091 # var type/ecx: (handle tree type-id) = int -8092 68/push 0/imm32/right/null -8093 68/push 1/imm32/left/int -8094 89/<- %ecx 4/r32/esp -8095 # var var-var1/ecx: var in eax -8096 68/push "eax"/imm32/register -8097 68/push 0/imm32/no-stack-offset -8098 68/push 1/imm32/block-depth -8099 51/push-ecx -8100 68/push "var1"/imm32 -8101 89/<- %ecx 4/r32/esp -8102 # var var-var2/edx: var -8103 68/push 0/imm32/no-register -8104 68/push 8/imm32/stack-offset -8105 68/push 1/imm32/block-depth -8106 ff 6/subop/push *(ecx+4) # Var-type -8107 68/push "var2"/imm32 -8108 89/<- %edx 4/r32/esp -8109 # var inouts/esi: (list var1 var2) -8110 68/push 0/imm32/next -8111 52/push-edx/var-var2 -8112 89/<- %esi 4/r32/esp -8113 56/push-esi -8114 51/push-ecx/var-var1 -8115 89/<- %esi 4/r32/esp -8116 # var stmt/esi: statement -8117 68/push 0/imm32/next -8118 68/push 0/imm32/outputs -8119 56/push-esi/inouts -8120 68/push "compare"/imm32/operation -8121 68/push 1/imm32 -8122 89/<- %esi 4/r32/esp -8123 # convert -8124 c7 0/subop/copy *Curr-block-depth 0/imm32 -8125 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -8126 (flush _test-output-buffered-file) -8127 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -8133 # check output -8134 (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem") -8135 # . epilogue -8136 89/<- %esp 5/r32/ebp -8137 5d/pop-to-ebp -8138 c3/return -8139 -8140 test-compare-mem-with-literal: -8141 # compare var1, 0x34 -8142 # => -8143 # 81 7/subop/compare *(ebp+___) 0x34/imm32 -8144 # -8145 # . prologue -8146 55/push-ebp -8147 89/<- %ebp 4/r32/esp -8148 # setup -8149 (clear-stream _test-output-stream) -8150 (clear-stream $_test-output-buffered-file->buffer) -8151 # var type/ecx: (handle tree type-id) = int -8152 68/push 0/imm32/right/null -8153 68/push 1/imm32/left/int -8154 89/<- %ecx 4/r32/esp -8155 # var var-var1/ecx: var -8156 68/push 0/imm32/no-register -8157 68/push 8/imm32/stack-offset -8158 68/push 1/imm32/block-depth -8159 51/push-ecx -8160 68/push "var1"/imm32 -8161 89/<- %ecx 4/r32/esp -8162 # var type/edx: (handle tree type-id) = literal -8163 68/push 0/imm32/right/null -8164 68/push 0/imm32/left/literal -8165 89/<- %edx 4/r32/esp -8166 # var var-var2/edx: var literal -8167 68/push 0/imm32/no-register -8168 68/push 0/imm32/no-stack-offset -8169 68/push 1/imm32/block-depth -8170 52/push-edx -8171 68/push "0x34"/imm32 -8172 89/<- %edx 4/r32/esp -8173 # var inouts/esi: (list var2) -8174 68/push 0/imm32/next -8175 52/push-edx/var-var2 -8176 89/<- %esi 4/r32/esp -8177 # var inouts = (list var1 inouts) -8178 56/push-esi/next -8179 51/push-ecx/var-var1 -8180 89/<- %esi 4/r32/esp -8181 # var stmt/esi: statement -8182 68/push 0/imm32/next -8183 68/push 0/imm32/outputs -8184 56/push-esi/inouts -8185 68/push "compare"/imm32/operation -8186 68/push 1/imm32 -8187 89/<- %esi 4/r32/esp -8188 # convert -8189 c7 0/subop/copy *Curr-block-depth 0/imm32 -8190 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -8191 (flush _test-output-buffered-file) -8192 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -8198 # check output -8199 (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal") -8200 # . epilogue -8201 89/<- %esp 5/r32/ebp -8202 5d/pop-to-ebp -8203 c3/return -8204 -8205 test-compare-eax-with-literal: -8206 # compare var1/eax 0x34 -8207 # => -8208 # 3d/compare-eax-with 0x34/imm32 -8209 # -8210 # . prologue -8211 55/push-ebp -8212 89/<- %ebp 4/r32/esp -8213 # setup -8214 (clear-stream _test-output-stream) -8215 (clear-stream $_test-output-buffered-file->buffer) -8216 # var type/ecx: (handle tree type-id) = int -8217 68/push 0/imm32/right/null -8218 68/push 1/imm32/left/int -8219 89/<- %ecx 4/r32/esp -8220 # var var-var1/ecx: var in eax -8221 68/push "eax"/imm32/register -8222 68/push 0/imm32/no-stack-offset -8223 68/push 1/imm32/block-depth -8224 51/push-ecx -8225 68/push "var1"/imm32 -8226 89/<- %ecx 4/r32/esp -8227 # var type/edx: (handle tree type-id) = literal -8228 68/push 0/imm32/right/null -8229 68/push 0/imm32/left/literal -8230 89/<- %edx 4/r32/esp -8231 # var var-var2/edx: var literal -8232 68/push 0/imm32/no-register -8233 68/push 0/imm32/no-stack-offset -8234 68/push 1/imm32/block-depth -8235 52/push-edx -8236 68/push "0x34"/imm32 -8237 89/<- %edx 4/r32/esp -8238 # var inouts/esi: (list var2) -8239 68/push 0/imm32/next -8240 52/push-edx/var-var2 -8241 89/<- %esi 4/r32/esp -8242 # var inouts = (list var1 inouts) -8243 56/push-esi/next -8244 51/push-ecx/var-var1 -8245 89/<- %esi 4/r32/esp -8246 # var stmt/esi: statement -8247 68/push 0/imm32/next -8248 68/push 0/imm32/outputs -8249 56/push-esi/inouts -8250 68/push "compare"/imm32/operation -8251 68/push 1/imm32/regular-stmt -8252 89/<- %esi 4/r32/esp -8253 # convert -8254 c7 0/subop/copy *Curr-block-depth 0/imm32 -8255 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -8256 (flush _test-output-buffered-file) -8257 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -8263 # check output -8264 (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal") -8265 # . epilogue -8266 89/<- %esp 5/r32/ebp -8267 5d/pop-to-ebp -8268 c3/return -8269 -8270 test-compare-reg-with-literal: -8271 # compare var1/ecx 0x34 -8272 # => -8273 # 81 7/subop/compare %ecx 0x34/imm32 -8274 # -8275 # . prologue -8276 55/push-ebp -8277 89/<- %ebp 4/r32/esp -8278 # setup -8279 (clear-stream _test-output-stream) -8280 (clear-stream $_test-output-buffered-file->buffer) -8281 # var type/ecx: (handle tree type-id) = int -8282 68/push 0/imm32/right/null -8283 68/push 1/imm32/left/int -8284 89/<- %ecx 4/r32/esp -8285 # var var-var1/ecx: var in ecx -8286 68/push "ecx"/imm32/register -8287 68/push 0/imm32/no-stack-offset -8288 68/push 1/imm32/block-depth -8289 51/push-ecx -8290 68/push "var1"/imm32 -8291 89/<- %ecx 4/r32/esp -8292 # var type/edx: (handle tree type-id) = literal -8293 68/push 0/imm32/right/null -8294 68/push 0/imm32/left/literal -8295 89/<- %edx 4/r32/esp -8296 # var var-var2/edx: var literal -8297 68/push 0/imm32/no-register -8298 68/push 0/imm32/no-stack-offset -8299 68/push 1/imm32/block-depth -8300 52/push-edx -8301 68/push "0x34"/imm32 -8302 89/<- %edx 4/r32/esp -8303 # var inouts/esi: (list var2) -8304 68/push 0/imm32/next -8305 52/push-edx/var-var2 -8306 89/<- %esi 4/r32/esp -8307 # var inouts = (list var1 inouts) -8308 56/push-esi/next -8309 51/push-ecx/var-var1 -8310 89/<- %esi 4/r32/esp -8311 # var stmt/esi: statement -8312 68/push 0/imm32/next -8313 68/push 0/imm32/outputs -8314 56/push-esi/inouts -8315 68/push "compare"/imm32/operation -8316 68/push 1/imm32/regular-stmt -8317 89/<- %esi 4/r32/esp -8318 # convert -8319 c7 0/subop/copy *Curr-block-depth 0/imm32 -8320 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -8321 (flush _test-output-buffered-file) -8322 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -8328 # check output -8329 (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal") -8330 # . epilogue -8331 89/<- %esp 5/r32/ebp -8332 5d/pop-to-ebp -8333 c3/return -8334 -8335 test-emit-subx-statement-function-call: -8336 # Call a function on a variable on the stack. -8337 # f foo -8338 # => -8339 # (f2 *(ebp-8)) -8340 # (Changing the function name supports overloading in general, but here it -8341 # just serves to help disambiguate things.) -8342 # -8343 # There's a variable on the var stack as follows: -8344 # name: 'foo' -8345 # type: int -8346 # stack-offset: -8 -8347 # -8348 # There's nothing in primitives. -8349 # -8350 # There's a function with this info: -8351 # name: 'f' -8352 # inout: int/mem -8353 # value: 'f2' -8354 # -8355 # . prologue -8356 55/push-ebp -8357 89/<- %ebp 4/r32/esp -8358 # setup -8359 (clear-stream _test-output-stream) -8360 (clear-stream $_test-output-buffered-file->buffer) -8361 # var type/ecx: (handle tree type-id) = int -8362 68/push 0/imm32/right/null -8363 68/push 1/imm32/left/int -8364 89/<- %ecx 4/r32/esp -8365 # var var-foo/ecx: var -8366 68/push 0/imm32/no-register -8367 68/push -8/imm32/stack-offset -8368 68/push 0/imm32/block-depth -8369 51/push-ecx -8370 68/push "foo"/imm32 -8371 89/<- %ecx 4/r32/esp -8372 # var operands/esi: (list var) -8373 68/push 0/imm32/next -8374 51/push-ecx/var-foo -8375 89/<- %esi 4/r32/esp -8376 # var stmt/esi: statement -8377 68/push 0/imm32/next -8378 68/push 0/imm32/outputs -8379 56/push-esi/inouts -8380 68/push "f"/imm32/operation -8381 68/push 1/imm32 -8382 89/<- %esi 4/r32/esp -8383 # var functions/ebx: function -8384 68/push 0/imm32/next -8385 68/push 0/imm32/body -8386 68/push 0/imm32/outputs -8387 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -8388 68/push "f2"/imm32/subx-name -8389 68/push "f"/imm32/name -8390 89/<- %ebx 4/r32/esp -8391 # convert -8392 c7 0/subop/copy *Curr-block-depth 0/imm32 -8393 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -8394 (flush _test-output-buffered-file) -8395 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -8401 # check output -8402 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") -8403 # . epilogue -8404 89/<- %esp 5/r32/ebp -8405 5d/pop-to-ebp -8406 c3/return -8407 -8408 test-emit-subx-statement-function-call-with-literal-arg: -8409 # Call a function on a literal. -8410 # f 34 +7769 # There's nothing in functions. +7770 # +7771 # . prologue +7772 55/push-ebp +7773 89/<- %ebp 4/r32/esp +7774 # setup +7775 (clear-stream _test-output-stream) +7776 (clear-stream $_test-output-buffered-file->buffer) +7777 # var type/ecx: (handle tree type-id) = int +7778 68/push 0/imm32/right/null +7779 68/push 1/imm32/left/int +7780 89/<- %ecx 4/r32/esp +7781 # var var-foo/ecx: var in eax +7782 68/push "eax"/imm32/register +7783 68/push 0/imm32/no-stack-offset +7784 68/push 1/imm32/block-depth +7785 51/push-ecx +7786 68/push "foo"/imm32 +7787 89/<- %ecx 4/r32/esp +7788 # var inouts/edi: (list var) +7789 68/push 0/imm32/next +7790 51/push-ecx/var-foo +7791 89/<- %edi 4/r32/esp +7792 # var stmt/esi: statement +7793 68/push 0/imm32/next +7794 68/push 0/imm32/outputs +7795 57/push-edi/inouts +7796 68/push "increment"/imm32/operation +7797 68/push 1/imm32 +7798 89/<- %esi 4/r32/esp +7799 # var formal-var/ebx: var in any register +7800 68/push Any-register/imm32 +7801 68/push 0/imm32/no-stack-offset +7802 68/push 1/imm32/block-depth +7803 ff 6/subop/push *(ecx+4) # Var-type +7804 68/push "dummy"/imm32 +7805 89/<- %ebx 4/r32/esp +7806 # var operand/ebx: (list var) +7807 68/push 0/imm32/next +7808 53/push-ebx/formal-var +7809 89/<- %ebx 4/r32/esp +7810 # var primitive1/ebx: primitive +7811 68/push 0/imm32/next +7812 68/push 0/imm32/output-is-write-only +7813 68/push 0/imm32/no-disp32 +7814 68/push 0/imm32/no-imm32 +7815 68/push 0/imm32/no-r32 +7816 68/push 3/imm32/rm32-in-first-output +7817 68/push "ff 0/subop/increment"/imm32/subx-name +7818 53/push-ebx/outputs/formal-outputs +7819 68/push 0/imm32/inouts +7820 68/push "increment"/imm32/name +7821 89/<- %ebx 4/r32/esp +7822 # var primitives/ebx: primitive +7823 53/push-ebx/next +7824 68/push 0/imm32/output-is-write-only +7825 68/push 0/imm32/no-disp32 +7826 68/push 0/imm32/no-imm32 +7827 68/push 0/imm32/no-r32 +7828 68/push 1/imm32/rm32-is-first-inout +7829 68/push "ff 0/subop/increment"/imm32/subx-name +7830 68/push 0/imm32/outputs +7831 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +7832 68/push "increment"/imm32/name +7833 89/<- %ebx 4/r32/esp +7834 # convert +7835 c7 0/subop/copy *Curr-block-depth 0/imm32 +7836 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +7837 (flush _test-output-buffered-file) +7838 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +7844 # check output +7845 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") +7846 # . epilogue +7847 89/<- %esp 5/r32/ebp +7848 5d/pop-to-ebp +7849 c3/return +7850 +7851 test-increment-register: +7852 # Select the right register between overloads. +7853 # foo <- increment +7854 # => +7855 # 50/increment-eax +7856 # +7857 # There's a variable on the var stack as follows: +7858 # name: 'foo' +7859 # type: int +7860 # register: 'eax' +7861 # +7862 # Primitives are the global definitions. +7863 # +7864 # There are no functions defined. +7865 # +7866 # . prologue +7867 55/push-ebp +7868 89/<- %ebp 4/r32/esp +7869 # setup +7870 (clear-stream _test-output-stream) +7871 (clear-stream $_test-output-buffered-file->buffer) +7872 # var type/ecx: (handle tree type-id) = int +7873 68/push 0/imm32/right/null +7874 68/push 1/imm32/left/int +7875 89/<- %ecx 4/r32/esp +7876 # var var-foo/ecx: var in eax +7877 68/push "eax"/imm32/register +7878 68/push 0/imm32/no-stack-offset +7879 68/push 1/imm32/block-depth +7880 51/push-ecx +7881 68/push "foo"/imm32 +7882 89/<- %ecx 4/r32/esp +7883 # var real-outputs/edi: (list var) +7884 68/push 0/imm32/next +7885 51/push-ecx/var-foo +7886 89/<- %edi 4/r32/esp +7887 # var stmt/esi: statement +7888 68/push 0/imm32/next +7889 57/push-edi/outputs +7890 68/push 0/imm32/inouts +7891 68/push "increment"/imm32/operation +7892 68/push 1/imm32/regular-statement +7893 89/<- %esi 4/r32/esp +7894 # convert +7895 c7 0/subop/copy *Curr-block-depth 0/imm32 +7896 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +7897 (flush _test-output-buffered-file) +7898 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +7904 # check output +7905 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") +7906 # . epilogue +7907 89/<- %esp 5/r32/ebp +7908 5d/pop-to-ebp +7909 c3/return +7910 +7911 test-increment-var: +7912 # Select the right primitive between overloads. +7913 # foo <- increment +7914 # => +7915 # ff 0/subop/increment %eax # sub-optimal, but should suffice +7916 # +7917 # There's a variable on the var stack as follows: +7918 # name: 'foo' +7919 # type: int +7920 # register: 'eax' +7921 # +7922 # Primitives are the global definitions. +7923 # +7924 # There are no functions defined. +7925 # +7926 # . prologue +7927 55/push-ebp +7928 89/<- %ebp 4/r32/esp +7929 # setup +7930 (clear-stream _test-output-stream) +7931 (clear-stream $_test-output-buffered-file->buffer) +7932 # var type/ecx: (handle tree type-id) = int +7933 68/push 0/imm32/right/null +7934 68/push 1/imm32/left/int +7935 89/<- %ecx 4/r32/esp +7936 # var var-foo/ecx: var in eax +7937 68/push "eax"/imm32/register +7938 68/push 0/imm32/no-stack-offset +7939 68/push 1/imm32/block-depth +7940 51/push-ecx +7941 68/push "foo"/imm32 +7942 89/<- %ecx 4/r32/esp +7943 # var inouts/edi: (list var) +7944 68/push 0/imm32/next +7945 51/push-ecx/var-foo +7946 89/<- %edi 4/r32/esp +7947 # var stmt/esi: statement +7948 68/push 0/imm32/next +7949 68/push 0/imm32/outputs +7950 57/push-edi/inouts +7951 68/push "increment"/imm32/operation +7952 68/push 1/imm32 +7953 89/<- %esi 4/r32/esp +7954 # convert +7955 c7 0/subop/copy *Curr-block-depth 0/imm32 +7956 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +7957 (flush _test-output-buffered-file) +7958 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +7964 # check output +7965 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") +7966 # . epilogue +7967 89/<- %esp 5/r32/ebp +7968 5d/pop-to-ebp +7969 c3/return +7970 +7971 test-add-reg-to-reg: +7972 # var1/reg <- add var2/reg +7973 # => +7974 # 01/add %var1 var2 +7975 # +7976 # . prologue +7977 55/push-ebp +7978 89/<- %ebp 4/r32/esp +7979 # setup +7980 (clear-stream _test-output-stream) +7981 (clear-stream $_test-output-buffered-file->buffer) +7982 # var type/ecx: (handle tree type-id) = int +7983 68/push 0/imm32/right/null +7984 68/push 1/imm32/left/int +7985 89/<- %ecx 4/r32/esp +7986 # var var-var1/ecx: var in eax +7987 68/push "eax"/imm32/register +7988 68/push 0/imm32/no-stack-offset +7989 68/push 1/imm32/block-depth +7990 51/push-ecx +7991 68/push "var1"/imm32 +7992 89/<- %ecx 4/r32/esp +7993 # var var-var2/edx: var in ecx +7994 68/push "ecx"/imm32/register +7995 68/push 0/imm32/no-stack-offset +7996 68/push 1/imm32/block-depth +7997 ff 6/subop/push *(ecx+4) # Var-type +7998 68/push "var2"/imm32 +7999 89/<- %edx 4/r32/esp +8000 # var inouts/esi: (list var2) +8001 68/push 0/imm32/next +8002 52/push-edx/var-var2 +8003 89/<- %esi 4/r32/esp +8004 # var outputs/edi: (list var1) +8005 68/push 0/imm32/next +8006 51/push-ecx/var-var1 +8007 89/<- %edi 4/r32/esp +8008 # var stmt/esi: statement +8009 68/push 0/imm32/next +8010 57/push-edi/outputs +8011 56/push-esi/inouts +8012 68/push "add"/imm32/operation +8013 68/push 1/imm32 +8014 89/<- %esi 4/r32/esp +8015 # convert +8016 c7 0/subop/copy *Curr-block-depth 0/imm32 +8017 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +8018 (flush _test-output-buffered-file) +8019 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8025 # check output +8026 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") +8027 # . epilogue +8028 89/<- %esp 5/r32/ebp +8029 5d/pop-to-ebp +8030 c3/return +8031 +8032 test-add-reg-to-mem: +8033 # add-to var1 var2/reg +8034 # => +8035 # 01/add *(ebp+__) var2 +8036 # +8037 # . prologue +8038 55/push-ebp +8039 89/<- %ebp 4/r32/esp +8040 # setup +8041 (clear-stream _test-output-stream) +8042 (clear-stream $_test-output-buffered-file->buffer) +8043 # var type/ecx: (handle tree type-id) = int +8044 68/push 0/imm32/right/null +8045 68/push 1/imm32/left/int +8046 89/<- %ecx 4/r32/esp +8047 # var var-var1/ecx: var +8048 68/push 0/imm32/no-register +8049 68/push 8/imm32/stack-offset +8050 68/push 1/imm32/block-depth +8051 51/push-ecx +8052 68/push "var1"/imm32 +8053 89/<- %ecx 4/r32/esp +8054 # var var-var2/edx: var in ecx +8055 68/push "ecx"/imm32/register +8056 68/push 0/imm32/no-stack-offset +8057 68/push 1/imm32/block-depth +8058 ff 6/subop/push *(ecx+4) # Var-type +8059 68/push "var2"/imm32 +8060 89/<- %edx 4/r32/esp +8061 # var inouts/esi: (list var2) +8062 68/push 0/imm32/next +8063 52/push-edx/var-var2 +8064 89/<- %esi 4/r32/esp +8065 # var inouts = (list var1 var2) +8066 56/push-esi/next +8067 51/push-ecx/var-var1 +8068 89/<- %esi 4/r32/esp +8069 # var stmt/esi: statement +8070 68/push 0/imm32/next +8071 68/push 0/imm32/outputs +8072 56/push-esi/inouts +8073 68/push "add-to"/imm32/operation +8074 68/push 1/imm32 +8075 89/<- %esi 4/r32/esp +8076 # convert +8077 c7 0/subop/copy *Curr-block-depth 0/imm32 +8078 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +8079 (flush _test-output-buffered-file) +8080 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8086 # check output +8087 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") +8088 # . epilogue +8089 89/<- %esp 5/r32/ebp +8090 5d/pop-to-ebp +8091 c3/return +8092 +8093 test-add-mem-to-reg: +8094 # var1/reg <- add var2 +8095 # => +8096 # 03/add *(ebp+__) var1 +8097 # +8098 # . prologue +8099 55/push-ebp +8100 89/<- %ebp 4/r32/esp +8101 # setup +8102 (clear-stream _test-output-stream) +8103 (clear-stream $_test-output-buffered-file->buffer) +8104 # var type/ecx: (handle tree type-id) = int +8105 68/push 0/imm32/right/null +8106 68/push 1/imm32/left/int +8107 89/<- %ecx 4/r32/esp +8108 # var var-var1/ecx: var in eax +8109 68/push "eax"/imm32/register +8110 68/push 0/imm32/no-stack-offset +8111 68/push 1/imm32/block-depth +8112 51/push-ecx +8113 68/push "var1"/imm32 +8114 89/<- %ecx 4/r32/esp +8115 # var var-var2/edx: var +8116 68/push 0/imm32/no-register +8117 68/push 8/imm32/stack-offset +8118 68/push 1/imm32/block-depth +8119 ff 6/subop/push *(ecx+4) # Var-type +8120 68/push "var2"/imm32 +8121 89/<- %edx 4/r32/esp +8122 # var inouts/esi: (list var2) +8123 68/push 0/imm32/next +8124 52/push-edx/var-var2 +8125 89/<- %esi 4/r32/esp +8126 # var outputs/edi: (list var1) +8127 68/push 0/imm32/next +8128 51/push-ecx/var-var1 +8129 89/<- %edi 4/r32/esp +8130 # var stmt/esi: statement +8131 68/push 0/imm32/next +8132 57/push-edi/outputs +8133 56/push-esi/inouts +8134 68/push "add"/imm32/operation +8135 68/push 1/imm32 +8136 89/<- %esi 4/r32/esp +8137 # convert +8138 c7 0/subop/copy *Curr-block-depth 0/imm32 +8139 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +8140 (flush _test-output-buffered-file) +8141 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8147 # check output +8148 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") +8149 # . epilogue +8150 89/<- %esp 5/r32/ebp +8151 5d/pop-to-ebp +8152 c3/return +8153 +8154 test-add-literal-to-eax: +8155 # var1/eax <- add 0x34 +8156 # => +8157 # 05/add-to-eax 0x34/imm32 +8158 # +8159 # . prologue +8160 55/push-ebp +8161 89/<- %ebp 4/r32/esp +8162 # setup +8163 (clear-stream _test-output-stream) +8164 (clear-stream $_test-output-buffered-file->buffer) +8165 # var type/ecx: (handle tree type-id) = int +8166 68/push 0/imm32/right/null +8167 68/push 1/imm32/left/int +8168 89/<- %ecx 4/r32/esp +8169 # var var-var1/ecx: var in eax +8170 68/push "eax"/imm32/register +8171 68/push 0/imm32/no-stack-offset +8172 68/push 1/imm32/block-depth +8173 51/push-ecx +8174 68/push "var1"/imm32 +8175 89/<- %ecx 4/r32/esp +8176 # var type/edx: (handle tree type-id) = literal +8177 68/push 0/imm32/right/null +8178 68/push 0/imm32/left/literal +8179 89/<- %edx 4/r32/esp +8180 # var var-var2/edx: var literal +8181 68/push 0/imm32/no-register +8182 68/push 0/imm32/no-stack-offset +8183 68/push 1/imm32/block-depth +8184 52/push-edx +8185 68/push "0x34"/imm32 +8186 89/<- %edx 4/r32/esp +8187 # var inouts/esi: (list var2) +8188 68/push 0/imm32/next +8189 52/push-edx/var-var2 +8190 89/<- %esi 4/r32/esp +8191 # var outputs/edi: (list var1) +8192 68/push 0/imm32/next +8193 51/push-ecx/var-var1 +8194 89/<- %edi 4/r32/esp +8195 # var stmt/esi: statement +8196 68/push 0/imm32/next +8197 57/push-edi/outputs +8198 56/push-esi/inouts +8199 68/push "add"/imm32/operation +8200 68/push 1/imm32 +8201 89/<- %esi 4/r32/esp +8202 # convert +8203 c7 0/subop/copy *Curr-block-depth 0/imm32 +8204 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +8205 (flush _test-output-buffered-file) +8206 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8212 # check output +8213 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") +8214 # . epilogue +8215 89/<- %esp 5/r32/ebp +8216 5d/pop-to-ebp +8217 c3/return +8218 +8219 test-add-literal-to-reg: +8220 # var1/ecx <- add 0x34 +8221 # => +8222 # 81 0/subop/add %ecx 0x34/imm32 +8223 # +8224 # . prologue +8225 55/push-ebp +8226 89/<- %ebp 4/r32/esp +8227 # setup +8228 (clear-stream _test-output-stream) +8229 (clear-stream $_test-output-buffered-file->buffer) +8230 # var type/ecx: (handle tree type-id) = int +8231 68/push 0/imm32/right/null +8232 68/push 1/imm32/left/int +8233 89/<- %ecx 4/r32/esp +8234 # var var-var1/ecx: var in ecx +8235 68/push "ecx"/imm32/register +8236 68/push 0/imm32/no-stack-offset +8237 68/push 1/imm32/block-depth +8238 51/push-ecx +8239 68/push "var1"/imm32 +8240 89/<- %ecx 4/r32/esp +8241 # var type/edx: (handle tree type-id) = literal +8242 68/push 0/imm32/right/null +8243 68/push 0/imm32/left/literal +8244 89/<- %edx 4/r32/esp +8245 # var var-var2/edx: var literal +8246 68/push 0/imm32/no-register +8247 68/push 0/imm32/no-stack-offset +8248 68/push 1/imm32/block-depth +8249 52/push-edx +8250 68/push "0x34"/imm32 +8251 89/<- %edx 4/r32/esp +8252 # var inouts/esi: (list var2) +8253 68/push 0/imm32/next +8254 52/push-edx/var-var2 +8255 89/<- %esi 4/r32/esp +8256 # var outputs/edi: (list var1) +8257 68/push 0/imm32/next +8258 51/push-ecx/var-var1 +8259 89/<- %edi 4/r32/esp +8260 # var stmt/esi: statement +8261 68/push 0/imm32/next +8262 57/push-edi/outputs +8263 56/push-esi/inouts +8264 68/push "add"/imm32/operation +8265 68/push 1/imm32 +8266 89/<- %esi 4/r32/esp +8267 # convert +8268 c7 0/subop/copy *Curr-block-depth 0/imm32 +8269 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +8270 (flush _test-output-buffered-file) +8271 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8277 # check output +8278 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") +8279 # . epilogue +8280 89/<- %esp 5/r32/ebp +8281 5d/pop-to-ebp +8282 c3/return +8283 +8284 test-add-literal-to-mem: +8285 # add-to var1, 0x34 +8286 # => +8287 # 81 0/subop/add %eax 0x34/imm32 +8288 # +8289 # . prologue +8290 55/push-ebp +8291 89/<- %ebp 4/r32/esp +8292 # setup +8293 (clear-stream _test-output-stream) +8294 (clear-stream $_test-output-buffered-file->buffer) +8295 # var type/ecx: (handle tree type-id) = int +8296 68/push 0/imm32/right/null +8297 68/push 1/imm32/left/int +8298 89/<- %ecx 4/r32/esp +8299 # var var-var1/ecx: var +8300 68/push 0/imm32/no-register +8301 68/push 8/imm32/stack-offset +8302 68/push 1/imm32/block-depth +8303 51/push-ecx +8304 68/push "var1"/imm32 +8305 89/<- %ecx 4/r32/esp +8306 # var type/edx: (handle tree type-id) = literal +8307 68/push 0/imm32/right/null +8308 68/push 0/imm32/left/literal +8309 89/<- %edx 4/r32/esp +8310 # var var-var2/edx: var literal +8311 68/push 0/imm32/no-register +8312 68/push 0/imm32/no-stack-offset +8313 68/push 1/imm32/block-depth +8314 52/push-edx +8315 68/push "0x34"/imm32 +8316 89/<- %edx 4/r32/esp +8317 # var inouts/esi: (list var2) +8318 68/push 0/imm32/next +8319 52/push-edx/var-var2 +8320 89/<- %esi 4/r32/esp +8321 # var inouts = (list var1 inouts) +8322 56/push-esi/next +8323 51/push-ecx/var-var1 +8324 89/<- %esi 4/r32/esp +8325 # var stmt/esi: statement +8326 68/push 0/imm32/next +8327 68/push 0/imm32/outputs +8328 56/push-esi/inouts +8329 68/push "add-to"/imm32/operation +8330 68/push 1/imm32 +8331 89/<- %esi 4/r32/esp +8332 # convert +8333 c7 0/subop/copy *Curr-block-depth 0/imm32 +8334 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +8335 (flush _test-output-buffered-file) +8336 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8342 # check output +8343 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") +8344 # . epilogue +8345 89/<- %esp 5/r32/ebp +8346 5d/pop-to-ebp +8347 c3/return +8348 +8349 test-compare-mem-with-reg: +8350 # compare var1, var2/eax +8351 # => +8352 # 39/compare *(ebp+___) 0/r32/eax +8353 # +8354 # . prologue +8355 55/push-ebp +8356 89/<- %ebp 4/r32/esp +8357 # setup +8358 (clear-stream _test-output-stream) +8359 (clear-stream $_test-output-buffered-file->buffer) +8360 # var type/ecx: (handle tree type-id) = int +8361 68/push 0/imm32/right/null +8362 68/push 1/imm32/left/int +8363 89/<- %ecx 4/r32/esp +8364 # var var-var2/ecx: var in eax +8365 68/push "eax"/imm32/register +8366 68/push 0/imm32/no-stack-offset +8367 68/push 1/imm32/block-depth +8368 51/push-ecx +8369 68/push "var2"/imm32 +8370 89/<- %ecx 4/r32/esp +8371 # var var-var1/edx: var +8372 68/push 0/imm32/no-register +8373 68/push 8/imm32/stack-offset +8374 68/push 1/imm32/block-depth +8375 ff 6/subop/push *(ecx+4) # Var-type +8376 68/push "var1"/imm32 +8377 89/<- %edx 4/r32/esp +8378 # var inouts/esi: (list var1 var2) +8379 68/push 0/imm32/next +8380 51/push-ecx/var-var2 +8381 89/<- %esi 4/r32/esp +8382 56/push-esi +8383 52/push-edx/var-var1 +8384 89/<- %esi 4/r32/esp +8385 # var stmt/esi: statement +8386 68/push 0/imm32/next +8387 68/push 0/imm32/outputs +8388 56/push-esi/inouts +8389 68/push "compare"/imm32/operation +8390 68/push 1/imm32 +8391 89/<- %esi 4/r32/esp +8392 # convert +8393 c7 0/subop/copy *Curr-block-depth 0/imm32 +8394 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +8395 (flush _test-output-buffered-file) +8396 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8402 # check output +8403 (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg") +8404 # . epilogue +8405 89/<- %esp 5/r32/ebp +8406 5d/pop-to-ebp +8407 c3/return +8408 +8409 test-compare-reg-with-mem: +8410 # compare var1/eax, var2 8411 # => -8412 # (f2 34) +8412 # 3b/compare *(ebp+___) 0/r32/eax 8413 # 8414 # . prologue 8415 55/push-ebp @@ -8172,100 +8163,404 @@ if ('onhashchange' in window) { 8417 # setup 8418 (clear-stream _test-output-stream) 8419 (clear-stream $_test-output-buffered-file->buffer) -8420 # var type/ecx: (handle tree type-id) = literal +8420 # var type/ecx: (handle tree type-id) = int 8421 68/push 0/imm32/right/null -8422 68/push 0/imm32/left/literal +8422 68/push 1/imm32/left/int 8423 89/<- %ecx 4/r32/esp -8424 # var var-foo/ecx: var literal -8425 68/push 0/imm32/no-register +8424 # var var-var1/ecx: var in eax +8425 68/push "eax"/imm32/register 8426 68/push 0/imm32/no-stack-offset -8427 68/push 0/imm32/block-depth +8427 68/push 1/imm32/block-depth 8428 51/push-ecx -8429 68/push "34"/imm32 +8429 68/push "var1"/imm32 8430 89/<- %ecx 4/r32/esp -8431 # var operands/esi: (list var) -8432 68/push 0/imm32/next -8433 51/push-ecx/var-foo -8434 89/<- %esi 4/r32/esp -8435 # var stmt/esi: statement -8436 68/push 0/imm32/next -8437 68/push 0/imm32/outputs -8438 56/push-esi/inouts -8439 68/push "f"/imm32/operation -8440 68/push 1/imm32 +8431 # var var-var2/edx: var +8432 68/push 0/imm32/no-register +8433 68/push 8/imm32/stack-offset +8434 68/push 1/imm32/block-depth +8435 ff 6/subop/push *(ecx+4) # Var-type +8436 68/push "var2"/imm32 +8437 89/<- %edx 4/r32/esp +8438 # var inouts/esi: (list var1 var2) +8439 68/push 0/imm32/next +8440 52/push-edx/var-var2 8441 89/<- %esi 4/r32/esp -8442 # var functions/ebx: function -8443 68/push 0/imm32/next -8444 68/push 0/imm32/body -8445 68/push 0/imm32/outputs -8446 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -8447 68/push "f2"/imm32/subx-name -8448 68/push "f"/imm32/name -8449 89/<- %ebx 4/r32/esp -8450 # convert -8451 c7 0/subop/copy *Curr-block-depth 0/imm32 -8452 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -8453 (flush _test-output-buffered-file) -8454 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- -8460 # check output -8461 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") -8462 # . epilogue -8463 89/<- %esp 5/r32/ebp -8464 5d/pop-to-ebp -8465 c3/return -8466 -8467 emit-indent: # out: (addr buffered-file), n: int -8468 # . prologue -8469 55/push-ebp -8470 89/<- %ebp 4/r32/esp -8471 # . save registers -8472 50/push-eax -8473 # var i/eax: int = n -8474 8b/-> *(ebp+0xc) 0/r32/eax -8475 { -8476 # if (i <= 0) break -8477 3d/compare-eax-with 0/imm32 -8478 7e/jump-if-<= break/disp8 -8479 (write-buffered *(ebp+8) " ") -8480 48/decrement-eax -8481 eb/jump loop/disp8 -8482 } -8483 $emit-indent:end: -8484 # . restore registers -8485 58/pop-to-eax -8486 # . epilogue -8487 89/<- %esp 5/r32/ebp -8488 5d/pop-to-ebp -8489 c3/return -8490 -8491 emit-subx-prologue: # out: (addr buffered-file) -8492 # . prologue -8493 55/push-ebp -8494 89/<- %ebp 4/r32/esp -8495 # -8496 (write-buffered *(ebp+8) " # . prologue\n") -8497 (write-buffered *(ebp+8) " 55/push-ebp\n") -8498 (write-buffered *(ebp+8) " 89/<- %ebp 4/r32/esp\n") -8499 $emit-subx-prologue:end: -8500 # . epilogue -8501 89/<- %esp 5/r32/ebp -8502 5d/pop-to-ebp -8503 c3/return -8504 -8505 emit-subx-epilogue: # out: (addr buffered-file) -8506 # . prologue -8507 55/push-ebp -8508 89/<- %ebp 4/r32/esp -8509 # -8510 (write-buffered *(ebp+8) " # . epilogue\n") -8511 (write-buffered *(ebp+8) " 89/<- %esp 5/r32/ebp\n") -8512 (write-buffered *(ebp+8) " 5d/pop-to-ebp\n") -8513 (write-buffered *(ebp+8) " c3/return\n") -8514 $emit-subx-epilogue:end: -8515 # . epilogue -8516 89/<- %esp 5/r32/ebp -8517 5d/pop-to-ebp -8518 c3/return +8442 56/push-esi +8443 51/push-ecx/var-var1 +8444 89/<- %esi 4/r32/esp +8445 # var stmt/esi: statement +8446 68/push 0/imm32/next +8447 68/push 0/imm32/outputs +8448 56/push-esi/inouts +8449 68/push "compare"/imm32/operation +8450 68/push 1/imm32 +8451 89/<- %esi 4/r32/esp +8452 # convert +8453 c7 0/subop/copy *Curr-block-depth 0/imm32 +8454 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +8455 (flush _test-output-buffered-file) +8456 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8462 # check output +8463 (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem") +8464 # . epilogue +8465 89/<- %esp 5/r32/ebp +8466 5d/pop-to-ebp +8467 c3/return +8468 +8469 test-compare-mem-with-literal: +8470 # compare var1, 0x34 +8471 # => +8472 # 81 7/subop/compare *(ebp+___) 0x34/imm32 +8473 # +8474 # . prologue +8475 55/push-ebp +8476 89/<- %ebp 4/r32/esp +8477 # setup +8478 (clear-stream _test-output-stream) +8479 (clear-stream $_test-output-buffered-file->buffer) +8480 # var type/ecx: (handle tree type-id) = int +8481 68/push 0/imm32/right/null +8482 68/push 1/imm32/left/int +8483 89/<- %ecx 4/r32/esp +8484 # var var-var1/ecx: var +8485 68/push 0/imm32/no-register +8486 68/push 8/imm32/stack-offset +8487 68/push 1/imm32/block-depth +8488 51/push-ecx +8489 68/push "var1"/imm32 +8490 89/<- %ecx 4/r32/esp +8491 # var type/edx: (handle tree type-id) = literal +8492 68/push 0/imm32/right/null +8493 68/push 0/imm32/left/literal +8494 89/<- %edx 4/r32/esp +8495 # var var-var2/edx: var literal +8496 68/push 0/imm32/no-register +8497 68/push 0/imm32/no-stack-offset +8498 68/push 1/imm32/block-depth +8499 52/push-edx +8500 68/push "0x34"/imm32 +8501 89/<- %edx 4/r32/esp +8502 # var inouts/esi: (list var2) +8503 68/push 0/imm32/next +8504 52/push-edx/var-var2 +8505 89/<- %esi 4/r32/esp +8506 # var inouts = (list var1 inouts) +8507 56/push-esi/next +8508 51/push-ecx/var-var1 +8509 89/<- %esi 4/r32/esp +8510 # var stmt/esi: statement +8511 68/push 0/imm32/next +8512 68/push 0/imm32/outputs +8513 56/push-esi/inouts +8514 68/push "compare"/imm32/operation +8515 68/push 1/imm32 +8516 89/<- %esi 4/r32/esp +8517 # convert +8518 c7 0/subop/copy *Curr-block-depth 0/imm32 +8519 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +8520 (flush _test-output-buffered-file) +8521 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8527 # check output +8528 (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal") +8529 # . epilogue +8530 89/<- %esp 5/r32/ebp +8531 5d/pop-to-ebp +8532 c3/return +8533 +8534 test-compare-eax-with-literal: +8535 # compare var1/eax 0x34 +8536 # => +8537 # 3d/compare-eax-with 0x34/imm32 +8538 # +8539 # . prologue +8540 55/push-ebp +8541 89/<- %ebp 4/r32/esp +8542 # setup +8543 (clear-stream _test-output-stream) +8544 (clear-stream $_test-output-buffered-file->buffer) +8545 # var type/ecx: (handle tree type-id) = int +8546 68/push 0/imm32/right/null +8547 68/push 1/imm32/left/int +8548 89/<- %ecx 4/r32/esp +8549 # var var-var1/ecx: var in eax +8550 68/push "eax"/imm32/register +8551 68/push 0/imm32/no-stack-offset +8552 68/push 1/imm32/block-depth +8553 51/push-ecx +8554 68/push "var1"/imm32 +8555 89/<- %ecx 4/r32/esp +8556 # var type/edx: (handle tree type-id) = literal +8557 68/push 0/imm32/right/null +8558 68/push 0/imm32/left/literal +8559 89/<- %edx 4/r32/esp +8560 # var var-var2/edx: var literal +8561 68/push 0/imm32/no-register +8562 68/push 0/imm32/no-stack-offset +8563 68/push 1/imm32/block-depth +8564 52/push-edx +8565 68/push "0x34"/imm32 +8566 89/<- %edx 4/r32/esp +8567 # var inouts/esi: (list var2) +8568 68/push 0/imm32/next +8569 52/push-edx/var-var2 +8570 89/<- %esi 4/r32/esp +8571 # var inouts = (list var1 inouts) +8572 56/push-esi/next +8573 51/push-ecx/var-var1 +8574 89/<- %esi 4/r32/esp +8575 # var stmt/esi: statement +8576 68/push 0/imm32/next +8577 68/push 0/imm32/outputs +8578 56/push-esi/inouts +8579 68/push "compare"/imm32/operation +8580 68/push 1/imm32/regular-stmt +8581 89/<- %esi 4/r32/esp +8582 # convert +8583 c7 0/subop/copy *Curr-block-depth 0/imm32 +8584 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +8585 (flush _test-output-buffered-file) +8586 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8592 # check output +8593 (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal") +8594 # . epilogue +8595 89/<- %esp 5/r32/ebp +8596 5d/pop-to-ebp +8597 c3/return +8598 +8599 test-compare-reg-with-literal: +8600 # compare var1/ecx 0x34 +8601 # => +8602 # 81 7/subop/compare %ecx 0x34/imm32 +8603 # +8604 # . prologue +8605 55/push-ebp +8606 89/<- %ebp 4/r32/esp +8607 # setup +8608 (clear-stream _test-output-stream) +8609 (clear-stream $_test-output-buffered-file->buffer) +8610 # var type/ecx: (handle tree type-id) = int +8611 68/push 0/imm32/right/null +8612 68/push 1/imm32/left/int +8613 89/<- %ecx 4/r32/esp +8614 # var var-var1/ecx: var in ecx +8615 68/push "ecx"/imm32/register +8616 68/push 0/imm32/no-stack-offset +8617 68/push 1/imm32/block-depth +8618 51/push-ecx +8619 68/push "var1"/imm32 +8620 89/<- %ecx 4/r32/esp +8621 # var type/edx: (handle tree type-id) = literal +8622 68/push 0/imm32/right/null +8623 68/push 0/imm32/left/literal +8624 89/<- %edx 4/r32/esp +8625 # var var-var2/edx: var literal +8626 68/push 0/imm32/no-register +8627 68/push 0/imm32/no-stack-offset +8628 68/push 1/imm32/block-depth +8629 52/push-edx +8630 68/push "0x34"/imm32 +8631 89/<- %edx 4/r32/esp +8632 # var inouts/esi: (list var2) +8633 68/push 0/imm32/next +8634 52/push-edx/var-var2 +8635 89/<- %esi 4/r32/esp +8636 # var inouts = (list var1 inouts) +8637 56/push-esi/next +8638 51/push-ecx/var-var1 +8639 89/<- %esi 4/r32/esp +8640 # var stmt/esi: statement +8641 68/push 0/imm32/next +8642 68/push 0/imm32/outputs +8643 56/push-esi/inouts +8644 68/push "compare"/imm32/operation +8645 68/push 1/imm32/regular-stmt +8646 89/<- %esi 4/r32/esp +8647 # convert +8648 c7 0/subop/copy *Curr-block-depth 0/imm32 +8649 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +8650 (flush _test-output-buffered-file) +8651 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8657 # check output +8658 (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal") +8659 # . epilogue +8660 89/<- %esp 5/r32/ebp +8661 5d/pop-to-ebp +8662 c3/return +8663 +8664 test-emit-subx-statement-function-call: +8665 # Call a function on a variable on the stack. +8666 # f foo +8667 # => +8668 # (f2 *(ebp-8)) +8669 # (Changing the function name supports overloading in general, but here it +8670 # just serves to help disambiguate things.) +8671 # +8672 # There's a variable on the var stack as follows: +8673 # name: 'foo' +8674 # type: int +8675 # stack-offset: -8 +8676 # +8677 # There's nothing in primitives. +8678 # +8679 # There's a function with this info: +8680 # name: 'f' +8681 # inout: int/mem +8682 # value: 'f2' +8683 # +8684 # . prologue +8685 55/push-ebp +8686 89/<- %ebp 4/r32/esp +8687 # setup +8688 (clear-stream _test-output-stream) +8689 (clear-stream $_test-output-buffered-file->buffer) +8690 # var type/ecx: (handle tree type-id) = int +8691 68/push 0/imm32/right/null +8692 68/push 1/imm32/left/int +8693 89/<- %ecx 4/r32/esp +8694 # var var-foo/ecx: var +8695 68/push 0/imm32/no-register +8696 68/push -8/imm32/stack-offset +8697 68/push 0/imm32/block-depth +8698 51/push-ecx +8699 68/push "foo"/imm32 +8700 89/<- %ecx 4/r32/esp +8701 # var operands/esi: (list var) +8702 68/push 0/imm32/next +8703 51/push-ecx/var-foo +8704 89/<- %esi 4/r32/esp +8705 # var stmt/esi: statement +8706 68/push 0/imm32/next +8707 68/push 0/imm32/outputs +8708 56/push-esi/inouts +8709 68/push "f"/imm32/operation +8710 68/push 1/imm32 +8711 89/<- %esi 4/r32/esp +8712 # var functions/ebx: function +8713 68/push 0/imm32/next +8714 68/push 0/imm32/body +8715 68/push 0/imm32/outputs +8716 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +8717 68/push "f2"/imm32/subx-name +8718 68/push "f"/imm32/name +8719 89/<- %ebx 4/r32/esp +8720 # convert +8721 c7 0/subop/copy *Curr-block-depth 0/imm32 +8722 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +8723 (flush _test-output-buffered-file) +8724 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8730 # check output +8731 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") +8732 # . epilogue +8733 89/<- %esp 5/r32/ebp +8734 5d/pop-to-ebp +8735 c3/return +8736 +8737 test-emit-subx-statement-function-call-with-literal-arg: +8738 # Call a function on a literal. +8739 # f 34 +8740 # => +8741 # (f2 34) +8742 # +8743 # . prologue +8744 55/push-ebp +8745 89/<- %ebp 4/r32/esp +8746 # setup +8747 (clear-stream _test-output-stream) +8748 (clear-stream $_test-output-buffered-file->buffer) +8749 # var type/ecx: (handle tree type-id) = literal +8750 68/push 0/imm32/right/null +8751 68/push 0/imm32/left/literal +8752 89/<- %ecx 4/r32/esp +8753 # var var-foo/ecx: var literal +8754 68/push 0/imm32/no-register +8755 68/push 0/imm32/no-stack-offset +8756 68/push 0/imm32/block-depth +8757 51/push-ecx +8758 68/push "34"/imm32 +8759 89/<- %ecx 4/r32/esp +8760 # var operands/esi: (list var) +8761 68/push 0/imm32/next +8762 51/push-ecx/var-foo +8763 89/<- %esi 4/r32/esp +8764 # var stmt/esi: statement +8765 68/push 0/imm32/next +8766 68/push 0/imm32/outputs +8767 56/push-esi/inouts +8768 68/push "f"/imm32/operation +8769 68/push 1/imm32 +8770 89/<- %esi 4/r32/esp +8771 # var functions/ebx: function +8772 68/push 0/imm32/next +8773 68/push 0/imm32/body +8774 68/push 0/imm32/outputs +8775 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +8776 68/push "f2"/imm32/subx-name +8777 68/push "f"/imm32/name +8778 89/<- %ebx 4/r32/esp +8779 # convert +8780 c7 0/subop/copy *Curr-block-depth 0/imm32 +8781 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +8782 (flush _test-output-buffered-file) +8783 +-- 6 lines: #? # dump _test-output-stream ----------------------------------------------------------------------------------------------------------------------------------------- +8789 # check output +8790 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") +8791 # . epilogue +8792 89/<- %esp 5/r32/ebp +8793 5d/pop-to-ebp +8794 c3/return +8795 +8796 emit-indent: # out: (addr buffered-file), n: int +8797 # . prologue +8798 55/push-ebp +8799 89/<- %ebp 4/r32/esp +8800 # . save registers +8801 50/push-eax +8802 # var i/eax: int = n +8803 8b/-> *(ebp+0xc) 0/r32/eax +8804 { +8805 # if (i <= 0) break +8806 3d/compare-eax-with 0/imm32 +8807 7e/jump-if-<= break/disp8 +8808 (write-buffered *(ebp+8) " ") +8809 48/decrement-eax +8810 eb/jump loop/disp8 +8811 } +8812 $emit-indent:end: +8813 # . restore registers +8814 58/pop-to-eax +8815 # . epilogue +8816 89/<- %esp 5/r32/ebp +8817 5d/pop-to-ebp +8818 c3/return +8819 +8820 emit-subx-prologue: # out: (addr buffered-file) +8821 # . prologue +8822 55/push-ebp +8823 89/<- %ebp 4/r32/esp +8824 # +8825 (write-buffered *(ebp+8) " # . prologue\n") +8826 (write-buffered *(ebp+8) " 55/push-ebp\n") +8827 (write-buffered *(ebp+8) " 89/<- %ebp 4/r32/esp\n") +8828 $emit-subx-prologue:end: +8829 # . epilogue +8830 89/<- %esp 5/r32/ebp +8831 5d/pop-to-ebp +8832 c3/return +8833 +8834 emit-subx-epilogue: # out: (addr buffered-file) +8835 # . prologue +8836 55/push-ebp +8837 89/<- %ebp 4/r32/esp +8838 # +8839 (write-buffered *(ebp+8) " # . epilogue\n") +8840 (write-buffered *(ebp+8) " 89/<- %esp 5/r32/ebp\n") +8841 (write-buffered *(ebp+8) " 5d/pop-to-ebp\n") +8842 (write-buffered *(ebp+8) " c3/return\n") +8843 $emit-subx-epilogue:end: +8844 # . epilogue +8845 89/<- %esp 5/r32/ebp +8846 5d/pop-to-ebp +8847 c3/return -- cgit 1.4.1-2-gfad0