From f833e0a0e70f119b907f9c36e5cc4fa2e60581e0 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 20 Jan 2020 03:09:06 -0800 Subject: 5912 --- html/apps/mu.subx.html | 8565 +++++++++++++++++++++++++----------------------- 1 file changed, 4450 insertions(+), 4115 deletions(-) (limited to 'html/apps/*.subx.html') diff --git a/html/apps/mu.subx.html b/html/apps/mu.subx.html index ba371346..3d699c70 100644 --- a/html/apps/mu.subx.html +++ b/html/apps/mu.subx.html @@ -414,7 +414,7 @@ if ('onhashchange' in window) { 352 # However, there's no need for singletons, so we can assume (int) == int 353 # - if x->right == nil, x is an atom 354 # - x->left contains either a pointer to a pair, or an atomic type-id directly. - 355 # type ids will be less than 0x10000. + 355 # type ids will be less than 0x10000 (MAX_TYPE_ID). 356 357 Tree-left: # either type-id or (addr tree type-id) 358 0/imm32 @@ -462,8 +462,8 @@ if ('onhashchange' in window) { 400 89/<- %ebp 4/r32/esp 401 # 402 (parse-mu *(ebp+8)) - 403 (check-mu-types) - 404 (emit-subx *(ebp+0xc)) + 403 (check-mu-types) + 404 (emit-subx *(ebp+0xc)) 405 $convert-mu:end: 406 # . epilogue 407 89/<- %esp 5/r32/ebp @@ -1068,7 +1068,7 @@ if ('onhashchange' in window) { 1056 (zero-out %eax *Function-size) 1057 (clear-stack %ebx) 1058 (populate-mu-function-header %ecx %eax %ebx) -1059 (populate-mu-function-body *(ebp+8) %eax %ebx) +1059 (populate-mu-function-body *(ebp+8) %eax %ebx) 1060 # *curr-function = new-function 1061 89/<- *edi 0/r32/eax 1062 # curr-function = &new-function->next @@ -1220,10 +1220,10 @@ if ('onhashchange' in window) { 1208 # v->stack-offset = next-offset 1209 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset 1210 # next-offset += size-of(v) -1211 (size-of %ebx) # => eax +1211 (size-of %ebx) # => eax 1212 01/add %edx 0/r32/eax 1213 # -1214 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax +1214 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax 1215 89/<- *(edi+8) 0/r32/eax # Function-inouts 1216 (push *(ebp+0x10) %ebx) 1217 # @@ -1251,12 +1251,12 @@ if ('onhashchange' in window) { 1239 # assert(var->register != null) 1240 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register 1241 0f 84/jump-if-= $populate-mu-function-header:error3/disp32 -1242 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax +1242 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax 1243 89/<- *(edi+0xc) 0/r32/eax # Function-outputs 1244 e9/jump loop/disp32 1245 } 1246 $populate-mu-function-header:done: -1247 (check-no-tokens-left *(ebp+8)) +1247 (check-no-tokens-left *(ebp+8)) 1248 $populate-mu-function-header:end: 1249 # . reclaim locals 1250 81 0/subop/add %esp 8/imm32 @@ -1493,4141 +1493,4476 @@ if ('onhashchange' in window) { 1481 # if (!slice-empty?(s)) 1482 # v->register = slice-to-string(s) 1483 # ## type -1484 # s = next-mu-token(first-line) -1485 # assert(s not in '{' '}' '->') -1486 # if (slice-empty?(s)) { -1487 # s = next-mu-token(first-line) -1488 # assert(type not in '{' '}' '->') -1489 # } -1490 # type = type-for(s) -1491 # v->type = type -1492 # return v -1493 # -1494 # . prologue -1495 55/push-ebp -1496 89/<- %ebp 4/r32/esp -1497 # . save registers -1498 51/push-ecx -1499 52/push-edx -1500 53/push-ebx -1501 56/push-esi -1502 57/push-edi -1503 # var result/edi : (handle var) = allocate(Heap, Var-size) -1504 (allocate Heap *Var-size) # => eax -1505 (zero-out %eax *Var-size) -1506 89/<- %edi 0/r32/eax -1507 # esi = name -1508 8b/-> *(ebp+8) 6/r32/esi -1509 # var s/ecx : slice -1510 68/push 0/imm32/end -1511 68/push 0/imm32/start -1512 89/<- %ecx 4/r32/esp -1513 $parse-var-with-type:save-name: -1514 # save v->name -1515 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' -1516 # . end/edx = s->end -1517 8b/-> *(ecx+4) 2/r32/edx -1518 # . if s ends with ':', decrement s->end -1519 { -1520 8b/-> *(ecx+4) 0/r32/eax -1521 48/decrement-eax -1522 8a/copy-byte *eax 3/r32/BL -1523 81 4/subop/and %ebx 0xff/imm32 -1524 81 7/subop/compare %ebx 0x3a/imm32/colon -1525 75/jump-if-!= break/disp8 -1526 89/<- *(ecx+4) 0/r32/eax -1527 } -1528 # . if s ends with ',', decrement s->end -1529 { -1530 8b/-> *(ecx+4) 0/r32/eax -1531 48/decrement-eax -1532 8a/copy-byte *eax 3/r32/BL -1533 81 4/subop/and %ebx 0xff/imm32 -1534 81 7/subop/compare %ebx 0x2c/imm32/comma -1535 75/jump-if-!= break/disp8 -1536 89/<- *(ecx+4) 0/r32/eax -1537 } -1538 $parse-var-with-type:write-name: -1539 (slice-to-string Heap %ecx) # => eax -1540 89/<- *edi 0/r32/eax # Var-name -1541 # save v->register -1542 $parse-var-with-type:save-register: -1543 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' -1544 # . if s ends with ':', decrement s->end -1545 { -1546 8b/-> *(ecx+4) 0/r32/eax -1547 48/decrement-eax -1548 8a/copy-byte *eax 3/r32/BL -1549 81 4/subop/and %ebx 0xff/imm32 -1550 81 7/subop/compare %ebx 0x3a/imm32/colon -1551 75/jump-if-!= break/disp8 -1552 89/<- *(ecx+4) 0/r32/eax -1553 } -1554 # . if s ends with ',', decrement s->end -1555 { -1556 8b/-> *(ecx+4) 0/r32/eax -1557 48/decrement-eax -1558 8a/copy-byte *eax 3/r32/BL -1559 81 4/subop/and %ebx 0xff/imm32 -1560 81 7/subop/compare %ebx 0x2c/imm32/comma -1561 75/jump-if-!= break/disp8 -1562 89/<- *(ecx+4) 0/r32/eax -1563 } -1564 # if (!slice-empty?(s)) v->register = slice-to-string(s) -1565 { -1566 $parse-var-with-type:write-register: -1567 # HACK: s->end can be less than s->start with all the decrements above -1568 # That's probably a sign we have the wrong algorithm for this function. -1569 8b/-> *ecx 0/r32/eax -1570 39/compare 0/r32/eax *(ecx+4) -1571 76/jump-if-<= break/disp8 -1572 (slice-to-string Heap %ecx) -1573 89/<- *(edi+0x10) 0/r32/eax # Var-register -1574 } -1575 # save v->type -1576 (next-mu-token *(ebp+0xc) %ecx) -1577 # if (word-slice == '{') abort -1578 (slice-equal? %ecx "{") # => eax -1579 3d/compare-eax-and 0/imm32 -1580 0f 85/jump-if-!= $parse-var-with-type:abort/disp32 -1581 # if (word-slice == '->') abort -1582 (slice-equal? %ecx "->") # => eax -1583 3d/compare-eax-and 0/imm32 -1584 0f 85/jump-if-!= $parse-var-with-type:abort/disp32 -1585 # if (word-slice == '}') abort -1586 (slice-equal? %ecx "}") # => eax -1587 3d/compare-eax-and 0/imm32 -1588 0f 85/jump-if-!= $parse-var-with-type:abort/disp32 -1589 # if (slice-empty?(type)) skip -1590 (slice-empty? %ecx) -1591 { -1592 3d/compare-eax-and 0/imm32 -1593 0f 84/jump-if-= break/disp32 -1594 (next-mu-token *(ebp+0xc) %ecx) -1595 # if (word-slice == '{') abort -1596 (slice-equal? %ecx "{") # => eax -1597 3d/compare-eax-and 0/imm32 -1598 0f 85/jump-if-!= $parse-var-with-type:abort/disp32 -1599 # if (word-slice == '->') abort -1600 (slice-equal? %ecx "->") # => eax -1601 3d/compare-eax-and 0/imm32 -1602 0f 85/jump-if-!= $parse-var-with-type:abort/disp32 -1603 # if (word-slice == '}') abort -1604 (slice-equal? %ecx "}") # => eax -1605 3d/compare-eax-and 0/imm32 -1606 0f 85/jump-if-!= $parse-var-with-type:abort/disp32 -1607 } -1608 (type-for %ecx) # => eax -1609 89/<- *(edi+4) 0/r32/eax # Var-type -1610 $parse-var-with-type:end: -1611 # return result -1612 89/<- %eax 7/r32/edi -1613 # . reclaim locals -1614 81 0/subop/add %esp 8/imm32 -1615 # . restore registers -1616 5f/pop-to-edi -1617 5e/pop-to-esi -1618 5b/pop-to-ebx -1619 5a/pop-to-edx -1620 59/pop-to-ecx -1621 # . epilogue -1622 89/<- %esp 5/r32/ebp -1623 5d/pop-to-ebp -1624 c3/return -1625 -1626 $parse-var-with-type:abort: -1627 # error("function header not in form 'fn <name> {'") -1628 (write-buffered Stderr "var should have form 'name: type' in '") -1629 (flush Stderr) -1630 (rewind-stream *(ebp+0xc)) -1631 (write-stream 2 *(ebp+0xc)) -1632 (write-buffered Stderr "'\n") -1633 (flush Stderr) -1634 # . syscall(exit, 1) -1635 bb/copy-to-ebx 1/imm32 -1636 b8/copy-to-eax 1/imm32/exit -1637 cd/syscall 0x80/imm8 -1638 # never gets here -1639 -1640 next-mu-token: # in: (addr stream byte), out: (addr slice) -1641 # . prologue -1642 55/push-ebp -1643 89/<- %ebp 4/r32/esp -1644 # . save registers -1645 50/push-eax -1646 57/push-edi -1647 # edi = out -1648 8b/-> *(ebp+0xc) 7/r32/edi -1649 # -1650 (next-word *(ebp+8) %edi) # TODO: support s-expressions -1651 # if out ends with ':', decrement out->end -1652 { -1653 8b/-> *(edi+4) 0/r32/eax -1654 48/decrement-eax -1655 8a/copy-byte *eax 3/r32/BL -1656 81 4/subop/and %ebx 0xff/imm32 -1657 81 7/subop/compare %ebx 0x3a/imm32/colon -1658 75/jump-if-!= break/disp8 -1659 89/<- *(edi+4) 0/r32/eax -1660 } -1661 # if out ends with ',', decrement out->end -1662 { -1663 8b/-> *(edi+4) 0/r32/eax -1664 48/decrement-eax -1665 8a/copy-byte *eax 3/r32/BL -1666 81 4/subop/and %ebx 0xff/imm32 -1667 81 7/subop/compare %ebx 0x2c/imm32/comma -1668 75/jump-if-!= break/disp8 -1669 89/<- *(edi+4) 0/r32/eax -1670 } -1671 $next-mu-token:end: -1672 b8/copy-to-eax 1/imm32/int -1673 # . restore registers -1674 5f/pop-to-edi -1675 58/pop-to-eax -1676 # . epilogue -1677 89/<- %esp 5/r32/ebp -1678 5d/pop-to-ebp -1679 c3/return -1680 -1681 type-for: # name: (addr slice) -> result/eax: (handle tree type-id) -1682 # . prologue -1683 55/push-ebp -1684 89/<- %ebp 4/r32/esp -1685 # . save registers -1686 51/push-ecx -1687 # -1688 (pos-slice Type-id *(ebp+8)) # => eax -1689 89/<- %ecx 0/r32/eax -1690 (allocate Heap *Tree-size) # => eax -1691 (zero-out %eax *Tree-size) -1692 89/<- *eax 1/r32/ecx # Tree-left -1693 $type-for:end: -1694 # . restore registers -1695 59/pop-to-ecx -1696 # . epilogue -1697 89/<- %esp 5/r32/ebp -1698 5d/pop-to-ebp -1699 c3/return -1700 -1701 # return the index in an array of strings matching 's' -1702 # index is denominated in elements, not bytes -1703 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int -1704 # . prologue -1705 55/push-ebp -1706 89/<- %ebp 4/r32/esp -1707 # . save registers -1708 51/push-ecx -1709 52/push-edx -1710 53/push-ebx -1711 56/push-esi -1712 # esi = arr -1713 8b/-> *(ebp+8) 6/r32/esi -1714 # var index/ecx: int = 0 -1715 b9/copy-to-ecx 0/imm32 -1716 # var curr/edx: (addr (addr array byte)) = arr->data -1717 8d/copy-address *(esi+0xc) 2/r32/edx -1718 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] -1719 8b/-> *esi 3/r32/ebx -1720 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx -1721 { -1722 # if (curr >= max) return -1 -1723 39/compare %edx 3/r32/ebx -1724 { -1725 72/jump-if-addr< break/disp8 -1726 b8/copy-to-eax 1/imm32 -1727 eb/jump $pos-slice:end/disp8 -1728 } -1729 # if (slice-equal?(s, *curr)) break -1730 (slice-equal? *(ebp+0xc) *edx) # => eax -1731 3d/compare-eax-and 0/imm32 -1732 75/jump-if-!= break/disp8 -1733 # ++index -1734 41/increment-ecx -1735 # curr += 4 -1736 81 0/subop/add %edx 4/imm32 -1737 } -1738 89/<- %eax 1/r32/ecx -1739 $pos-slice:end: -1740 # . restore registers -1741 5e/pop-to-esi -1742 5b/pop-to-ebx -1743 5a/pop-to-edx -1744 59/pop-to-ecx -1745 # . epilogue -1746 89/<- %esp 5/r32/ebp -1747 5d/pop-to-ebp -1748 c3/return -1749 -1750 == data -1751 -1752 Type-id: # (stream (address array byte)) -1753 0x1c/imm32/write -1754 0/imm32/read -1755 0x100/imm32/length -1756 # data -1757 "literal"/imm32 # 0 -1758 "int"/imm32 # 1 -1759 "addr"/imm32 # 2 -1760 "array"/imm32 # 3 -1761 "handle"/imm32 # 4 -1762 "bool"/imm32 # 5 -1763 0/imm32 -1764 0/imm32 -1765 # 0x20 -1766 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1767 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1768 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1769 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1770 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1771 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1772 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1773 -1774 == code -1775 -1776 test-parse-var-with-type: -1777 # . prologue -1778 55/push-ebp -1779 89/<- %ebp 4/r32/esp -1780 # (eax..ecx) = "x:" -1781 b8/copy-to-eax "x:"/imm32 -1782 8b/-> *eax 1/r32/ecx -1783 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1784 05/add-to-eax 4/imm32 -1785 # var slice/ecx : slice = {eax, ecx} -1786 51/push-ecx -1787 50/push-eax -1788 89/<- %ecx 4/r32/esp -1789 # _test-input-stream contains "int" -1790 (clear-stream _test-input-stream) -1791 (write _test-input-stream "int") -1792 # -1793 (parse-var-with-type %ecx _test-input-stream) -1794 8b/-> *eax 2/r32/edx # Var-name -1795 (check-strings-equal %edx "x" "F - test-var-with-type/name") -1796 8b/-> *(eax+4) 2/r32/edx # Var-type -1797 (check-ints-equal *edx 1 "F - test-var-with-type/type") -1798 (check-ints-equal *(edx+4) 0 "F - test-var-with-type/type") -1799 # . epilogue -1800 89/<- %esp 5/r32/ebp -1801 5d/pop-to-ebp -1802 c3/return -1803 -1804 test-parse-var-with-type-and-register: -1805 # . prologue -1806 55/push-ebp -1807 89/<- %ebp 4/r32/esp -1808 # (eax..ecx) = "x/eax" -1809 b8/copy-to-eax "x/eax"/imm32 -1810 8b/-> *eax 1/r32/ecx -1811 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1812 05/add-to-eax 4/imm32 -1813 # var slice/ecx : slice = {eax, ecx} -1814 51/push-ecx -1815 50/push-eax -1816 89/<- %ecx 4/r32/esp -1817 # _test-input-stream contains ": int" -1818 (clear-stream _test-input-stream) -1819 (write _test-input-stream ": int") -1820 # -1821 (parse-var-with-type %ecx _test-input-stream) -1822 8b/-> *eax 2/r32/edx # Var-name -1823 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") -1824 8b/-> *(eax+0x10) 2/r32/edx # Var-register -1825 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") -1826 8b/-> *(eax+4) 2/r32/edx # Var-type -1827 (check-ints-equal *edx 1 "F - test-var-with-type-and-register/type") -1828 (check-ints-equal *(edx+4) 0 "F - test-var-with-type-and-register/type") -1829 # . epilogue -1830 89/<- %esp 5/r32/ebp -1831 5d/pop-to-ebp -1832 c3/return -1833 -1834 test-parse-var-with-trailing-characters: -1835 # . prologue -1836 55/push-ebp -1837 89/<- %ebp 4/r32/esp -1838 # (eax..ecx) = "x:" -1839 b8/copy-to-eax "x:"/imm32 -1840 8b/-> *eax 1/r32/ecx -1841 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1842 05/add-to-eax 4/imm32 -1843 # var slice/ecx : slice = {eax, ecx} -1844 51/push-ecx -1845 50/push-eax -1846 89/<- %ecx 4/r32/esp -1847 # _test-input-stream contains "int," -1848 (clear-stream _test-input-stream) -1849 (write _test-input-stream "int,") -1850 # -1851 (parse-var-with-type %ecx _test-input-stream) -1852 8b/-> *eax 2/r32/edx # Var-name -1853 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") -1854 8b/-> *(eax+0x10) 2/r32/edx # Var-register -1855 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") -1856 8b/-> *(eax+4) 2/r32/edx # Var-type -1857 (check-ints-equal *edx 1 "F - test-var-with-trailing-characters/type") -1858 (check-ints-equal *(edx+4) 0 "F - test-var-with-trailing-characters/type") -1859 # . epilogue -1860 89/<- %esp 5/r32/ebp -1861 5d/pop-to-ebp -1862 c3/return -1863 -1864 test-parse-var-with-register-and-trailing-characters: -1865 # . prologue -1866 55/push-ebp -1867 89/<- %ebp 4/r32/esp -1868 # (eax..ecx) = "x/eax:" -1869 b8/copy-to-eax "x/eax:"/imm32 -1870 8b/-> *eax 1/r32/ecx -1871 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1872 05/add-to-eax 4/imm32 -1873 # var slice/ecx : slice = {eax, ecx} -1874 51/push-ecx -1875 50/push-eax -1876 89/<- %ecx 4/r32/esp -1877 # _test-input-stream contains "int," -1878 (clear-stream _test-input-stream) -1879 (write _test-input-stream "int,") -1880 # -1881 (parse-var-with-type %ecx _test-input-stream) -1882 8b/-> *eax 2/r32/edx # Var-name -1883 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") -1884 8b/-> *(eax+0x10) 2/r32/edx # Var-register -1885 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") -1886 8b/-> *(eax+4) 2/r32/edx # Var-type -1887 (check-ints-equal *edx 1 "F - test-var-with-register-and-trailing-characters/type") -1888 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") -1889 # . epilogue -1890 89/<- %esp 5/r32/ebp -1891 5d/pop-to-ebp -1892 c3/return -1893 -1894 # identifier starts with a letter or '$' or '_' -1895 # no constraints at the moment on later letters -1896 # all we really want to do so far is exclude '{', '}' and '->' -1897 is-identifier?: # in : (addr slice) -> result/eax : boolean -1898 # . prologue -1899 55/push-ebp -1900 89/<- %ebp 4/r32/esp -1901 # if (slice-empty?(in)) return false -1902 (slice-empty? *(ebp+8)) # => eax -1903 3d/compare-eax-and 0/imm32 -1904 75/jump-if-!= $is-identifier?:false/disp8 -1905 # var c/eax : byte = *in->start -1906 8b/-> *(ebp+8) 0/r32/eax -1907 8b/-> *eax 0/r32/eax -1908 8a/copy-byte *eax 0/r32/AL -1909 81 4/subop/and %eax 0xff/imm32 -1910 # if (c == '$') return true -1911 3d/compare-eax-and 0x24/imm32/$ -1912 74/jump-if-= $is-identifier?:true/disp8 -1913 # if (c == '_') return true -1914 3d/compare-eax-and 0x5f/imm32/_ -1915 74/jump-if-= $is-identifier?:true/disp8 -1916 # drop case -1917 25/and-eax-with 0x5f/imm32 -1918 # if (c < 'A') return false -1919 3d/compare-eax-and 0x41/imm32/A -1920 7c/jump-if-< $is-identifier?:false/disp8 -1921 # if (c > 'Z') return false -1922 3d/compare-eax-and 0x5a/imm32/Z -1923 7f/jump-if-> $is-identifier?:false/disp8 -1924 # otherwise return true -1925 $is-identifier?:true: -1926 b8/copy-to-eax 1/imm32/true -1927 eb/jump $is-identifier?:end/disp8 -1928 $is-identifier?:false: -1929 b8/copy-to-eax 0/imm32/false -1930 $is-identifier?:end: -1931 # . epilogue -1932 89/<- %esp 5/r32/ebp -1933 5d/pop-to-ebp -1934 c3/return -1935 -1936 test-is-identifier-dollar: -1937 # . prologue -1938 55/push-ebp -1939 89/<- %ebp 4/r32/esp -1940 # (eax..ecx) = "$a" -1941 b8/copy-to-eax "$a"/imm32 -1942 8b/-> *eax 1/r32/ecx -1943 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1944 05/add-to-eax 4/imm32 -1945 # var slice/ecx : slice = {eax, ecx} -1946 51/push-ecx -1947 50/push-eax -1948 89/<- %ecx 4/r32/esp -1949 # -1950 (is-identifier? %ecx) -1951 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") -1952 # . epilogue -1953 89/<- %esp 5/r32/ebp -1954 5d/pop-to-ebp -1955 c3/return -1956 -1957 test-is-identifier-underscore: -1958 # . prologue -1959 55/push-ebp -1960 89/<- %ebp 4/r32/esp -1961 # (eax..ecx) = "_a" -1962 b8/copy-to-eax "_a"/imm32 -1963 8b/-> *eax 1/r32/ecx -1964 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1965 05/add-to-eax 4/imm32 -1966 # var slice/ecx : slice = {eax, ecx} -1967 51/push-ecx -1968 50/push-eax -1969 89/<- %ecx 4/r32/esp -1970 # -1971 (is-identifier? %ecx) -1972 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") -1973 # . epilogue -1974 89/<- %esp 5/r32/ebp -1975 5d/pop-to-ebp -1976 c3/return -1977 -1978 test-is-identifier-a: -1979 # . prologue -1980 55/push-ebp -1981 89/<- %ebp 4/r32/esp -1982 # (eax..ecx) = "a$" -1983 b8/copy-to-eax "a$"/imm32 -1984 8b/-> *eax 1/r32/ecx -1985 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1986 05/add-to-eax 4/imm32 -1987 # var slice/ecx : slice = {eax, ecx} -1988 51/push-ecx -1989 50/push-eax -1990 89/<- %ecx 4/r32/esp -1991 # -1992 (is-identifier? %ecx) -1993 (check-ints-equal %eax 1 "F - test-is-identifier-a") -1994 # . epilogue -1995 89/<- %esp 5/r32/ebp -1996 5d/pop-to-ebp -1997 c3/return -1998 -1999 test-is-identifier-z: -2000 # . prologue -2001 55/push-ebp -2002 89/<- %ebp 4/r32/esp -2003 # (eax..ecx) = "z$" -2004 b8/copy-to-eax "z$"/imm32 -2005 8b/-> *eax 1/r32/ecx -2006 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2007 05/add-to-eax 4/imm32 -2008 # var slice/ecx : slice = {eax, ecx} -2009 51/push-ecx -2010 50/push-eax -2011 89/<- %ecx 4/r32/esp -2012 # -2013 (is-identifier? %ecx) -2014 (check-ints-equal %eax 1 "F - test-is-identifier-z") -2015 # . epilogue -2016 89/<- %esp 5/r32/ebp -2017 5d/pop-to-ebp -2018 c3/return -2019 -2020 test-is-identifier-A: -2021 # . prologue -2022 55/push-ebp -2023 89/<- %ebp 4/r32/esp -2024 # (eax..ecx) = "A$" -2025 b8/copy-to-eax "A$"/imm32 -2026 8b/-> *eax 1/r32/ecx -2027 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2028 05/add-to-eax 4/imm32 -2029 # var slice/ecx : slice = {eax, ecx} -2030 51/push-ecx -2031 50/push-eax -2032 89/<- %ecx 4/r32/esp -2033 # -2034 (is-identifier? %ecx) -2035 (check-ints-equal %eax 1 "F - test-is-identifier-A") -2036 # . epilogue -2037 89/<- %esp 5/r32/ebp -2038 5d/pop-to-ebp -2039 c3/return -2040 -2041 test-is-identifier-Z: -2042 # . prologue -2043 55/push-ebp -2044 89/<- %ebp 4/r32/esp -2045 # (eax..ecx) = "Z$" -2046 b8/copy-to-eax "Z$"/imm32 -2047 8b/-> *eax 1/r32/ecx -2048 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2049 05/add-to-eax 4/imm32 -2050 # var slice/ecx : slice = {eax, ecx} -2051 51/push-ecx -2052 50/push-eax -2053 89/<- %ecx 4/r32/esp -2054 # -2055 (is-identifier? %ecx) -2056 (check-ints-equal %eax 1 "F - test-is-identifier-Z") -2057 # . epilogue -2058 89/<- %esp 5/r32/ebp -2059 5d/pop-to-ebp -2060 c3/return -2061 -2062 test-is-identifier-@: -2063 # character before 'A' is invalid -2064 # . prologue -2065 55/push-ebp -2066 89/<- %ebp 4/r32/esp -2067 # (eax..ecx) = "@a" -2068 b8/copy-to-eax "@a"/imm32 -2069 8b/-> *eax 1/r32/ecx -2070 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2071 05/add-to-eax 4/imm32 -2072 # var slice/ecx : slice = {eax, ecx} -2073 51/push-ecx -2074 50/push-eax -2075 89/<- %ecx 4/r32/esp -2076 # -2077 (is-identifier? %ecx) -2078 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2079 # . epilogue -2080 89/<- %esp 5/r32/ebp -2081 5d/pop-to-ebp -2082 c3/return -2083 -2084 test-is-identifier-square-bracket: -2085 # character after 'Z' is invalid -2086 # . prologue -2087 55/push-ebp -2088 89/<- %ebp 4/r32/esp -2089 # (eax..ecx) = "[a" -2090 b8/copy-to-eax "[a"/imm32 -2091 8b/-> *eax 1/r32/ecx -2092 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2093 05/add-to-eax 4/imm32 -2094 # var slice/ecx : slice = {eax, ecx} -2095 51/push-ecx -2096 50/push-eax -2097 89/<- %ecx 4/r32/esp -2098 # -2099 (is-identifier? %ecx) -2100 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2101 # . epilogue -2102 89/<- %esp 5/r32/ebp -2103 5d/pop-to-ebp -2104 c3/return -2105 -2106 test-is-identifier-backtick: -2107 # character before 'a' is invalid -2108 # . prologue -2109 55/push-ebp -2110 89/<- %ebp 4/r32/esp -2111 # (eax..ecx) = "`a" -2112 b8/copy-to-eax "`a"/imm32 -2113 8b/-> *eax 1/r32/ecx -2114 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2115 05/add-to-eax 4/imm32 -2116 # var slice/ecx : slice = {eax, ecx} -2117 51/push-ecx -2118 50/push-eax -2119 89/<- %ecx 4/r32/esp -2120 # -2121 (is-identifier? %ecx) -2122 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") -2123 # . epilogue -2124 89/<- %esp 5/r32/ebp -2125 5d/pop-to-ebp -2126 c3/return -2127 -2128 test-is-identifier-curly-brace-open: -2129 # character after 'z' is invalid; also used for blocks -2130 # . prologue -2131 55/push-ebp -2132 89/<- %ebp 4/r32/esp -2133 # (eax..ecx) = "{a" -2134 b8/copy-to-eax "{a"/imm32 -2135 8b/-> *eax 1/r32/ecx -2136 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2137 05/add-to-eax 4/imm32 -2138 # var slice/ecx : slice = {eax, ecx} -2139 51/push-ecx -2140 50/push-eax -2141 89/<- %ecx 4/r32/esp -2142 # -2143 (is-identifier? %ecx) -2144 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") -2145 # . epilogue -2146 89/<- %esp 5/r32/ebp -2147 5d/pop-to-ebp -2148 c3/return -2149 -2150 test-is-identifier-curly-brace-close: -2151 # . prologue -2152 55/push-ebp -2153 89/<- %ebp 4/r32/esp -2154 # (eax..ecx) = "}a" -2155 b8/copy-to-eax "}a"/imm32 -2156 8b/-> *eax 1/r32/ecx -2157 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2158 05/add-to-eax 4/imm32 -2159 # var slice/ecx : slice = {eax, ecx} -2160 51/push-ecx -2161 50/push-eax -2162 89/<- %ecx 4/r32/esp -2163 # -2164 (is-identifier? %ecx) -2165 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") -2166 # . epilogue -2167 89/<- %esp 5/r32/ebp -2168 5d/pop-to-ebp -2169 c3/return -2170 -2171 test-is-identifier-hyphen: -2172 # disallow leading '-' since '->' has special meaning -2173 # . prologue -2174 55/push-ebp -2175 89/<- %ebp 4/r32/esp -2176 # (eax..ecx) = "-a" -2177 b8/copy-to-eax "-a"/imm32 -2178 8b/-> *eax 1/r32/ecx -2179 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2180 05/add-to-eax 4/imm32 -2181 # var slice/ecx : slice = {eax, ecx} -2182 51/push-ecx -2183 50/push-eax -2184 89/<- %ecx 4/r32/esp -2185 # -2186 (is-identifier? %ecx) -2187 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") -2188 # . epilogue -2189 89/<- %esp 5/r32/ebp -2190 5d/pop-to-ebp -2191 c3/return -2192 -2193 populate-mu-function-body: # in : (addr buffered-file), out : (handle function), vars : (addr stack (handle var)) -2194 # . prologue -2195 55/push-ebp -2196 89/<- %ebp 4/r32/esp -2197 # . save registers -2198 50/push-eax -2199 56/push-esi -2200 57/push-edi -2201 # esi = in -2202 8b/-> *(ebp+8) 6/r32/esi -2203 # edi = out -2204 8b/-> *(ebp+0xc) 7/r32/edi -2205 # var eax : (handle block) = parse-mu-block(in, vars) -2206 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax -2207 # out->body = eax -2208 89/<- *(edi+0x10) 0/r32/eax # Function-body -2209 $populate-mu-function-body:end: -2210 # . restore registers -2211 5f/pop-to-edi -2212 5e/pop-to-esi -2213 58/pop-to-eax -2214 # . epilogue -2215 89/<- %esp 5/r32/ebp -2216 5d/pop-to-ebp -2217 c3/return -2218 -2219 # parses a block, assuming that the leading '{' has already been read by the caller -2220 parse-mu-block: # in : (addr buffered-file), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle block) -2221 # pseudocode: -2222 # var line : (stream byte 512) -2223 # var word-slice : slice -2224 # result/eax = allocate(Heap, Stmt-size) -2225 # result->tag = 0/Block -2226 # while true # line loop -2227 # clear-stream(line) -2228 # read-line-buffered(in, line) -2229 # if (line->write == 0) break # end of file -2230 # word-slice = next-word(line) -2231 # if slice-empty?(word-slice) # end of line -2232 # continue -2233 # else if slice-starts-with?(word-slice, "#") -2234 # continue -2235 # else if slice-equal?(word-slice, "{") -2236 # assert(no-tokens-in(line)) -2237 # block = parse-mu-block(in, vars, fn) -2238 # append-to-block(result, block) -2239 # else if slice-equal?(word-slice, "}") -2240 # break -2241 # else if slice-ends-with?(word-slice, ":") -2242 # named-block = parse-mu-named-block(word-slice, line, in, vars, fn) -2243 # append-to-block(result, named-block) -2244 # else if slice-equal?(word-slice, "var") -2245 # var-def = parse-mu-var-def(line, vars) -2246 # append-to-block(result, var-def) -2247 # else -2248 # stmt = parse-mu-stmt(line, vars, fn) -2249 # append-to-block(result, stmt) -2250 # return result -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 53/push-ebx -2259 57/push-edi -2260 # var line/ecx : (stream byte 512) -2261 81 5/subop/subtract %esp 0x200/imm32 -2262 68/push 0x200/imm32/length -2263 68/push 0/imm32/read -2264 68/push 0/imm32/write -2265 89/<- %ecx 4/r32/esp -2266 # var word-slice/edx : slice -2267 68/push 0/imm32/end -2268 68/push 0/imm32/start -2269 89/<- %edx 4/r32/esp -2270 # edi = result -2271 (allocate Heap *Stmt-size) # => eax -2272 (zero-out %eax *Stmt-size) -2273 89/<- %edi 0/r32/eax -2274 { # line loop -2275 $parse-mu-block:line-loop: -2276 # line = read-line-buffered(in) -2277 (clear-stream %ecx) -2278 (read-line-buffered *(ebp+8) %ecx) -2279 #? (write-buffered Stderr "line: ") -2280 #? (write-stream-data Stderr %ecx) -2281 #? (write-buffered Stderr Newline) -2282 #? (flush Stderr) -2283 # if (line->write == 0) break -2284 81 7/subop/compare *ecx 0/imm32 -2285 0f 84/jump-if-= break/disp32 -2286 # word-slice = next-word(line) -2287 (next-word %ecx %edx) -2288 #? (write-buffered Stderr "word: ") -2289 #? (write-slice-buffered Stderr %edx) -2290 #? (write-buffered Stderr Newline) -2291 #? (flush Stderr) -2292 # if slice-empty?(word-slice) continue -2293 (slice-empty? %edx) -2294 3d/compare-eax-and 0/imm32 -2295 0f 85/jump-if-!= loop/disp32 -2296 # if (slice-starts-with?(word-slice, '#') continue -2297 # . eax = *word-slice->start -2298 8b/-> *edx 0/r32/eax -2299 8a/copy-byte *eax 0/r32/AL -2300 81 4/subop/and %eax 0xff/imm32 -2301 # . if (eax == '#') continue -2302 3d/compare-eax-and 0x23/imm32/hash -2303 0f 84/jump-if-= loop/disp32 -2304 # if slice-equal?(word-slice, "{") -2305 { -2306 $parse-mu-block:check-for-block: -2307 (slice-equal? %edx "{") -2308 3d/compare-eax-and 0/imm32 -2309 74/jump-if-= break/disp8 -2310 (check-no-tokens-left %ecx) -2311 # parse new block and append -2312 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -2313 (append-to-block %edi %eax) -2314 e9/jump $parse-mu-block:line-loop/disp32 -2315 } -2316 # if slice-equal?(word-slice, "}") break -2317 $parse-mu-block:check-for-end: -2318 (slice-equal? %edx "}") -2319 3d/compare-eax-and 0/imm32 -2320 0f 85/jump-if-!= break/disp32 -2321 # if slice-ends-with?(word-slice, ":") parse named block and append -2322 { -2323 $parse-mu-block:check-for-named-block: -2324 # . eax = *word-slice->end -2325 8b/-> *(edx+4) 0/r32/eax -2326 8a/copy-byte *eax 0/r32/AL -2327 81 4/subop/and %eax 0xff/imm32 -2328 # . if (eax != ':') break -2329 3d/compare-eax-and 0x23/imm32/hash -2330 0f 85/jump-if-!= break/disp32 -2331 # -2332 (parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -2333 (append-to-block %edi %eax) -2334 e9/jump $parse-mu-block:line-loop/disp32 -2335 } -2336 # if slice-equal?(word-slice, "var") -2337 { -2338 $parse-mu-block:check-for-var: -2339 (slice-equal? %edx "var") -2340 3d/compare-eax-and 0/imm32 -2341 74/jump-if-= break/disp8 -2342 # -2343 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax -2344 (append-to-block %edi %eax) -2345 e9/jump $parse-mu-block:line-loop/disp32 -2346 } -2347 $parse-mu-block:regular-stmt: -2348 # otherwise -2349 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -2350 (append-to-block Heap %edi %eax) -2351 e9/jump loop/disp32 -2352 } # end line loop -2353 # return result -2354 89/<- %eax 7/r32/edi -2355 $parse-mu-block:end: -2356 # . reclaim locals -2357 81 0/subop/add %esp 0x214/imm32 -2358 # . restore registers -2359 5f/pop-to-edi -2360 5b/pop-to-ebx -2361 5a/pop-to-edx -2362 59/pop-to-ecx -2363 # . epilogue -2364 89/<- %esp 5/r32/ebp -2365 5d/pop-to-ebp -2366 c3/return -2367 -2368 $parse-mu-block:abort: -2369 # error("'{' or '}' should be on its own line, but got '") -2370 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2371 (rewind-stream %ecx) -2372 (write-stream 2 %ecx) -2373 (write-buffered Stderr "'\n") -2374 (flush Stderr) -2375 # . syscall(exit, 1) -2376 bb/copy-to-ebx 1/imm32 -2377 b8/copy-to-eax 1/imm32/exit -2378 cd/syscall 0x80/imm8 -2379 # never gets here -2380 -2381 check-no-tokens-left: # line : (addr stream byte) -2382 # . prologue -2383 55/push-ebp -2384 89/<- %ebp 4/r32/esp -2385 # . save registers -2386 50/push-eax -2387 51/push-ecx -2388 # var s/ecx : slice -2389 68/push 0/imm32/end -2390 68/push 0/imm32/start -2391 89/<- %ecx 4/r32/esp -2392 # -2393 (next-word *(ebp+8) %ecx) -2394 # if slice-empty?(s) return -2395 (slice-empty? %ecx) -2396 3d/compare-eax-and 0/imm32 -2397 75/jump-if-!= $check-no-tokens-left:end/disp8 -2398 # if (slice-starts-with?(s, '#') return -2399 # . eax = *s->start -2400 8b/-> *edx 0/r32/eax -2401 8a/copy-byte *eax 0/r32/AL -2402 81 4/subop/and %eax 0xff/imm32 -2403 # . if (eax == '#') continue -2404 3d/compare-eax-and 0x23/imm32/hash -2405 74/jump-if-= $check-no-tokens-left:end/disp8 -2406 # abort -2407 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2408 (rewind-stream %ecx) -2409 (write-stream 2 %ecx) -2410 (write-buffered Stderr "'\n") -2411 (flush Stderr) -2412 # . syscall(exit, 1) -2413 bb/copy-to-ebx 1/imm32 -2414 b8/copy-to-eax 1/imm32/exit -2415 cd/syscall 0x80/imm8 -2416 # never gets here -2417 $check-no-tokens-left:end: -2418 # . reclaim locals -2419 81 0/subop/add %esp 8/imm32 -2420 # . restore registers -2421 59/pop-to-ecx -2422 58/pop-to-eax -2423 # . epilogue -2424 89/<- %esp 5/r32/ebp -2425 5d/pop-to-ebp -2426 c3/return -2427 -2428 parse-mu-named-block: # name : (addr slice), first-line : (addr stream byte), in : (addr buffered-file), vars : (addr stack (handle var)) -> result/eax : (handle stmt) -2429 # pseudocode: -2430 # var line : (stream byte 512) -2431 # var word-slice : slice -2432 # result/eax = allocate(Heap, Stmt-size) -2433 # result->tag = 4/Named-block -2434 # result->name = name -2435 # assert(next-word(first-line) == "{") -2436 # assert(no-tokens-in(first-line)) -2437 # while true # line loop -2438 # clear-stream(line) -2439 # read-line-buffered(in, line) -2440 # if (line->write == 0) break # end of file -2441 # word-slice = next-word(line) -2442 # if slice-empty?(word-slice) # end of line -2443 # break -2444 # else if slice-equal?(word-slice, "{") -2445 # block = parse-mu-block(in, vars) -2446 # append-to-block(result, block) -2447 # else if slice-equal?(word-slice, "}") -2448 # break -2449 # else if slice-ends-with?(word-slice, ":") -2450 # named-block = parse-mu-named-block(word-slice, in, vars) -2451 # append-to-block(result, named-block) -2452 # else if slice-equal?(word-slice, "var") -2453 # var-def = parse-mu-var-def(line, vars) -2454 # append-to-block(result, var-def) -2455 # else -2456 # stmt = parse-mu-stmt(line, vars, fn) -2457 # append-to-block(result, stmt) -2458 # return result -2459 # -2460 # . prologue -2461 55/push-ebp -2462 89/<- %ebp 4/r32/esp -2463 # . save registers -2464 $parse-mu-named-block:end: -2465 # . reclaim locals -2466 # . restore registers -2467 # . epilogue -2468 89/<- %esp 5/r32/ebp -2469 5d/pop-to-ebp -2470 c3/return -2471 -2472 parse-mu-var-def: # line : (addr stream byte), vars : (addr stack (handle var)) -> result/eax : (handle stmt) -2473 # pseudocode: -2474 # -2475 # . prologue -2476 55/push-ebp -2477 89/<- %ebp 4/r32/esp -2478 # . save registers -2479 $parse-mu-var-def:end: -2480 # . reclaim locals -2481 # . restore registers -2482 # . epilogue -2483 89/<- %esp 5/r32/ebp -2484 5d/pop-to-ebp -2485 c3/return -2486 -2487 parse-mu-stmt: # line : (addr stream byte), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle stmt) -2488 # pseudocode: -2489 # var name : slice -2490 # result = allocate(Heap, Stmt-size) -2491 # if stmt-has-outputs?(line) -2492 # while true -2493 # name = next-word(line) -2494 # if (name == '<-') break -2495 # assert(is-identifier?(name)) -2496 # var v : (handle var) = lookup-or-define-var(name, vars) -2497 # result->outputs = append(result->outputs, v) -2498 # result->name = slice-to-string(next-word(line)) -2499 # while true -2500 # name = next-word-or-string(line) -2501 # v = lookup-var-or-literal(name) -2502 # result->inouts = append(result->inouts, v) -2503 # -2504 # . prologue -2505 55/push-ebp -2506 89/<- %ebp 4/r32/esp -2507 # . save registers -2508 51/push-ecx -2509 57/push-edi -2510 # var name/ecx : slice -2511 68/push 0/imm32/end -2512 68/push 0/imm32/start -2513 89/<- %ecx 4/r32/esp -2514 # result/edi : (handle stmt) -2515 (allocate Heap *Stmt-size) # => eax -2516 (zero-out %eax *Stmt-size) -2517 89/<- %edi 0/r32/eax -2518 # result->tag = 1/stmt -2519 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag -2520 { -2521 (stmt-has-outputs? *(ebp+8)) -2522 3d/compare-eax-and 0/imm32 -2523 0f 84/jump-if-= break/disp32 -2524 { -2525 $parse-mu-stmt:read-outputs: -2526 # name = next-word(line) -2527 (next-word *(ebp+8) %ecx) -2528 # if slice-empty?(word-slice) break -2529 (slice-empty? %ecx) -2530 3d/compare-eax-and 0/imm32 -2531 0f 85/jump-if-!= break/disp32 -2532 # if (name == "<-") break -2533 (slice-equal? %ecx "<-") -2534 3d/compare-eax-and 0/imm32 -2535 75/jump-if-!= break/disp8 -2536 # assert(is-identifier?(name)) -2537 (is-identifier? %ecx) -2538 3d/compare-eax-and 0/imm32 -2539 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 -2540 # -2541 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -2542 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax -2543 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs -2544 e9/jump loop/disp32 -2545 } -2546 } -2547 $parse-mu-stmt:read-operation: -2548 (next-word *(ebp+8) %ecx) -2549 (slice-to-string Heap %ecx) -2550 89/<- *(edi+4) 0/r32/eax # Stmt1-operation -2551 { -2552 $parse-mu-stmt:read-inouts: -2553 # name = next-word-or-string(line) -2554 (next-word-or-string *(ebp+8) %ecx) -2555 # if slice-empty?(word-slice) break -2556 (slice-empty? %ecx) -2557 3d/compare-eax-and 0/imm32 -2558 0f 85/jump-if-!= break/disp32 -2559 # if (name == "<-") abort -2560 (slice-equal? %ecx "<-") -2561 3d/compare-eax-and 0/imm32 -2562 0f 85/jump-if-!= $parse-mu-stmt:abort2/disp32 -2563 # -2564 (lookup-var-or-literal %ecx *(ebp+0xc)) # => eax -2565 (append-list Heap %eax *(edi+8)) # Stmt1-inouts => eax -2566 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts -2567 e9/jump loop/disp32 -2568 } -2569 $parse-mu-stmt:end: -2570 # return result -2571 89/<- %eax 7/r32/edi -2572 # . reclaim locals -2573 81 0/subop/add %esp 8/imm32 -2574 # . restore registers -2575 5f/pop-to-edi -2576 59/pop-to-ecx -2577 # . epilogue -2578 89/<- %esp 5/r32/ebp -2579 5d/pop-to-ebp -2580 c3/return -2581 -2582 $parse-mu-stmt:abort: -2583 # error("invalid identifier '" name "'\n") -2584 (write-buffered Stderr "invalid identifier '") -2585 (write-slice-buffered Stderr %ecx) -2586 (write-buffered Stderr "'\n") -2587 (flush Stderr) -2588 # . syscall(exit, 1) -2589 bb/copy-to-ebx 1/imm32 -2590 b8/copy-to-eax 1/imm32/exit -2591 cd/syscall 0x80/imm8 -2592 # never gets here -2593 -2594 $parse-mu-stmt:abort2: -2595 # error("invalid statement '" line "'\n") -2596 (rewind-stream *(ebp+8)) -2597 (write-buffered Stderr "invalid identifier '") -2598 (write-stream Stderr *(ebp+8)) -2599 (write-buffered Stderr "'\n") -2600 (flush Stderr) -2601 # . syscall(exit, 1) -2602 bb/copy-to-ebx 1/imm32 -2603 b8/copy-to-eax 1/imm32/exit -2604 cd/syscall 0x80/imm8 -2605 # never gets here -2606 -2607 stmt-has-outputs?: # line : (addr stream byte) -> result/eax : boolean -2608 # . prologue -2609 55/push-ebp -2610 89/<- %ebp 4/r32/esp -2611 # . save registers -2612 51/push-ecx -2613 # var word-slice/ecx : slice -2614 68/push 0/imm32/end -2615 68/push 0/imm32/start -2616 89/<- %ecx 4/r32/esp -2617 # result = false -2618 b8/copy-to-eax 0/imm32/false -2619 (rewind-stream *(ebp+8)) -2620 { -2621 (next-word-or-string *(ebp+8) %ecx) -2622 # if slice-empty?(word-slice) break -2623 (slice-empty? %ecx) -2624 3d/compare-eax-and 0/imm32 -2625 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -2626 0f 85/jump-if-!= break/disp32 -2627 # if slice-starts-with?(word-slice, '#') break -2628 # . eax = *word-slice->start -2629 8b/-> *ecx 0/r32/eax -2630 8a/copy-byte *eax 0/r32/AL -2631 81 4/subop/and %eax 0xff/imm32 -2632 # . if (eax == '#') break -2633 3d/compare-eax-and 0x23/imm32/hash -2634 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -2635 0f 84/jump-if-= break/disp32 -2636 # if slice-equal?(word-slice, '<-') return true -2637 (slice-equal? %ecx "<-") -2638 3d/compare-eax-and 0/imm32 -2639 74/jump-if-= loop/disp8 -2640 b8/copy-to-eax 1/imm32/true -2641 } -2642 $stmt-has-outputs:end: -2643 (rewind-stream *(ebp+8)) -2644 # . reclaim locals -2645 81 0/subop/add %esp 8/imm32 -2646 # . restore registers -2647 59/pop-to-ecx -2648 # . epilogue -2649 89/<- %esp 5/r32/ebp -2650 5d/pop-to-ebp -2651 c3/return -2652 -2653 # if 'name' starts with a digit, create a new literal var for it -2654 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found -2655 lookup-var-or-literal: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) -2656 # . prologue -2657 55/push-ebp -2658 89/<- %ebp 4/r32/esp -2659 # . save registers -2660 51/push-ecx -2661 56/push-esi -2662 # esi = name -2663 8b/-> *(ebp+8) 6/r32/esi -2664 # if slice-empty?(name) abort -2665 (slice-empty? %esi) # => eax -2666 3d/compare-eax-and 0/imm32 -2667 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 -2668 # var ecx : byte = *name->start -2669 8b/-> *esi 1/r32/ecx -2670 8a/copy-byte *ecx 1/r32/CL -2671 81 4/subop/and %ecx 0xff/imm32 -2672 # if is-decimal-digit?(*name->start) return new var(name) -2673 (is-decimal-digit? %ecx) # => eax -2674 81 7/subop/compare %eax 0/imm32 -2675 { -2676 74/jump-if-= break/disp8 -2677 (new-literal-integer Heap %esi) # => eax -2678 } -2679 # otherwise return lookup-var(name, vars) -2680 { -2681 75/jump-if-!= break/disp8 -2682 (lookup-var %esi *(ebp+0xc)) # => eax -2683 } -2684 $lookup-var-or-literal:end: -2685 # . restore registers -2686 5e/pop-to-esi -2687 59/pop-to-ecx -2688 # . epilogue -2689 89/<- %esp 5/r32/ebp -2690 5d/pop-to-ebp -2691 c3/return -2692 -2693 $lookup-var-or-literal:abort: -2694 (write-buffered Stderr "empty variable!") -2695 (flush Stderr) -2696 # . syscall(exit, 1) -2697 bb/copy-to-ebx 1/imm32 -2698 b8/copy-to-eax 1/imm32/exit -2699 cd/syscall 0x80/imm8 -2700 # never gets here -2701 -2702 # return first 'name' from the top (back) of 'vars' and abort if not found -2703 lookup-var: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) -2704 # . prologue -2705 55/push-ebp -2706 89/<- %ebp 4/r32/esp -2707 # var target/eax : (handle array byte) = slice-to-string(name) -2708 (slice-to-string Heap *(ebp+8)) # => eax -2709 # -2710 (lookup-var-helper %eax *(ebp+0xc)) # => eax -2711 # if (result == 0) abort -2712 3d/compare-eax-and 0/imm32 -2713 74/jump-if-= $lookup-var:abort/disp8 -2714 $lookup-var:end: -2715 # . epilogue -2716 89/<- %esp 5/r32/ebp -2717 5d/pop-to-ebp -2718 c3/return -2719 -2720 $lookup-var:abort: -2721 (write-buffered Stderr "unknown variable '") -2722 (write-slice-buffered Stderr *(ebp+8)) -2723 (write-buffered Stderr "'\n") -2724 (flush Stderr) -2725 # . syscall(exit, 1) -2726 bb/copy-to-ebx 1/imm32 -2727 b8/copy-to-eax 1/imm32/exit -2728 cd/syscall 0x80/imm8 -2729 # never gets here -2730 -2731 # return first 'name' from the top (back) of 'vars', and 0/null if not found -2732 lookup-var-helper: # name: (addr array byte), vars : (addr stack (handle var)) -> result/eax: (handle var) -2733 # pseudocode: -2734 # var curr : (addr handle var) = &vars->data[vars->top - 4] -2735 # var min = vars->data -2736 # while curr >= min -2737 # var v : (handle var) = *curr -2738 # if v->name == name -2739 # return v -2740 # return 0 -2741 # -2742 # . prologue -2743 55/push-ebp -2744 89/<- %ebp 4/r32/esp -2745 # . save registers -2746 52/push-edx -2747 53/push-ebx -2748 56/push-esi -2749 # esi = vars -2750 8b/-> *(ebp+0xc) 6/r32/esi -2751 # ebx = vars->top -2752 8b/-> *esi 3/r32/ebx -2753 # if (vars->top > vars->length) abort -2754 3b/compare 0/r32/eax *(esi+4) -2755 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 -2756 # var min/edx : (addr handle var) = vars->data -2757 8d/copy-address *(esi+8) 2/r32/edx -2758 # var curr/ebx : (addr handle var) = &vars->data[vars->top - 4] -2759 81 5/subop/subtract %ebx 4/imm32 -2760 8d/copy-address *(esi+ebx+8) 3/r32/ebx -2761 { -2762 # if (curr < min) return 0 -2763 39/compare %ebx 2/r32/edx -2764 b8/copy-to-eax 0/imm32 -2765 0f 82/jump-if-addr< break/disp32 -2766 # var v/eax : (handle var) = *curr -2767 8b/-> *ebx 0/r32/eax -2768 # if (v->name == name) return v -2769 (string-equal? *eax *(ebp+8)) # Var-name -2770 3d/compare-eax-and 0/imm32 -2771 8b/-> *ebx 0/r32/eax -2772 75/jump-if-!= break/disp8 -2773 # curr -= 4 -2774 81 5/subop/subtract %ebx 4/imm32 -2775 e9/jump loop/disp32 -2776 } -2777 $lookup-var-helper:end: -2778 # . restore registers -2779 5e/pop-to-esi -2780 5b/pop-to-ebx -2781 5a/pop-to-edx -2782 # . epilogue -2783 89/<- %esp 5/r32/ebp -2784 5d/pop-to-ebp -2785 c3/return -2786 -2787 $lookup-var-helper:error1: -2788 (write-buffered Stderr "malformed stack when looking up '") -2789 (write-slice-buffered Stderr *(ebp+8)) -2790 (write-buffered Stderr "'\n") -2791 (flush Stderr) -2792 # . syscall(exit, 1) -2793 bb/copy-to-ebx 1/imm32 -2794 b8/copy-to-eax 1/imm32/exit -2795 cd/syscall 0x80/imm8 -2796 # never gets here -2797 -2798 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found -2799 lookup-or-define-var: # name: (addr slice), vars : (addr stack (handle var)), fn : (handle function) -> result/eax: (handle var) -2800 # . prologue -2801 55/push-ebp -2802 89/<- %ebp 4/r32/esp -2803 # . save registers -2804 51/push-ecx -2805 # var target/ecx : (handle array byte) = slice-to-string(name) -2806 (slice-to-string Heap *(ebp+8)) # => eax -2807 89/<- %ecx 0/r32/eax -2808 # -2809 (lookup-var-helper *(ebp+8) *(ebp+0xc)) # => eax -2810 { -2811 # if (result != 0) return -2812 3d/compare-eax-and 0/imm32 -2813 75/jump-if-!= break/disp8 -2814 # if name is one of fn's outputs, return it -2815 { -2816 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax -2817 3d/compare-eax-and 0/imm32 -2818 # otherwise abort -2819 0f 84/jump-if-!= $lookup-var:abort/disp32 -2820 } -2821 } -2822 $lookup-or-define-var:end: -2823 # . restore registers -2824 59/pop-to-ecx -2825 # . epilogue -2826 89/<- %esp 5/r32/ebp -2827 5d/pop-to-ebp -2828 c3/return -2829 -2830 find-in-function-outputs: # fn : (handle function), name : (handle array byte) => result/eax : (handle var) -2831 # . prologue -2832 55/push-ebp -2833 89/<- %ebp 4/r32/esp -2834 # . save registers -2835 51/push-ecx -2836 # var curr/ecx : (handle list var) = fn->outputs -2837 8b/-> *(ebp+8) 1/r32/ecx -2838 8b/-> *(ecx+0xc) 1/r32/ecx -2839 # while curr != null -2840 { -2841 81 7/subop/compare %ecx 0/imm32 -2842 74/jump-if-= break/disp8 -2843 # var v : (handle var) = *curr -2844 8b/-> *ecx 0/r32/eax # List-value -2845 # if (curr->name == name) return curr -2846 50/push-eax -2847 (string-equal? *eax *(ebp+0xc)) -2848 3d/compare-eax-and 0/imm32 -2849 58/pop-to-eax -2850 75/jump-if-!= $find-in-function-outputs:end/disp8 -2851 # curr = curr->next -2852 8b/-> *(ecx+4) 1/r32/ecx # List-next -2853 eb/jump loop/disp8 -2854 } -2855 b8/copy-to-eax 0/imm32 -2856 $find-in-function-outputs:end: -2857 # . restore registers -2858 59/pop-to-ecx -2859 # . epilogue -2860 89/<- %esp 5/r32/ebp -2861 5d/pop-to-ebp -2862 c3/return -2863 -2864 test-parse-mu-stmt: -2865 # 'increment n' -2866 # . prologue -2867 55/push-ebp -2868 89/<- %ebp 4/r32/esp -2869 # setup -2870 (clear-stream _test-input-stream) -2871 (write _test-input-stream "increment n\n") -2872 # var vars/ecx : (stack (addr var) 4) -2873 81 5/subop/subtract %esp 0x10/imm32 -2874 68/push 0x10/imm32/length -2875 68/push 0/imm32/top -2876 89/<- %ecx 4/r32/esp -2877 (clear-stack %ecx) -2878 # var v/edx : var -2879 81 5/subop/subtract %esp 0x14/imm32 # Var-size -2880 89/<- %edx 4/r32/esp -2881 (zero-out %edx 0x14) -2882 # v->name = "n" -2883 c7 0/subop/copy *edx "n"/imm32 # Var-name -2884 # -2885 (push %ecx %edx) -2886 # convert -2887 (parse-mu-stmt _test-input-stream %ecx) -2888 # check result -2889 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation -2890 # edx : (handle list var) = result->inouts -2891 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts -2892 # ebx : (handle var) = result->inouts->value -2893 8b/-> *edx 3/r32/ebx # List-value -2894 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name -2895 # . epilogue -2896 89/<- %esp 5/r32/ebp -2897 5d/pop-to-ebp -2898 c3/return -2899 -2900 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) -2901 # . prologue -2902 55/push-ebp -2903 89/<- %ebp 4/r32/esp -2904 # . save registers -2905 51/push-ecx -2906 # -2907 (allocate *(ebp+8) *Function-size) # => eax -2908 8b/-> *(ebp+0xc) 1/r32/ecx -2909 89/<- *eax 1/r32/ecx # Function-name -2910 8b/-> *(ebp+0x10) 1/r32/ecx -2911 89/<- *(eax+4) 1/r32/ecx # Function-subx-name -2912 8b/-> *(ebp+0x14) 1/r32/ecx -2913 89/<- *(eax+8) 1/r32/ecx # Function-inouts -2914 8b/-> *(ebp+0x18) 1/r32/ecx -2915 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs -2916 8b/-> *(ebp+0x1c) 1/r32/ecx -2917 89/<- *(eax+0x10) 1/r32/ecx # Function-body -2918 8b/-> *(ebp+0x20) 1/r32/ecx -2919 89/<- *(eax+0x14) 1/r32/ecx # Function-next -2920 $new-function:end: -2921 # . restore registers -2922 59/pop-to-ecx -2923 # . epilogue -2924 89/<- %esp 5/r32/ebp -2925 5d/pop-to-ebp -2926 c3/return -2927 -2928 new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, block: int, stack-offset: int, register: (addr array byte) -> result/eax: (handle var) -2929 # . prologue -2930 55/push-ebp -2931 89/<- %ebp 4/r32/esp -2932 # . save registers -2933 51/push-ecx -2934 # -2935 (allocate *(ebp+8) *Var-size) # => eax -2936 8b/-> *(ebp+0xc) 1/r32/ecx -2937 89/<- *eax 1/r32/ecx # Var-name -2938 8b/-> *(ebp+0x10) 1/r32/ecx -2939 89/<- *(eax+4) 1/r32/ecx # Var-type -2940 8b/-> *(ebp+0x14) 1/r32/ecx -2941 89/<- *(eax+8) 1/r32/ecx # Var-block -2942 8b/-> *(ebp+0x18) 1/r32/ecx -2943 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset -2944 8b/-> *(ebp+0x1c) 1/r32/ecx -2945 89/<- *(eax+0x10) 1/r32/ecx # Var-register -2946 $new-var:end: -2947 # . restore registers -2948 59/pop-to-ecx -2949 # . epilogue -2950 89/<- %esp 5/r32/ebp -2951 5d/pop-to-ebp -2952 c3/return -2953 -2954 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) -2955 # . prologue -2956 55/push-ebp -2957 89/<- %ebp 4/r32/esp -2958 # . save registers -2959 51/push-ecx -2960 # if (!is-hex-int?(name)) abort -2961 (is-hex-int? *(ebp+0xc)) # => eax -2962 3d/compare-eax-and 0/imm32 -2963 0f 84/jump-if-= $new-literal-integer:abort/disp32 -2964 # var s/ecx : (addr array byte) -2965 (slice-to-string Heap *(ebp+0xc)) # => eax -2966 89/<- %ecx 0/r32/eax -2967 # -2968 (allocate *(ebp+8) *Var-size) # => eax -2969 89/<- *eax 1/r32/ecx # Var-name -2970 89/<- %ecx 0/r32/eax -2971 (allocate *(ebp+8) *Tree-size) # => eax -2972 89/<- *(ecx+4) 0/r32/eax # Var-type -2973 89/<- %eax 1/r32/ecx -2974 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block -2975 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset -2976 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register -2977 $new-literal-integer:end: -2978 # . restore registers -2979 59/pop-to-ecx -2980 # . epilogue -2981 89/<- %esp 5/r32/ebp -2982 5d/pop-to-ebp -2983 c3/return -2984 -2985 $new-literal-integer:abort: -2986 (write-buffered Stderr "variable cannot begin with a digit '") -2987 (write-slice-buffered Stderr *(ebp+0xc)) -2988 (write-buffered Stderr "'\n") -2989 (flush Stderr) -2990 # . syscall(exit, 1) -2991 bb/copy-to-ebx 1/imm32 -2992 b8/copy-to-eax 1/imm32/exit -2993 cd/syscall 0x80/imm8 -2994 # never gets here -2995 -2996 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) -2997 # . prologue -2998 55/push-ebp -2999 89/<- %ebp 4/r32/esp -3000 # . save registers -3001 51/push-ecx -3002 # -3003 (allocate *(ebp+8) *Stmt-size) # => eax -3004 (zero-out %eax *Stmt-size) -3005 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag -3006 8b/-> *(ebp+0xc) 1/r32/ecx -3007 89/<- *(eax+4) 1/r32/ecx # Block-statements -3008 $new-block:end: -3009 # . restore registers -3010 59/pop-to-ecx -3011 # . epilogue -3012 89/<- %esp 5/r32/ebp -3013 5d/pop-to-ebp -3014 c3/return -3015 -3016 new-stmt: # ad: (addr allocation-descriptor), operation: (addr array byte), inouts: (handle list var), outputs: (handle list var) -> result/eax: (handle statement) -3017 # . prologue -3018 55/push-ebp -3019 89/<- %ebp 4/r32/esp -3020 # . save registers -3021 51/push-ecx -3022 # -3023 (allocate *(ebp+8) *Stmt-size) # => eax -3024 (zero-out %eax *Stmt-size) -3025 c7 0/subop/copy *eax 1/imm32/tag/regular-stmt # Stmt-tag -3026 8b/-> *(ebp+0xc) 1/r32/ecx -3027 89/<- *(eax+4) 1/r32/ecx # Stmt1-operation -3028 8b/-> *(ebp+0x10) 1/r32/ecx -3029 89/<- *(eax+8) 1/r32/ecx # Stmt1-inouts -3030 8b/-> *(ebp+0x14) 1/r32/ecx -3031 89/<- *(eax+0xc) 1/r32/ecx # Stmt1-outputs -3032 $new-stmt:end: -3033 # . restore registers -3034 59/pop-to-ecx -3035 # . epilogue -3036 89/<- %esp 5/r32/ebp -3037 5d/pop-to-ebp -3038 c3/return -3039 -3040 new-vardef: # ad: (addr allocation-descriptor), name: (addr array byte), type: int -> result/eax: (handle statement) -3041 # . prologue -3042 55/push-ebp -3043 89/<- %ebp 4/r32/esp -3044 # . save registers -3045 51/push-ecx -3046 # -3047 (allocate *(ebp+8) *Stmt-size) # => eax -3048 (zero-out %eax *Stmt-size) -3049 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag -3050 8b/-> *(ebp+0xc) 1/r32/ecx -3051 89/<- *(eax+4) 1/r32/ecx # Vardef-name -3052 8b/-> *(ebp+0x10) 1/r32/ecx -3053 89/<- *(eax+8) 1/r32/ecx # Vardef-type -3054 $new-vardef:end: -3055 # . restore registers -3056 59/pop-to-ecx -3057 # . epilogue -3058 89/<- %esp 5/r32/ebp -3059 5d/pop-to-ebp -3060 c3/return -3061 -3062 new-regvardef: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, register: (addr array byte) -> result/eax: (handle statement) -3063 # . prologue -3064 55/push-ebp -3065 89/<- %ebp 4/r32/esp -3066 # . save registers -3067 51/push-ecx -3068 # -3069 (allocate *(ebp+8) *Stmt-size) # => eax -3070 (zero-out %eax *Stmt-size) -3071 c7 0/subop/copy *eax 3/imm32/tag/var-in-register -3072 8b/-> *(ebp+0xc) 1/r32/ecx -3073 89/<- *(eax+4) 1/r32/ecx # Regvardef-name -3074 8b/-> *(ebp+0x10) 1/r32/ecx -3075 89/<- *(eax+8) 1/r32/ecx # Regvardef-type -3076 8b/-> *(ebp+0x14) 1/r32/ecx -3077 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-register -3078 $new-regvardef:end: -3079 # . restore registers -3080 59/pop-to-ecx -3081 # . epilogue -3082 89/<- %esp 5/r32/ebp -3083 5d/pop-to-ebp -3084 c3/return -3085 -3086 new-named-block: # ad: (addr allocation-descriptor), name: (addr array byte), data: (handle list statement) -> result/eax: (handle statement) -3087 # . prologue -3088 55/push-ebp -3089 89/<- %ebp 4/r32/esp -3090 # . save registers -3091 51/push-ecx -3092 # -3093 (allocate *(ebp+8) *Stmt-size) # => eax -3094 (zero-out %eax *Stmt-size) -3095 c7 0/subop/copy *eax 4/imm32/tag/named-block -3096 8b/-> *(ebp+0xc) 1/r32/ecx -3097 89/<- *(eax+4) 1/r32/ecx # Named-block-name -3098 8b/-> *(ebp+0x10) 1/r32/ecx -3099 89/<- *(eax+8) 1/r32/ecx # Named-block-statements -3100 $new-named-block:end: -3101 # . restore registers -3102 59/pop-to-ecx -3103 # . epilogue -3104 89/<- %esp 5/r32/ebp -3105 5d/pop-to-ebp -3106 c3/return -3107 -3108 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax : (handle list _type) -3109 # . prologue -3110 55/push-ebp -3111 89/<- %ebp 4/r32/esp -3112 # . save registers -3113 51/push-ecx -3114 # -3115 (allocate *(ebp+8) *List-size) # => eax -3116 8b/-> *(ebp+0xc) 1/r32/ecx -3117 89/<- *eax 1/r32/ecx # List-value -3118 8b/-> *(ebp+0x10) 1/r32/ecx -3119 89/<- *(eax+4) 1/r32/ecx # List-next -3120 $new-list:end: -3121 # . restore registers -3122 59/pop-to-ecx -3123 # . epilogue -3124 89/<- %esp 5/r32/ebp -3125 5d/pop-to-ebp -3126 c3/return -3127 -3128 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax : (handle list _type) -3129 # . prologue -3130 55/push-ebp -3131 89/<- %ebp 4/r32/esp -3132 # . save registers -3133 51/push-ecx -3134 # -3135 (allocate *(ebp+8) *List-size) # => eax -3136 8b/-> *(ebp+0xc) 1/r32/ecx -3137 89/<- *eax 1/r32/ecx # List-value -3138 # if (list == null) return result -3139 81 7/subop/compare *(ebp+0x10) 0/imm32 -3140 74/jump-if-= $new-list:end/disp8 -3141 # otherwise append -3142 # var curr/ecx = list -3143 8b/-> *(ebp+0x10) 1/r32/ecx -3144 # while (curr->next != null) curr = curr->next +1484 # var type : (handle tree type-id) = parse-type(first-line) +1485 # v->type = type +1486 # return v +1487 # +1488 # . prologue +1489 55/push-ebp +1490 89/<- %ebp 4/r32/esp +1491 # . save registers +1492 51/push-ecx +1493 52/push-edx +1494 53/push-ebx +1495 56/push-esi +1496 57/push-edi +1497 # var result/edi : (handle var) = allocate(Heap, Var-size) +1498 (allocate Heap *Var-size) # => eax +1499 (zero-out %eax *Var-size) +1500 89/<- %edi 0/r32/eax +1501 # esi = name +1502 8b/-> *(ebp+8) 6/r32/esi +1503 # var s/ecx : slice +1504 68/push 0/imm32/end +1505 68/push 0/imm32/start +1506 89/<- %ecx 4/r32/esp +1507 $parse-var-with-type:save-name: +1508 # save v->name +1509 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' +1510 # . end/edx = s->end +1511 8b/-> *(ecx+4) 2/r32/edx +1512 # . if s ends with ':', decrement s->end +1513 { +1514 8b/-> *(ecx+4) 0/r32/eax +1515 48/decrement-eax +1516 8a/copy-byte *eax 3/r32/BL +1517 81 4/subop/and %ebx 0xff/imm32 +1518 81 7/subop/compare %ebx 0x3a/imm32/colon +1519 75/jump-if-!= break/disp8 +1520 89/<- *(ecx+4) 0/r32/eax +1521 } +1522 # . if s ends with ',', decrement s->end +1523 { +1524 8b/-> *(ecx+4) 0/r32/eax +1525 48/decrement-eax +1526 8a/copy-byte *eax 3/r32/BL +1527 81 4/subop/and %ebx 0xff/imm32 +1528 81 7/subop/compare %ebx 0x2c/imm32/comma +1529 75/jump-if-!= break/disp8 +1530 89/<- *(ecx+4) 0/r32/eax +1531 } +1532 $parse-var-with-type:write-name: +1533 (slice-to-string Heap %ecx) # => eax +1534 89/<- *edi 0/r32/eax # Var-name +1535 # save v->register +1536 $parse-var-with-type:save-register: +1537 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' +1538 # . if s ends with ':', decrement s->end +1539 { +1540 8b/-> *(ecx+4) 0/r32/eax +1541 48/decrement-eax +1542 8a/copy-byte *eax 3/r32/BL +1543 81 4/subop/and %ebx 0xff/imm32 +1544 81 7/subop/compare %ebx 0x3a/imm32/colon +1545 75/jump-if-!= break/disp8 +1546 89/<- *(ecx+4) 0/r32/eax +1547 } +1548 # . if s ends with ',', decrement s->end +1549 { +1550 8b/-> *(ecx+4) 0/r32/eax +1551 48/decrement-eax +1552 8a/copy-byte *eax 3/r32/BL +1553 81 4/subop/and %ebx 0xff/imm32 +1554 81 7/subop/compare %ebx 0x2c/imm32/comma +1555 75/jump-if-!= break/disp8 +1556 89/<- *(ecx+4) 0/r32/eax +1557 } +1558 # if (!slice-empty?(s)) v->register = slice-to-string(s) +1559 { +1560 $parse-var-with-type:write-register: +1561 # HACK: s->end can be less than s->start with all the decrements above +1562 # That's probably a sign we have the wrong algorithm for this function. +1563 8b/-> *ecx 0/r32/eax +1564 39/compare 0/r32/eax *(ecx+4) +1565 76/jump-if-<= break/disp8 +1566 (slice-to-string Heap %ecx) +1567 89/<- *(edi+0x10) 0/r32/eax # Var-register +1568 } +1569 $parse-var-with-type:save-type: +1570 (parse-type Heap *(ebp+0xc)) # => eax +1571 89/<- *(edi+4) 0/r32/eax # Var-type +1572 $parse-var-with-type:end: +1573 # return result +1574 89/<- %eax 7/r32/edi +1575 # . reclaim locals +1576 81 0/subop/add %esp 8/imm32 +1577 # . restore registers +1578 5f/pop-to-edi +1579 5e/pop-to-esi +1580 5b/pop-to-ebx +1581 5a/pop-to-edx +1582 59/pop-to-ecx +1583 # . epilogue +1584 89/<- %esp 5/r32/ebp +1585 5d/pop-to-ebp +1586 c3/return +1587 +1588 $parse-var-with-type:abort: +1589 # error("function header not in form 'fn <name> {'") +1590 (write-buffered Stderr "var should have form 'name: type' in '") +1591 (flush Stderr) +1592 (rewind-stream *(ebp+0xc)) +1593 (write-stream 2 *(ebp+0xc)) +1594 (write-buffered Stderr "'\n") +1595 (flush Stderr) +1596 # . syscall(exit, 1) +1597 bb/copy-to-ebx 1/imm32 +1598 b8/copy-to-eax 1/imm32/exit +1599 cd/syscall 0x80/imm8 +1600 # never gets here +1601 +1602 parse-type: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) +1603 # pseudocode: +1604 # var s: slice = next-mu-token(in) +1605 # assert s != "" +1606 # assert s != "->" +1607 # assert s != "{" +1608 # assert s != "}" +1609 # if s == ")" +1610 # return 0 +1611 # result = allocate(Tree) +1612 # zero-out(result, *Tree-size) +1613 # if s != "(" +1614 # result->left = pos-slice(Type-id, s) +1615 # return +1616 # result->left = parse-type(ad, in) +1617 # result->right = parse-type-tree(ad, in) +1618 # +1619 # . prologue +1620 55/push-ebp +1621 89/<- %ebp 4/r32/esp +1622 # . save registers +1623 51/push-ecx +1624 52/push-edx +1625 # var s/ecx: slice +1626 68/push 0/imm32 +1627 68/push 0/imm32 +1628 89/<- %ecx 4/r32/esp +1629 # s = next-mu-token(in) +1630 (next-mu-token *(ebp+0xc) %ecx) +1631 #? (write-buffered Stderr "tok: ") +1632 #? (write-slice-buffered Stderr %ecx) +1633 #? (write-buffered Stderr "$\n") +1634 #? (flush Stderr) +1635 # assert s != "" +1636 (slice-equal? %ecx "") +1637 3d/compare-eax-and 0/imm32 +1638 0f 85/jump-if-not-equal $parse-type:abort/disp32 +1639 # assert s != "{" +1640 (slice-equal? %ecx "{") +1641 3d/compare-eax-and 0/imm32 +1642 0f 85/jump-if-not-equal $parse-type:abort/disp32 +1643 # assert s != "}" +1644 (slice-equal? %ecx "}") +1645 3d/compare-eax-and 0/imm32 +1646 0f 85/jump-if-not-equal $parse-type:abort/disp32 +1647 # assert s != "->" +1648 (slice-equal? %ecx "->") +1649 3d/compare-eax-and 0/imm32 +1650 0f 85/jump-if-not-equal $parse-type:abort/disp32 +1651 # if (s == ")") return 0 +1652 (slice-equal? %ecx ")") +1653 3d/compare-eax-and 0/imm32 +1654 b8/copy-to-eax 0/imm32 +1655 0f 85/jump-if-not-equal $parse-type:end/disp32 +1656 #? { +1657 #? 74/jump-if-equal break/disp8 +1658 #? (write-buffered Stderr "=> 0\n") +1659 #? (flush Stderr) +1660 #? e9/jump $parse-type:end/disp32 +1661 #? } +1662 # var result/edx: (handle tree type-id) +1663 (allocate *(ebp+8) *Tree-size) # => eax +1664 (zero-out %eax *Tree-size) +1665 89/<- %edx 0/r32/eax +1666 { +1667 # if (s != "(") break +1668 (slice-equal? %ecx "(") +1669 3d/compare-eax-and 0/imm32 +1670 75/jump-if-not-equal break/disp8 +1671 # result->left = pos-slice(Type-id, s) +1672 (pos-slice Type-id %ecx) +1673 #? (write-buffered Stderr "=> {") +1674 #? (print-int32-buffered Stderr %eax) +1675 #? (write-buffered Stderr ", 0}\n") +1676 #? (flush Stderr) +1677 89/<- *edx 0/r32/eax # Tree-left +1678 e9/jump $parse-type:return-edx/disp32 +1679 } +1680 # otherwise s == "(" +1681 # result->left = parse-type(ad, in) +1682 (parse-type *(ebp+8) *(ebp+0xc)) +1683 #? (write-buffered Stderr "=> {") +1684 #? (print-int32-buffered Stderr %eax) +1685 89/<- *edx 0/r32/eax # Tree-left +1686 # result->right = parse-type-tree(ad, in) +1687 (parse-type-tree *(ebp+8) *(ebp+0xc)) +1688 #? (write-buffered Stderr Space) +1689 #? (print-int32-buffered Stderr %eax) +1690 #? (write-buffered Stderr "}\n") +1691 #? (flush Stderr) +1692 89/<- *(edx+4) 0/r32/eax # Tree-right +1693 $parse-type:return-edx: +1694 89/<- %eax 2/r32/edx +1695 $parse-type:end: +1696 # . reclaim locals +1697 81 0/subop/add %esp 8/imm32 +1698 # . restore registers +1699 5a/pop-to-edx +1700 59/pop-to-ecx +1701 # . epilogue +1702 89/<- %esp 5/r32/ebp +1703 5d/pop-to-ebp +1704 c3/return +1705 +1706 $parse-type:abort: +1707 # error("unexpected token when parsing type: '" s "'\n") +1708 (write-buffered Stderr "unexpected token when parsing type: '") +1709 (write-slice-buffered Stderr %ecx) +1710 (write-buffered Stderr "'\n") +1711 (flush Stderr) +1712 # . syscall(exit, 1) +1713 bb/copy-to-ebx 1/imm32 +1714 b8/copy-to-eax 1/imm32/exit +1715 cd/syscall 0x80/imm8 +1716 # never gets here +1717 +1718 parse-type-tree: # ad: (address allocation-descriptor), in: (addr stream byte) -> result/eax: (handle tree type-id) +1719 # pseudocode: +1720 # var tmp: (handle tree type-id) = parse-type(ad, in) +1721 # if tmp == 0 +1722 # return 0 +1723 # result = allocate(Tree) +1724 # zero-out(result, *Tree-size) +1725 # result->left = tmp +1726 # result->right = parse-type-tree(ad, in) +1727 # +1728 # . prologue +1729 55/push-ebp +1730 89/<- %ebp 4/r32/esp +1731 # . save registers +1732 51/push-ecx +1733 52/push-edx +1734 # var tmp/eax: (handle tree type-id) = parse-type(ad, in) +1735 (parse-type *(ebp+8) *(ebp+0xc)) +1736 # if (tmp == 0) return tmp +1737 3d/compare-eax-and 0/imm32 +1738 74/jump-if-equal $parse-type-tree:end/disp8 +1739 # var tmp2/ecx = tmp +1740 89/<- %ecx 0/r32/eax +1741 # var result/edx: (handle tree type-id) +1742 (allocate *(ebp+8) *Tree-size) # => eax +1743 (zero-out %eax *Tree-size) +1744 89/<- %edx 0/r32/eax +1745 # result->left = tmp2 +1746 89/<- *edx 1/r32/ecx # Tree-left +1747 # result->right = parse-type-tree(ad, in) +1748 (parse-type-tree *(ebp+8) *(ebp+0xc)) +1749 89/<- *(edx+4) 0/r32/eax # Tree-right +1750 $parse-type-tree:return-edx: +1751 89/<- %eax 2/r32/edx +1752 $parse-type-tree:end: +1753 # . restore registers +1754 5a/pop-to-edx +1755 59/pop-to-ecx +1756 # . epilogue +1757 89/<- %esp 5/r32/ebp +1758 5d/pop-to-ebp +1759 c3/return +1760 +1761 next-mu-token: # in: (addr stream byte), out: (addr slice) +1762 # pseudocode: +1763 # start: +1764 # skip-chars-matching(in, ' ') +1765 # if in->read >= in->write # end of in +1766 # out = {0, 0} +1767 # return +1768 # out->start = &in->data[in->read] +1769 # var curr-byte/eax: byte = in->data[in->read] +1770 # if curr->byte == ':' # comment token +1771 # ++in->read +1772 # goto start +1773 # if curr->byte == ',' # comment token +1774 # ++in->read +1775 # goto start +1776 # if curr-byte == '#' # comment +1777 # in->read = in->write # skip to end of in +1778 # goto done +1779 # if curr-byte == '"' # string literal +1780 # skip-string(in) +1781 # goto done # no metadata +1782 # if curr-byte == '(' +1783 # ++in->read +1784 # goto done +1785 # if curr-byte == ')' +1786 # ++in->read +1787 # goto done +1788 # # read a word +1789 # while true +1790 # if in->read >= in->write +1791 # break +1792 # curr-byte = in->data[in->read] +1793 # if curr-byte == ' ' +1794 # break +1795 # if curr-byte == '(' +1796 # break +1797 # if curr-byte == ')' +1798 # break +1799 # if curr-byte == ':' +1800 # break +1801 # if curr-byte == ',' +1802 # break +1803 # ++in->read +1804 # done: +1805 # out->end = &in->data[in->read] +1806 # # hack: skip a few trailing delimiters, because we don't always use +1807 # # this correct tokenizer in later tokens +1808 # while true +1809 # if in->read >= in->write +1810 # break +1811 # curr-byte = in->data[in->read] +1812 # if curr-byte == ':' +1813 # ++in->read +1814 # else if curr-byte == ',' +1815 # ++in->read +1816 # else +1817 # break +1818 # +1819 # . prologue +1820 55/push-ebp +1821 89/<- %ebp 4/r32/esp +1822 # . save registers +1823 50/push-eax +1824 51/push-ecx +1825 56/push-esi +1826 57/push-edi +1827 # esi = in +1828 8b/-> *(ebp+8) 6/r32/esi +1829 # edi = out +1830 8b/-> *(ebp+0xc) 7/r32/edi +1831 $next-mu-token:start: +1832 # skip-chars-matching(in, ' ') +1833 (skip-chars-matching %esi 0x20) # ' ' +1834 $next-mu-token:check0: +1835 # if (in->read >= in->write) return out = {0, 0} +1836 # . ecx = in->read +1837 8b/-> *(esi+4) 1/r32/ecx +1838 # . if (ecx >= in->write) return out = {0, 0} +1839 3b/compare 1/r32/ecx *esi +1840 c7 0/subop/copy *edi 0/imm32 +1841 c7 0/subop/copy *(edi+4) 0/imm32 +1842 0f 8d/jump-if->= $next-mu-token:end/disp32 +1843 # out->start = &in->data[in->read] +1844 8d/copy-address *(esi+ecx+0xc) 0/r32/eax +1845 89/<- *edi 0/r32/eax +1846 # var curr-byte/eax : byte = in->data[in->read] +1847 31/xor %eax 0/r32/eax +1848 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +1849 { +1850 $next-mu-token:check-for-colon: +1851 # if (curr-byte != ':') break +1852 3d/compare-eax-and 0x3a/imm32/colon +1853 75/jump-if-!= break/disp8 +1854 # ++in->read +1855 ff 0/subop/increment *(esi+4) +1856 # restart +1857 e9/jump $next-mu-token:start/disp32 +1858 } +1859 { +1860 $next-mu-token:check-for-comma: +1861 # if (curr-byte != ',') break +1862 3d/compare-eax-and 0x2c/imm32/comma +1863 75/jump-if-!= break/disp8 +1864 # ++in->read +1865 ff 0/subop/increment *(esi+4) +1866 # restart +1867 e9/jump $next-mu-token:start/disp32 +1868 } +1869 { +1870 $next-mu-token:check-for-comment: +1871 # if (curr-byte != '#') break +1872 3d/compare-eax-and 0x23/imm32/pound +1873 75/jump-if-!= break/disp8 +1874 # in->read = in->write # skip rest of in +1875 8b/-> *esi 0/r32/eax +1876 89/<- *(esi+4) 0/r32/eax +1877 # return +1878 e9/jump $next-mu-token:done/disp32 +1879 } +1880 { +1881 $next-mu-token:check-for-string-literal: +1882 # if (curr-byte != '"') break +1883 3d/compare-eax-and 0x22/imm32/dquote +1884 75/jump-if-!= break/disp8 +1885 (skip-string %esi) +1886 # return +1887 e9/jump $next-mu-token:done/disp32 +1888 } +1889 { +1890 $next-mu-token:check-for-open-paren: +1891 # if (curr-byte != '(') break +1892 3d/compare-eax-and 0x28/imm32/open-paren +1893 75/jump-if-!= break/disp8 +1894 # ++in->read +1895 ff 0/subop/increment *(esi+4) +1896 # return +1897 e9/jump $next-mu-token:done/disp32 +1898 } +1899 { +1900 $next-mu-token:check-for-close-paren: +1901 # if (curr-byte != ')') break +1902 3d/compare-eax-and 0x29/imm32/close-paren +1903 75/jump-if-!= break/disp8 +1904 # ++in->read +1905 ff 0/subop/increment *(esi+4) +1906 # return +1907 e9/jump $next-mu-token:done/disp32 +1908 } +1909 { +1910 $next-mu-token:regular-word-without-metadata: +1911 # if (in->read >= in->write) break +1912 # . ecx = in->read +1913 8b/-> *(esi+4) 1/r32/ecx +1914 # . if (ecx >= in->write) break +1915 3b/compare *esi 1/r32/ecx +1916 7d/jump-if->= break/disp8 +1917 # var c/eax: byte = in->data[in->read] +1918 31/xor %eax 0/r32/eax +1919 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +1920 # if (c == ' ') break +1921 3d/compare-eax-and 0x20/imm32/space +1922 74/jump-if-= break/disp8 +1923 # if (c == '(') break +1924 3d/compare-eax-and 0x28/imm32/open-paren +1925 0f 84/jump-if-= break/disp32 +1926 # if (c == ')') break +1927 3d/compare-eax-and 0x29/imm32/close-paren +1928 0f 84/jump-if-= break/disp32 +1929 # if (c == ':') break +1930 3d/compare-eax-and 0x3a/imm32/colon +1931 0f 84/jump-if-= break/disp32 +1932 # if (c == ',') break +1933 3d/compare-eax-and 0x2c/imm32/comma +1934 0f 84/jump-if-= break/disp32 +1935 # ++in->read +1936 ff 0/subop/increment *(esi+4) +1937 # +1938 e9/jump loop/disp32 +1939 } +1940 $next-mu-token:done: +1941 # out->end = &in->data[in->read] +1942 8b/-> *(esi+4) 1/r32/ecx +1943 8d/copy-address *(esi+ecx+0xc) 0/r32/eax +1944 89/<- *(edi+4) 0/r32/eax +1945 { +1946 $next-mu-token:skip-trailing-delimiters: +1947 # if (in->read >= in->write) break +1948 # . ecx = in->read +1949 8b/-> *(esi+4) 1/r32/ecx +1950 # . if (ecx >= in->write) break +1951 3b/compare *esi 1/r32/ecx +1952 7d/jump-if->= break/disp8 +1953 # var c/eax: byte = in->data[in->read] +1954 31/xor %eax 0/r32/eax +1955 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL +1956 # if (c == ':') ++in->read and loop +1957 { +1958 3d/compare-eax-and 0x3a/imm32/colon +1959 75/jump-if-!= break/disp8 +1960 # ++in->read +1961 ff 0/subop/increment *(esi+4) +1962 # +1963 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 +1964 } +1965 # if (c == ',') ++in->read and loop +1966 { +1967 3d/compare-eax-and 0x2c/imm32/comma +1968 75/jump-if-!= break/disp8 +1969 # ++in->read +1970 ff 0/subop/increment *(esi+4) +1971 # +1972 eb/jump $next-mu-token:skip-trailing-delimiters/disp8 +1973 } +1974 # else break +1975 } +1976 $next-mu-token:end: +1977 # . restore registers +1978 5f/pop-to-edi +1979 5e/pop-to-esi +1980 59/pop-to-ecx +1981 58/pop-to-eax +1982 # . epilogue +1983 89/<- %esp 5/r32/ebp +1984 5d/pop-to-ebp +1985 c3/return +1986 +1987 # return the index in an array of strings matching 's' +1988 # index is denominated in elements, not bytes +1989 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int +1990 # . prologue +1991 55/push-ebp +1992 89/<- %ebp 4/r32/esp +1993 # . save registers +1994 51/push-ecx +1995 52/push-edx +1996 53/push-ebx +1997 56/push-esi +1998 #? (write-buffered Stderr "pos-slice: ") +1999 #? (write-slice-buffered Stderr *(ebp+0xc)) +2000 #? (write-buffered Stderr "\n") +2001 #? (flush Stderr) +2002 # esi = arr +2003 8b/-> *(ebp+8) 6/r32/esi +2004 # var index/ecx: int = 0 +2005 b9/copy-to-ecx 0/imm32 +2006 # var curr/edx: (addr (addr array byte)) = arr->data +2007 8d/copy-address *(esi+0xc) 2/r32/edx +2008 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] +2009 8b/-> *esi 3/r32/ebx +2010 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx +2011 { +2012 #? (write-buffered Stderr " ") +2013 #? (print-int32-buffered Stderr %ecx) +2014 #? (write-buffered Stderr "\n") +2015 #? (flush Stderr) +2016 # if (curr >= max) return -1 +2017 39/compare %edx 3/r32/ebx +2018 b8/copy-to-eax -1/imm32 +2019 73/jump-if-addr>= $pos-slice:end/disp8 +2020 # if (slice-equal?(s, *curr)) break +2021 (slice-equal? *(ebp+0xc) *edx) # => eax +2022 3d/compare-eax-and 0/imm32 +2023 75/jump-if-!= break/disp8 +2024 # ++index +2025 41/increment-ecx +2026 # curr += 4 +2027 81 0/subop/add %edx 4/imm32 +2028 # +2029 eb/jump loop/disp8 +2030 } +2031 # return index +2032 89/<- %eax 1/r32/ecx +2033 $pos-slice:end: +2034 #? (write-buffered Stderr "=> ") +2035 #? (print-int32-buffered Stderr %eax) +2036 #? (write-buffered Stderr "\n") +2037 # . restore registers +2038 5e/pop-to-esi +2039 5b/pop-to-ebx +2040 5a/pop-to-edx +2041 59/pop-to-ecx +2042 # . epilogue +2043 89/<- %esp 5/r32/ebp +2044 5d/pop-to-ebp +2045 c3/return +2046 +2047 == data +2048 +2049 Type-id: # (stream (address array byte)) +2050 0x18/imm32/write +2051 0/imm32/read +2052 0x100/imm32/length +2053 # data +2054 "literal"/imm32 # 0 +2055 "int"/imm32 # 1 +2056 "addr"/imm32 # 2 +2057 "array"/imm32 # 3 +2058 "handle"/imm32 # 4 +2059 "bool"/imm32 # 5 +2060 0/imm32 +2061 0/imm32 +2062 # 0x20 +2063 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2064 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2065 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2066 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2067 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2068 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2069 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +2070 +2071 == code +2072 +2073 test-parse-var-with-type: +2074 # . prologue +2075 55/push-ebp +2076 89/<- %ebp 4/r32/esp +2077 # (eax..ecx) = "x:" +2078 b8/copy-to-eax "x:"/imm32 +2079 8b/-> *eax 1/r32/ecx +2080 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2081 05/add-to-eax 4/imm32 +2082 # var slice/ecx : slice = {eax, ecx} +2083 51/push-ecx +2084 50/push-eax +2085 89/<- %ecx 4/r32/esp +2086 # _test-input-stream contains "int" +2087 (clear-stream _test-input-stream) +2088 (write _test-input-stream "int") +2089 # +2090 (parse-var-with-type %ecx _test-input-stream) +2091 8b/-> *eax 2/r32/edx # Var-name +2092 (check-strings-equal %edx "x" "F - test-var-with-type/name") +2093 8b/-> *(eax+4) 2/r32/edx # Var-type +2094 (check-ints-equal *edx 1 "F - test-var-with-type/type") +2095 (check-ints-equal *(edx+4) 0 "F - test-var-with-type/type") +2096 # . epilogue +2097 89/<- %esp 5/r32/ebp +2098 5d/pop-to-ebp +2099 c3/return +2100 +2101 test-parse-var-with-type-and-register: +2102 # . prologue +2103 55/push-ebp +2104 89/<- %ebp 4/r32/esp +2105 # (eax..ecx) = "x/eax" +2106 b8/copy-to-eax "x/eax"/imm32 +2107 8b/-> *eax 1/r32/ecx +2108 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2109 05/add-to-eax 4/imm32 +2110 # var slice/ecx : slice = {eax, ecx} +2111 51/push-ecx +2112 50/push-eax +2113 89/<- %ecx 4/r32/esp +2114 # _test-input-stream contains ": int" +2115 (clear-stream _test-input-stream) +2116 (write _test-input-stream ": int") +2117 # +2118 (parse-var-with-type %ecx _test-input-stream) +2119 8b/-> *eax 2/r32/edx # Var-name +2120 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") +2121 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2122 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") +2123 8b/-> *(eax+4) 2/r32/edx # Var-type +2124 (check-ints-equal *edx 1 "F - test-var-with-type-and-register/type") +2125 (check-ints-equal *(edx+4) 0 "F - test-var-with-type-and-register/type") +2126 # . epilogue +2127 89/<- %esp 5/r32/ebp +2128 5d/pop-to-ebp +2129 c3/return +2130 +2131 test-parse-var-with-trailing-characters: +2132 # . prologue +2133 55/push-ebp +2134 89/<- %ebp 4/r32/esp +2135 # (eax..ecx) = "x:" +2136 b8/copy-to-eax "x:"/imm32 +2137 8b/-> *eax 1/r32/ecx +2138 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2139 05/add-to-eax 4/imm32 +2140 # var slice/ecx : slice = {eax, ecx} +2141 51/push-ecx +2142 50/push-eax +2143 89/<- %ecx 4/r32/esp +2144 # _test-input-stream contains "int," +2145 (clear-stream _test-input-stream) +2146 (write _test-input-stream "int,") +2147 # +2148 (parse-var-with-type %ecx _test-input-stream) +2149 8b/-> *eax 2/r32/edx # Var-name +2150 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") +2151 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2152 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") +2153 8b/-> *(eax+4) 2/r32/edx # Var-type +2154 (check-ints-equal *edx 1 "F - test-var-with-trailing-characters/type") +2155 (check-ints-equal *(edx+4) 0 "F - test-var-with-trailing-characters/type") +2156 # . epilogue +2157 89/<- %esp 5/r32/ebp +2158 5d/pop-to-ebp +2159 c3/return +2160 +2161 test-parse-var-with-register-and-trailing-characters: +2162 # . prologue +2163 55/push-ebp +2164 89/<- %ebp 4/r32/esp +2165 # (eax..ecx) = "x/eax:" +2166 b8/copy-to-eax "x/eax:"/imm32 +2167 8b/-> *eax 1/r32/ecx +2168 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2169 05/add-to-eax 4/imm32 +2170 # var slice/ecx : slice = {eax, ecx} +2171 51/push-ecx +2172 50/push-eax +2173 89/<- %ecx 4/r32/esp +2174 # _test-input-stream contains "int," +2175 (clear-stream _test-input-stream) +2176 (write _test-input-stream "int,") +2177 # +2178 (parse-var-with-type %ecx _test-input-stream) +2179 8b/-> *eax 2/r32/edx # Var-name +2180 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") +2181 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2182 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") +2183 8b/-> *(eax+4) 2/r32/edx # Var-type +2184 (check-ints-equal *edx 1 "F - test-var-with-register-and-trailing-characters/type") +2185 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") +2186 # . epilogue +2187 89/<- %esp 5/r32/ebp +2188 5d/pop-to-ebp +2189 c3/return +2190 +2191 test-parse-var-with-compound-type: +2192 # . prologue +2193 55/push-ebp +2194 89/<- %ebp 4/r32/esp +2195 # (eax..ecx) = "x:" +2196 b8/copy-to-eax "x:"/imm32 +2197 8b/-> *eax 1/r32/ecx +2198 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2199 05/add-to-eax 4/imm32 +2200 # var slice/ecx : slice = {eax, ecx} +2201 51/push-ecx +2202 50/push-eax +2203 89/<- %ecx 4/r32/esp +2204 # _test-input-stream contains "(addr int)" +2205 (clear-stream _test-input-stream) +2206 (write _test-input-stream "(addr int)") +2207 # +2208 (parse-var-with-type %ecx _test-input-stream) +2209 8b/-> *eax 2/r32/edx # Var-name +2210 (check-strings-equal %edx "x" "F - test-var-with-compound-type/name") +2211 8b/-> *(eax+0x10) 2/r32/edx # Var-register +2212 (check-ints-equal %edx 0 "F - test-var-with-compound-type/register") +2213 # var type/edx: (handle tree type-id) = var->type +2214 8b/-> *(eax+4) 2/r32/edx # Var-type +2215 # type->left == atom(addr) +2216 8b/-> *edx 0/r32/eax # Atom-value +2217 (check-ints-equal *eax 2 "F - test-var-with-compound-type/type:0") # Tree-left +2218 # type->right->left == atom(int) +2219 8b/-> *(edx+4) 2/r32/edx # Tree-right +2220 8b/-> *edx 0/r32/eax # Tree-left +2221 (check-ints-equal *eax 1 "F - test-var-with-compound-type/type:1") # Atom-value +2222 # type->right->right == null +2223 (check-ints-equal *(edx+4) 0 "F - test-var-with-compound-type/type:2") # Tree-right +2224 # . epilogue +2225 89/<- %esp 5/r32/ebp +2226 5d/pop-to-ebp +2227 c3/return +2228 +2229 # identifier starts with a letter or '$' or '_' +2230 # no constraints at the moment on later letters +2231 # all we really want to do so far is exclude '{', '}' and '->' +2232 is-identifier?: # in : (addr slice) -> result/eax : boolean +2233 # . prologue +2234 55/push-ebp +2235 89/<- %ebp 4/r32/esp +2236 # if (slice-empty?(in)) return false +2237 (slice-empty? *(ebp+8)) # => eax +2238 3d/compare-eax-and 0/imm32 +2239 75/jump-if-!= $is-identifier?:false/disp8 +2240 # var c/eax : byte = *in->start +2241 8b/-> *(ebp+8) 0/r32/eax +2242 8b/-> *eax 0/r32/eax +2243 8a/copy-byte *eax 0/r32/AL +2244 81 4/subop/and %eax 0xff/imm32 +2245 # if (c == '$') return true +2246 3d/compare-eax-and 0x24/imm32/$ +2247 74/jump-if-= $is-identifier?:true/disp8 +2248 # if (c == '_') return true +2249 3d/compare-eax-and 0x5f/imm32/_ +2250 74/jump-if-= $is-identifier?:true/disp8 +2251 # drop case +2252 25/and-eax-with 0x5f/imm32 +2253 # if (c < 'A') return false +2254 3d/compare-eax-and 0x41/imm32/A +2255 7c/jump-if-< $is-identifier?:false/disp8 +2256 # if (c > 'Z') return false +2257 3d/compare-eax-and 0x5a/imm32/Z +2258 7f/jump-if-> $is-identifier?:false/disp8 +2259 # otherwise return true +2260 $is-identifier?:true: +2261 b8/copy-to-eax 1/imm32/true +2262 eb/jump $is-identifier?:end/disp8 +2263 $is-identifier?:false: +2264 b8/copy-to-eax 0/imm32/false +2265 $is-identifier?:end: +2266 # . epilogue +2267 89/<- %esp 5/r32/ebp +2268 5d/pop-to-ebp +2269 c3/return +2270 +2271 test-is-identifier-dollar: +2272 # . prologue +2273 55/push-ebp +2274 89/<- %ebp 4/r32/esp +2275 # (eax..ecx) = "$a" +2276 b8/copy-to-eax "$a"/imm32 +2277 8b/-> *eax 1/r32/ecx +2278 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2279 05/add-to-eax 4/imm32 +2280 # var slice/ecx : slice = {eax, ecx} +2281 51/push-ecx +2282 50/push-eax +2283 89/<- %ecx 4/r32/esp +2284 # +2285 (is-identifier? %ecx) +2286 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") +2287 # . epilogue +2288 89/<- %esp 5/r32/ebp +2289 5d/pop-to-ebp +2290 c3/return +2291 +2292 test-is-identifier-underscore: +2293 # . prologue +2294 55/push-ebp +2295 89/<- %ebp 4/r32/esp +2296 # (eax..ecx) = "_a" +2297 b8/copy-to-eax "_a"/imm32 +2298 8b/-> *eax 1/r32/ecx +2299 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2300 05/add-to-eax 4/imm32 +2301 # var slice/ecx : slice = {eax, ecx} +2302 51/push-ecx +2303 50/push-eax +2304 89/<- %ecx 4/r32/esp +2305 # +2306 (is-identifier? %ecx) +2307 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") +2308 # . epilogue +2309 89/<- %esp 5/r32/ebp +2310 5d/pop-to-ebp +2311 c3/return +2312 +2313 test-is-identifier-a: +2314 # . prologue +2315 55/push-ebp +2316 89/<- %ebp 4/r32/esp +2317 # (eax..ecx) = "a$" +2318 b8/copy-to-eax "a$"/imm32 +2319 8b/-> *eax 1/r32/ecx +2320 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2321 05/add-to-eax 4/imm32 +2322 # var slice/ecx : slice = {eax, ecx} +2323 51/push-ecx +2324 50/push-eax +2325 89/<- %ecx 4/r32/esp +2326 # +2327 (is-identifier? %ecx) +2328 (check-ints-equal %eax 1 "F - test-is-identifier-a") +2329 # . epilogue +2330 89/<- %esp 5/r32/ebp +2331 5d/pop-to-ebp +2332 c3/return +2333 +2334 test-is-identifier-z: +2335 # . prologue +2336 55/push-ebp +2337 89/<- %ebp 4/r32/esp +2338 # (eax..ecx) = "z$" +2339 b8/copy-to-eax "z$"/imm32 +2340 8b/-> *eax 1/r32/ecx +2341 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2342 05/add-to-eax 4/imm32 +2343 # var slice/ecx : slice = {eax, ecx} +2344 51/push-ecx +2345 50/push-eax +2346 89/<- %ecx 4/r32/esp +2347 # +2348 (is-identifier? %ecx) +2349 (check-ints-equal %eax 1 "F - test-is-identifier-z") +2350 # . epilogue +2351 89/<- %esp 5/r32/ebp +2352 5d/pop-to-ebp +2353 c3/return +2354 +2355 test-is-identifier-A: +2356 # . prologue +2357 55/push-ebp +2358 89/<- %ebp 4/r32/esp +2359 # (eax..ecx) = "A$" +2360 b8/copy-to-eax "A$"/imm32 +2361 8b/-> *eax 1/r32/ecx +2362 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2363 05/add-to-eax 4/imm32 +2364 # var slice/ecx : slice = {eax, ecx} +2365 51/push-ecx +2366 50/push-eax +2367 89/<- %ecx 4/r32/esp +2368 # +2369 (is-identifier? %ecx) +2370 (check-ints-equal %eax 1 "F - test-is-identifier-A") +2371 # . epilogue +2372 89/<- %esp 5/r32/ebp +2373 5d/pop-to-ebp +2374 c3/return +2375 +2376 test-is-identifier-Z: +2377 # . prologue +2378 55/push-ebp +2379 89/<- %ebp 4/r32/esp +2380 # (eax..ecx) = "Z$" +2381 b8/copy-to-eax "Z$"/imm32 +2382 8b/-> *eax 1/r32/ecx +2383 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2384 05/add-to-eax 4/imm32 +2385 # var slice/ecx : slice = {eax, ecx} +2386 51/push-ecx +2387 50/push-eax +2388 89/<- %ecx 4/r32/esp +2389 # +2390 (is-identifier? %ecx) +2391 (check-ints-equal %eax 1 "F - test-is-identifier-Z") +2392 # . epilogue +2393 89/<- %esp 5/r32/ebp +2394 5d/pop-to-ebp +2395 c3/return +2396 +2397 test-is-identifier-@: +2398 # character before 'A' is invalid +2399 # . prologue +2400 55/push-ebp +2401 89/<- %ebp 4/r32/esp +2402 # (eax..ecx) = "@a" +2403 b8/copy-to-eax "@a"/imm32 +2404 8b/-> *eax 1/r32/ecx +2405 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2406 05/add-to-eax 4/imm32 +2407 # var slice/ecx : slice = {eax, ecx} +2408 51/push-ecx +2409 50/push-eax +2410 89/<- %ecx 4/r32/esp +2411 # +2412 (is-identifier? %ecx) +2413 (check-ints-equal %eax 0 "F - test-is-identifier-@") +2414 # . epilogue +2415 89/<- %esp 5/r32/ebp +2416 5d/pop-to-ebp +2417 c3/return +2418 +2419 test-is-identifier-square-bracket: +2420 # character after 'Z' is invalid +2421 # . prologue +2422 55/push-ebp +2423 89/<- %ebp 4/r32/esp +2424 # (eax..ecx) = "[a" +2425 b8/copy-to-eax "[a"/imm32 +2426 8b/-> *eax 1/r32/ecx +2427 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2428 05/add-to-eax 4/imm32 +2429 # var slice/ecx : slice = {eax, ecx} +2430 51/push-ecx +2431 50/push-eax +2432 89/<- %ecx 4/r32/esp +2433 # +2434 (is-identifier? %ecx) +2435 (check-ints-equal %eax 0 "F - test-is-identifier-@") +2436 # . epilogue +2437 89/<- %esp 5/r32/ebp +2438 5d/pop-to-ebp +2439 c3/return +2440 +2441 test-is-identifier-backtick: +2442 # character before 'a' is invalid +2443 # . prologue +2444 55/push-ebp +2445 89/<- %ebp 4/r32/esp +2446 # (eax..ecx) = "`a" +2447 b8/copy-to-eax "`a"/imm32 +2448 8b/-> *eax 1/r32/ecx +2449 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2450 05/add-to-eax 4/imm32 +2451 # var slice/ecx : slice = {eax, ecx} +2452 51/push-ecx +2453 50/push-eax +2454 89/<- %ecx 4/r32/esp +2455 # +2456 (is-identifier? %ecx) +2457 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") +2458 # . epilogue +2459 89/<- %esp 5/r32/ebp +2460 5d/pop-to-ebp +2461 c3/return +2462 +2463 test-is-identifier-curly-brace-open: +2464 # character after 'z' is invalid; also used for blocks +2465 # . prologue +2466 55/push-ebp +2467 89/<- %ebp 4/r32/esp +2468 # (eax..ecx) = "{a" +2469 b8/copy-to-eax "{a"/imm32 +2470 8b/-> *eax 1/r32/ecx +2471 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2472 05/add-to-eax 4/imm32 +2473 # var slice/ecx : slice = {eax, ecx} +2474 51/push-ecx +2475 50/push-eax +2476 89/<- %ecx 4/r32/esp +2477 # +2478 (is-identifier? %ecx) +2479 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") +2480 # . epilogue +2481 89/<- %esp 5/r32/ebp +2482 5d/pop-to-ebp +2483 c3/return +2484 +2485 test-is-identifier-curly-brace-close: +2486 # . prologue +2487 55/push-ebp +2488 89/<- %ebp 4/r32/esp +2489 # (eax..ecx) = "}a" +2490 b8/copy-to-eax "}a"/imm32 +2491 8b/-> *eax 1/r32/ecx +2492 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2493 05/add-to-eax 4/imm32 +2494 # var slice/ecx : slice = {eax, ecx} +2495 51/push-ecx +2496 50/push-eax +2497 89/<- %ecx 4/r32/esp +2498 # +2499 (is-identifier? %ecx) +2500 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") +2501 # . epilogue +2502 89/<- %esp 5/r32/ebp +2503 5d/pop-to-ebp +2504 c3/return +2505 +2506 test-is-identifier-hyphen: +2507 # disallow leading '-' since '->' has special meaning +2508 # . prologue +2509 55/push-ebp +2510 89/<- %ebp 4/r32/esp +2511 # (eax..ecx) = "-a" +2512 b8/copy-to-eax "-a"/imm32 +2513 8b/-> *eax 1/r32/ecx +2514 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2515 05/add-to-eax 4/imm32 +2516 # var slice/ecx : slice = {eax, ecx} +2517 51/push-ecx +2518 50/push-eax +2519 89/<- %ecx 4/r32/esp +2520 # +2521 (is-identifier? %ecx) +2522 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") +2523 # . epilogue +2524 89/<- %esp 5/r32/ebp +2525 5d/pop-to-ebp +2526 c3/return +2527 +2528 populate-mu-function-body: # in : (addr buffered-file), out : (handle function), vars : (addr stack (handle var)) +2529 # . prologue +2530 55/push-ebp +2531 89/<- %ebp 4/r32/esp +2532 # . save registers +2533 50/push-eax +2534 56/push-esi +2535 57/push-edi +2536 # esi = in +2537 8b/-> *(ebp+8) 6/r32/esi +2538 # edi = out +2539 8b/-> *(ebp+0xc) 7/r32/edi +2540 # var eax : (handle block) = parse-mu-block(in, vars) +2541 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax +2542 # out->body = eax +2543 89/<- *(edi+0x10) 0/r32/eax # Function-body +2544 $populate-mu-function-body:end: +2545 # . restore registers +2546 5f/pop-to-edi +2547 5e/pop-to-esi +2548 58/pop-to-eax +2549 # . epilogue +2550 89/<- %esp 5/r32/ebp +2551 5d/pop-to-ebp +2552 c3/return +2553 +2554 # parses a block, assuming that the leading '{' has already been read by the caller +2555 parse-mu-block: # in : (addr buffered-file), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle block) +2556 # pseudocode: +2557 # var line : (stream byte 512) +2558 # var word-slice : slice +2559 # result/eax = allocate(Heap, Stmt-size) +2560 # result->tag = 0/Block +2561 # while true # line loop +2562 # clear-stream(line) +2563 # read-line-buffered(in, line) +2564 # if (line->write == 0) break # end of file +2565 # word-slice = next-word(line) +2566 # if slice-empty?(word-slice) # end of line +2567 # continue +2568 # else if slice-starts-with?(word-slice, "#") +2569 # continue +2570 # else if slice-equal?(word-slice, "{") +2571 # assert(no-tokens-in(line)) +2572 # block = parse-mu-block(in, vars, fn) +2573 # append-to-block(result, block) +2574 # else if slice-equal?(word-slice, "}") +2575 # break +2576 # else if slice-ends-with?(word-slice, ":") +2577 # named-block = parse-mu-named-block(word-slice, line, in, vars, fn) +2578 # append-to-block(result, named-block) +2579 # else if slice-equal?(word-slice, "var") +2580 # var-def = parse-mu-var-def(line, vars) +2581 # append-to-block(result, var-def) +2582 # else +2583 # stmt = parse-mu-stmt(line, vars, fn) +2584 # append-to-block(result, stmt) +2585 # return result +2586 # +2587 # . prologue +2588 55/push-ebp +2589 89/<- %ebp 4/r32/esp +2590 # . save registers +2591 51/push-ecx +2592 52/push-edx +2593 53/push-ebx +2594 57/push-edi +2595 # var line/ecx : (stream byte 512) +2596 81 5/subop/subtract %esp 0x200/imm32 +2597 68/push 0x200/imm32/length +2598 68/push 0/imm32/read +2599 68/push 0/imm32/write +2600 89/<- %ecx 4/r32/esp +2601 # var word-slice/edx : slice +2602 68/push 0/imm32/end +2603 68/push 0/imm32/start +2604 89/<- %edx 4/r32/esp +2605 # edi = result +2606 (allocate Heap *Stmt-size) # => eax +2607 (zero-out %eax *Stmt-size) +2608 89/<- %edi 0/r32/eax +2609 { # line loop +2610 $parse-mu-block:line-loop: +2611 # line = read-line-buffered(in) +2612 (clear-stream %ecx) +2613 (read-line-buffered *(ebp+8) %ecx) +2614 #? (write-buffered Stderr "line: ") +2615 #? (write-stream-data Stderr %ecx) +2616 #? (write-buffered Stderr Newline) +2617 #? (flush Stderr) +2618 # if (line->write == 0) break +2619 81 7/subop/compare *ecx 0/imm32 +2620 0f 84/jump-if-= break/disp32 +2621 # word-slice = next-word(line) +2622 (next-word %ecx %edx) +2623 #? (write-buffered Stderr "word: ") +2624 #? (write-slice-buffered Stderr %edx) +2625 #? (write-buffered Stderr Newline) +2626 #? (flush Stderr) +2627 # if slice-empty?(word-slice) continue +2628 (slice-empty? %edx) +2629 3d/compare-eax-and 0/imm32 +2630 0f 85/jump-if-!= loop/disp32 +2631 # if (slice-starts-with?(word-slice, '#') continue +2632 # . eax = *word-slice->start +2633 8b/-> *edx 0/r32/eax +2634 8a/copy-byte *eax 0/r32/AL +2635 81 4/subop/and %eax 0xff/imm32 +2636 # . if (eax == '#') continue +2637 3d/compare-eax-and 0x23/imm32/hash +2638 0f 84/jump-if-= loop/disp32 +2639 # if slice-equal?(word-slice, "{") +2640 { +2641 $parse-mu-block:check-for-block: +2642 (slice-equal? %edx "{") +2643 3d/compare-eax-and 0/imm32 +2644 74/jump-if-= break/disp8 +2645 (check-no-tokens-left %ecx) +2646 # parse new block and append +2647 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2648 (append-to-block %edi %eax) +2649 e9/jump $parse-mu-block:line-loop/disp32 +2650 } +2651 # if slice-equal?(word-slice, "}") break +2652 $parse-mu-block:check-for-end: +2653 (slice-equal? %edx "}") +2654 3d/compare-eax-and 0/imm32 +2655 0f 85/jump-if-!= break/disp32 +2656 # if slice-ends-with?(word-slice, ":") parse named block and append +2657 { +2658 $parse-mu-block:check-for-named-block: +2659 # . eax = *word-slice->end +2660 8b/-> *(edx+4) 0/r32/eax +2661 8a/copy-byte *eax 0/r32/AL +2662 81 4/subop/and %eax 0xff/imm32 +2663 # . if (eax != ':') break +2664 3d/compare-eax-and 0x23/imm32/hash +2665 0f 85/jump-if-!= break/disp32 +2666 # +2667 (parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2668 (append-to-block %edi %eax) +2669 e9/jump $parse-mu-block:line-loop/disp32 +2670 } +2671 # if slice-equal?(word-slice, "var") +2672 { +2673 $parse-mu-block:check-for-var: +2674 (slice-equal? %edx "var") +2675 3d/compare-eax-and 0/imm32 +2676 74/jump-if-= break/disp8 +2677 # +2678 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax +2679 (append-to-block %edi %eax) +2680 e9/jump $parse-mu-block:line-loop/disp32 +2681 } +2682 $parse-mu-block:regular-stmt: +2683 # otherwise +2684 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +2685 (append-to-block Heap %edi %eax) +2686 e9/jump loop/disp32 +2687 } # end line loop +2688 # return result +2689 89/<- %eax 7/r32/edi +2690 $parse-mu-block:end: +2691 # . reclaim locals +2692 81 0/subop/add %esp 0x214/imm32 +2693 # . restore registers +2694 5f/pop-to-edi +2695 5b/pop-to-ebx +2696 5a/pop-to-edx +2697 59/pop-to-ecx +2698 # . epilogue +2699 89/<- %esp 5/r32/ebp +2700 5d/pop-to-ebp +2701 c3/return +2702 +2703 $parse-mu-block:abort: +2704 # error("'{' or '}' should be on its own line, but got '") +2705 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +2706 (rewind-stream %ecx) +2707 (write-stream 2 %ecx) +2708 (write-buffered Stderr "'\n") +2709 (flush Stderr) +2710 # . syscall(exit, 1) +2711 bb/copy-to-ebx 1/imm32 +2712 b8/copy-to-eax 1/imm32/exit +2713 cd/syscall 0x80/imm8 +2714 # never gets here +2715 +2716 check-no-tokens-left: # line : (addr stream byte) +2717 # . prologue +2718 55/push-ebp +2719 89/<- %ebp 4/r32/esp +2720 # . save registers +2721 50/push-eax +2722 51/push-ecx +2723 # var s/ecx : slice +2724 68/push 0/imm32/end +2725 68/push 0/imm32/start +2726 89/<- %ecx 4/r32/esp +2727 # +2728 (next-word *(ebp+8) %ecx) +2729 # if slice-empty?(s) return +2730 (slice-empty? %ecx) +2731 3d/compare-eax-and 0/imm32 +2732 75/jump-if-!= $check-no-tokens-left:end/disp8 +2733 # if (slice-starts-with?(s, '#') return +2734 # . eax = *s->start +2735 8b/-> *edx 0/r32/eax +2736 8a/copy-byte *eax 0/r32/AL +2737 81 4/subop/and %eax 0xff/imm32 +2738 # . if (eax == '#') continue +2739 3d/compare-eax-and 0x23/imm32/hash +2740 74/jump-if-= $check-no-tokens-left:end/disp8 +2741 # abort +2742 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +2743 (rewind-stream %ecx) +2744 (write-stream 2 %ecx) +2745 (write-buffered Stderr "'\n") +2746 (flush Stderr) +2747 # . syscall(exit, 1) +2748 bb/copy-to-ebx 1/imm32 +2749 b8/copy-to-eax 1/imm32/exit +2750 cd/syscall 0x80/imm8 +2751 # never gets here +2752 $check-no-tokens-left:end: +2753 # . reclaim locals +2754 81 0/subop/add %esp 8/imm32 +2755 # . restore registers +2756 59/pop-to-ecx +2757 58/pop-to-eax +2758 # . epilogue +2759 89/<- %esp 5/r32/ebp +2760 5d/pop-to-ebp +2761 c3/return +2762 +2763 parse-mu-named-block: # name : (addr slice), first-line : (addr stream byte), in : (addr buffered-file), vars : (addr stack (handle var)) -> result/eax : (handle stmt) +2764 # pseudocode: +2765 # var line : (stream byte 512) +2766 # var word-slice : slice +2767 # result/eax = allocate(Heap, Stmt-size) +2768 # result->tag = 4/Named-block +2769 # result->name = name +2770 # assert(next-word(first-line) == "{") +2771 # assert(no-tokens-in(first-line)) +2772 # while true # line loop +2773 # clear-stream(line) +2774 # read-line-buffered(in, line) +2775 # if (line->write == 0) break # end of file +2776 # word-slice = next-word(line) +2777 # if slice-empty?(word-slice) # end of line +2778 # break +2779 # else if slice-equal?(word-slice, "{") +2780 # block = parse-mu-block(in, vars) +2781 # append-to-block(result, block) +2782 # else if slice-equal?(word-slice, "}") +2783 # break +2784 # else if slice-ends-with?(word-slice, ":") +2785 # named-block = parse-mu-named-block(word-slice, in, vars) +2786 # append-to-block(result, named-block) +2787 # else if slice-equal?(word-slice, "var") +2788 # var-def = parse-mu-var-def(line, vars) +2789 # append-to-block(result, var-def) +2790 # else +2791 # stmt = parse-mu-stmt(line, vars, fn) +2792 # append-to-block(result, stmt) +2793 # return result +2794 # +2795 # . prologue +2796 55/push-ebp +2797 89/<- %ebp 4/r32/esp +2798 # . save registers +2799 $parse-mu-named-block:end: +2800 # . reclaim locals +2801 # . restore registers +2802 # . epilogue +2803 89/<- %esp 5/r32/ebp +2804 5d/pop-to-ebp +2805 c3/return +2806 +2807 parse-mu-var-def: # line : (addr stream byte), vars : (addr stack (handle var)) -> result/eax : (handle stmt) +2808 # pseudocode: +2809 # +2810 # . prologue +2811 55/push-ebp +2812 89/<- %ebp 4/r32/esp +2813 # . save registers +2814 $parse-mu-var-def:end: +2815 # . reclaim locals +2816 # . restore registers +2817 # . epilogue +2818 89/<- %esp 5/r32/ebp +2819 5d/pop-to-ebp +2820 c3/return +2821 +2822 parse-mu-stmt: # line : (addr stream byte), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle stmt) +2823 # pseudocode: +2824 # var name : slice +2825 # result = allocate(Heap, Stmt-size) +2826 # if stmt-has-outputs?(line) +2827 # while true +2828 # name = next-word(line) +2829 # if (name == '<-') break +2830 # assert(is-identifier?(name)) +2831 # var v : (handle var) = lookup-or-define-var(name, vars) +2832 # result->outputs = append(result->outputs, v) +2833 # result->name = slice-to-string(next-word(line)) +2834 # while true +2835 # name = next-word-or-string(line) +2836 # v = lookup-var-or-literal(name) +2837 # result->inouts = append(result->inouts, v) +2838 # +2839 # . prologue +2840 55/push-ebp +2841 89/<- %ebp 4/r32/esp +2842 # . save registers +2843 51/push-ecx +2844 57/push-edi +2845 # var name/ecx : slice +2846 68/push 0/imm32/end +2847 68/push 0/imm32/start +2848 89/<- %ecx 4/r32/esp +2849 # result/edi : (handle stmt) +2850 (allocate Heap *Stmt-size) # => eax +2851 (zero-out %eax *Stmt-size) +2852 89/<- %edi 0/r32/eax +2853 # result->tag = 1/stmt +2854 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag +2855 { +2856 (stmt-has-outputs? *(ebp+8)) +2857 3d/compare-eax-and 0/imm32 +2858 0f 84/jump-if-= break/disp32 +2859 { +2860 $parse-mu-stmt:read-outputs: +2861 # name = next-word(line) +2862 (next-word *(ebp+8) %ecx) +2863 # if slice-empty?(word-slice) break +2864 (slice-empty? %ecx) +2865 3d/compare-eax-and 0/imm32 +2866 0f 85/jump-if-!= break/disp32 +2867 # if (name == "<-") break +2868 (slice-equal? %ecx "<-") +2869 3d/compare-eax-and 0/imm32 +2870 75/jump-if-!= break/disp8 +2871 # assert(is-identifier?(name)) +2872 (is-identifier? %ecx) +2873 3d/compare-eax-and 0/imm32 +2874 0f 84/jump-if-= $parse-mu-stmt:abort/disp32 +2875 # +2876 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +2877 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax +2878 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs +2879 e9/jump loop/disp32 +2880 } +2881 } +2882 $parse-mu-stmt:read-operation: +2883 (next-word *(ebp+8) %ecx) +2884 (slice-to-string Heap %ecx) +2885 89/<- *(edi+4) 0/r32/eax # Stmt1-operation +2886 { +2887 $parse-mu-stmt:read-inouts: +2888 # name = next-word-or-string(line) +2889 (next-word-or-string *(ebp+8) %ecx) +2890 # if slice-empty?(word-slice) break +2891 (slice-empty? %ecx) +2892 3d/compare-eax-and 0/imm32 +2893 0f 85/jump-if-!= break/disp32 +2894 # if (name == "<-") abort +2895 (slice-equal? %ecx "<-") +2896 3d/compare-eax-and 0/imm32 +2897 0f 85/jump-if-!= $parse-mu-stmt:abort2/disp32 +2898 # +2899 (lookup-var-or-literal %ecx *(ebp+0xc)) # => eax +2900 (append-list Heap %eax *(edi+8)) # Stmt1-inouts => eax +2901 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts +2902 e9/jump loop/disp32 +2903 } +2904 $parse-mu-stmt:end: +2905 # return result +2906 89/<- %eax 7/r32/edi +2907 # . reclaim locals +2908 81 0/subop/add %esp 8/imm32 +2909 # . restore registers +2910 5f/pop-to-edi +2911 59/pop-to-ecx +2912 # . epilogue +2913 89/<- %esp 5/r32/ebp +2914 5d/pop-to-ebp +2915 c3/return +2916 +2917 $parse-mu-stmt:abort: +2918 # error("invalid identifier '" name "'\n") +2919 (write-buffered Stderr "invalid identifier '") +2920 (write-slice-buffered Stderr %ecx) +2921 (write-buffered Stderr "'\n") +2922 (flush Stderr) +2923 # . syscall(exit, 1) +2924 bb/copy-to-ebx 1/imm32 +2925 b8/copy-to-eax 1/imm32/exit +2926 cd/syscall 0x80/imm8 +2927 # never gets here +2928 +2929 $parse-mu-stmt:abort2: +2930 # error("invalid statement '" line "'\n") +2931 (rewind-stream *(ebp+8)) +2932 (write-buffered Stderr "invalid identifier '") +2933 (write-stream Stderr *(ebp+8)) +2934 (write-buffered Stderr "'\n") +2935 (flush Stderr) +2936 # . syscall(exit, 1) +2937 bb/copy-to-ebx 1/imm32 +2938 b8/copy-to-eax 1/imm32/exit +2939 cd/syscall 0x80/imm8 +2940 # never gets here +2941 +2942 stmt-has-outputs?: # line : (addr stream byte) -> result/eax : boolean +2943 # . prologue +2944 55/push-ebp +2945 89/<- %ebp 4/r32/esp +2946 # . save registers +2947 51/push-ecx +2948 # var word-slice/ecx : slice +2949 68/push 0/imm32/end +2950 68/push 0/imm32/start +2951 89/<- %ecx 4/r32/esp +2952 # result = false +2953 b8/copy-to-eax 0/imm32/false +2954 (rewind-stream *(ebp+8)) +2955 { +2956 (next-word-or-string *(ebp+8) %ecx) +2957 # if slice-empty?(word-slice) break +2958 (slice-empty? %ecx) +2959 3d/compare-eax-and 0/imm32 +2960 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +2961 0f 85/jump-if-!= break/disp32 +2962 # if slice-starts-with?(word-slice, '#') break +2963 # . eax = *word-slice->start +2964 8b/-> *ecx 0/r32/eax +2965 8a/copy-byte *eax 0/r32/AL +2966 81 4/subop/and %eax 0xff/imm32 +2967 # . if (eax == '#') break +2968 3d/compare-eax-and 0x23/imm32/hash +2969 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +2970 0f 84/jump-if-= break/disp32 +2971 # if slice-equal?(word-slice, '<-') return true +2972 (slice-equal? %ecx "<-") +2973 3d/compare-eax-and 0/imm32 +2974 74/jump-if-= loop/disp8 +2975 b8/copy-to-eax 1/imm32/true +2976 } +2977 $stmt-has-outputs:end: +2978 (rewind-stream *(ebp+8)) +2979 # . reclaim locals +2980 81 0/subop/add %esp 8/imm32 +2981 # . restore registers +2982 59/pop-to-ecx +2983 # . epilogue +2984 89/<- %esp 5/r32/ebp +2985 5d/pop-to-ebp +2986 c3/return +2987 +2988 # if 'name' starts with a digit, create a new literal var for it +2989 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found +2990 lookup-var-or-literal: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) +2991 # . prologue +2992 55/push-ebp +2993 89/<- %ebp 4/r32/esp +2994 # . save registers +2995 51/push-ecx +2996 56/push-esi +2997 # esi = name +2998 8b/-> *(ebp+8) 6/r32/esi +2999 # if slice-empty?(name) abort +3000 (slice-empty? %esi) # => eax +3001 3d/compare-eax-and 0/imm32 +3002 0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32 +3003 # var ecx : byte = *name->start +3004 8b/-> *esi 1/r32/ecx +3005 8a/copy-byte *ecx 1/r32/CL +3006 81 4/subop/and %ecx 0xff/imm32 +3007 # if is-decimal-digit?(*name->start) return new var(name) +3008 (is-decimal-digit? %ecx) # => eax +3009 81 7/subop/compare %eax 0/imm32 +3010 { +3011 74/jump-if-= break/disp8 +3012 (new-literal-integer Heap %esi) # => eax +3013 } +3014 # otherwise return lookup-var(name, vars) +3015 { +3016 75/jump-if-!= break/disp8 +3017 (lookup-var %esi *(ebp+0xc)) # => eax +3018 } +3019 $lookup-var-or-literal:end: +3020 # . restore registers +3021 5e/pop-to-esi +3022 59/pop-to-ecx +3023 # . epilogue +3024 89/<- %esp 5/r32/ebp +3025 5d/pop-to-ebp +3026 c3/return +3027 +3028 $lookup-var-or-literal:abort: +3029 (write-buffered Stderr "empty variable!") +3030 (flush Stderr) +3031 # . syscall(exit, 1) +3032 bb/copy-to-ebx 1/imm32 +3033 b8/copy-to-eax 1/imm32/exit +3034 cd/syscall 0x80/imm8 +3035 # never gets here +3036 +3037 # return first 'name' from the top (back) of 'vars' and abort if not found +3038 lookup-var: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) +3039 # . prologue +3040 55/push-ebp +3041 89/<- %ebp 4/r32/esp +3042 # var target/eax : (handle array byte) = slice-to-string(name) +3043 (slice-to-string Heap *(ebp+8)) # => eax +3044 # +3045 (lookup-var-helper %eax *(ebp+0xc)) # => eax +3046 # if (result == 0) abort +3047 3d/compare-eax-and 0/imm32 +3048 74/jump-if-= $lookup-var:abort/disp8 +3049 $lookup-var:end: +3050 # . epilogue +3051 89/<- %esp 5/r32/ebp +3052 5d/pop-to-ebp +3053 c3/return +3054 +3055 $lookup-var:abort: +3056 (write-buffered Stderr "unknown variable '") +3057 (write-slice-buffered Stderr *(ebp+8)) +3058 (write-buffered Stderr "'\n") +3059 (flush Stderr) +3060 # . syscall(exit, 1) +3061 bb/copy-to-ebx 1/imm32 +3062 b8/copy-to-eax 1/imm32/exit +3063 cd/syscall 0x80/imm8 +3064 # never gets here +3065 +3066 # return first 'name' from the top (back) of 'vars', and 0/null if not found +3067 lookup-var-helper: # name: (addr array byte), vars : (addr stack (handle var)) -> result/eax: (handle var) +3068 # pseudocode: +3069 # var curr : (addr handle var) = &vars->data[vars->top - 4] +3070 # var min = vars->data +3071 # while curr >= min +3072 # var v : (handle var) = *curr +3073 # if v->name == name +3074 # return v +3075 # return 0 +3076 # +3077 # . prologue +3078 55/push-ebp +3079 89/<- %ebp 4/r32/esp +3080 # . save registers +3081 52/push-edx +3082 53/push-ebx +3083 56/push-esi +3084 # esi = vars +3085 8b/-> *(ebp+0xc) 6/r32/esi +3086 # ebx = vars->top +3087 8b/-> *esi 3/r32/ebx +3088 # if (vars->top > vars->length) abort +3089 3b/compare 0/r32/eax *(esi+4) +3090 0f 8f/jump-if-> $lookup-var-helper:error1/disp32 +3091 # var min/edx : (addr handle var) = vars->data +3092 8d/copy-address *(esi+8) 2/r32/edx +3093 # var curr/ebx : (addr handle var) = &vars->data[vars->top - 4] +3094 81 5/subop/subtract %ebx 4/imm32 +3095 8d/copy-address *(esi+ebx+8) 3/r32/ebx +3096 { +3097 # if (curr < min) return 0 +3098 39/compare %ebx 2/r32/edx +3099 b8/copy-to-eax 0/imm32 +3100 0f 82/jump-if-addr< break/disp32 +3101 # var v/eax : (handle var) = *curr +3102 8b/-> *ebx 0/r32/eax +3103 # if (v->name == name) return v +3104 (string-equal? *eax *(ebp+8)) # Var-name +3105 3d/compare-eax-and 0/imm32 +3106 8b/-> *ebx 0/r32/eax +3107 75/jump-if-!= break/disp8 +3108 # curr -= 4 +3109 81 5/subop/subtract %ebx 4/imm32 +3110 e9/jump loop/disp32 +3111 } +3112 $lookup-var-helper:end: +3113 # . restore registers +3114 5e/pop-to-esi +3115 5b/pop-to-ebx +3116 5a/pop-to-edx +3117 # . epilogue +3118 89/<- %esp 5/r32/ebp +3119 5d/pop-to-ebp +3120 c3/return +3121 +3122 $lookup-var-helper:error1: +3123 (write-buffered Stderr "malformed stack when looking up '") +3124 (write-slice-buffered Stderr *(ebp+8)) +3125 (write-buffered Stderr "'\n") +3126 (flush Stderr) +3127 # . syscall(exit, 1) +3128 bb/copy-to-ebx 1/imm32 +3129 b8/copy-to-eax 1/imm32/exit +3130 cd/syscall 0x80/imm8 +3131 # never gets here +3132 +3133 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found +3134 lookup-or-define-var: # name: (addr slice), vars : (addr stack (handle var)), fn : (handle function) -> result/eax: (handle var) +3135 # . prologue +3136 55/push-ebp +3137 89/<- %ebp 4/r32/esp +3138 # . save registers +3139 51/push-ecx +3140 # var target/ecx : (handle array byte) = slice-to-string(name) +3141 (slice-to-string Heap *(ebp+8)) # => eax +3142 89/<- %ecx 0/r32/eax +3143 # +3144 (lookup-var-helper *(ebp+8) *(ebp+0xc)) # => eax 3145 { -3146 81 7/subop/compare *(ecx+4) 0/imm32 # List-next -3147 74/jump-if-= break/disp8 -3148 # curr = curr->next -3149 8b/-> *(ecx+4) 1/r32/ecx -3150 eb/jump loop/disp8 -3151 } -3152 # curr->next = result -3153 89/<- *(ecx+4) 0/r32/eax -3154 # return list -3155 8b/-> *(ebp+0x10) 0/r32/eax -3156 $append-list:end: -3157 # . restore registers -3158 59/pop-to-ecx -3159 # . epilogue -3160 89/<- %esp 5/r32/ebp -3161 5d/pop-to-ebp -3162 c3/return -3163 -3164 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) -3165 # . prologue -3166 55/push-ebp -3167 89/<- %ebp 4/r32/esp -3168 # . save registers -3169 56/push-esi -3170 # esi = block -3171 8b/-> *(ebp+0xc) 6/r32/esi -3172 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements -3173 89/<- *(esi+4) 0/r32/eax # Block-statements -3174 $append-to-block:end: -3175 # . restore registers -3176 5e/pop-to-esi -3177 # . epilogue -3178 89/<- %esp 5/r32/ebp -3179 5d/pop-to-ebp -3180 c3/return -3181 -3182 ####################################################### -3183 # Type-checking -3184 ####################################################### -3185 -3186 check-mu-types: -3187 # . prologue -3188 55/push-ebp -3189 89/<- %ebp 4/r32/esp -3190 # -3191 $check-mu-types:end: -3192 # . epilogue -3193 89/<- %esp 5/r32/ebp -3194 5d/pop-to-ebp -3195 c3/return -3196 -3197 size-of: # n : (addr var) -3198 # . prologue -3199 55/push-ebp -3200 89/<- %ebp 4/r32/esp -3201 # hard-coded since we only support 'int' types for now -3202 b8/copy-to-eax 4/imm32 -3203 $size-of:end: -3204 # . epilogue -3205 89/<- %esp 5/r32/ebp -3206 5d/pop-to-ebp -3207 c3/return -3208 -3209 ####################################################### -3210 # Code-generation -3211 ####################################################### -3212 -3213 emit-subx: # out : (addr buffered-file) -3214 # . prologue -3215 55/push-ebp -3216 89/<- %ebp 4/r32/esp -3217 # . save registers -3218 50/push-eax -3219 51/push-ecx -3220 57/push-edi -3221 # edi = out -3222 8b/-> *(ebp+8) 7/r32/edi -3223 # var curr/ecx : (handle function) = *Program -3224 8b/-> *Program 1/r32/ecx -3225 { -3226 # if (curr == null) break -3227 81 7/subop/compare %ecx 0/imm32 -3228 0f 84/jump-if-= break/disp32 -3229 (emit-subx-function %edi %ecx) -3230 # curr = curr->next -3231 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -3232 e9/jump loop/disp32 -3233 } -3234 $emit-subx:end: -3235 # . restore registers -3236 5f/pop-to-edi -3237 59/pop-to-ecx -3238 58/pop-to-eax -3239 # . epilogue -3240 89/<- %esp 5/r32/ebp -3241 5d/pop-to-ebp -3242 c3/return -3243 -3244 emit-subx-function: # out : (addr buffered-file), f : (handle function) -3245 # . prologue -3246 55/push-ebp -3247 89/<- %ebp 4/r32/esp -3248 # . save registers -3249 50/push-eax -3250 51/push-ecx -3251 57/push-edi -3252 # edi = out -3253 8b/-> *(ebp+8) 7/r32/edi -3254 # ecx = f -3255 8b/-> *(ebp+0xc) 1/r32/ecx -3256 # -3257 (write-buffered %edi *ecx) -3258 (write-buffered %edi ":\n") -3259 (emit-subx-prologue %edi) -3260 (emit-subx-block %edi *(ecx+0x10)) # Function-body -3261 (emit-subx-epilogue %edi) -3262 $emit-subx-function:end: -3263 # . restore registers -3264 5f/pop-to-edi -3265 59/pop-to-ecx -3266 58/pop-to-eax -3267 # . epilogue -3268 89/<- %esp 5/r32/ebp -3269 5d/pop-to-ebp -3270 c3/return -3271 -3272 emit-subx-block: # out : (addr buffered-file), block : (handle block) -3273 # . prologue -3274 55/push-ebp -3275 89/<- %ebp 4/r32/esp -3276 # curr/esi : (handle list statement) = block->statements -3277 8b/-> *(ebp+0xc) 6/r32/esi -3278 8b/-> *(esi+4) 6/r32/esi # Block-statements -3279 # -3280 { -3281 $emit-subx-block:check-empty: -3282 81 7/subop/compare %esi 0/imm32 -3283 0f 84/jump-if-= break/disp32 -3284 (write-buffered *(ebp+8) "{\n") -3285 { -3286 $emit-subx-block:stmt: -3287 81 7/subop/compare %esi 0/imm32 -3288 74/jump-if-= break/disp8 -3289 (emit-subx-statement *(ebp+8) *esi Primitives *Program) -3290 (write-buffered *(ebp+8) Newline) -3291 8b/-> *(esi+4) 6/r32/esi # List-next -3292 eb/jump loop/disp8 -3293 } -3294 (write-buffered *(ebp+8) "}\n") -3295 } -3296 $emit-subx-block:end: -3297 # . epilogue -3298 89/<- %esp 5/r32/ebp -3299 5d/pop-to-ebp -3300 c3/return -3301 -3302 emit-subx-statement: # out : (addr buffered-file), stmt : (handle statement), primitives : (handle primitive), functions : (handle function) -3303 # . prologue -3304 55/push-ebp -3305 89/<- %ebp 4/r32/esp -3306 # . save registers -3307 50/push-eax -3308 51/push-ecx -3309 # if stmt matches a primitive, emit it -3310 { -3311 $emit-subx-statement:primitive: -3312 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax -3313 3d/compare-eax-and 0/imm32 -3314 74/jump-if-= break/disp8 -3315 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -3316 e9/jump $emit-subx-statement:end/disp32 -3317 } -3318 # else if stmt matches a function, emit a call to it -3319 { -3320 $emit-subx-statement:call: -3321 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax -3322 3d/compare-eax-and 0/imm32 -3323 74/jump-if-= break/disp8 -3324 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -3325 e9/jump $emit-subx-statement:end/disp32 -3326 } -3327 # else abort -3328 e9/jump $emit-subx-statement:abort/disp32 -3329 $emit-subx-statement:end: -3330 # . restore registers -3331 59/pop-to-ecx -3332 58/pop-to-eax -3333 # . epilogue -3334 89/<- %esp 5/r32/ebp -3335 5d/pop-to-ebp -3336 c3/return -3337 -3338 $emit-subx-statement:abort: -3339 # error("couldn't translate '" stmt "'\n") -3340 (write-buffered Stderr "couldn't translate '") -3341 #? (emit-string Stderr *(ebp+0xc)) # TODO -3342 (write-buffered Stderr "'\n") -3343 (flush Stderr) -3344 # . syscall(exit, 1) -3345 bb/copy-to-ebx 1/imm32 -3346 b8/copy-to-eax 1/imm32/exit -3347 cd/syscall 0x80/imm8 -3348 # never gets here -3349 -3350 # Primitives supported -3351 # For each operation, put variants with hard-coded registers before flexible ones. -3352 == data -3353 Primitives: -3354 # - increment/decrement -3355 _Primitive-inc-eax: -3356 # var/eax <- increment => 40/increment-eax -3357 "increment"/imm32/name -3358 0/imm32/no-inouts -3359 Single-int-var-in-eax/imm32/outputs -3360 "40/increment-eax"/imm32/subx-name -3361 0/imm32/no-rm32 -3362 0/imm32/no-r32 -3363 0/imm32/no-imm32 -3364 0/imm32/output-is-write-only -3365 _Primitive-inc-ecx/imm32/next -3366 _Primitive-inc-ecx: -3367 # var/ecx <- increment => 41/increment-ecx -3368 "increment"/imm32/name -3369 0/imm32/no-inouts -3370 Single-int-var-in-ecx/imm32/outputs -3371 "41/increment-ecx"/imm32/subx-name -3372 0/imm32/no-rm32 -3373 0/imm32/no-r32 -3374 0/imm32/no-imm32 -3375 0/imm32/output-is-write-only -3376 _Primitive-inc-edx/imm32/next -3377 _Primitive-inc-edx: -3378 # var/edx <- increment => 42/increment-edx -3379 "increment"/imm32/name -3380 0/imm32/no-inouts -3381 Single-int-var-in-edx/imm32/outputs -3382 "42/increment-edx"/imm32/subx-name -3383 0/imm32/no-rm32 -3384 0/imm32/no-r32 -3385 0/imm32/no-imm32 -3386 0/imm32/output-is-write-only -3387 _Primitive-inc-ebx/imm32/next -3388 _Primitive-inc-ebx: -3389 # var/ebx <- increment => 43/increment-ebx -3390 "increment"/imm32/name -3391 0/imm32/no-inouts -3392 Single-int-var-in-ebx/imm32/outputs -3393 "43/increment-ebx"/imm32/subx-name -3394 0/imm32/no-rm32 -3395 0/imm32/no-r32 -3396 0/imm32/no-imm32 -3397 0/imm32/output-is-write-only -3398 _Primitive-inc-esi/imm32/next -3399 _Primitive-inc-esi: -3400 # var/esi <- increment => 46/increment-esi -3401 "increment"/imm32/name -3402 0/imm32/no-inouts -3403 Single-int-var-in-esi/imm32/outputs -3404 "46/increment-esi"/imm32/subx-name -3405 0/imm32/no-rm32 -3406 0/imm32/no-r32 -3407 0/imm32/no-imm32 -3408 0/imm32/output-is-write-only -3409 _Primitive-inc-edi/imm32/next -3410 _Primitive-inc-edi: -3411 # var/edi <- increment => 47/increment-edi -3412 "increment"/imm32/name -3413 0/imm32/no-inouts -3414 Single-int-var-in-edi/imm32/outputs -3415 "47/increment-edi"/imm32/subx-name -3416 0/imm32/no-rm32 -3417 0/imm32/no-r32 -3418 0/imm32/no-imm32 -3419 0/imm32/output-is-write-only -3420 _Primitive-dec-eax/imm32/next -3421 _Primitive-dec-eax: -3422 # var/eax <- decrement => 48/decrement-eax -3423 "decrement"/imm32/name -3424 0/imm32/no-inouts -3425 Single-int-var-in-eax/imm32/outputs -3426 "48/decrement-eax"/imm32/subx-name -3427 0/imm32/no-rm32 -3428 0/imm32/no-r32 -3429 0/imm32/no-imm32 -3430 0/imm32/output-is-write-only -3431 _Primitive-dec-ecx/imm32/next -3432 _Primitive-dec-ecx: -3433 # var/ecx <- decrement => 49/decrement-ecx -3434 "decrement"/imm32/name -3435 0/imm32/no-inouts -3436 Single-int-var-in-ecx/imm32/outputs -3437 "49/decrement-ecx"/imm32/subx-name -3438 0/imm32/no-rm32 -3439 0/imm32/no-r32 -3440 0/imm32/no-imm32 -3441 0/imm32/output-is-write-only -3442 _Primitive-dec-edx/imm32/next -3443 _Primitive-dec-edx: -3444 # var/edx <- decrement => 4a/decrement-edx -3445 "decrement"/imm32/name -3446 0/imm32/no-inouts -3447 Single-int-var-in-edx/imm32/outputs -3448 "4a/decrement-edx"/imm32/subx-name -3449 0/imm32/no-rm32 -3450 0/imm32/no-r32 -3451 0/imm32/no-imm32 -3452 0/imm32/output-is-write-only -3453 _Primitive-dec-ebx/imm32/next -3454 _Primitive-dec-ebx: -3455 # var/ebx <- decrement => 4b/decrement-ebx -3456 "decrement"/imm32/name -3457 0/imm32/no-inouts -3458 Single-int-var-in-ebx/imm32/outputs -3459 "4b/decrement-ebx"/imm32/subx-name -3460 0/imm32/no-rm32 -3461 0/imm32/no-r32 -3462 0/imm32/no-imm32 -3463 0/imm32/output-is-write-only -3464 _Primitive-dec-esi/imm32/next -3465 _Primitive-dec-esi: -3466 # var/esi <- decrement => 4e/decrement-esi -3467 "decrement"/imm32/name -3468 0/imm32/no-inouts -3469 Single-int-var-in-esi/imm32/outputs -3470 "4e/decrement-esi"/imm32/subx-name -3471 0/imm32/no-rm32 -3472 0/imm32/no-r32 -3473 0/imm32/no-imm32 -3474 0/imm32/output-is-write-only -3475 _Primitive-dec-edi/imm32/next -3476 _Primitive-dec-edi: -3477 # var/edi <- decrement => 4f/decrement-edi -3478 "decrement"/imm32/name -3479 0/imm32/no-inouts -3480 Single-int-var-in-edi/imm32/outputs -3481 "4f/decrement-edi"/imm32/subx-name -3482 0/imm32/no-rm32 -3483 0/imm32/no-r32 -3484 0/imm32/no-imm32 -3485 0/imm32/output-is-write-only -3486 _Primitive-inc-mem/imm32/next -3487 _Primitive-inc-mem: -3488 # increment var => ff 0/subop/increment *(ebp+__) -3489 "increment"/imm32/name -3490 Single-int-var-on-stack/imm32/inouts -3491 0/imm32/no-outputs -3492 "ff 0/subop/increment"/imm32/subx-name -3493 1/imm32/rm32-is-first-inout -3494 0/imm32/no-r32 -3495 0/imm32/no-imm32 -3496 0/imm32/output-is-write-only -3497 _Primitive-inc-reg/imm32/next -3498 _Primitive-inc-reg: -3499 # var/reg <- increment => ff 0/subop/increment %__ -3500 "increment"/imm32/name -3501 0/imm32/no-inouts -3502 Single-int-var-in-some-register/imm32/outputs -3503 "ff 0/subop/increment"/imm32/subx-name -3504 3/imm32/rm32-is-first-output -3505 0/imm32/no-r32 -3506 0/imm32/no-imm32 -3507 0/imm32/output-is-write-only -3508 _Primitive-dec-mem/imm32/next -3509 _Primitive-dec-mem: -3510 # decrement var => ff 1/subop/decrement *(ebp+__) -3511 "decrement"/imm32/name -3512 Single-int-var-on-stack/imm32/inouts -3513 0/imm32/no-outputs -3514 "ff 1/subop/decrement"/imm32/subx-name -3515 1/imm32/rm32-is-first-inout -3516 0/imm32/no-r32 -3517 0/imm32/no-imm32 -3518 0/imm32/output-is-write-only -3519 _Primitive-dec-reg/imm32/next -3520 _Primitive-dec-reg: -3521 # var/reg <- decrement => ff 1/subop/decrement %__ -3522 "decrement"/imm32/name -3523 0/imm32/no-inouts -3524 Single-int-var-in-some-register/imm32/outputs -3525 "ff 1/subop/decrement"/imm32/subx-name -3526 3/imm32/rm32-is-first-output -3527 0/imm32/no-r32 -3528 0/imm32/no-imm32 -3529 0/imm32/output-is-write-only -3530 _Primitive-add-to-eax/imm32/next -3531 # - add -3532 _Primitive-add-to-eax: -3533 # var/eax <- add lit => 05/add-to-eax lit/imm32 -3534 "add"/imm32/name -3535 Single-lit-var/imm32/inouts -3536 Single-int-var-in-eax/imm32/outputs -3537 "05/add-to-eax"/imm32/subx-name -3538 0/imm32/no-rm32 -3539 0/imm32/no-r32 -3540 1/imm32/imm32-is-first-inout -3541 0/imm32/output-is-write-only -3542 _Primitive-add-reg-to-reg/imm32/next -3543 _Primitive-add-reg-to-reg: -3544 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 -3545 "add"/imm32/name -3546 Single-int-var-in-some-register/imm32/inouts -3547 Single-int-var-in-some-register/imm32/outputs -3548 "01/add-to"/imm32/subx-name -3549 3/imm32/rm32-is-first-output -3550 1/imm32/r32-is-first-inout -3551 0/imm32/no-imm32 -3552 0/imm32/output-is-write-only -3553 _Primitive-add-reg-to-mem/imm32/next -3554 _Primitive-add-reg-to-mem: -3555 # add-to var1 var2/reg => 01/add-to var1 var2/r32 -3556 "add-to"/imm32/name -3557 Int-var-and-second-int-var-in-some-register/imm32/inouts -3558 0/imm32/outputs -3559 "01/add-to"/imm32/subx-name -3560 1/imm32/rm32-is-first-inout -3561 2/imm32/r32-is-second-inout -3562 0/imm32/no-imm32 -3563 0/imm32/output-is-write-only -3564 _Primitive-add-mem-to-reg/imm32/next -3565 _Primitive-add-mem-to-reg: -3566 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 -3567 "add"/imm32/name -3568 Single-int-var-on-stack/imm32/inouts -3569 Single-int-var-in-some-register/imm32/outputs -3570 "03/add"/imm32/subx-name -3571 1/imm32/rm32-is-first-inout -3572 3/imm32/r32-is-first-output -3573 0/imm32/no-imm32 -3574 0/imm32/output-is-write-only -3575 _Primitive-add-lit-to-reg/imm32/next -3576 _Primitive-add-lit-to-reg: -3577 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 -3578 "add"/imm32/name -3579 Single-lit-var/imm32/inouts -3580 Single-int-var-in-some-register/imm32/outputs -3581 "81 0/subop/add"/imm32/subx-name -3582 3/imm32/rm32-is-first-output -3583 0/imm32/no-r32 -3584 1/imm32/imm32-is-first-inout -3585 0/imm32/output-is-write-only -3586 _Primitive-add-lit-to-mem/imm32/next -3587 _Primitive-add-lit-to-mem: -3588 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 -3589 "add-to"/imm32/name -3590 Int-var-and-literal/imm32/inouts -3591 0/imm32/outputs -3592 "81 0/subop/add"/imm32/subx-name -3593 1/imm32/rm32-is-first-inout -3594 0/imm32/no-r32 -3595 2/imm32/imm32-is-first-inout -3596 0/imm32/output-is-write-only -3597 _Primitive-subtract-from-eax/imm32/next -3598 # - subtract -3599 _Primitive-subtract-from-eax: -3600 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 -3601 "subtract"/imm32/name -3602 Single-lit-var/imm32/inouts -3603 Single-int-var-in-eax/imm32/outputs -3604 "2d/subtract-from-eax"/imm32/subx-name -3605 0/imm32/no-rm32 -3606 0/imm32/no-r32 -3607 1/imm32/imm32-is-first-inout -3608 0/imm32/output-is-write-only -3609 _Primitive-subtract-reg-from-reg/imm32/next -3610 _Primitive-subtract-reg-from-reg: -3611 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 -3612 "subtract"/imm32/name -3613 Single-int-var-in-some-register/imm32/inouts -3614 Single-int-var-in-some-register/imm32/outputs -3615 "29/subtract-from"/imm32/subx-name -3616 3/imm32/rm32-is-first-output -3617 1/imm32/r32-is-first-inout -3618 0/imm32/no-imm32 -3619 0/imm32/output-is-write-only -3620 _Primitive-subtract-reg-from-mem/imm32/next -3621 _Primitive-subtract-reg-from-mem: -3622 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 -3623 "subtract-from"/imm32/name -3624 Int-var-and-second-int-var-in-some-register/imm32/inouts -3625 0/imm32/outputs -3626 "29/subtract-from"/imm32/subx-name -3627 1/imm32/rm32-is-first-inout -3628 2/imm32/r32-is-second-inout -3629 0/imm32/no-imm32 -3630 0/imm32/output-is-write-only -3631 _Primitive-subtract-mem-from-reg/imm32/next -3632 _Primitive-subtract-mem-from-reg: -3633 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 -3634 "subtract"/imm32/name -3635 Single-int-var-on-stack/imm32/inouts -3636 Single-int-var-in-some-register/imm32/outputs -3637 "2b/subtract"/imm32/subx-name -3638 1/imm32/rm32-is-first-inout -3639 3/imm32/r32-is-first-output -3640 0/imm32/no-imm32 -3641 0/imm32/output-is-write-only -3642 _Primitive-subtract-lit-from-reg/imm32/next -3643 _Primitive-subtract-lit-from-reg: -3644 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 -3645 "subtract"/imm32/name -3646 Single-lit-var/imm32/inouts -3647 Single-int-var-in-some-register/imm32/outputs -3648 "81 5/subop/subtract"/imm32/subx-name -3649 3/imm32/rm32-is-first-output -3650 0/imm32/no-r32 -3651 1/imm32/imm32-is-first-inout -3652 0/imm32/output-is-write-only -3653 _Primitive-subtract-lit-from-mem/imm32/next -3654 _Primitive-subtract-lit-from-mem: -3655 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 -3656 "subtract-from"/imm32/name -3657 Int-var-and-literal/imm32/inouts -3658 0/imm32/outputs -3659 "81 5/subop/subtract"/imm32/subx-name -3660 1/imm32/rm32-is-first-inout -3661 0/imm32/no-r32 -3662 2/imm32/imm32-is-first-inout -3663 0/imm32/output-is-write-only -3664 _Primitive-and-with-eax/imm32/next -3665 # - and -3666 _Primitive-and-with-eax: -3667 # var/eax <- and lit => 25/and-with-eax lit/imm32 -3668 "and"/imm32/name -3669 Single-lit-var/imm32/inouts -3670 Single-int-var-in-eax/imm32/outputs -3671 "25/and-with-eax"/imm32/subx-name -3672 0/imm32/no-rm32 -3673 0/imm32/no-r32 -3674 1/imm32/imm32-is-first-inout -3675 0/imm32/output-is-write-only -3676 _Primitive-and-reg-with-reg/imm32/next -3677 _Primitive-and-reg-with-reg: -3678 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 -3679 "and"/imm32/name -3680 Single-int-var-in-some-register/imm32/inouts -3681 Single-int-var-in-some-register/imm32/outputs -3682 "21/and-with"/imm32/subx-name -3683 3/imm32/rm32-is-first-output -3684 1/imm32/r32-is-first-inout -3685 0/imm32/no-imm32 -3686 0/imm32/output-is-write-only -3687 _Primitive-and-reg-with-mem/imm32/next -3688 _Primitive-and-reg-with-mem: -3689 # and-with var1 var2/reg => 21/and-with var1 var2/r32 -3690 "and-with"/imm32/name -3691 Int-var-and-second-int-var-in-some-register/imm32/inouts -3692 0/imm32/outputs -3693 "21/and-with"/imm32/subx-name -3694 1/imm32/rm32-is-first-inout -3695 2/imm32/r32-is-second-inout -3696 0/imm32/no-imm32 -3697 0/imm32/output-is-write-only -3698 _Primitive-and-mem-with-reg/imm32/next -3699 _Primitive-and-mem-with-reg: -3700 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 -3701 "and"/imm32/name -3702 Single-int-var-on-stack/imm32/inouts -3703 Single-int-var-in-some-register/imm32/outputs -3704 "23/and"/imm32/subx-name -3705 1/imm32/rm32-is-first-inout -3706 3/imm32/r32-is-first-output -3707 0/imm32/no-imm32 -3708 0/imm32/output-is-write-only -3709 _Primitive-and-lit-with-reg/imm32/next -3710 _Primitive-and-lit-with-reg: -3711 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 -3712 "and"/imm32/name -3713 Single-lit-var/imm32/inouts -3714 Single-int-var-in-some-register/imm32/outputs -3715 "81 4/subop/and"/imm32/subx-name -3716 3/imm32/rm32-is-first-output -3717 0/imm32/no-r32 -3718 1/imm32/imm32-is-first-inout -3719 0/imm32/output-is-write-only -3720 _Primitive-and-lit-with-mem/imm32/next -3721 _Primitive-and-lit-with-mem: -3722 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 -3723 "and-with"/imm32/name -3724 Int-var-and-literal/imm32/inouts -3725 0/imm32/outputs -3726 "81 4/subop/and"/imm32/subx-name -3727 1/imm32/rm32-is-first-inout -3728 0/imm32/no-r32 -3729 2/imm32/imm32-is-first-inout -3730 0/imm32/output-is-write-only -3731 _Primitive-or-with-eax/imm32/next -3732 # - or -3733 _Primitive-or-with-eax: -3734 # var/eax <- or lit => 0d/or-with-eax lit/imm32 -3735 "or"/imm32/name -3736 Single-lit-var/imm32/inouts -3737 Single-int-var-in-eax/imm32/outputs -3738 "0d/or-with-eax"/imm32/subx-name -3739 0/imm32/no-rm32 -3740 0/imm32/no-r32 -3741 1/imm32/imm32-is-first-inout -3742 0/imm32/output-is-write-only -3743 _Primitive-or-reg-with-reg/imm32/next -3744 _Primitive-or-reg-with-reg: -3745 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 -3746 "or"/imm32/name -3747 Single-int-var-in-some-register/imm32/inouts -3748 Single-int-var-in-some-register/imm32/outputs -3749 "09/or-with"/imm32/subx-name -3750 3/imm32/rm32-is-first-output -3751 1/imm32/r32-is-first-inout -3752 0/imm32/no-imm32 -3753 0/imm32/output-is-write-only -3754 _Primitive-or-reg-with-mem/imm32/next -3755 _Primitive-or-reg-with-mem: -3756 # or-with var1 var2/reg => 09/or-with var1 var2/r32 -3757 "or-with"/imm32/name -3758 Int-var-and-second-int-var-in-some-register/imm32/inouts -3759 0/imm32/outputs -3760 "09/or-with"/imm32/subx-name -3761 1/imm32/rm32-is-first-inout -3762 2/imm32/r32-is-second-inout -3763 0/imm32/no-imm32 -3764 0/imm32/output-is-write-only -3765 _Primitive-or-mem-with-reg/imm32/next -3766 _Primitive-or-mem-with-reg: -3767 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 -3768 "or"/imm32/name -3769 Single-int-var-on-stack/imm32/inouts -3770 Single-int-var-in-some-register/imm32/outputs -3771 "0b/or"/imm32/subx-name -3772 1/imm32/rm32-is-first-inout -3773 3/imm32/r32-is-first-output -3774 0/imm32/no-imm32 -3775 0/imm32/output-is-write-only -3776 _Primitive-or-lit-with-reg/imm32/next -3777 _Primitive-or-lit-with-reg: -3778 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 -3779 "or"/imm32/name -3780 Single-lit-var/imm32/inouts -3781 Single-int-var-in-some-register/imm32/outputs -3782 "81 4/subop/or"/imm32/subx-name -3783 3/imm32/rm32-is-first-output -3784 0/imm32/no-r32 -3785 1/imm32/imm32-is-first-inout -3786 0/imm32/output-is-write-only -3787 _Primitive-or-lit-with-mem/imm32/next -3788 _Primitive-or-lit-with-mem: -3789 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 -3790 "or-with"/imm32/name -3791 Int-var-and-literal/imm32/inouts -3792 0/imm32/outputs -3793 "81 4/subop/or"/imm32/subx-name -3794 1/imm32/rm32-is-first-inout -3795 0/imm32/no-r32 -3796 2/imm32/imm32-is-first-inout -3797 0/imm32/output-is-write-only -3798 _Primitive-xor-with-eax/imm32/next -3799 # - xor -3800 _Primitive-xor-with-eax: -3801 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 -3802 "xor"/imm32/name -3803 Single-lit-var/imm32/inouts -3804 Single-int-var-in-eax/imm32/outputs -3805 "35/xor-with-eax"/imm32/subx-name +3146 # if (result != 0) return +3147 3d/compare-eax-and 0/imm32 +3148 75/jump-if-!= break/disp8 +3149 # if name is one of fn's outputs, return it +3150 { +3151 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax +3152 3d/compare-eax-and 0/imm32 +3153 # otherwise abort +3154 0f 84/jump-if-!= $lookup-var:abort/disp32 +3155 } +3156 } +3157 $lookup-or-define-var:end: +3158 # . restore registers +3159 59/pop-to-ecx +3160 # . epilogue +3161 89/<- %esp 5/r32/ebp +3162 5d/pop-to-ebp +3163 c3/return +3164 +3165 find-in-function-outputs: # fn : (handle function), name : (handle array byte) => result/eax : (handle var) +3166 # . prologue +3167 55/push-ebp +3168 89/<- %ebp 4/r32/esp +3169 # . save registers +3170 51/push-ecx +3171 # var curr/ecx : (handle list var) = fn->outputs +3172 8b/-> *(ebp+8) 1/r32/ecx +3173 8b/-> *(ecx+0xc) 1/r32/ecx +3174 # while curr != null +3175 { +3176 81 7/subop/compare %ecx 0/imm32 +3177 74/jump-if-= break/disp8 +3178 # var v : (handle var) = *curr +3179 8b/-> *ecx 0/r32/eax # List-value +3180 # if (curr->name == name) return curr +3181 50/push-eax +3182 (string-equal? *eax *(ebp+0xc)) +3183 3d/compare-eax-and 0/imm32 +3184 58/pop-to-eax +3185 75/jump-if-!= $find-in-function-outputs:end/disp8 +3186 # curr = curr->next +3187 8b/-> *(ecx+4) 1/r32/ecx # List-next +3188 eb/jump loop/disp8 +3189 } +3190 b8/copy-to-eax 0/imm32 +3191 $find-in-function-outputs:end: +3192 # . restore registers +3193 59/pop-to-ecx +3194 # . epilogue +3195 89/<- %esp 5/r32/ebp +3196 5d/pop-to-ebp +3197 c3/return +3198 +3199 test-parse-mu-stmt: +3200 # 'increment n' +3201 # . prologue +3202 55/push-ebp +3203 89/<- %ebp 4/r32/esp +3204 # setup +3205 (clear-stream _test-input-stream) +3206 (write _test-input-stream "increment n\n") +3207 # var vars/ecx : (stack (addr var) 4) +3208 81 5/subop/subtract %esp 0x10/imm32 +3209 68/push 0x10/imm32/length +3210 68/push 0/imm32/top +3211 89/<- %ecx 4/r32/esp +3212 (clear-stack %ecx) +3213 # var v/edx : var +3214 81 5/subop/subtract %esp 0x14/imm32 # Var-size +3215 89/<- %edx 4/r32/esp +3216 (zero-out %edx 0x14) +3217 # v->name = "n" +3218 c7 0/subop/copy *edx "n"/imm32 # Var-name +3219 # +3220 (push %ecx %edx) +3221 # convert +3222 (parse-mu-stmt _test-input-stream %ecx) +3223 # check result +3224 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation +3225 # edx : (handle list var) = result->inouts +3226 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts +3227 # ebx : (handle var) = result->inouts->value +3228 8b/-> *edx 3/r32/ebx # List-value +3229 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name +3230 # . epilogue +3231 89/<- %esp 5/r32/ebp +3232 5d/pop-to-ebp +3233 c3/return +3234 +3235 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) +3236 # . prologue +3237 55/push-ebp +3238 89/<- %ebp 4/r32/esp +3239 # . save registers +3240 51/push-ecx +3241 # +3242 (allocate *(ebp+8) *Function-size) # => eax +3243 8b/-> *(ebp+0xc) 1/r32/ecx +3244 89/<- *eax 1/r32/ecx # Function-name +3245 8b/-> *(ebp+0x10) 1/r32/ecx +3246 89/<- *(eax+4) 1/r32/ecx # Function-subx-name +3247 8b/-> *(ebp+0x14) 1/r32/ecx +3248 89/<- *(eax+8) 1/r32/ecx # Function-inouts +3249 8b/-> *(ebp+0x18) 1/r32/ecx +3250 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs +3251 8b/-> *(ebp+0x1c) 1/r32/ecx +3252 89/<- *(eax+0x10) 1/r32/ecx # Function-body +3253 8b/-> *(ebp+0x20) 1/r32/ecx +3254 89/<- *(eax+0x14) 1/r32/ecx # Function-next +3255 $new-function:end: +3256 # . restore registers +3257 59/pop-to-ecx +3258 # . epilogue +3259 89/<- %esp 5/r32/ebp +3260 5d/pop-to-ebp +3261 c3/return +3262 +3263 new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, block: int, stack-offset: int, register: (addr array byte) -> result/eax: (handle var) +3264 # . prologue +3265 55/push-ebp +3266 89/<- %ebp 4/r32/esp +3267 # . save registers +3268 51/push-ecx +3269 # +3270 (allocate *(ebp+8) *Var-size) # => eax +3271 8b/-> *(ebp+0xc) 1/r32/ecx +3272 89/<- *eax 1/r32/ecx # Var-name +3273 8b/-> *(ebp+0x10) 1/r32/ecx +3274 89/<- *(eax+4) 1/r32/ecx # Var-type +3275 8b/-> *(ebp+0x14) 1/r32/ecx +3276 89/<- *(eax+8) 1/r32/ecx # Var-block +3277 8b/-> *(ebp+0x18) 1/r32/ecx +3278 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset +3279 8b/-> *(ebp+0x1c) 1/r32/ecx +3280 89/<- *(eax+0x10) 1/r32/ecx # Var-register +3281 $new-var:end: +3282 # . restore registers +3283 59/pop-to-ecx +3284 # . epilogue +3285 89/<- %esp 5/r32/ebp +3286 5d/pop-to-ebp +3287 c3/return +3288 +3289 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) +3290 # . prologue +3291 55/push-ebp +3292 89/<- %ebp 4/r32/esp +3293 # . save registers +3294 51/push-ecx +3295 # if (!is-hex-int?(name)) abort +3296 (is-hex-int? *(ebp+0xc)) # => eax +3297 3d/compare-eax-and 0/imm32 +3298 0f 84/jump-if-= $new-literal-integer:abort/disp32 +3299 # var s/ecx : (addr array byte) +3300 (slice-to-string Heap *(ebp+0xc)) # => eax +3301 89/<- %ecx 0/r32/eax +3302 # +3303 (allocate *(ebp+8) *Var-size) # => eax +3304 89/<- *eax 1/r32/ecx # Var-name +3305 89/<- %ecx 0/r32/eax +3306 (allocate *(ebp+8) *Tree-size) # => eax +3307 89/<- *(ecx+4) 0/r32/eax # Var-type +3308 89/<- %eax 1/r32/ecx +3309 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block +3310 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset +3311 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register +3312 $new-literal-integer:end: +3313 # . restore registers +3314 59/pop-to-ecx +3315 # . epilogue +3316 89/<- %esp 5/r32/ebp +3317 5d/pop-to-ebp +3318 c3/return +3319 +3320 $new-literal-integer:abort: +3321 (write-buffered Stderr "variable cannot begin with a digit '") +3322 (write-slice-buffered Stderr *(ebp+0xc)) +3323 (write-buffered Stderr "'\n") +3324 (flush Stderr) +3325 # . syscall(exit, 1) +3326 bb/copy-to-ebx 1/imm32 +3327 b8/copy-to-eax 1/imm32/exit +3328 cd/syscall 0x80/imm8 +3329 # never gets here +3330 +3331 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) +3332 # . prologue +3333 55/push-ebp +3334 89/<- %ebp 4/r32/esp +3335 # . save registers +3336 51/push-ecx +3337 # +3338 (allocate *(ebp+8) *Stmt-size) # => eax +3339 (zero-out %eax *Stmt-size) +3340 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag +3341 8b/-> *(ebp+0xc) 1/r32/ecx +3342 89/<- *(eax+4) 1/r32/ecx # Block-statements +3343 $new-block:end: +3344 # . restore registers +3345 59/pop-to-ecx +3346 # . epilogue +3347 89/<- %esp 5/r32/ebp +3348 5d/pop-to-ebp +3349 c3/return +3350 +3351 new-stmt: # ad: (addr allocation-descriptor), operation: (addr array byte), inouts: (handle list var), outputs: (handle list var) -> result/eax: (handle statement) +3352 # . prologue +3353 55/push-ebp +3354 89/<- %ebp 4/r32/esp +3355 # . save registers +3356 51/push-ecx +3357 # +3358 (allocate *(ebp+8) *Stmt-size) # => eax +3359 (zero-out %eax *Stmt-size) +3360 c7 0/subop/copy *eax 1/imm32/tag/regular-stmt # Stmt-tag +3361 8b/-> *(ebp+0xc) 1/r32/ecx +3362 89/<- *(eax+4) 1/r32/ecx # Stmt1-operation +3363 8b/-> *(ebp+0x10) 1/r32/ecx +3364 89/<- *(eax+8) 1/r32/ecx # Stmt1-inouts +3365 8b/-> *(ebp+0x14) 1/r32/ecx +3366 89/<- *(eax+0xc) 1/r32/ecx # Stmt1-outputs +3367 $new-stmt:end: +3368 # . restore registers +3369 59/pop-to-ecx +3370 # . epilogue +3371 89/<- %esp 5/r32/ebp +3372 5d/pop-to-ebp +3373 c3/return +3374 +3375 new-vardef: # ad: (addr allocation-descriptor), name: (addr array byte), type: int -> result/eax: (handle statement) +3376 # . prologue +3377 55/push-ebp +3378 89/<- %ebp 4/r32/esp +3379 # . save registers +3380 51/push-ecx +3381 # +3382 (allocate *(ebp+8) *Stmt-size) # => eax +3383 (zero-out %eax *Stmt-size) +3384 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag +3385 8b/-> *(ebp+0xc) 1/r32/ecx +3386 89/<- *(eax+4) 1/r32/ecx # Vardef-name +3387 8b/-> *(ebp+0x10) 1/r32/ecx +3388 89/<- *(eax+8) 1/r32/ecx # Vardef-type +3389 $new-vardef:end: +3390 # . restore registers +3391 59/pop-to-ecx +3392 # . epilogue +3393 89/<- %esp 5/r32/ebp +3394 5d/pop-to-ebp +3395 c3/return +3396 +3397 new-regvardef: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, register: (addr array byte) -> result/eax: (handle statement) +3398 # . prologue +3399 55/push-ebp +3400 89/<- %ebp 4/r32/esp +3401 # . save registers +3402 51/push-ecx +3403 # +3404 (allocate *(ebp+8) *Stmt-size) # => eax +3405 (zero-out %eax *Stmt-size) +3406 c7 0/subop/copy *eax 3/imm32/tag/var-in-register +3407 8b/-> *(ebp+0xc) 1/r32/ecx +3408 89/<- *(eax+4) 1/r32/ecx # Regvardef-name +3409 8b/-> *(ebp+0x10) 1/r32/ecx +3410 89/<- *(eax+8) 1/r32/ecx # Regvardef-type +3411 8b/-> *(ebp+0x14) 1/r32/ecx +3412 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-register +3413 $new-regvardef:end: +3414 # . restore registers +3415 59/pop-to-ecx +3416 # . epilogue +3417 89/<- %esp 5/r32/ebp +3418 5d/pop-to-ebp +3419 c3/return +3420 +3421 new-named-block: # ad: (addr allocation-descriptor), name: (addr array byte), data: (handle list statement) -> result/eax: (handle statement) +3422 # . prologue +3423 55/push-ebp +3424 89/<- %ebp 4/r32/esp +3425 # . save registers +3426 51/push-ecx +3427 # +3428 (allocate *(ebp+8) *Stmt-size) # => eax +3429 (zero-out %eax *Stmt-size) +3430 c7 0/subop/copy *eax 4/imm32/tag/named-block +3431 8b/-> *(ebp+0xc) 1/r32/ecx +3432 89/<- *(eax+4) 1/r32/ecx # Named-block-name +3433 8b/-> *(ebp+0x10) 1/r32/ecx +3434 89/<- *(eax+8) 1/r32/ecx # Named-block-statements +3435 $new-named-block:end: +3436 # . restore registers +3437 59/pop-to-ecx +3438 # . epilogue +3439 89/<- %esp 5/r32/ebp +3440 5d/pop-to-ebp +3441 c3/return +3442 +3443 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax : (handle list _type) +3444 # . prologue +3445 55/push-ebp +3446 89/<- %ebp 4/r32/esp +3447 # . save registers +3448 51/push-ecx +3449 # +3450 (allocate *(ebp+8) *List-size) # => eax +3451 8b/-> *(ebp+0xc) 1/r32/ecx +3452 89/<- *eax 1/r32/ecx # List-value +3453 8b/-> *(ebp+0x10) 1/r32/ecx +3454 89/<- *(eax+4) 1/r32/ecx # List-next +3455 $new-list:end: +3456 # . restore registers +3457 59/pop-to-ecx +3458 # . epilogue +3459 89/<- %esp 5/r32/ebp +3460 5d/pop-to-ebp +3461 c3/return +3462 +3463 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax : (handle list _type) +3464 # . prologue +3465 55/push-ebp +3466 89/<- %ebp 4/r32/esp +3467 # . save registers +3468 51/push-ecx +3469 # +3470 (allocate *(ebp+8) *List-size) # => eax +3471 8b/-> *(ebp+0xc) 1/r32/ecx +3472 89/<- *eax 1/r32/ecx # List-value +3473 # if (list == null) return result +3474 81 7/subop/compare *(ebp+0x10) 0/imm32 +3475 74/jump-if-= $new-list:end/disp8 +3476 # otherwise append +3477 # var curr/ecx = list +3478 8b/-> *(ebp+0x10) 1/r32/ecx +3479 # while (curr->next != null) curr = curr->next +3480 { +3481 81 7/subop/compare *(ecx+4) 0/imm32 # List-next +3482 74/jump-if-= break/disp8 +3483 # curr = curr->next +3484 8b/-> *(ecx+4) 1/r32/ecx +3485 eb/jump loop/disp8 +3486 } +3487 # curr->next = result +3488 89/<- *(ecx+4) 0/r32/eax +3489 # return list +3490 8b/-> *(ebp+0x10) 0/r32/eax +3491 $append-list:end: +3492 # . restore registers +3493 59/pop-to-ecx +3494 # . epilogue +3495 89/<- %esp 5/r32/ebp +3496 5d/pop-to-ebp +3497 c3/return +3498 +3499 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) +3500 # . prologue +3501 55/push-ebp +3502 89/<- %ebp 4/r32/esp +3503 # . save registers +3504 56/push-esi +3505 # esi = block +3506 8b/-> *(ebp+0xc) 6/r32/esi +3507 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements +3508 89/<- *(esi+4) 0/r32/eax # Block-statements +3509 $append-to-block:end: +3510 # . restore registers +3511 5e/pop-to-esi +3512 # . epilogue +3513 89/<- %esp 5/r32/ebp +3514 5d/pop-to-ebp +3515 c3/return +3516 +3517 ####################################################### +3518 # Type-checking +3519 ####################################################### +3520 +3521 check-mu-types: +3522 # . prologue +3523 55/push-ebp +3524 89/<- %ebp 4/r32/esp +3525 # +3526 $check-mu-types:end: +3527 # . epilogue +3528 89/<- %esp 5/r32/ebp +3529 5d/pop-to-ebp +3530 c3/return +3531 +3532 size-of: # n : (addr var) +3533 # . prologue +3534 55/push-ebp +3535 89/<- %ebp 4/r32/esp +3536 # hard-coded since we only support 'int' types for now +3537 b8/copy-to-eax 4/imm32 +3538 $size-of:end: +3539 # . epilogue +3540 89/<- %esp 5/r32/ebp +3541 5d/pop-to-ebp +3542 c3/return +3543 +3544 ####################################################### +3545 # Code-generation +3546 ####################################################### +3547 +3548 emit-subx: # out : (addr buffered-file) +3549 # . prologue +3550 55/push-ebp +3551 89/<- %ebp 4/r32/esp +3552 # . save registers +3553 50/push-eax +3554 51/push-ecx +3555 57/push-edi +3556 # edi = out +3557 8b/-> *(ebp+8) 7/r32/edi +3558 # var curr/ecx : (handle function) = *Program +3559 8b/-> *Program 1/r32/ecx +3560 { +3561 # if (curr == null) break +3562 81 7/subop/compare %ecx 0/imm32 +3563 0f 84/jump-if-= break/disp32 +3564 (emit-subx-function %edi %ecx) +3565 # curr = curr->next +3566 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +3567 e9/jump loop/disp32 +3568 } +3569 $emit-subx:end: +3570 # . restore registers +3571 5f/pop-to-edi +3572 59/pop-to-ecx +3573 58/pop-to-eax +3574 # . epilogue +3575 89/<- %esp 5/r32/ebp +3576 5d/pop-to-ebp +3577 c3/return +3578 +3579 emit-subx-function: # out : (addr buffered-file), f : (handle function) +3580 # . prologue +3581 55/push-ebp +3582 89/<- %ebp 4/r32/esp +3583 # . save registers +3584 50/push-eax +3585 51/push-ecx +3586 57/push-edi +3587 # edi = out +3588 8b/-> *(ebp+8) 7/r32/edi +3589 # ecx = f +3590 8b/-> *(ebp+0xc) 1/r32/ecx +3591 # +3592 (write-buffered %edi *ecx) +3593 (write-buffered %edi ":\n") +3594 (emit-subx-prologue %edi) +3595 (emit-subx-block %edi *(ecx+0x10)) # Function-body +3596 (emit-subx-epilogue %edi) +3597 $emit-subx-function:end: +3598 # . restore registers +3599 5f/pop-to-edi +3600 59/pop-to-ecx +3601 58/pop-to-eax +3602 # . epilogue +3603 89/<- %esp 5/r32/ebp +3604 5d/pop-to-ebp +3605 c3/return +3606 +3607 emit-subx-block: # out : (addr buffered-file), block : (handle block) +3608 # . prologue +3609 55/push-ebp +3610 89/<- %ebp 4/r32/esp +3611 # curr/esi : (handle list statement) = block->statements +3612 8b/-> *(ebp+0xc) 6/r32/esi +3613 8b/-> *(esi+4) 6/r32/esi # Block-statements +3614 # +3615 { +3616 $emit-subx-block:check-empty: +3617 81 7/subop/compare %esi 0/imm32 +3618 0f 84/jump-if-= break/disp32 +3619 (write-buffered *(ebp+8) "{\n") +3620 { +3621 $emit-subx-block:stmt: +3622 81 7/subop/compare %esi 0/imm32 +3623 74/jump-if-= break/disp8 +3624 (emit-subx-statement *(ebp+8) *esi Primitives *Program) +3625 (write-buffered *(ebp+8) Newline) +3626 8b/-> *(esi+4) 6/r32/esi # List-next +3627 eb/jump loop/disp8 +3628 } +3629 (write-buffered *(ebp+8) "}\n") +3630 } +3631 $emit-subx-block:end: +3632 # . epilogue +3633 89/<- %esp 5/r32/ebp +3634 5d/pop-to-ebp +3635 c3/return +3636 +3637 emit-subx-statement: # out : (addr buffered-file), stmt : (handle statement), primitives : (handle primitive), functions : (handle function) +3638 # . prologue +3639 55/push-ebp +3640 89/<- %ebp 4/r32/esp +3641 # . save registers +3642 50/push-eax +3643 51/push-ecx +3644 # if stmt matches a primitive, emit it +3645 { +3646 $emit-subx-statement:primitive: +3647 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax +3648 3d/compare-eax-and 0/imm32 +3649 74/jump-if-= break/disp8 +3650 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +3651 e9/jump $emit-subx-statement:end/disp32 +3652 } +3653 # else if stmt matches a function, emit a call to it +3654 { +3655 $emit-subx-statement:call: +3656 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax +3657 3d/compare-eax-and 0/imm32 +3658 74/jump-if-= break/disp8 +3659 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +3660 e9/jump $emit-subx-statement:end/disp32 +3661 } +3662 # else abort +3663 e9/jump $emit-subx-statement:abort/disp32 +3664 $emit-subx-statement:end: +3665 # . restore registers +3666 59/pop-to-ecx +3667 58/pop-to-eax +3668 # . epilogue +3669 89/<- %esp 5/r32/ebp +3670 5d/pop-to-ebp +3671 c3/return +3672 +3673 $emit-subx-statement:abort: +3674 # error("couldn't translate '" stmt "'\n") +3675 (write-buffered Stderr "couldn't translate '") +3676 #? (emit-string Stderr *(ebp+0xc)) # TODO +3677 (write-buffered Stderr "'\n") +3678 (flush Stderr) +3679 # . syscall(exit, 1) +3680 bb/copy-to-ebx 1/imm32 +3681 b8/copy-to-eax 1/imm32/exit +3682 cd/syscall 0x80/imm8 +3683 # never gets here +3684 +3685 # Primitives supported +3686 # For each operation, put variants with hard-coded registers before flexible ones. +3687 == data +3688 Primitives: +3689 # - increment/decrement +3690 _Primitive-inc-eax: +3691 # var/eax <- increment => 40/increment-eax +3692 "increment"/imm32/name +3693 0/imm32/no-inouts +3694 Single-int-var-in-eax/imm32/outputs +3695 "40/increment-eax"/imm32/subx-name +3696 0/imm32/no-rm32 +3697 0/imm32/no-r32 +3698 0/imm32/no-imm32 +3699 0/imm32/output-is-write-only +3700 _Primitive-inc-ecx/imm32/next +3701 _Primitive-inc-ecx: +3702 # var/ecx <- increment => 41/increment-ecx +3703 "increment"/imm32/name +3704 0/imm32/no-inouts +3705 Single-int-var-in-ecx/imm32/outputs +3706 "41/increment-ecx"/imm32/subx-name +3707 0/imm32/no-rm32 +3708 0/imm32/no-r32 +3709 0/imm32/no-imm32 +3710 0/imm32/output-is-write-only +3711 _Primitive-inc-edx/imm32/next +3712 _Primitive-inc-edx: +3713 # var/edx <- increment => 42/increment-edx +3714 "increment"/imm32/name +3715 0/imm32/no-inouts +3716 Single-int-var-in-edx/imm32/outputs +3717 "42/increment-edx"/imm32/subx-name +3718 0/imm32/no-rm32 +3719 0/imm32/no-r32 +3720 0/imm32/no-imm32 +3721 0/imm32/output-is-write-only +3722 _Primitive-inc-ebx/imm32/next +3723 _Primitive-inc-ebx: +3724 # var/ebx <- increment => 43/increment-ebx +3725 "increment"/imm32/name +3726 0/imm32/no-inouts +3727 Single-int-var-in-ebx/imm32/outputs +3728 "43/increment-ebx"/imm32/subx-name +3729 0/imm32/no-rm32 +3730 0/imm32/no-r32 +3731 0/imm32/no-imm32 +3732 0/imm32/output-is-write-only +3733 _Primitive-inc-esi/imm32/next +3734 _Primitive-inc-esi: +3735 # var/esi <- increment => 46/increment-esi +3736 "increment"/imm32/name +3737 0/imm32/no-inouts +3738 Single-int-var-in-esi/imm32/outputs +3739 "46/increment-esi"/imm32/subx-name +3740 0/imm32/no-rm32 +3741 0/imm32/no-r32 +3742 0/imm32/no-imm32 +3743 0/imm32/output-is-write-only +3744 _Primitive-inc-edi/imm32/next +3745 _Primitive-inc-edi: +3746 # var/edi <- increment => 47/increment-edi +3747 "increment"/imm32/name +3748 0/imm32/no-inouts +3749 Single-int-var-in-edi/imm32/outputs +3750 "47/increment-edi"/imm32/subx-name +3751 0/imm32/no-rm32 +3752 0/imm32/no-r32 +3753 0/imm32/no-imm32 +3754 0/imm32/output-is-write-only +3755 _Primitive-dec-eax/imm32/next +3756 _Primitive-dec-eax: +3757 # var/eax <- decrement => 48/decrement-eax +3758 "decrement"/imm32/name +3759 0/imm32/no-inouts +3760 Single-int-var-in-eax/imm32/outputs +3761 "48/decrement-eax"/imm32/subx-name +3762 0/imm32/no-rm32 +3763 0/imm32/no-r32 +3764 0/imm32/no-imm32 +3765 0/imm32/output-is-write-only +3766 _Primitive-dec-ecx/imm32/next +3767 _Primitive-dec-ecx: +3768 # var/ecx <- decrement => 49/decrement-ecx +3769 "decrement"/imm32/name +3770 0/imm32/no-inouts +3771 Single-int-var-in-ecx/imm32/outputs +3772 "49/decrement-ecx"/imm32/subx-name +3773 0/imm32/no-rm32 +3774 0/imm32/no-r32 +3775 0/imm32/no-imm32 +3776 0/imm32/output-is-write-only +3777 _Primitive-dec-edx/imm32/next +3778 _Primitive-dec-edx: +3779 # var/edx <- decrement => 4a/decrement-edx +3780 "decrement"/imm32/name +3781 0/imm32/no-inouts +3782 Single-int-var-in-edx/imm32/outputs +3783 "4a/decrement-edx"/imm32/subx-name +3784 0/imm32/no-rm32 +3785 0/imm32/no-r32 +3786 0/imm32/no-imm32 +3787 0/imm32/output-is-write-only +3788 _Primitive-dec-ebx/imm32/next +3789 _Primitive-dec-ebx: +3790 # var/ebx <- decrement => 4b/decrement-ebx +3791 "decrement"/imm32/name +3792 0/imm32/no-inouts +3793 Single-int-var-in-ebx/imm32/outputs +3794 "4b/decrement-ebx"/imm32/subx-name +3795 0/imm32/no-rm32 +3796 0/imm32/no-r32 +3797 0/imm32/no-imm32 +3798 0/imm32/output-is-write-only +3799 _Primitive-dec-esi/imm32/next +3800 _Primitive-dec-esi: +3801 # var/esi <- decrement => 4e/decrement-esi +3802 "decrement"/imm32/name +3803 0/imm32/no-inouts +3804 Single-int-var-in-esi/imm32/outputs +3805 "4e/decrement-esi"/imm32/subx-name 3806 0/imm32/no-rm32 3807 0/imm32/no-r32 -3808 1/imm32/imm32-is-first-inout +3808 0/imm32/no-imm32 3809 0/imm32/output-is-write-only -3810 _Primitive-xor-reg-with-reg/imm32/next -3811 _Primitive-xor-reg-with-reg: -3812 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 -3813 "xor"/imm32/name -3814 Single-int-var-in-some-register/imm32/inouts -3815 Single-int-var-in-some-register/imm32/outputs -3816 "31/xor-with"/imm32/subx-name -3817 3/imm32/rm32-is-first-output -3818 1/imm32/r32-is-first-inout +3810 _Primitive-dec-edi/imm32/next +3811 _Primitive-dec-edi: +3812 # var/edi <- decrement => 4f/decrement-edi +3813 "decrement"/imm32/name +3814 0/imm32/no-inouts +3815 Single-int-var-in-edi/imm32/outputs +3816 "4f/decrement-edi"/imm32/subx-name +3817 0/imm32/no-rm32 +3818 0/imm32/no-r32 3819 0/imm32/no-imm32 3820 0/imm32/output-is-write-only -3821 _Primitive-xor-reg-with-mem/imm32/next -3822 _Primitive-xor-reg-with-mem: -3823 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 -3824 "xor-with"/imm32/name -3825 Int-var-and-second-int-var-in-some-register/imm32/inouts -3826 0/imm32/outputs -3827 "31/xor-with"/imm32/subx-name +3821 _Primitive-inc-mem/imm32/next +3822 _Primitive-inc-mem: +3823 # increment var => ff 0/subop/increment *(ebp+__) +3824 "increment"/imm32/name +3825 Single-int-var-on-stack/imm32/inouts +3826 0/imm32/no-outputs +3827 "ff 0/subop/increment"/imm32/subx-name 3828 1/imm32/rm32-is-first-inout -3829 2/imm32/r32-is-second-inout +3829 0/imm32/no-r32 3830 0/imm32/no-imm32 3831 0/imm32/output-is-write-only -3832 _Primitive-xor-mem-with-reg/imm32/next -3833 _Primitive-xor-mem-with-reg: -3834 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 -3835 "xor"/imm32/name -3836 Single-int-var-on-stack/imm32/inouts -3837 Single-int-var-in-some-register/imm32/outputs -3838 "33/xor"/imm32/subx-name -3839 1/imm32/rm32-is-first-inout -3840 3/imm32/r32-is-first-output +3832 _Primitive-inc-reg/imm32/next +3833 _Primitive-inc-reg: +3834 # var/reg <- increment => ff 0/subop/increment %__ +3835 "increment"/imm32/name +3836 0/imm32/no-inouts +3837 Single-int-var-in-some-register/imm32/outputs +3838 "ff 0/subop/increment"/imm32/subx-name +3839 3/imm32/rm32-is-first-output +3840 0/imm32/no-r32 3841 0/imm32/no-imm32 3842 0/imm32/output-is-write-only -3843 _Primitive-xor-lit-with-reg/imm32/next -3844 _Primitive-xor-lit-with-reg: -3845 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 -3846 "xor"/imm32/name -3847 Single-lit-var/imm32/inouts -3848 Single-int-var-in-some-register/imm32/outputs -3849 "81 4/subop/xor"/imm32/subx-name -3850 3/imm32/rm32-is-first-output +3843 _Primitive-dec-mem/imm32/next +3844 _Primitive-dec-mem: +3845 # decrement var => ff 1/subop/decrement *(ebp+__) +3846 "decrement"/imm32/name +3847 Single-int-var-on-stack/imm32/inouts +3848 0/imm32/no-outputs +3849 "ff 1/subop/decrement"/imm32/subx-name +3850 1/imm32/rm32-is-first-inout 3851 0/imm32/no-r32 -3852 1/imm32/imm32-is-first-inout +3852 0/imm32/no-imm32 3853 0/imm32/output-is-write-only -3854 _Primitive-xor-lit-with-mem/imm32/next -3855 _Primitive-xor-lit-with-mem: -3856 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 -3857 "xor-with"/imm32/name -3858 Int-var-and-literal/imm32/inouts -3859 0/imm32/outputs -3860 "81 4/subop/xor"/imm32/subx-name -3861 1/imm32/rm32-is-first-inout +3854 _Primitive-dec-reg/imm32/next +3855 _Primitive-dec-reg: +3856 # var/reg <- decrement => ff 1/subop/decrement %__ +3857 "decrement"/imm32/name +3858 0/imm32/no-inouts +3859 Single-int-var-in-some-register/imm32/outputs +3860 "ff 1/subop/decrement"/imm32/subx-name +3861 3/imm32/rm32-is-first-output 3862 0/imm32/no-r32 -3863 2/imm32/imm32-is-first-inout +3863 0/imm32/no-imm32 3864 0/imm32/output-is-write-only -3865 _Primitive-copy-to-eax/imm32/next -3866 # - copy -3867 _Primitive-copy-to-eax: -3868 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 -3869 "copy"/imm32/name -3870 Single-lit-var/imm32/inouts -3871 Single-int-var-in-eax/imm32/outputs -3872 "b8/copy-to-eax"/imm32/subx-name +3865 _Primitive-add-to-eax/imm32/next +3866 # - add +3867 _Primitive-add-to-eax: +3868 # var/eax <- add lit => 05/add-to-eax lit/imm32 +3869 "add"/imm32/name +3870 Single-lit-var/imm32/inouts +3871 Single-int-var-in-eax/imm32/outputs +3872 "05/add-to-eax"/imm32/subx-name 3873 0/imm32/no-rm32 3874 0/imm32/no-r32 3875 1/imm32/imm32-is-first-inout -3876 1/imm32/output-is-write-only -3877 _Primitive-copy-to-ecx/imm32/next -3878 _Primitive-copy-to-ecx: -3879 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 -3880 "copy"/imm32/name -3881 Single-lit-var/imm32/inouts -3882 Single-int-var-in-ecx/imm32/outputs -3883 "b9/copy-to-ecx"/imm32/subx-name -3884 0/imm32/no-rm32 -3885 0/imm32/no-r32 -3886 1/imm32/imm32-is-first-inout -3887 1/imm32/output-is-write-only -3888 _Primitive-copy-to-edx/imm32/next -3889 _Primitive-copy-to-edx: -3890 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 -3891 "copy"/imm32/name -3892 Single-lit-var/imm32/inouts -3893 Single-int-var-in-edx/imm32/outputs -3894 "ba/copy-to-edx"/imm32/subx-name -3895 0/imm32/no-rm32 -3896 0/imm32/no-r32 -3897 1/imm32/imm32-is-first-inout -3898 1/imm32/output-is-write-only -3899 _Primitive-copy-to-ebx/imm32/next -3900 _Primitive-copy-to-ebx: -3901 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 -3902 "copy"/imm32/name -3903 Single-lit-var/imm32/inouts -3904 Single-int-var-in-ebx/imm32/outputs -3905 "bb/copy-to-ebx"/imm32/subx-name -3906 0/imm32/no-rm32 -3907 0/imm32/no-r32 -3908 1/imm32/imm32-is-first-inout -3909 1/imm32/output-is-write-only -3910 _Primitive-copy-to-esi/imm32/next -3911 _Primitive-copy-to-esi: -3912 # var/esi <- copy lit => be/copy-to-esi lit/imm32 -3913 "copy"/imm32/name -3914 Single-lit-var/imm32/inouts -3915 Single-int-var-in-esi/imm32/outputs -3916 "be/copy-to-esi"/imm32/subx-name -3917 0/imm32/no-rm32 +3876 0/imm32/output-is-write-only +3877 _Primitive-add-reg-to-reg/imm32/next +3878 _Primitive-add-reg-to-reg: +3879 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 +3880 "add"/imm32/name +3881 Single-int-var-in-some-register/imm32/inouts +3882 Single-int-var-in-some-register/imm32/outputs +3883 "01/add-to"/imm32/subx-name +3884 3/imm32/rm32-is-first-output +3885 1/imm32/r32-is-first-inout +3886 0/imm32/no-imm32 +3887 0/imm32/output-is-write-only +3888 _Primitive-add-reg-to-mem/imm32/next +3889 _Primitive-add-reg-to-mem: +3890 # add-to var1 var2/reg => 01/add-to var1 var2/r32 +3891 "add-to"/imm32/name +3892 Int-var-and-second-int-var-in-some-register/imm32/inouts +3893 0/imm32/outputs +3894 "01/add-to"/imm32/subx-name +3895 1/imm32/rm32-is-first-inout +3896 2/imm32/r32-is-second-inout +3897 0/imm32/no-imm32 +3898 0/imm32/output-is-write-only +3899 _Primitive-add-mem-to-reg/imm32/next +3900 _Primitive-add-mem-to-reg: +3901 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 +3902 "add"/imm32/name +3903 Single-int-var-on-stack/imm32/inouts +3904 Single-int-var-in-some-register/imm32/outputs +3905 "03/add"/imm32/subx-name +3906 1/imm32/rm32-is-first-inout +3907 3/imm32/r32-is-first-output +3908 0/imm32/no-imm32 +3909 0/imm32/output-is-write-only +3910 _Primitive-add-lit-to-reg/imm32/next +3911 _Primitive-add-lit-to-reg: +3912 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 +3913 "add"/imm32/name +3914 Single-lit-var/imm32/inouts +3915 Single-int-var-in-some-register/imm32/outputs +3916 "81 0/subop/add"/imm32/subx-name +3917 3/imm32/rm32-is-first-output 3918 0/imm32/no-r32 3919 1/imm32/imm32-is-first-inout -3920 1/imm32/output-is-write-only -3921 _Primitive-copy-to-edi/imm32/next -3922 _Primitive-copy-to-edi: -3923 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 -3924 "copy"/imm32/name -3925 Single-lit-var/imm32/inouts -3926 Single-int-var-in-edi/imm32/outputs -3927 "bf/copy-to-edi"/imm32/subx-name -3928 0/imm32/no-rm32 +3920 0/imm32/output-is-write-only +3921 _Primitive-add-lit-to-mem/imm32/next +3922 _Primitive-add-lit-to-mem: +3923 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 +3924 "add-to"/imm32/name +3925 Int-var-and-literal/imm32/inouts +3926 0/imm32/outputs +3927 "81 0/subop/add"/imm32/subx-name +3928 1/imm32/rm32-is-first-inout 3929 0/imm32/no-r32 -3930 1/imm32/imm32-is-first-inout -3931 1/imm32/output-is-write-only -3932 _Primitive-copy-reg-to-reg/imm32/next -3933 _Primitive-copy-reg-to-reg: -3934 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 -3935 "copy"/imm32/name -3936 Single-int-var-in-some-register/imm32/inouts -3937 Single-int-var-in-some-register/imm32/outputs -3938 "89/copy-to"/imm32/subx-name -3939 3/imm32/rm32-is-first-output -3940 1/imm32/r32-is-first-inout -3941 0/imm32/no-imm32 -3942 1/imm32/output-is-write-only -3943 _Primitive-copy-reg-to-mem/imm32/next -3944 _Primitive-copy-reg-to-mem: -3945 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 -3946 "copy-to"/imm32/name -3947 Int-var-and-second-int-var-in-some-register/imm32/inouts -3948 0/imm32/outputs -3949 "89/copy-to"/imm32/subx-name -3950 1/imm32/rm32-is-first-inout -3951 2/imm32/r32-is-second-inout -3952 0/imm32/no-imm32 -3953 1/imm32/output-is-write-only -3954 _Primitive-copy-mem-to-reg/imm32/next -3955 _Primitive-copy-mem-to-reg: -3956 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 -3957 "copy"/imm32/name -3958 Single-int-var-on-stack/imm32/inouts -3959 Single-int-var-in-some-register/imm32/outputs -3960 "8b/copy-from"/imm32/subx-name -3961 1/imm32/rm32-is-first-inout -3962 3/imm32/r32-is-first-output -3963 0/imm32/no-imm32 -3964 1/imm32/output-is-write-only -3965 _Primitive-copy-lit-to-reg/imm32/next -3966 _Primitive-copy-lit-to-reg: -3967 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 -3968 "copy"/imm32/name -3969 Single-lit-var/imm32/inouts -3970 Single-int-var-in-some-register/imm32/outputs -3971 "c7 0/subop/copy"/imm32/subx-name -3972 3/imm32/rm32-is-first-output -3973 0/imm32/no-r32 -3974 1/imm32/imm32-is-first-inout -3975 1/imm32/output-is-write-only -3976 _Primitive-copy-lit-to-mem/imm32/next -3977 _Primitive-copy-lit-to-mem: -3978 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 -3979 "copy-to"/imm32/name -3980 Int-var-and-literal/imm32/inouts -3981 0/imm32/outputs -3982 "c7 0/subop/copy"/imm32/subx-name -3983 1/imm32/rm32-is-first-inout -3984 0/imm32/no-r32 -3985 2/imm32/imm32-is-first-inout -3986 1/imm32/output-is-write-only -3987 0/imm32/next -3988 -3989 Single-int-var-on-stack: -3990 Int-var-on-stack/imm32 -3991 0/imm32/next -3992 -3993 Int-var-on-stack: -3994 "arg1"/imm32/name -3995 Type-int/imm32 -3996 1/imm32/some-block-depth -3997 1/imm32/some-stack-offset -3998 0/imm32/no-register -3999 -4000 Int-var-and-second-int-var-in-some-register: -4001 Int-var-on-stack/imm32 -4002 Single-int-var-in-some-register/imm32/next -4003 -4004 Int-var-and-literal: -4005 Int-var-on-stack/imm32 -4006 Single-lit-var/imm32/next -4007 -4008 Single-int-var-in-some-register: -4009 Int-var-in-some-register/imm32 -4010 0/imm32/next -4011 -4012 Int-var-in-some-register: -4013 "arg1"/imm32/name -4014 Type-int/imm32 -4015 1/imm32/some-block-depth -4016 0/imm32/no-stack-offset -4017 "*"/imm32/register -4018 -4019 Single-int-var-in-eax: -4020 Int-var-in-eax/imm32 -4021 0/imm32/next -4022 -4023 Int-var-in-eax: -4024 "arg1"/imm32/name -4025 Type-int/imm32 -4026 1/imm32/some-block-depth -4027 0/imm32/no-stack-offset -4028 "eax"/imm32/register -4029 -4030 Single-int-var-in-ecx: -4031 Int-var-in-ecx/imm32 -4032 0/imm32/next -4033 -4034 Int-var-in-ecx: -4035 "arg1"/imm32/name -4036 Type-int/imm32 -4037 1/imm32/some-block-depth -4038 0/imm32/no-stack-offset -4039 "ecx"/imm32/register -4040 -4041 Single-int-var-in-edx: -4042 Int-var-in-edx/imm32 -4043 0/imm32/next -4044 -4045 Int-var-in-edx: -4046 "arg1"/imm32/name -4047 Type-int/imm32 -4048 1/imm32/some-block-depth -4049 0/imm32/no-stack-offset -4050 "edx"/imm32/register -4051 -4052 Single-int-var-in-ebx: -4053 Int-var-in-ebx/imm32 -4054 0/imm32/next -4055 -4056 Int-var-in-ebx: -4057 "arg1"/imm32/name -4058 Type-int/imm32 -4059 1/imm32/some-block-depth -4060 0/imm32/no-stack-offset -4061 "ebx"/imm32/register -4062 -4063 Single-int-var-in-esi: -4064 Int-var-in-esi/imm32 -4065 0/imm32/next -4066 -4067 Int-var-in-esi: -4068 "arg1"/imm32/name -4069 Type-int/imm32 -4070 1/imm32/some-block-depth -4071 0/imm32/no-stack-offset -4072 "esi"/imm32/register -4073 -4074 Single-int-var-in-edi: -4075 Int-var-in-edi/imm32 -4076 0/imm32/next -4077 -4078 Int-var-in-edi: -4079 "arg1"/imm32/name -4080 Type-int/imm32 -4081 1/imm32/some-block-depth -4082 0/imm32/no-stack-offset -4083 "edi"/imm32/register -4084 -4085 Single-lit-var: -4086 Lit-var/imm32 -4087 0/imm32/next -4088 -4089 Lit-var: -4090 "literal"/imm32/name -4091 Type-literal/imm32 -4092 1/imm32/some-block-depth -4093 0/imm32/no-stack-offset -4094 0/imm32/no-register -4095 -4096 Type-int: -4097 1/imm32/left/int -4098 0/imm32/right/null -4099 -4100 Type-literal: -4101 0/imm32/left/literal -4102 0/imm32/right/null -4103 -4104 == code -4105 emit-subx-primitive: # out : (addr buffered-file), stmt : (handle statement), primitive : (handle function) -4106 # . prologue -4107 55/push-ebp -4108 89/<- %ebp 4/r32/esp -4109 # . save registers -4110 50/push-eax -4111 51/push-ecx -4112 # ecx = primitive -4113 8b/-> *(ebp+0x10) 1/r32/ecx -4114 # emit primitive name -4115 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name -4116 # emit rm32 if necessary -4117 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt -4118 # emit r32 if necessary -4119 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt -4120 # emit imm32 if necessary -4121 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt -4122 $emit-subx-primitive:end: -4123 # . restore registers -4124 59/pop-to-ecx -4125 58/pop-to-eax -4126 # . epilogue -4127 89/<- %esp 5/r32/ebp -4128 5d/pop-to-ebp -4129 c3/return -4130 -4131 emit-subx-rm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) -4132 # . prologue -4133 55/push-ebp -4134 89/<- %ebp 4/r32/esp -4135 # . save registers -4136 50/push-eax -4137 # if (l == 0) return -4138 81 7/subop/compare *(ebp+0xc) 0/imm32 -4139 74/jump-if-= $emit-subx-rm32:end/disp8 -4140 # -4141 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4142 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var -4143 $emit-subx-rm32:end: -4144 # . restore registers -4145 58/pop-to-eax -4146 # . epilogue -4147 89/<- %esp 5/r32/ebp -4148 5d/pop-to-ebp -4149 c3/return -4150 -4151 get-stmt-operand-from-arg-location: # stmt : (handle statement), l : arg-location -> var/eax : (handle variable) -4152 # . prologue -4153 55/push-ebp -4154 89/<- %ebp 4/r32/esp -4155 # . save registers -4156 51/push-ecx -4157 # eax = l -4158 8b/-> *(ebp+0xc) 0/r32/eax -4159 # ecx = stmt -4160 8b/-> *(ebp+8) 1/r32/ecx -4161 # if (l == 1) return stmt->inouts->var -4162 { -4163 3d/compare-eax-and 1/imm32 -4164 75/jump-if-!= break/disp8 -4165 $get-stmt-operand-from-arg-location:1: -4166 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -4167 8b/-> *eax 0/r32/eax # Operand-var -4168 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4169 } -4170 # if (l == 2) return stmt->inouts->next->var -4171 { -4172 3d/compare-eax-and 2/imm32 -4173 75/jump-if-!= break/disp8 -4174 $get-stmt-operand-from-arg-location:2: -4175 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -4176 8b/-> *(eax+4) 0/r32/eax # Operand-next -4177 8b/-> *eax 0/r32/eax # Operand-var -4178 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4179 } -4180 # if (l == 3) return stmt->outputs -4181 { -4182 3d/compare-eax-and 3/imm32 -4183 75/jump-if-!= break/disp8 -4184 $get-stmt-operand-from-arg-location:3: -4185 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs -4186 8b/-> *eax 0/r32/eax # Operand-var -4187 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4188 } -4189 # abort -4190 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 -4191 $get-stmt-operand-from-arg-location:end: -4192 # . restore registers -4193 59/pop-to-ecx -4194 # . epilogue -4195 89/<- %esp 5/r32/ebp -4196 5d/pop-to-ebp -4197 c3/return -4198 -4199 $get-stmt-operand-from-arg-location:abort: -4200 # error("invalid arg-location " eax) -4201 (write-buffered Stderr "invalid arg-location ") -4202 (print-int32-buffered Stderr %eax) -4203 (write-buffered Stderr "\n") -4204 (flush Stderr) -4205 # . syscall(exit, 1) -4206 bb/copy-to-ebx 1/imm32 -4207 b8/copy-to-eax 1/imm32/exit -4208 cd/syscall 0x80/imm8 -4209 # never gets here -4210 -4211 emit-subx-r32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) -4212 # . prologue -4213 55/push-ebp -4214 89/<- %ebp 4/r32/esp -4215 # . save registers -4216 50/push-eax -4217 51/push-ecx -4218 # if (location == 0) return -4219 81 7/subop/compare *(ebp+0xc) 0/imm32 -4220 0f 84/jump-if-= $emit-subx-r32:end/disp32 -4221 # -4222 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4223 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (addr register-index) -4224 (write-buffered *(ebp+8) Space) -4225 (print-int32-buffered *(ebp+8) *eax) -4226 (write-buffered *(ebp+8) "/r32") -4227 $emit-subx-r32:end: -4228 # . restore registers -4229 59/pop-to-ecx -4230 58/pop-to-eax -4231 # . epilogue -4232 89/<- %esp 5/r32/ebp -4233 5d/pop-to-ebp -4234 c3/return -4235 -4236 emit-subx-imm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) -4237 # . prologue -4238 55/push-ebp -4239 89/<- %ebp 4/r32/esp -4240 # . save registers -4241 50/push-eax -4242 51/push-ecx -4243 # if (location == 0) return -4244 81 7/subop/compare *(ebp+0xc) 0/imm32 -4245 74/jump-if-= $emit-subx-imm32:end/disp8 -4246 # -4247 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4248 (write-buffered *(ebp+8) Space) -4249 (write-buffered *(ebp+8) *eax) # Var-name -4250 (write-buffered *(ebp+8) "/imm32") -4251 $emit-subx-imm32:end: -4252 # . restore registers -4253 59/pop-to-ecx -4254 58/pop-to-eax -4255 # . epilogue -4256 89/<- %esp 5/r32/ebp -4257 5d/pop-to-ebp -4258 c3/return -4259 -4260 emit-subx-call: # out : (addr buffered-file), stmt : (handle statement), callee : (handle function) -4261 # . prologue -4262 55/push-ebp -4263 89/<- %ebp 4/r32/esp -4264 # . save registers -4265 50/push-eax -4266 51/push-ecx -4267 # -4268 (write-buffered *(ebp+8) "(") -4269 # - emit function name -4270 8b/-> *(ebp+0x10) 1/r32/ecx -4271 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name -4272 # - emit arguments -4273 # var curr/ecx : (handle list var) = stmt->inouts -4274 8b/-> *(ebp+0xc) 1/r32/ecx -4275 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts -4276 { -4277 # if (curr == null) break -4278 81 7/subop/compare %ecx 0/imm32 -4279 74/jump-if-= break/disp8 -4280 # -4281 (emit-subx-call-operand *(ebp+8) *ecx) -4282 # curr = curr->next -4283 8b/-> *(ecx+4) 1/r32/ecx -4284 eb/jump loop/disp8 -4285 } -4286 # -4287 (write-buffered *(ebp+8) ")") -4288 $emit-subx-call:end: -4289 # . restore registers -4290 59/pop-to-ecx -4291 58/pop-to-eax -4292 # . epilogue -4293 89/<- %esp 5/r32/ebp -4294 5d/pop-to-ebp -4295 c3/return -4296 -4297 emit-subx-call-operand: # out : (addr buffered-file), operand : (handle variable) -4298 # . prologue -4299 55/push-ebp -4300 89/<- %ebp 4/r32/esp -4301 # . save registers -4302 50/push-eax -4303 # eax = operand -4304 8b/-> *(ebp+0xc) 0/r32/eax -4305 # if (operand->register) emit "%__" -4306 { -4307 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -4308 74/jump-if-= break/disp8 -4309 $emit-subx-call-operand:register: -4310 (write-buffered *(ebp+8) " %") -4311 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -4312 e9/jump $emit-subx-call-operand:end/disp32 -4313 } -4314 # else if (operand->stack-offset) emit "*(ebp+__)" -4315 { -4316 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -4317 74/jump-if-= break/disp8 -4318 $emit-subx-call-operand:stack: -4319 (write-buffered *(ebp+8) Space) -4320 (write-buffered *(ebp+8) "*(ebp+") -4321 8b/-> *(ebp+0xc) 0/r32/eax -4322 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -4323 (write-buffered *(ebp+8) ")") -4324 e9/jump $emit-subx-call-operand:end/disp32 -4325 } -4326 # else if (operand->type == literal) emit "__" -4327 { -4328 50/push-eax -4329 8b/-> *(eax+4) 0/r32/eax # Var-type -4330 81 7/subop/compare *eax 0/imm32 # Tree-left -4331 58/pop-to-eax -4332 75/jump-if-!= break/disp8 -4333 $emit-subx-call-operand:literal: -4334 (write-buffered *(ebp+8) Space) -4335 (write-buffered *(ebp+8) *eax) -4336 } -4337 $emit-subx-call-operand:end: -4338 # . restore registers -4339 58/pop-to-eax -4340 # . epilogue -4341 89/<- %esp 5/r32/ebp -4342 5d/pop-to-ebp -4343 c3/return -4344 -4345 emit-subx-var-as-rm32: # out : (addr buffered-file), operand : (handle variable) -4346 # . prologue -4347 55/push-ebp -4348 89/<- %ebp 4/r32/esp -4349 # . save registers -4350 50/push-eax -4351 # eax = operand -4352 8b/-> *(ebp+0xc) 0/r32/eax -4353 # if (operand->register) emit "%__" -4354 { -4355 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -4356 74/jump-if-= break/disp8 -4357 $emit-subx-var-as-rm32:register: -4358 (write-buffered *(ebp+8) " %") -4359 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -4360 } -4361 # else if (operand->stack-offset) emit "*(ebp+__)" -4362 { -4363 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -4364 74/jump-if-= break/disp8 -4365 $emit-subx-var-as-rm32:stack: -4366 (write-buffered *(ebp+8) Space) -4367 (write-buffered *(ebp+8) "*(ebp+") -4368 8b/-> *(ebp+0xc) 0/r32/eax -4369 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -4370 (write-buffered *(ebp+8) ")") -4371 } -4372 $emit-subx-var-as-rm32:end: -4373 # . restore registers -4374 58/pop-to-eax -4375 # . epilogue -4376 89/<- %esp 5/r32/ebp -4377 5d/pop-to-ebp -4378 c3/return +3930 2/imm32/imm32-is-first-inout +3931 0/imm32/output-is-write-only +3932 _Primitive-subtract-from-eax/imm32/next +3933 # - subtract +3934 _Primitive-subtract-from-eax: +3935 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 +3936 "subtract"/imm32/name +3937 Single-lit-var/imm32/inouts +3938 Single-int-var-in-eax/imm32/outputs +3939 "2d/subtract-from-eax"/imm32/subx-name +3940 0/imm32/no-rm32 +3941 0/imm32/no-r32 +3942 1/imm32/imm32-is-first-inout +3943 0/imm32/output-is-write-only +3944 _Primitive-subtract-reg-from-reg/imm32/next +3945 _Primitive-subtract-reg-from-reg: +3946 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 +3947 "subtract"/imm32/name +3948 Single-int-var-in-some-register/imm32/inouts +3949 Single-int-var-in-some-register/imm32/outputs +3950 "29/subtract-from"/imm32/subx-name +3951 3/imm32/rm32-is-first-output +3952 1/imm32/r32-is-first-inout +3953 0/imm32/no-imm32 +3954 0/imm32/output-is-write-only +3955 _Primitive-subtract-reg-from-mem/imm32/next +3956 _Primitive-subtract-reg-from-mem: +3957 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 +3958 "subtract-from"/imm32/name +3959 Int-var-and-second-int-var-in-some-register/imm32/inouts +3960 0/imm32/outputs +3961 "29/subtract-from"/imm32/subx-name +3962 1/imm32/rm32-is-first-inout +3963 2/imm32/r32-is-second-inout +3964 0/imm32/no-imm32 +3965 0/imm32/output-is-write-only +3966 _Primitive-subtract-mem-from-reg/imm32/next +3967 _Primitive-subtract-mem-from-reg: +3968 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 +3969 "subtract"/imm32/name +3970 Single-int-var-on-stack/imm32/inouts +3971 Single-int-var-in-some-register/imm32/outputs +3972 "2b/subtract"/imm32/subx-name +3973 1/imm32/rm32-is-first-inout +3974 3/imm32/r32-is-first-output +3975 0/imm32/no-imm32 +3976 0/imm32/output-is-write-only +3977 _Primitive-subtract-lit-from-reg/imm32/next +3978 _Primitive-subtract-lit-from-reg: +3979 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 +3980 "subtract"/imm32/name +3981 Single-lit-var/imm32/inouts +3982 Single-int-var-in-some-register/imm32/outputs +3983 "81 5/subop/subtract"/imm32/subx-name +3984 3/imm32/rm32-is-first-output +3985 0/imm32/no-r32 +3986 1/imm32/imm32-is-first-inout +3987 0/imm32/output-is-write-only +3988 _Primitive-subtract-lit-from-mem/imm32/next +3989 _Primitive-subtract-lit-from-mem: +3990 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 +3991 "subtract-from"/imm32/name +3992 Int-var-and-literal/imm32/inouts +3993 0/imm32/outputs +3994 "81 5/subop/subtract"/imm32/subx-name +3995 1/imm32/rm32-is-first-inout +3996 0/imm32/no-r32 +3997 2/imm32/imm32-is-first-inout +3998 0/imm32/output-is-write-only +3999 _Primitive-and-with-eax/imm32/next +4000 # - and +4001 _Primitive-and-with-eax: +4002 # var/eax <- and lit => 25/and-with-eax lit/imm32 +4003 "and"/imm32/name +4004 Single-lit-var/imm32/inouts +4005 Single-int-var-in-eax/imm32/outputs +4006 "25/and-with-eax"/imm32/subx-name +4007 0/imm32/no-rm32 +4008 0/imm32/no-r32 +4009 1/imm32/imm32-is-first-inout +4010 0/imm32/output-is-write-only +4011 _Primitive-and-reg-with-reg/imm32/next +4012 _Primitive-and-reg-with-reg: +4013 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 +4014 "and"/imm32/name +4015 Single-int-var-in-some-register/imm32/inouts +4016 Single-int-var-in-some-register/imm32/outputs +4017 "21/and-with"/imm32/subx-name +4018 3/imm32/rm32-is-first-output +4019 1/imm32/r32-is-first-inout +4020 0/imm32/no-imm32 +4021 0/imm32/output-is-write-only +4022 _Primitive-and-reg-with-mem/imm32/next +4023 _Primitive-and-reg-with-mem: +4024 # and-with var1 var2/reg => 21/and-with var1 var2/r32 +4025 "and-with"/imm32/name +4026 Int-var-and-second-int-var-in-some-register/imm32/inouts +4027 0/imm32/outputs +4028 "21/and-with"/imm32/subx-name +4029 1/imm32/rm32-is-first-inout +4030 2/imm32/r32-is-second-inout +4031 0/imm32/no-imm32 +4032 0/imm32/output-is-write-only +4033 _Primitive-and-mem-with-reg/imm32/next +4034 _Primitive-and-mem-with-reg: +4035 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 +4036 "and"/imm32/name +4037 Single-int-var-on-stack/imm32/inouts +4038 Single-int-var-in-some-register/imm32/outputs +4039 "23/and"/imm32/subx-name +4040 1/imm32/rm32-is-first-inout +4041 3/imm32/r32-is-first-output +4042 0/imm32/no-imm32 +4043 0/imm32/output-is-write-only +4044 _Primitive-and-lit-with-reg/imm32/next +4045 _Primitive-and-lit-with-reg: +4046 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 +4047 "and"/imm32/name +4048 Single-lit-var/imm32/inouts +4049 Single-int-var-in-some-register/imm32/outputs +4050 "81 4/subop/and"/imm32/subx-name +4051 3/imm32/rm32-is-first-output +4052 0/imm32/no-r32 +4053 1/imm32/imm32-is-first-inout +4054 0/imm32/output-is-write-only +4055 _Primitive-and-lit-with-mem/imm32/next +4056 _Primitive-and-lit-with-mem: +4057 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 +4058 "and-with"/imm32/name +4059 Int-var-and-literal/imm32/inouts +4060 0/imm32/outputs +4061 "81 4/subop/and"/imm32/subx-name +4062 1/imm32/rm32-is-first-inout +4063 0/imm32/no-r32 +4064 2/imm32/imm32-is-first-inout +4065 0/imm32/output-is-write-only +4066 _Primitive-or-with-eax/imm32/next +4067 # - or +4068 _Primitive-or-with-eax: +4069 # var/eax <- or lit => 0d/or-with-eax lit/imm32 +4070 "or"/imm32/name +4071 Single-lit-var/imm32/inouts +4072 Single-int-var-in-eax/imm32/outputs +4073 "0d/or-with-eax"/imm32/subx-name +4074 0/imm32/no-rm32 +4075 0/imm32/no-r32 +4076 1/imm32/imm32-is-first-inout +4077 0/imm32/output-is-write-only +4078 _Primitive-or-reg-with-reg/imm32/next +4079 _Primitive-or-reg-with-reg: +4080 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 +4081 "or"/imm32/name +4082 Single-int-var-in-some-register/imm32/inouts +4083 Single-int-var-in-some-register/imm32/outputs +4084 "09/or-with"/imm32/subx-name +4085 3/imm32/rm32-is-first-output +4086 1/imm32/r32-is-first-inout +4087 0/imm32/no-imm32 +4088 0/imm32/output-is-write-only +4089 _Primitive-or-reg-with-mem/imm32/next +4090 _Primitive-or-reg-with-mem: +4091 # or-with var1 var2/reg => 09/or-with var1 var2/r32 +4092 "or-with"/imm32/name +4093 Int-var-and-second-int-var-in-some-register/imm32/inouts +4094 0/imm32/outputs +4095 "09/or-with"/imm32/subx-name +4096 1/imm32/rm32-is-first-inout +4097 2/imm32/r32-is-second-inout +4098 0/imm32/no-imm32 +4099 0/imm32/output-is-write-only +4100 _Primitive-or-mem-with-reg/imm32/next +4101 _Primitive-or-mem-with-reg: +4102 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 +4103 "or"/imm32/name +4104 Single-int-var-on-stack/imm32/inouts +4105 Single-int-var-in-some-register/imm32/outputs +4106 "0b/or"/imm32/subx-name +4107 1/imm32/rm32-is-first-inout +4108 3/imm32/r32-is-first-output +4109 0/imm32/no-imm32 +4110 0/imm32/output-is-write-only +4111 _Primitive-or-lit-with-reg/imm32/next +4112 _Primitive-or-lit-with-reg: +4113 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 +4114 "or"/imm32/name +4115 Single-lit-var/imm32/inouts +4116 Single-int-var-in-some-register/imm32/outputs +4117 "81 4/subop/or"/imm32/subx-name +4118 3/imm32/rm32-is-first-output +4119 0/imm32/no-r32 +4120 1/imm32/imm32-is-first-inout +4121 0/imm32/output-is-write-only +4122 _Primitive-or-lit-with-mem/imm32/next +4123 _Primitive-or-lit-with-mem: +4124 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 +4125 "or-with"/imm32/name +4126 Int-var-and-literal/imm32/inouts +4127 0/imm32/outputs +4128 "81 4/subop/or"/imm32/subx-name +4129 1/imm32/rm32-is-first-inout +4130 0/imm32/no-r32 +4131 2/imm32/imm32-is-first-inout +4132 0/imm32/output-is-write-only +4133 _Primitive-xor-with-eax/imm32/next +4134 # - xor +4135 _Primitive-xor-with-eax: +4136 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 +4137 "xor"/imm32/name +4138 Single-lit-var/imm32/inouts +4139 Single-int-var-in-eax/imm32/outputs +4140 "35/xor-with-eax"/imm32/subx-name +4141 0/imm32/no-rm32 +4142 0/imm32/no-r32 +4143 1/imm32/imm32-is-first-inout +4144 0/imm32/output-is-write-only +4145 _Primitive-xor-reg-with-reg/imm32/next +4146 _Primitive-xor-reg-with-reg: +4147 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 +4148 "xor"/imm32/name +4149 Single-int-var-in-some-register/imm32/inouts +4150 Single-int-var-in-some-register/imm32/outputs +4151 "31/xor-with"/imm32/subx-name +4152 3/imm32/rm32-is-first-output +4153 1/imm32/r32-is-first-inout +4154 0/imm32/no-imm32 +4155 0/imm32/output-is-write-only +4156 _Primitive-xor-reg-with-mem/imm32/next +4157 _Primitive-xor-reg-with-mem: +4158 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 +4159 "xor-with"/imm32/name +4160 Int-var-and-second-int-var-in-some-register/imm32/inouts +4161 0/imm32/outputs +4162 "31/xor-with"/imm32/subx-name +4163 1/imm32/rm32-is-first-inout +4164 2/imm32/r32-is-second-inout +4165 0/imm32/no-imm32 +4166 0/imm32/output-is-write-only +4167 _Primitive-xor-mem-with-reg/imm32/next +4168 _Primitive-xor-mem-with-reg: +4169 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 +4170 "xor"/imm32/name +4171 Single-int-var-on-stack/imm32/inouts +4172 Single-int-var-in-some-register/imm32/outputs +4173 "33/xor"/imm32/subx-name +4174 1/imm32/rm32-is-first-inout +4175 3/imm32/r32-is-first-output +4176 0/imm32/no-imm32 +4177 0/imm32/output-is-write-only +4178 _Primitive-xor-lit-with-reg/imm32/next +4179 _Primitive-xor-lit-with-reg: +4180 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 +4181 "xor"/imm32/name +4182 Single-lit-var/imm32/inouts +4183 Single-int-var-in-some-register/imm32/outputs +4184 "81 4/subop/xor"/imm32/subx-name +4185 3/imm32/rm32-is-first-output +4186 0/imm32/no-r32 +4187 1/imm32/imm32-is-first-inout +4188 0/imm32/output-is-write-only +4189 _Primitive-xor-lit-with-mem/imm32/next +4190 _Primitive-xor-lit-with-mem: +4191 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 +4192 "xor-with"/imm32/name +4193 Int-var-and-literal/imm32/inouts +4194 0/imm32/outputs +4195 "81 4/subop/xor"/imm32/subx-name +4196 1/imm32/rm32-is-first-inout +4197 0/imm32/no-r32 +4198 2/imm32/imm32-is-first-inout +4199 0/imm32/output-is-write-only +4200 _Primitive-copy-to-eax/imm32/next +4201 # - copy +4202 _Primitive-copy-to-eax: +4203 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 +4204 "copy"/imm32/name +4205 Single-lit-var/imm32/inouts +4206 Single-int-var-in-eax/imm32/outputs +4207 "b8/copy-to-eax"/imm32/subx-name +4208 0/imm32/no-rm32 +4209 0/imm32/no-r32 +4210 1/imm32/imm32-is-first-inout +4211 1/imm32/output-is-write-only +4212 _Primitive-copy-to-ecx/imm32/next +4213 _Primitive-copy-to-ecx: +4214 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 +4215 "copy"/imm32/name +4216 Single-lit-var/imm32/inouts +4217 Single-int-var-in-ecx/imm32/outputs +4218 "b9/copy-to-ecx"/imm32/subx-name +4219 0/imm32/no-rm32 +4220 0/imm32/no-r32 +4221 1/imm32/imm32-is-first-inout +4222 1/imm32/output-is-write-only +4223 _Primitive-copy-to-edx/imm32/next +4224 _Primitive-copy-to-edx: +4225 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 +4226 "copy"/imm32/name +4227 Single-lit-var/imm32/inouts +4228 Single-int-var-in-edx/imm32/outputs +4229 "ba/copy-to-edx"/imm32/subx-name +4230 0/imm32/no-rm32 +4231 0/imm32/no-r32 +4232 1/imm32/imm32-is-first-inout +4233 1/imm32/output-is-write-only +4234 _Primitive-copy-to-ebx/imm32/next +4235 _Primitive-copy-to-ebx: +4236 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 +4237 "copy"/imm32/name +4238 Single-lit-var/imm32/inouts +4239 Single-int-var-in-ebx/imm32/outputs +4240 "bb/copy-to-ebx"/imm32/subx-name +4241 0/imm32/no-rm32 +4242 0/imm32/no-r32 +4243 1/imm32/imm32-is-first-inout +4244 1/imm32/output-is-write-only +4245 _Primitive-copy-to-esi/imm32/next +4246 _Primitive-copy-to-esi: +4247 # var/esi <- copy lit => be/copy-to-esi lit/imm32 +4248 "copy"/imm32/name +4249 Single-lit-var/imm32/inouts +4250 Single-int-var-in-esi/imm32/outputs +4251 "be/copy-to-esi"/imm32/subx-name +4252 0/imm32/no-rm32 +4253 0/imm32/no-r32 +4254 1/imm32/imm32-is-first-inout +4255 1/imm32/output-is-write-only +4256 _Primitive-copy-to-edi/imm32/next +4257 _Primitive-copy-to-edi: +4258 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 +4259 "copy"/imm32/name +4260 Single-lit-var/imm32/inouts +4261 Single-int-var-in-edi/imm32/outputs +4262 "bf/copy-to-edi"/imm32/subx-name +4263 0/imm32/no-rm32 +4264 0/imm32/no-r32 +4265 1/imm32/imm32-is-first-inout +4266 1/imm32/output-is-write-only +4267 _Primitive-copy-reg-to-reg/imm32/next +4268 _Primitive-copy-reg-to-reg: +4269 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 +4270 "copy"/imm32/name +4271 Single-int-var-in-some-register/imm32/inouts +4272 Single-int-var-in-some-register/imm32/outputs +4273 "89/copy-to"/imm32/subx-name +4274 3/imm32/rm32-is-first-output +4275 1/imm32/r32-is-first-inout +4276 0/imm32/no-imm32 +4277 1/imm32/output-is-write-only +4278 _Primitive-copy-reg-to-mem/imm32/next +4279 _Primitive-copy-reg-to-mem: +4280 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 +4281 "copy-to"/imm32/name +4282 Int-var-and-second-int-var-in-some-register/imm32/inouts +4283 0/imm32/outputs +4284 "89/copy-to"/imm32/subx-name +4285 1/imm32/rm32-is-first-inout +4286 2/imm32/r32-is-second-inout +4287 0/imm32/no-imm32 +4288 1/imm32/output-is-write-only +4289 _Primitive-copy-mem-to-reg/imm32/next +4290 _Primitive-copy-mem-to-reg: +4291 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 +4292 "copy"/imm32/name +4293 Single-int-var-on-stack/imm32/inouts +4294 Single-int-var-in-some-register/imm32/outputs +4295 "8b/copy-from"/imm32/subx-name +4296 1/imm32/rm32-is-first-inout +4297 3/imm32/r32-is-first-output +4298 0/imm32/no-imm32 +4299 1/imm32/output-is-write-only +4300 _Primitive-copy-lit-to-reg/imm32/next +4301 _Primitive-copy-lit-to-reg: +4302 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 +4303 "copy"/imm32/name +4304 Single-lit-var/imm32/inouts +4305 Single-int-var-in-some-register/imm32/outputs +4306 "c7 0/subop/copy"/imm32/subx-name +4307 3/imm32/rm32-is-first-output +4308 0/imm32/no-r32 +4309 1/imm32/imm32-is-first-inout +4310 1/imm32/output-is-write-only +4311 _Primitive-copy-lit-to-mem/imm32/next +4312 _Primitive-copy-lit-to-mem: +4313 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 +4314 "copy-to"/imm32/name +4315 Int-var-and-literal/imm32/inouts +4316 0/imm32/outputs +4317 "c7 0/subop/copy"/imm32/subx-name +4318 1/imm32/rm32-is-first-inout +4319 0/imm32/no-r32 +4320 2/imm32/imm32-is-first-inout +4321 1/imm32/output-is-write-only +4322 0/imm32/next +4323 +4324 Single-int-var-on-stack: +4325 Int-var-on-stack/imm32 +4326 0/imm32/next +4327 +4328 Int-var-on-stack: +4329 "arg1"/imm32/name +4330 Type-int/imm32 +4331 1/imm32/some-block-depth +4332 1/imm32/some-stack-offset +4333 0/imm32/no-register +4334 +4335 Int-var-and-second-int-var-in-some-register: +4336 Int-var-on-stack/imm32 +4337 Single-int-var-in-some-register/imm32/next +4338 +4339 Int-var-and-literal: +4340 Int-var-on-stack/imm32 +4341 Single-lit-var/imm32/next +4342 +4343 Single-int-var-in-some-register: +4344 Int-var-in-some-register/imm32 +4345 0/imm32/next +4346 +4347 Int-var-in-some-register: +4348 "arg1"/imm32/name +4349 Type-int/imm32 +4350 1/imm32/some-block-depth +4351 0/imm32/no-stack-offset +4352 "*"/imm32/register +4353 +4354 Single-int-var-in-eax: +4355 Int-var-in-eax/imm32 +4356 0/imm32/next +4357 +4358 Int-var-in-eax: +4359 "arg1"/imm32/name +4360 Type-int/imm32 +4361 1/imm32/some-block-depth +4362 0/imm32/no-stack-offset +4363 "eax"/imm32/register +4364 +4365 Single-int-var-in-ecx: +4366 Int-var-in-ecx/imm32 +4367 0/imm32/next +4368 +4369 Int-var-in-ecx: +4370 "arg1"/imm32/name +4371 Type-int/imm32 +4372 1/imm32/some-block-depth +4373 0/imm32/no-stack-offset +4374 "ecx"/imm32/register +4375 +4376 Single-int-var-in-edx: +4377 Int-var-in-edx/imm32 +4378 0/imm32/next 4379 -4380 find-matching-function: # functions : (addr function), stmt : (handle statement) -> result/eax : (handle function) -4381 # . prologue -4382 55/push-ebp -4383 89/<- %ebp 4/r32/esp -4384 # . save registers -4385 51/push-ecx -4386 # var curr/ecx : (handle function) = functions -4387 8b/-> *(ebp+8) 1/r32/ecx -4388 { -4389 # if (curr == null) break -4390 81 7/subop/compare %ecx 0/imm32 -4391 74/jump-if-= break/disp8 -4392 # if match(stmt, curr) return curr -4393 { -4394 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax -4395 3d/compare-eax-and 0/imm32 -4396 74/jump-if-= break/disp8 -4397 89/<- %eax 1/r32/ecx -4398 eb/jump $find-matching-function:end/disp8 -4399 } -4400 # curr = curr->next -4401 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -4402 eb/jump loop/disp8 -4403 } -4404 # return null -4405 b8/copy-to-eax 0/imm32 -4406 $find-matching-function:end: -4407 # . restore registers -4408 59/pop-to-ecx -4409 # . epilogue -4410 89/<- %esp 5/r32/ebp -4411 5d/pop-to-ebp -4412 c3/return -4413 -4414 find-matching-primitive: # primitives : (handle primitive), stmt : (handle statement) -> result/eax : (handle primitive) -4415 # . prologue -4416 55/push-ebp -4417 89/<- %ebp 4/r32/esp -4418 # . save registers -4419 51/push-ecx -4420 # var curr/ecx : (handle primitive) = primitives -4421 8b/-> *(ebp+8) 1/r32/ecx -4422 { -4423 $find-matching-primitive:loop: -4424 # if (curr == null) break -4425 81 7/subop/compare %ecx 0/imm32 -4426 0f 84/jump-if-= break/disp32 -4427 #? (write-buffered Stderr "prim: ") -4428 #? (write-buffered Stderr *ecx) # Primitive-name -4429 #? (write-buffered Stderr " => ") -4430 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name -4431 #? (write-buffered Stderr "\n") -4432 #? (flush Stderr) -4433 # if match(curr, stmt) return curr -4434 { -4435 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax -4436 3d/compare-eax-and 0/imm32 -4437 74/jump-if-= break/disp8 -4438 89/<- %eax 1/r32/ecx -4439 eb/jump $find-matching-primitive:end/disp8 -4440 } -4441 $find-matching-primitive:next-primitive: -4442 # curr = curr->next -4443 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next -4444 e9/jump loop/disp32 -4445 } -4446 # return null -4447 b8/copy-to-eax 0/imm32 -4448 $find-matching-primitive:end: -4449 # . restore registers -4450 59/pop-to-ecx -4451 # . epilogue -4452 89/<- %esp 5/r32/ebp -4453 5d/pop-to-ebp -4454 c3/return -4455 -4456 mu-stmt-matches-function?: # stmt : (handle statement), function : (handle function) => result/eax : boolean -4457 # . prologue -4458 55/push-ebp -4459 89/<- %ebp 4/r32/esp -4460 # . save registers -4461 51/push-ecx -4462 # return function->name == stmt->operation -4463 8b/-> *(ebp+8) 1/r32/ecx -4464 8b/-> *(ebp+0xc) 0/r32/eax -4465 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax -4466 $mu-stmt-matches-function?:end: -4467 # . restore registers -4468 59/pop-to-ecx -4469 # . epilogue -4470 89/<- %esp 5/r32/ebp -4471 5d/pop-to-ebp -4472 c3/return -4473 -4474 mu-stmt-matches-primitive?: # stmt : (handle statement), primitive : (handle primitive) => result/eax : boolean -4475 # A mu stmt matches a primitive if the name matches, all the inout vars -4476 # match, and all the output vars match. -4477 # Vars match if types match and registers match. -4478 # In addition, a stmt output matches a primitive's output if types match -4479 # and the primitive has a wildcard register. -4480 # . prologue -4481 55/push-ebp -4482 89/<- %ebp 4/r32/esp -4483 # . save registers -4484 51/push-ecx -4485 52/push-edx -4486 53/push-ebx -4487 56/push-esi -4488 57/push-edi -4489 # ecx = stmt -4490 8b/-> *(ebp+8) 1/r32/ecx -4491 # edx = primitive -4492 8b/-> *(ebp+0xc) 2/r32/edx -4493 { -4494 $mu-stmt-matches-primitive?:check-name: -4495 # if (primitive->name != stmt->operation) return false -4496 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax -4497 3d/compare-eax-and 0/imm32 -4498 75/jump-if-!= break/disp8 -4499 b8/copy-to-eax 0/imm32 -4500 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4501 } -4502 $mu-stmt-matches-primitive?:check-inouts: -4503 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) -4504 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts -4505 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts +4380 Int-var-in-edx: +4381 "arg1"/imm32/name +4382 Type-int/imm32 +4383 1/imm32/some-block-depth +4384 0/imm32/no-stack-offset +4385 "edx"/imm32/register +4386 +4387 Single-int-var-in-ebx: +4388 Int-var-in-ebx/imm32 +4389 0/imm32/next +4390 +4391 Int-var-in-ebx: +4392 "arg1"/imm32/name +4393 Type-int/imm32 +4394 1/imm32/some-block-depth +4395 0/imm32/no-stack-offset +4396 "ebx"/imm32/register +4397 +4398 Single-int-var-in-esi: +4399 Int-var-in-esi/imm32 +4400 0/imm32/next +4401 +4402 Int-var-in-esi: +4403 "arg1"/imm32/name +4404 Type-int/imm32 +4405 1/imm32/some-block-depth +4406 0/imm32/no-stack-offset +4407 "esi"/imm32/register +4408 +4409 Single-int-var-in-edi: +4410 Int-var-in-edi/imm32 +4411 0/imm32/next +4412 +4413 Int-var-in-edi: +4414 "arg1"/imm32/name +4415 Type-int/imm32 +4416 1/imm32/some-block-depth +4417 0/imm32/no-stack-offset +4418 "edi"/imm32/register +4419 +4420 Single-lit-var: +4421 Lit-var/imm32 +4422 0/imm32/next +4423 +4424 Lit-var: +4425 "literal"/imm32/name +4426 Type-literal/imm32 +4427 1/imm32/some-block-depth +4428 0/imm32/no-stack-offset +4429 0/imm32/no-register +4430 +4431 Type-int: +4432 1/imm32/left/int +4433 0/imm32/right/null +4434 +4435 Type-literal: +4436 0/imm32/left/literal +4437 0/imm32/right/null +4438 +4439 == code +4440 emit-subx-primitive: # out : (addr buffered-file), stmt : (handle statement), primitive : (handle function) +4441 # . prologue +4442 55/push-ebp +4443 89/<- %ebp 4/r32/esp +4444 # . save registers +4445 50/push-eax +4446 51/push-ecx +4447 # ecx = primitive +4448 8b/-> *(ebp+0x10) 1/r32/ecx +4449 # emit primitive name +4450 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name +4451 # emit rm32 if necessary +4452 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt +4453 # emit r32 if necessary +4454 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt +4455 # emit imm32 if necessary +4456 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt +4457 $emit-subx-primitive:end: +4458 # . restore registers +4459 59/pop-to-ecx +4460 58/pop-to-eax +4461 # . epilogue +4462 89/<- %esp 5/r32/ebp +4463 5d/pop-to-ebp +4464 c3/return +4465 +4466 emit-subx-rm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) +4467 # . prologue +4468 55/push-ebp +4469 89/<- %ebp 4/r32/esp +4470 # . save registers +4471 50/push-eax +4472 # if (l == 0) return +4473 81 7/subop/compare *(ebp+0xc) 0/imm32 +4474 74/jump-if-= $emit-subx-rm32:end/disp8 +4475 # +4476 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4477 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var +4478 $emit-subx-rm32:end: +4479 # . restore registers +4480 58/pop-to-eax +4481 # . epilogue +4482 89/<- %esp 5/r32/ebp +4483 5d/pop-to-ebp +4484 c3/return +4485 +4486 get-stmt-operand-from-arg-location: # stmt : (handle statement), l : arg-location -> var/eax : (handle variable) +4487 # . prologue +4488 55/push-ebp +4489 89/<- %ebp 4/r32/esp +4490 # . save registers +4491 51/push-ecx +4492 # eax = l +4493 8b/-> *(ebp+0xc) 0/r32/eax +4494 # ecx = stmt +4495 8b/-> *(ebp+8) 1/r32/ecx +4496 # if (l == 1) return stmt->inouts->var +4497 { +4498 3d/compare-eax-and 1/imm32 +4499 75/jump-if-!= break/disp8 +4500 $get-stmt-operand-from-arg-location:1: +4501 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +4502 8b/-> *eax 0/r32/eax # Operand-var +4503 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4504 } +4505 # if (l == 2) return stmt->inouts->next->var 4506 { -4507 # if (curr == 0 && curr2 == 0) move on to check outputs -4508 { -4509 81 7/subop/compare %esi 0/imm32 -4510 75/jump-if-!= break/disp8 -4511 $mu-stmt-matches-primitive?:stmt-inout-is-null: -4512 { -4513 81 7/subop/compare %edi 0/imm32 -4514 75/jump-if-!= break/disp8 -4515 # -4516 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 -4517 } -4518 # return false -4519 b8/copy-to-eax 0/imm32/false -4520 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4521 } -4522 # if (curr2 == 0) return false -4523 { -4524 81 7/subop/compare %edi 0/imm32 -4525 75/jump-if-!= break/disp8 -4526 $mu-stmt-matches-primitive?:prim-inout-is-null: -4527 b8/copy-to-eax 0/imm32/false -4528 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4529 } -4530 # if (curr != curr2) return false -4531 { -4532 (operand-matches-primitive? *esi *edi) # => eax -4533 3d/compare-eax-and 0/imm32 -4534 75/jump-if-!= break/disp8 -4535 b8/copy-to-eax 0/imm32/false -4536 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4537 } -4538 # curr=curr->next -4539 8b/-> *(esi+4) 6/r32/esi # Operand-next -4540 # curr2=curr2->next -4541 8b/-> *(edi+4) 7/r32/edi # Operand-next -4542 eb/jump loop/disp8 -4543 } -4544 $mu-stmt-matches-primitive?:check-outputs: -4545 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) -4546 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs -4547 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs -4548 { -4549 # if (curr == 0) return (curr2 == 0) -4550 { -4551 $mu-stmt-matches-primitive?:check-output: -4552 81 7/subop/compare %esi 0/imm32 -4553 75/jump-if-!= break/disp8 -4554 { -4555 81 7/subop/compare %edi 0/imm32 -4556 75/jump-if-!= break/disp8 -4557 # return true -4558 b8/copy-to-eax 1/imm32 -4559 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4560 } -4561 # return false -4562 b8/copy-to-eax 0/imm32 -4563 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4564 } -4565 # if (curr2 == 0) return false -4566 { -4567 81 7/subop/compare %edi 0/imm32 -4568 75/jump-if-!= break/disp8 -4569 b8/copy-to-eax 0/imm32 -4570 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4571 } -4572 # if (curr != curr2) return false -4573 { -4574 (operand-matches-primitive? *esi *edi) # List-value List-value => eax -4575 3d/compare-eax-and 0/imm32 -4576 75/jump-if-!= break/disp8 -4577 b8/copy-to-eax 0/imm32 -4578 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4579 } -4580 # curr=curr->next -4581 8b/-> *(esi+4) 6/r32/esi # Operand-next -4582 # curr2=curr2->next -4583 8b/-> *(edi+4) 7/r32/edi # Operand-next -4584 eb/jump loop/disp8 -4585 } -4586 $mu-stmt-matches-primitive?:return-true: -4587 b8/copy-to-eax 1/imm32 -4588 $mu-stmt-matches-primitive?:end: -4589 # . restore registers -4590 5f/pop-to-edi -4591 5e/pop-to-esi -4592 5b/pop-to-ebx -4593 5a/pop-to-edx -4594 59/pop-to-ecx -4595 # . epilogue -4596 89/<- %esp 5/r32/ebp -4597 5d/pop-to-ebp -4598 c3/return -4599 -4600 operand-matches-primitive?: # var : (handle var), prim-var : (handle var) => result/eax : boolean -4601 # . prologue -4602 55/push-ebp -4603 89/<- %ebp 4/r32/esp -4604 # . save registers -4605 56/push-esi -4606 57/push-edi -4607 # esi = var -4608 8b/-> *(ebp+8) 6/r32/esi -4609 # edi = prim-var -4610 8b/-> *(ebp+0xc) 7/r32/edi -4611 # if (var->type != prim-var->type) return false -4612 (type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax -4613 3d/compare-eax-and 0/imm32 -4614 b8/copy-to-eax 0/imm32/false -4615 74/jump-if-= $operand-matches-primitive?:end/disp8 -4616 # return false if var->register doesn't match prim-var->register -4617 { -4618 # if addresses are equal, don't return here -4619 8b/-> *(esi+0x10) 0/r32/eax -4620 39/compare *(edi+0x10) 0/r32/eax -4621 74/jump-if-= break/disp8 -4622 # if either address is 0, return false -4623 3d/compare-eax-and 0/imm32 -4624 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -4625 81 7/subop/compare *(edi+0x10) 0/imm32 -4626 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -4627 # if prim-var->register is "*", return true -4628 (string-equal? *(edi+0x10) "*") # Var-register -4629 3d/compare-eax-and 0/imm32 -4630 b8/copy-to-eax 1/imm32/true -4631 75/jump-if-!= $operand-matches-primitive?:end/disp8 -4632 # if string contents don't match, return false -4633 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register -4634 3d/compare-eax-and 0/imm32 -4635 b8/copy-to-eax 0/imm32/false -4636 74/jump-if-= $operand-matches-primitive?:end/disp8 -4637 } -4638 # return true -4639 b8/copy-to-eax 1/imm32/true -4640 $operand-matches-primitive?:end: -4641 # . restore registers -4642 5f/pop-to-edi -4643 5e/pop-to-esi -4644 # . epilogue -4645 89/<- %esp 5/r32/ebp -4646 5d/pop-to-ebp -4647 c3/return -4648 -4649 type-equal?: # a : (handle tree type-id), b : (handle tree type-id) => result/eax : boolean -4650 # . prologue -4651 55/push-ebp -4652 89/<- %ebp 4/r32/esp -4653 # . save registers -4654 51/push-ecx -4655 52/push-edx -4656 # ecx = a -4657 8b/-> *(ebp+8) 1/r32/ecx -4658 # edx = b -4659 8b/-> *(ebp+0xc) 2/r32/edx -4660 # if (a == b) return true -4661 8b/-> %ecx 0/r32/eax # Var-type -4662 39/compare %edx 0/r32/eax # Var-type -4663 b8/copy-to-eax 1/imm32/true -4664 0f 84/jump-if-= $type-equal?:end/disp32 -4665 # if (a == 0) return false -4666 81 7/subop/compare %ecx 0/imm32 -4667 b8/copy-to-eax 0/imm32/false -4668 0f 84/jump-if-= $type-equal?:end/disp32 -4669 # if (b == 0) return false -4670 81 7/subop/compare %edx 0/imm32 -4671 b8/copy-to-eax 0/imm32/false -4672 0f 84/jump-if-= $type-equal?:end/disp32 -4673 # if (!type-equal?(a->left, b->left)) return false -4674 (type-equal? *ecx *edx) # Tree-left, Tree-left => eax -4675 3d/compare-eax-and 0/imm32 -4676 0f 84/jump-if-= $type-equal?:end/disp32 -4677 # return type-equal?(a->right, b->right -4678 (type-equal? *(ecx+4) *(edx+4)) # Tree-right, Tree-right => eax -4679 $type-equal?:end: -4680 # . restore registers -4681 5a/pop-to-edx -4682 59/pop-to-ecx -4683 # . epilogue -4684 89/<- %esp 5/r32/ebp -4685 5d/pop-to-ebp -4686 c3/return -4687 -4688 test-emit-subx-statement-primitive: -4689 # Primitive operation on a variable on the stack. -4690 # increment foo -4691 # => -4692 # ff 0/subop/increment *(ebp-8) -4693 # -4694 # There's a variable on the var stack as follows: -4695 # name: 'foo' -4696 # type: int -4697 # stack-offset: -8 -4698 # -4699 # There's a primitive with this info: -4700 # name: 'increment' -4701 # inouts: int/mem -4702 # value: 'ff 0/subop/increment' -4703 # -4704 # There's nothing in functions. -4705 # -4706 # . prologue -4707 55/push-ebp -4708 89/<- %ebp 4/r32/esp -4709 # setup -4710 (clear-stream _test-output-stream) -4711 (clear-stream $_test-output-buffered-file->buffer) -4712 # var type/ecx : (handle tree type-id) = int -4713 68/push 0/imm32/right/null -4714 68/push 1/imm32/left/int -4715 89/<- %ecx 4/r32/esp -4716 # var var-foo/ecx : var -4717 68/push 0/imm32/no-register -4718 68/push -8/imm32/stack-offset -4719 68/push 1/imm32/block-depth +4507 3d/compare-eax-and 2/imm32 +4508 75/jump-if-!= break/disp8 +4509 $get-stmt-operand-from-arg-location:2: +4510 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +4511 8b/-> *(eax+4) 0/r32/eax # Operand-next +4512 8b/-> *eax 0/r32/eax # Operand-var +4513 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4514 } +4515 # if (l == 3) return stmt->outputs +4516 { +4517 3d/compare-eax-and 3/imm32 +4518 75/jump-if-!= break/disp8 +4519 $get-stmt-operand-from-arg-location:3: +4520 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs +4521 8b/-> *eax 0/r32/eax # Operand-var +4522 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4523 } +4524 # abort +4525 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 +4526 $get-stmt-operand-from-arg-location:end: +4527 # . restore registers +4528 59/pop-to-ecx +4529 # . epilogue +4530 89/<- %esp 5/r32/ebp +4531 5d/pop-to-ebp +4532 c3/return +4533 +4534 $get-stmt-operand-from-arg-location:abort: +4535 # error("invalid arg-location " eax) +4536 (write-buffered Stderr "invalid arg-location ") +4537 (print-int32-buffered Stderr %eax) +4538 (write-buffered Stderr "\n") +4539 (flush Stderr) +4540 # . syscall(exit, 1) +4541 bb/copy-to-ebx 1/imm32 +4542 b8/copy-to-eax 1/imm32/exit +4543 cd/syscall 0x80/imm8 +4544 # never gets here +4545 +4546 emit-subx-r32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) +4547 # . prologue +4548 55/push-ebp +4549 89/<- %ebp 4/r32/esp +4550 # . save registers +4551 50/push-eax +4552 51/push-ecx +4553 # if (location == 0) return +4554 81 7/subop/compare *(ebp+0xc) 0/imm32 +4555 0f 84/jump-if-= $emit-subx-r32:end/disp32 +4556 # +4557 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4558 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (addr register-index) +4559 (write-buffered *(ebp+8) Space) +4560 (print-int32-buffered *(ebp+8) *eax) +4561 (write-buffered *(ebp+8) "/r32") +4562 $emit-subx-r32:end: +4563 # . restore registers +4564 59/pop-to-ecx +4565 58/pop-to-eax +4566 # . epilogue +4567 89/<- %esp 5/r32/ebp +4568 5d/pop-to-ebp +4569 c3/return +4570 +4571 emit-subx-imm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) +4572 # . prologue +4573 55/push-ebp +4574 89/<- %ebp 4/r32/esp +4575 # . save registers +4576 50/push-eax +4577 51/push-ecx +4578 # if (location == 0) return +4579 81 7/subop/compare *(ebp+0xc) 0/imm32 +4580 74/jump-if-= $emit-subx-imm32:end/disp8 +4581 # +4582 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4583 (write-buffered *(ebp+8) Space) +4584 (write-buffered *(ebp+8) *eax) # Var-name +4585 (write-buffered *(ebp+8) "/imm32") +4586 $emit-subx-imm32:end: +4587 # . restore registers +4588 59/pop-to-ecx +4589 58/pop-to-eax +4590 # . epilogue +4591 89/<- %esp 5/r32/ebp +4592 5d/pop-to-ebp +4593 c3/return +4594 +4595 emit-subx-call: # out : (addr buffered-file), stmt : (handle statement), callee : (handle function) +4596 # . prologue +4597 55/push-ebp +4598 89/<- %ebp 4/r32/esp +4599 # . save registers +4600 50/push-eax +4601 51/push-ecx +4602 # +4603 (write-buffered *(ebp+8) "(") +4604 # - emit function name +4605 8b/-> *(ebp+0x10) 1/r32/ecx +4606 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name +4607 # - emit arguments +4608 # var curr/ecx : (handle list var) = stmt->inouts +4609 8b/-> *(ebp+0xc) 1/r32/ecx +4610 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts +4611 { +4612 # if (curr == null) break +4613 81 7/subop/compare %ecx 0/imm32 +4614 74/jump-if-= break/disp8 +4615 # +4616 (emit-subx-call-operand *(ebp+8) *ecx) +4617 # curr = curr->next +4618 8b/-> *(ecx+4) 1/r32/ecx +4619 eb/jump loop/disp8 +4620 } +4621 # +4622 (write-buffered *(ebp+8) ")") +4623 $emit-subx-call:end: +4624 # . restore registers +4625 59/pop-to-ecx +4626 58/pop-to-eax +4627 # . epilogue +4628 89/<- %esp 5/r32/ebp +4629 5d/pop-to-ebp +4630 c3/return +4631 +4632 emit-subx-call-operand: # out : (addr buffered-file), operand : (handle variable) +4633 # . prologue +4634 55/push-ebp +4635 89/<- %ebp 4/r32/esp +4636 # . save registers +4637 50/push-eax +4638 # eax = operand +4639 8b/-> *(ebp+0xc) 0/r32/eax +4640 # if (operand->register) emit "%__" +4641 { +4642 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +4643 74/jump-if-= break/disp8 +4644 $emit-subx-call-operand:register: +4645 (write-buffered *(ebp+8) " %") +4646 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +4647 e9/jump $emit-subx-call-operand:end/disp32 +4648 } +4649 # else if (operand->stack-offset) emit "*(ebp+__)" +4650 { +4651 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +4652 74/jump-if-= break/disp8 +4653 $emit-subx-call-operand:stack: +4654 (write-buffered *(ebp+8) Space) +4655 (write-buffered *(ebp+8) "*(ebp+") +4656 8b/-> *(ebp+0xc) 0/r32/eax +4657 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +4658 (write-buffered *(ebp+8) ")") +4659 e9/jump $emit-subx-call-operand:end/disp32 +4660 } +4661 # else if (operand->type == literal) emit "__" +4662 { +4663 50/push-eax +4664 8b/-> *(eax+4) 0/r32/eax # Var-type +4665 81 7/subop/compare *eax 0/imm32 # Tree-left +4666 58/pop-to-eax +4667 75/jump-if-!= break/disp8 +4668 $emit-subx-call-operand:literal: +4669 (write-buffered *(ebp+8) Space) +4670 (write-buffered *(ebp+8) *eax) +4671 } +4672 $emit-subx-call-operand:end: +4673 # . restore registers +4674 58/pop-to-eax +4675 # . epilogue +4676 89/<- %esp 5/r32/ebp +4677 5d/pop-to-ebp +4678 c3/return +4679 +4680 emit-subx-var-as-rm32: # out : (addr buffered-file), operand : (handle variable) +4681 # . prologue +4682 55/push-ebp +4683 89/<- %ebp 4/r32/esp +4684 # . save registers +4685 50/push-eax +4686 # eax = operand +4687 8b/-> *(ebp+0xc) 0/r32/eax +4688 # if (operand->register) emit "%__" +4689 { +4690 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +4691 74/jump-if-= break/disp8 +4692 $emit-subx-var-as-rm32:register: +4693 (write-buffered *(ebp+8) " %") +4694 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +4695 } +4696 # else if (operand->stack-offset) emit "*(ebp+__)" +4697 { +4698 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +4699 74/jump-if-= break/disp8 +4700 $emit-subx-var-as-rm32:stack: +4701 (write-buffered *(ebp+8) Space) +4702 (write-buffered *(ebp+8) "*(ebp+") +4703 8b/-> *(ebp+0xc) 0/r32/eax +4704 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +4705 (write-buffered *(ebp+8) ")") +4706 } +4707 $emit-subx-var-as-rm32:end: +4708 # . restore registers +4709 58/pop-to-eax +4710 # . epilogue +4711 89/<- %esp 5/r32/ebp +4712 5d/pop-to-ebp +4713 c3/return +4714 +4715 find-matching-function: # functions : (addr function), stmt : (handle statement) -> result/eax : (handle function) +4716 # . prologue +4717 55/push-ebp +4718 89/<- %ebp 4/r32/esp +4719 # . save registers 4720 51/push-ecx -4721 68/push "foo"/imm32 -4722 89/<- %ecx 4/r32/esp -4723 # var operand/ebx : (list var) -4724 68/push 0/imm32/next -4725 51/push-ecx/var-foo -4726 89/<- %ebx 4/r32/esp -4727 # var stmt/esi : statement -4728 68/push 0/imm32/next -4729 68/push 0/imm32/outputs -4730 53/push-ebx/operands -4731 68/push "increment"/imm32/operation -4732 68/push 1/imm32 -4733 89/<- %esi 4/r32/esp -4734 # var primitives/ebx : primitive -4735 68/push 0/imm32/next -4736 68/push 0/imm32/output-is-write-only -4737 68/push 0/imm32/no-imm32 -4738 68/push 0/imm32/no-r32 -4739 68/push 1/imm32/rm32-is-first-inout -4740 68/push "ff 0/subop/increment"/imm32/subx-name -4741 68/push 0/imm32/outputs -4742 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call -4743 68/push "increment"/imm32/name -4744 89/<- %ebx 4/r32/esp -4745 # convert -4746 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -4747 (flush _test-output-buffered-file) -4748 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4754 # check output -4755 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") -4756 # . epilogue -4757 89/<- %esp 5/r32/ebp -4758 5d/pop-to-ebp -4759 c3/return -4760 -4761 test-emit-subx-statement-primitive-register: -4762 # Primitive operation on a variable in a register. -4763 # foo <- increment -4764 # => -4765 # ff 0/subop/increment %eax # sub-optimal, but should suffice -4766 # -4767 # There's a variable on the var stack as follows: -4768 # name: 'foo' -4769 # type: int -4770 # register: 'eax' -4771 # -4772 # There's a primitive with this info: -4773 # name: 'increment' -4774 # out: int/reg -4775 # value: 'ff 0/subop/increment' -4776 # -4777 # There's nothing in functions. -4778 # -4779 # . prologue -4780 55/push-ebp -4781 89/<- %ebp 4/r32/esp -4782 # setup -4783 (clear-stream _test-output-stream) -4784 (clear-stream $_test-output-buffered-file->buffer) -4785 # var type/ecx : (handle tree type-id) = int -4786 68/push 0/imm32/right/null -4787 68/push 1/imm32/left/int -4788 89/<- %ecx 4/r32/esp -4789 # var var-foo/ecx : var in eax -4790 68/push "eax"/imm32/register -4791 68/push 0/imm32/no-stack-offset -4792 68/push 1/imm32/block-depth -4793 51/push-ecx -4794 68/push "foo"/imm32 -4795 89/<- %ecx 4/r32/esp -4796 # var operand/ebx : (list var) -4797 68/push 0/imm32/next -4798 51/push-ecx/var-foo -4799 89/<- %ebx 4/r32/esp -4800 # var stmt/esi : statement -4801 68/push 0/imm32/next -4802 53/push-ebx/outputs -4803 68/push 0/imm32/inouts -4804 68/push "increment"/imm32/operation -4805 68/push 1/imm32 -4806 89/<- %esi 4/r32/esp -4807 # var formal-var/ebx : var in any register -4808 68/push Any-register/imm32 -4809 68/push 0/imm32/no-stack-offset -4810 68/push 1/imm32/block-depth -4811 ff 6/subop/push *(ecx+4) # Var-type -4812 68/push "dummy"/imm32 -4813 89/<- %ebx 4/r32/esp -4814 # var operand/ebx : (list var) -4815 68/push 0/imm32/next -4816 53/push-ebx/formal-var -4817 89/<- %ebx 4/r32/esp -4818 # var primitives/ebx : primitive -4819 68/push 0/imm32/next -4820 68/push 0/imm32/output-is-write-only -4821 68/push 0/imm32/no-imm32 -4822 68/push 0/imm32/no-r32 -4823 68/push 3/imm32/rm32-in-first-output -4824 68/push "ff 0/subop/increment"/imm32/subx-name -4825 53/push-ebx/outputs -4826 68/push 0/imm32/inouts -4827 68/push "increment"/imm32/name -4828 89/<- %ebx 4/r32/esp -4829 # convert -4830 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -4831 (flush _test-output-buffered-file) -4832 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4838 # check output -4839 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") -4840 # . epilogue -4841 89/<- %esp 5/r32/ebp -4842 5d/pop-to-ebp -4843 c3/return -4844 -4845 test-emit-subx-statement-select-primitive: -4846 # Select the right primitive between overloads. -4847 # foo <- increment -4848 # => -4849 # ff 0/subop/increment %eax # sub-optimal, but should suffice -4850 # -4851 # There's a variable on the var stack as follows: -4852 # name: 'foo' -4853 # type: int -4854 # register: 'eax' -4855 # -4856 # There's two primitives, as follows: -4857 # - name: 'increment' -4858 # out: int/reg -4859 # value: 'ff 0/subop/increment' -4860 # - name: 'increment' -4861 # inout: int/mem -4862 # value: 'ff 0/subop/increment' -4863 # -4864 # There's nothing in functions. -4865 # -4866 # . prologue -4867 55/push-ebp -4868 89/<- %ebp 4/r32/esp -4869 # setup -4870 (clear-stream _test-output-stream) -4871 (clear-stream $_test-output-buffered-file->buffer) -4872 # var type/ecx : (handle tree type-id) = int -4873 68/push 0/imm32/right/null -4874 68/push 1/imm32/left/int -4875 89/<- %ecx 4/r32/esp -4876 # var var-foo/ecx : var in eax -4877 68/push "eax"/imm32/register -4878 68/push 0/imm32/no-stack-offset -4879 68/push 1/imm32/block-depth -4880 51/push-ecx -4881 68/push "foo"/imm32 -4882 89/<- %ecx 4/r32/esp -4883 # var real-outputs/edi : (list var) -4884 68/push 0/imm32/next -4885 51/push-ecx/var-foo -4886 89/<- %edi 4/r32/esp -4887 # var stmt/esi : statement -4888 68/push 0/imm32/next -4889 57/push-edi/outputs -4890 68/push 0/imm32/inouts -4891 68/push "increment"/imm32/operation -4892 68/push 1/imm32 -4893 89/<- %esi 4/r32/esp -4894 # var formal-var/ebx : var in any register -4895 68/push Any-register/imm32 -4896 68/push 0/imm32/no-stack-offset -4897 68/push 1/imm32/block-depth -4898 ff 6/subop/push *(ecx+4) # Var-type -4899 68/push "dummy"/imm32 -4900 89/<- %ebx 4/r32/esp -4901 # var formal-outputs/ebx : (list var) = {formal-var, 0} -4902 68/push 0/imm32/next -4903 53/push-ebx/formal-var -4904 89/<- %ebx 4/r32/esp -4905 # var primitive1/ebx : primitive -4906 68/push 0/imm32/next -4907 68/push 0/imm32/output-is-write-only -4908 68/push 0/imm32/no-imm32 -4909 68/push 0/imm32/no-r32 -4910 68/push 3/imm32/rm32-in-first-output -4911 68/push "ff 0/subop/increment"/imm32/subx-name -4912 53/push-ebx/outputs/formal-outputs -4913 68/push 0/imm32/inouts -4914 68/push "increment"/imm32/name -4915 89/<- %ebx 4/r32/esp -4916 # var primitives/ebx : primitive -4917 53/push-ebx/next -4918 68/push 0/imm32/output-is-write-only -4919 68/push 0/imm32/no-imm32 -4920 68/push 0/imm32/no-r32 -4921 68/push 1/imm32/rm32-is-first-inout -4922 68/push "ff 0/subop/increment"/imm32/subx-name -4923 68/push 0/imm32/outputs -4924 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -4925 68/push "increment"/imm32/name -4926 89/<- %ebx 4/r32/esp -4927 # convert -4928 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -4929 (flush _test-output-buffered-file) -4930 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4936 # check output -4937 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") -4938 # . epilogue -4939 89/<- %esp 5/r32/ebp -4940 5d/pop-to-ebp -4941 c3/return -4942 -4943 test-emit-subx-statement-select-primitive-2: -4944 # Select the right primitive between overloads. -4945 # foo <- increment -4946 # => -4947 # ff 0/subop/increment %eax # sub-optimal, but should suffice -4948 # -4949 # There's a variable on the var stack as follows: -4950 # name: 'foo' -4951 # type: int -4952 # register: 'eax' -4953 # -4954 # There's two primitives, as follows: -4955 # - name: 'increment' -4956 # out: int/reg -4957 # value: 'ff 0/subop/increment' -4958 # - name: 'increment' -4959 # inout: int/mem -4960 # value: 'ff 0/subop/increment' -4961 # -4962 # There's nothing in functions. -4963 # -4964 # . prologue -4965 55/push-ebp -4966 89/<- %ebp 4/r32/esp -4967 # setup -4968 (clear-stream _test-output-stream) -4969 (clear-stream $_test-output-buffered-file->buffer) -4970 # var type/ecx : (handle tree type-id) = int -4971 68/push 0/imm32/right/null -4972 68/push 1/imm32/left/int -4973 89/<- %ecx 4/r32/esp -4974 # var var-foo/ecx : var in eax -4975 68/push "eax"/imm32/register -4976 68/push 0/imm32/no-stack-offset -4977 68/push 1/imm32/block-depth -4978 51/push-ecx -4979 68/push "foo"/imm32 -4980 89/<- %ecx 4/r32/esp -4981 # var inouts/edi : (list var) -4982 68/push 0/imm32/next -4983 51/push-ecx/var-foo -4984 89/<- %edi 4/r32/esp -4985 # var stmt/esi : statement -4986 68/push 0/imm32/next -4987 68/push 0/imm32/outputs -4988 57/push-edi/inouts -4989 68/push "increment"/imm32/operation -4990 68/push 1/imm32 -4991 89/<- %esi 4/r32/esp -4992 # var formal-var/ebx : var in any register -4993 68/push Any-register/imm32 -4994 68/push 0/imm32/no-stack-offset -4995 68/push 1/imm32/block-depth -4996 ff 6/subop/push *(ecx+4) # Var-type -4997 68/push "dummy"/imm32 -4998 89/<- %ebx 4/r32/esp -4999 # var operand/ebx : (list var) -5000 68/push 0/imm32/next -5001 53/push-ebx/formal-var -5002 89/<- %ebx 4/r32/esp -5003 # var primitive1/ebx : primitive -5004 68/push 0/imm32/next -5005 68/push 0/imm32/output-is-write-only -5006 68/push 0/imm32/no-imm32 -5007 68/push 0/imm32/no-r32 -5008 68/push 3/imm32/rm32-in-first-output -5009 68/push "ff 0/subop/increment"/imm32/subx-name -5010 53/push-ebx/outputs/formal-outputs -5011 68/push 0/imm32/inouts -5012 68/push "increment"/imm32/name -5013 89/<- %ebx 4/r32/esp -5014 # var primitives/ebx : primitive -5015 53/push-ebx/next -5016 68/push 0/imm32/output-is-write-only -5017 68/push 0/imm32/no-imm32 -5018 68/push 0/imm32/no-r32 -5019 68/push 1/imm32/rm32-is-first-inout -5020 68/push "ff 0/subop/increment"/imm32/subx-name -5021 68/push 0/imm32/outputs -5022 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -5023 68/push "increment"/imm32/name -5024 89/<- %ebx 4/r32/esp -5025 # convert -5026 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -5027 (flush _test-output-buffered-file) -5028 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5034 # check output -5035 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") -5036 # . epilogue -5037 89/<- %esp 5/r32/ebp -5038 5d/pop-to-ebp -5039 c3/return -5040 -5041 test-increment-register: -5042 # Select the right primitive between overloads. -5043 # foo <- increment -5044 # => -5045 # 50/increment-eax -5046 # -5047 # There's a variable on the var stack as follows: -5048 # name: 'foo' -5049 # type: int -5050 # register: 'eax' -5051 # -5052 # Primitives are the global definitions. -5053 # -5054 # There are no functions defined. -5055 # -5056 # . prologue -5057 55/push-ebp -5058 89/<- %ebp 4/r32/esp -5059 # setup -5060 (clear-stream _test-output-stream) -5061 (clear-stream $_test-output-buffered-file->buffer) -5062 # var type/ecx : (handle tree type-id) = int -5063 68/push 0/imm32/right/null -5064 68/push 1/imm32/left/int -5065 89/<- %ecx 4/r32/esp -5066 # var var-foo/ecx : var in eax -5067 68/push "eax"/imm32/register -5068 68/push 0/imm32/no-stack-offset -5069 68/push 1/imm32/block-depth -5070 51/push-ecx -5071 68/push "foo"/imm32 -5072 89/<- %ecx 4/r32/esp -5073 # var real-outputs/edi : (list var) -5074 68/push 0/imm32/next -5075 51/push-ecx/var-foo -5076 89/<- %edi 4/r32/esp -5077 # var stmt/esi : statement -5078 68/push 0/imm32/next -5079 57/push-edi/outputs -5080 68/push 0/imm32/inouts -5081 68/push "increment"/imm32/operation -5082 68/push 1/imm32/regular-statement -5083 89/<- %esi 4/r32/esp -5084 # convert -5085 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5086 (flush _test-output-buffered-file) -5087 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5093 # check output -5094 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") -5095 # . epilogue -5096 89/<- %esp 5/r32/ebp -5097 5d/pop-to-ebp -5098 c3/return -5099 -5100 test-increment-var: -5101 # Select the right primitive between overloads. -5102 # foo <- increment -5103 # => -5104 # ff 0/subop/increment %eax # sub-optimal, but should suffice -5105 # -5106 # There's a variable on the var stack as follows: -5107 # name: 'foo' -5108 # type: int -5109 # register: 'eax' -5110 # -5111 # Primitives are the global definitions. -5112 # -5113 # There are no functions defined. -5114 # -5115 # . prologue -5116 55/push-ebp -5117 89/<- %ebp 4/r32/esp -5118 # setup -5119 (clear-stream _test-output-stream) -5120 (clear-stream $_test-output-buffered-file->buffer) -5121 # var type/ecx : (handle tree type-id) = int -5122 68/push 0/imm32/right/null -5123 68/push 1/imm32/left/int -5124 89/<- %ecx 4/r32/esp -5125 # var var-foo/ecx : var in eax -5126 68/push "eax"/imm32/register -5127 68/push 0/imm32/no-stack-offset -5128 68/push 1/imm32/block-depth -5129 51/push-ecx -5130 68/push "foo"/imm32 -5131 89/<- %ecx 4/r32/esp -5132 # var inouts/edi : (list var) -5133 68/push 0/imm32/next -5134 51/push-ecx/var-foo -5135 89/<- %edi 4/r32/esp -5136 # var stmt/esi : statement -5137 68/push 0/imm32/next -5138 68/push 0/imm32/outputs -5139 57/push-edi/inouts -5140 68/push "increment"/imm32/operation -5141 68/push 1/imm32 -5142 89/<- %esi 4/r32/esp -5143 # convert -5144 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5145 (flush _test-output-buffered-file) -5146 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5152 # check output -5153 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") -5154 # . epilogue -5155 89/<- %esp 5/r32/ebp -5156 5d/pop-to-ebp -5157 c3/return -5158 -5159 test-add-reg-to-reg: -5160 # var1/reg <- add var2/reg -5161 # => -5162 # 01/add %var1 var2 -5163 # -5164 # . prologue -5165 55/push-ebp -5166 89/<- %ebp 4/r32/esp -5167 # setup -5168 (clear-stream _test-output-stream) -5169 (clear-stream $_test-output-buffered-file->buffer) -5170 # var type/ecx : (handle tree type-id) = int -5171 68/push 0/imm32/right/null -5172 68/push 1/imm32/left/int -5173 89/<- %ecx 4/r32/esp -5174 # var var-var1/ecx : var in eax -5175 68/push "eax"/imm32/register -5176 68/push 0/imm32/no-stack-offset -5177 68/push 1/imm32/block-depth -5178 51/push-ecx -5179 68/push "var1"/imm32 -5180 89/<- %ecx 4/r32/esp -5181 # var var-var2/edx : var in ecx -5182 68/push "ecx"/imm32/register -5183 68/push 0/imm32/no-stack-offset -5184 68/push 1/imm32/block-depth -5185 ff 6/subop/push *(ecx+4) # Var-type -5186 68/push "var2"/imm32 -5187 89/<- %edx 4/r32/esp -5188 # var inouts/esi : (list var2) -5189 68/push 0/imm32/next -5190 52/push-edx/var-var2 -5191 89/<- %esi 4/r32/esp -5192 # var outputs/edi : (list var1) -5193 68/push 0/imm32/next -5194 51/push-ecx/var-var1 -5195 89/<- %edi 4/r32/esp -5196 # var stmt/esi : statement -5197 68/push 0/imm32/next -5198 57/push-edi/outputs -5199 56/push-esi/inouts -5200 68/push "add"/imm32/operation -5201 68/push 1/imm32 -5202 89/<- %esi 4/r32/esp -5203 # convert -5204 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5205 (flush _test-output-buffered-file) -5206 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5212 # check output -5213 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") -5214 # . epilogue -5215 89/<- %esp 5/r32/ebp -5216 5d/pop-to-ebp -5217 c3/return -5218 -5219 test-add-reg-to-mem: -5220 # add-to var1 var2/reg -5221 # => -5222 # 01/add *(ebp+__) var2 -5223 # -5224 # . prologue -5225 55/push-ebp -5226 89/<- %ebp 4/r32/esp -5227 # setup -5228 (clear-stream _test-output-stream) -5229 (clear-stream $_test-output-buffered-file->buffer) -5230 # var type/ecx : (handle tree type-id) = int -5231 68/push 0/imm32/right/null -5232 68/push 1/imm32/left/int -5233 89/<- %ecx 4/r32/esp -5234 # var var-var1/ecx : var -5235 68/push 0/imm32/no-register -5236 68/push 8/imm32/stack-offset -5237 68/push 1/imm32/block-depth -5238 51/push-ecx -5239 68/push "var1"/imm32 -5240 89/<- %ecx 4/r32/esp -5241 # var var-var2/edx : var in ecx -5242 68/push "ecx"/imm32/register -5243 68/push 0/imm32/no-stack-offset -5244 68/push 1/imm32/block-depth -5245 ff 6/subop/push *(ecx+4) # Var-type -5246 68/push "var2"/imm32 -5247 89/<- %edx 4/r32/esp -5248 # var inouts/esi : (list var2) -5249 68/push 0/imm32/next -5250 52/push-edx/var-var2 -5251 89/<- %esi 4/r32/esp -5252 # var inouts = (list var1 var2) -5253 56/push-esi/next -5254 51/push-ecx/var-var1 -5255 89/<- %esi 4/r32/esp -5256 # var stmt/esi : statement -5257 68/push 0/imm32/next +4721 # var curr/ecx : (handle function) = functions +4722 8b/-> *(ebp+8) 1/r32/ecx +4723 { +4724 # if (curr == null) break +4725 81 7/subop/compare %ecx 0/imm32 +4726 74/jump-if-= break/disp8 +4727 # if match(stmt, curr) return curr +4728 { +4729 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax +4730 3d/compare-eax-and 0/imm32 +4731 74/jump-if-= break/disp8 +4732 89/<- %eax 1/r32/ecx +4733 eb/jump $find-matching-function:end/disp8 +4734 } +4735 # curr = curr->next +4736 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +4737 eb/jump loop/disp8 +4738 } +4739 # return null +4740 b8/copy-to-eax 0/imm32 +4741 $find-matching-function:end: +4742 # . restore registers +4743 59/pop-to-ecx +4744 # . epilogue +4745 89/<- %esp 5/r32/ebp +4746 5d/pop-to-ebp +4747 c3/return +4748 +4749 find-matching-primitive: # primitives : (handle primitive), stmt : (handle statement) -> result/eax : (handle primitive) +4750 # . prologue +4751 55/push-ebp +4752 89/<- %ebp 4/r32/esp +4753 # . save registers +4754 51/push-ecx +4755 # var curr/ecx : (handle primitive) = primitives +4756 8b/-> *(ebp+8) 1/r32/ecx +4757 { +4758 $find-matching-primitive:loop: +4759 # if (curr == null) break +4760 81 7/subop/compare %ecx 0/imm32 +4761 0f 84/jump-if-= break/disp32 +4762 #? (write-buffered Stderr "prim: ") +4763 #? (write-buffered Stderr *ecx) # Primitive-name +4764 #? (write-buffered Stderr " => ") +4765 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name +4766 #? (write-buffered Stderr "\n") +4767 #? (flush Stderr) +4768 # if match(curr, stmt) return curr +4769 { +4770 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax +4771 3d/compare-eax-and 0/imm32 +4772 74/jump-if-= break/disp8 +4773 89/<- %eax 1/r32/ecx +4774 eb/jump $find-matching-primitive:end/disp8 +4775 } +4776 $find-matching-primitive:next-primitive: +4777 # curr = curr->next +4778 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next +4779 e9/jump loop/disp32 +4780 } +4781 # return null +4782 b8/copy-to-eax 0/imm32 +4783 $find-matching-primitive:end: +4784 # . restore registers +4785 59/pop-to-ecx +4786 # . epilogue +4787 89/<- %esp 5/r32/ebp +4788 5d/pop-to-ebp +4789 c3/return +4790 +4791 mu-stmt-matches-function?: # stmt : (handle statement), function : (handle function) => result/eax : boolean +4792 # . prologue +4793 55/push-ebp +4794 89/<- %ebp 4/r32/esp +4795 # . save registers +4796 51/push-ecx +4797 # return function->name == stmt->operation +4798 8b/-> *(ebp+8) 1/r32/ecx +4799 8b/-> *(ebp+0xc) 0/r32/eax +4800 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax +4801 $mu-stmt-matches-function?:end: +4802 # . restore registers +4803 59/pop-to-ecx +4804 # . epilogue +4805 89/<- %esp 5/r32/ebp +4806 5d/pop-to-ebp +4807 c3/return +4808 +4809 mu-stmt-matches-primitive?: # stmt : (handle statement), primitive : (handle primitive) => result/eax : boolean +4810 # A mu stmt matches a primitive if the name matches, all the inout vars +4811 # match, and all the output vars match. +4812 # Vars match if types match and registers match. +4813 # In addition, a stmt output matches a primitive's output if types match +4814 # and the primitive has a wildcard register. +4815 # . prologue +4816 55/push-ebp +4817 89/<- %ebp 4/r32/esp +4818 # . save registers +4819 51/push-ecx +4820 52/push-edx +4821 53/push-ebx +4822 56/push-esi +4823 57/push-edi +4824 # ecx = stmt +4825 8b/-> *(ebp+8) 1/r32/ecx +4826 # edx = primitive +4827 8b/-> *(ebp+0xc) 2/r32/edx +4828 { +4829 $mu-stmt-matches-primitive?:check-name: +4830 # if (primitive->name != stmt->operation) return false +4831 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax +4832 3d/compare-eax-and 0/imm32 +4833 75/jump-if-!= break/disp8 +4834 b8/copy-to-eax 0/imm32 +4835 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4836 } +4837 $mu-stmt-matches-primitive?:check-inouts: +4838 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) +4839 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts +4840 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts +4841 { +4842 # if (curr == 0 && curr2 == 0) move on to check outputs +4843 { +4844 81 7/subop/compare %esi 0/imm32 +4845 75/jump-if-!= break/disp8 +4846 $mu-stmt-matches-primitive?:stmt-inout-is-null: +4847 { +4848 81 7/subop/compare %edi 0/imm32 +4849 75/jump-if-!= break/disp8 +4850 # +4851 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 +4852 } +4853 # return false +4854 b8/copy-to-eax 0/imm32/false +4855 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4856 } +4857 # if (curr2 == 0) return false +4858 { +4859 81 7/subop/compare %edi 0/imm32 +4860 75/jump-if-!= break/disp8 +4861 $mu-stmt-matches-primitive?:prim-inout-is-null: +4862 b8/copy-to-eax 0/imm32/false +4863 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4864 } +4865 # if (curr != curr2) return false +4866 { +4867 (operand-matches-primitive? *esi *edi) # => eax +4868 3d/compare-eax-and 0/imm32 +4869 75/jump-if-!= break/disp8 +4870 b8/copy-to-eax 0/imm32/false +4871 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4872 } +4873 # curr=curr->next +4874 8b/-> *(esi+4) 6/r32/esi # Operand-next +4875 # curr2=curr2->next +4876 8b/-> *(edi+4) 7/r32/edi # Operand-next +4877 eb/jump loop/disp8 +4878 } +4879 $mu-stmt-matches-primitive?:check-outputs: +4880 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) +4881 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs +4882 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs +4883 { +4884 # if (curr == 0) return (curr2 == 0) +4885 { +4886 $mu-stmt-matches-primitive?:check-output: +4887 81 7/subop/compare %esi 0/imm32 +4888 75/jump-if-!= break/disp8 +4889 { +4890 81 7/subop/compare %edi 0/imm32 +4891 75/jump-if-!= break/disp8 +4892 # return true +4893 b8/copy-to-eax 1/imm32 +4894 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4895 } +4896 # return false +4897 b8/copy-to-eax 0/imm32 +4898 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4899 } +4900 # if (curr2 == 0) return false +4901 { +4902 81 7/subop/compare %edi 0/imm32 +4903 75/jump-if-!= break/disp8 +4904 b8/copy-to-eax 0/imm32 +4905 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4906 } +4907 # if (curr != curr2) return false +4908 { +4909 (operand-matches-primitive? *esi *edi) # List-value List-value => eax +4910 3d/compare-eax-and 0/imm32 +4911 75/jump-if-!= break/disp8 +4912 b8/copy-to-eax 0/imm32 +4913 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4914 } +4915 # curr=curr->next +4916 8b/-> *(esi+4) 6/r32/esi # Operand-next +4917 # curr2=curr2->next +4918 8b/-> *(edi+4) 7/r32/edi # Operand-next +4919 eb/jump loop/disp8 +4920 } +4921 $mu-stmt-matches-primitive?:return-true: +4922 b8/copy-to-eax 1/imm32 +4923 $mu-stmt-matches-primitive?:end: +4924 # . restore registers +4925 5f/pop-to-edi +4926 5e/pop-to-esi +4927 5b/pop-to-ebx +4928 5a/pop-to-edx +4929 59/pop-to-ecx +4930 # . epilogue +4931 89/<- %esp 5/r32/ebp +4932 5d/pop-to-ebp +4933 c3/return +4934 +4935 operand-matches-primitive?: # var : (handle var), prim-var : (handle var) => result/eax : boolean +4936 # . prologue +4937 55/push-ebp +4938 89/<- %ebp 4/r32/esp +4939 # . save registers +4940 56/push-esi +4941 57/push-edi +4942 # esi = var +4943 8b/-> *(ebp+8) 6/r32/esi +4944 # edi = prim-var +4945 8b/-> *(ebp+0xc) 7/r32/edi +4946 # if (var->type != prim-var->type) return false +4947 (type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax +4948 3d/compare-eax-and 0/imm32 +4949 b8/copy-to-eax 0/imm32/false +4950 74/jump-if-= $operand-matches-primitive?:end/disp8 +4951 # return false if var->register doesn't match prim-var->register +4952 { +4953 # if addresses are equal, don't return here +4954 8b/-> *(esi+0x10) 0/r32/eax +4955 39/compare *(edi+0x10) 0/r32/eax +4956 74/jump-if-= break/disp8 +4957 # if either address is 0, return false +4958 3d/compare-eax-and 0/imm32 +4959 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +4960 81 7/subop/compare *(edi+0x10) 0/imm32 +4961 74/jump-if-= $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +4962 # if prim-var->register is "*", return true +4963 (string-equal? *(edi+0x10) "*") # Var-register +4964 3d/compare-eax-and 0/imm32 +4965 b8/copy-to-eax 1/imm32/true +4966 75/jump-if-!= $operand-matches-primitive?:end/disp8 +4967 # if string contents don't match, return false +4968 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register +4969 3d/compare-eax-and 0/imm32 +4970 b8/copy-to-eax 0/imm32/false +4971 74/jump-if-= $operand-matches-primitive?:end/disp8 +4972 } +4973 # return true +4974 b8/copy-to-eax 1/imm32/true +4975 $operand-matches-primitive?:end: +4976 # . restore registers +4977 5f/pop-to-edi +4978 5e/pop-to-esi +4979 # . epilogue +4980 89/<- %esp 5/r32/ebp +4981 5d/pop-to-ebp +4982 c3/return +4983 +4984 type-equal?: # a : (handle tree type-id), b : (handle tree type-id) => result/eax : boolean +4985 # . prologue +4986 55/push-ebp +4987 89/<- %ebp 4/r32/esp +4988 # . save registers +4989 51/push-ecx +4990 52/push-edx +4991 # ecx = a +4992 8b/-> *(ebp+8) 1/r32/ecx +4993 # edx = b +4994 8b/-> *(ebp+0xc) 2/r32/edx +4995 # if (a == b) return true +4996 8b/-> %ecx 0/r32/eax # Var-type +4997 39/compare %edx 0/r32/eax # Var-type +4998 b8/copy-to-eax 1/imm32/true +4999 74/jump-if-= $type-equal?:end/disp8 +5000 # if (a < MAX_TYPE_ID) return false +5001 81 7/subop/compare %ecx 0x10000/imm32 +5002 b8/copy-to-eax 0/imm32/false +5003 72/jump-if-addr< $type-equal?:end/disp8 +5004 # if (b < MAX_TYPE_ID) return false +5005 81 7/subop/compare %edx 0x10000/imm32 +5006 b8/copy-to-eax 0/imm32/false +5007 72/jump-if-addr< $type-equal?:end/disp8 +5008 # if (!type-equal?(a->left, b->left)) return false +5009 (type-equal? *ecx *edx) # Tree-left, Tree-left => eax +5010 3d/compare-eax-and 0/imm32 +5011 74/jump-if-= $type-equal?:end/disp8 +5012 # return type-equal?(a->right, b->right) +5013 (type-equal? *(ecx+4) *(edx+4)) # Tree-right, Tree-right => eax +5014 $type-equal?:end: +5015 # . restore registers +5016 5a/pop-to-edx +5017 59/pop-to-ecx +5018 # . epilogue +5019 89/<- %esp 5/r32/ebp +5020 5d/pop-to-ebp +5021 c3/return +5022 +5023 test-emit-subx-statement-primitive: +5024 # Primitive operation on a variable on the stack. +5025 # increment foo +5026 # => +5027 # ff 0/subop/increment *(ebp-8) +5028 # +5029 # There's a variable on the var stack as follows: +5030 # name: 'foo' +5031 # type: int +5032 # stack-offset: -8 +5033 # +5034 # There's a primitive with this info: +5035 # name: 'increment' +5036 # inouts: int/mem +5037 # value: 'ff 0/subop/increment' +5038 # +5039 # There's nothing in functions. +5040 # +5041 # . prologue +5042 55/push-ebp +5043 89/<- %ebp 4/r32/esp +5044 # setup +5045 (clear-stream _test-output-stream) +5046 (clear-stream $_test-output-buffered-file->buffer) +5047 # var type/ecx : (handle tree type-id) = int +5048 68/push 0/imm32/right/null +5049 68/push 1/imm32/left/int +5050 89/<- %ecx 4/r32/esp +5051 # var var-foo/ecx : var +5052 68/push 0/imm32/no-register +5053 68/push -8/imm32/stack-offset +5054 68/push 1/imm32/block-depth +5055 51/push-ecx +5056 68/push "foo"/imm32 +5057 89/<- %ecx 4/r32/esp +5058 # var operand/ebx : (list var) +5059 68/push 0/imm32/next +5060 51/push-ecx/var-foo +5061 89/<- %ebx 4/r32/esp +5062 # var stmt/esi : statement +5063 68/push 0/imm32/next +5064 68/push 0/imm32/outputs +5065 53/push-ebx/operands +5066 68/push "increment"/imm32/operation +5067 68/push 1/imm32 +5068 89/<- %esi 4/r32/esp +5069 # var primitives/ebx : primitive +5070 68/push 0/imm32/next +5071 68/push 0/imm32/output-is-write-only +5072 68/push 0/imm32/no-imm32 +5073 68/push 0/imm32/no-r32 +5074 68/push 1/imm32/rm32-is-first-inout +5075 68/push "ff 0/subop/increment"/imm32/subx-name +5076 68/push 0/imm32/outputs +5077 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call +5078 68/push "increment"/imm32/name +5079 89/<- %ebx 4/r32/esp +5080 # convert +5081 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5082 (flush _test-output-buffered-file) +5083 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5089 # check output +5090 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") +5091 # . epilogue +5092 89/<- %esp 5/r32/ebp +5093 5d/pop-to-ebp +5094 c3/return +5095 +5096 test-emit-subx-statement-primitive-register: +5097 # Primitive operation on a variable in a register. +5098 # foo <- increment +5099 # => +5100 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5101 # +5102 # There's a variable on the var stack as follows: +5103 # name: 'foo' +5104 # type: int +5105 # register: 'eax' +5106 # +5107 # There's a primitive with this info: +5108 # name: 'increment' +5109 # out: int/reg +5110 # value: 'ff 0/subop/increment' +5111 # +5112 # There's nothing in functions. +5113 # +5114 # . prologue +5115 55/push-ebp +5116 89/<- %ebp 4/r32/esp +5117 # setup +5118 (clear-stream _test-output-stream) +5119 (clear-stream $_test-output-buffered-file->buffer) +5120 # var type/ecx : (handle tree type-id) = int +5121 68/push 0/imm32/right/null +5122 68/push 1/imm32/left/int +5123 89/<- %ecx 4/r32/esp +5124 # var var-foo/ecx : var in eax +5125 68/push "eax"/imm32/register +5126 68/push 0/imm32/no-stack-offset +5127 68/push 1/imm32/block-depth +5128 51/push-ecx +5129 68/push "foo"/imm32 +5130 89/<- %ecx 4/r32/esp +5131 # var operand/ebx : (list var) +5132 68/push 0/imm32/next +5133 51/push-ecx/var-foo +5134 89/<- %ebx 4/r32/esp +5135 # var stmt/esi : statement +5136 68/push 0/imm32/next +5137 53/push-ebx/outputs +5138 68/push 0/imm32/inouts +5139 68/push "increment"/imm32/operation +5140 68/push 1/imm32 +5141 89/<- %esi 4/r32/esp +5142 # var formal-var/ebx : var in any register +5143 68/push Any-register/imm32 +5144 68/push 0/imm32/no-stack-offset +5145 68/push 1/imm32/block-depth +5146 ff 6/subop/push *(ecx+4) # Var-type +5147 68/push "dummy"/imm32 +5148 89/<- %ebx 4/r32/esp +5149 # var operand/ebx : (list var) +5150 68/push 0/imm32/next +5151 53/push-ebx/formal-var +5152 89/<- %ebx 4/r32/esp +5153 # var primitives/ebx : primitive +5154 68/push 0/imm32/next +5155 68/push 0/imm32/output-is-write-only +5156 68/push 0/imm32/no-imm32 +5157 68/push 0/imm32/no-r32 +5158 68/push 3/imm32/rm32-in-first-output +5159 68/push "ff 0/subop/increment"/imm32/subx-name +5160 53/push-ebx/outputs +5161 68/push 0/imm32/inouts +5162 68/push "increment"/imm32/name +5163 89/<- %ebx 4/r32/esp +5164 # convert +5165 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5166 (flush _test-output-buffered-file) +5167 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5173 # check output +5174 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") +5175 # . epilogue +5176 89/<- %esp 5/r32/ebp +5177 5d/pop-to-ebp +5178 c3/return +5179 +5180 test-emit-subx-statement-select-primitive: +5181 # Select the right primitive between overloads. +5182 # foo <- increment +5183 # => +5184 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5185 # +5186 # There's a variable on the var stack as follows: +5187 # name: 'foo' +5188 # type: int +5189 # register: 'eax' +5190 # +5191 # There's two primitives, as follows: +5192 # - name: 'increment' +5193 # out: int/reg +5194 # value: 'ff 0/subop/increment' +5195 # - name: 'increment' +5196 # inout: int/mem +5197 # value: 'ff 0/subop/increment' +5198 # +5199 # There's nothing in functions. +5200 # +5201 # . prologue +5202 55/push-ebp +5203 89/<- %ebp 4/r32/esp +5204 # setup +5205 (clear-stream _test-output-stream) +5206 (clear-stream $_test-output-buffered-file->buffer) +5207 # var type/ecx : (handle tree type-id) = int +5208 68/push 0/imm32/right/null +5209 68/push 1/imm32/left/int +5210 89/<- %ecx 4/r32/esp +5211 # var var-foo/ecx : var in eax +5212 68/push "eax"/imm32/register +5213 68/push 0/imm32/no-stack-offset +5214 68/push 1/imm32/block-depth +5215 51/push-ecx +5216 68/push "foo"/imm32 +5217 89/<- %ecx 4/r32/esp +5218 # var real-outputs/edi : (list var) +5219 68/push 0/imm32/next +5220 51/push-ecx/var-foo +5221 89/<- %edi 4/r32/esp +5222 # var stmt/esi : statement +5223 68/push 0/imm32/next +5224 57/push-edi/outputs +5225 68/push 0/imm32/inouts +5226 68/push "increment"/imm32/operation +5227 68/push 1/imm32 +5228 89/<- %esi 4/r32/esp +5229 # var formal-var/ebx : var in any register +5230 68/push Any-register/imm32 +5231 68/push 0/imm32/no-stack-offset +5232 68/push 1/imm32/block-depth +5233 ff 6/subop/push *(ecx+4) # Var-type +5234 68/push "dummy"/imm32 +5235 89/<- %ebx 4/r32/esp +5236 # var formal-outputs/ebx : (list var) = {formal-var, 0} +5237 68/push 0/imm32/next +5238 53/push-ebx/formal-var +5239 89/<- %ebx 4/r32/esp +5240 # var primitive1/ebx : primitive +5241 68/push 0/imm32/next +5242 68/push 0/imm32/output-is-write-only +5243 68/push 0/imm32/no-imm32 +5244 68/push 0/imm32/no-r32 +5245 68/push 3/imm32/rm32-in-first-output +5246 68/push "ff 0/subop/increment"/imm32/subx-name +5247 53/push-ebx/outputs/formal-outputs +5248 68/push 0/imm32/inouts +5249 68/push "increment"/imm32/name +5250 89/<- %ebx 4/r32/esp +5251 # var primitives/ebx : primitive +5252 53/push-ebx/next +5253 68/push 0/imm32/output-is-write-only +5254 68/push 0/imm32/no-imm32 +5255 68/push 0/imm32/no-r32 +5256 68/push 1/imm32/rm32-is-first-inout +5257 68/push "ff 0/subop/increment"/imm32/subx-name 5258 68/push 0/imm32/outputs -5259 56/push-esi/inouts -5260 68/push "add-to"/imm32/operation -5261 68/push 1/imm32 -5262 89/<- %esi 4/r32/esp -5263 # convert -5264 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5265 (flush _test-output-buffered-file) -5266 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5272 # check output -5273 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") -5274 # . epilogue -5275 89/<- %esp 5/r32/ebp -5276 5d/pop-to-ebp -5277 c3/return -5278 -5279 test-add-mem-to-reg: -5280 # var1/reg <- add var2 +5259 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +5260 68/push "increment"/imm32/name +5261 89/<- %ebx 4/r32/esp +5262 # convert +5263 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5264 (flush _test-output-buffered-file) +5265 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5271 # check output +5272 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") +5273 # . epilogue +5274 89/<- %esp 5/r32/ebp +5275 5d/pop-to-ebp +5276 c3/return +5277 +5278 test-emit-subx-statement-select-primitive-2: +5279 # Select the right primitive between overloads. +5280 # foo <- increment 5281 # => -5282 # 03/add *(ebp+__) var1 +5282 # ff 0/subop/increment %eax # sub-optimal, but should suffice 5283 # -5284 # . prologue -5285 55/push-ebp -5286 89/<- %ebp 4/r32/esp -5287 # setup -5288 (clear-stream _test-output-stream) -5289 (clear-stream $_test-output-buffered-file->buffer) -5290 # var type/ecx : (handle tree type-id) = int -5291 68/push 0/imm32/right/null -5292 68/push 1/imm32/left/int -5293 89/<- %ecx 4/r32/esp -5294 # var var-var1/ecx : var in eax -5295 68/push "eax"/imm32/register -5296 68/push 0/imm32/no-stack-offset -5297 68/push 1/imm32/block-depth -5298 51/push-ecx -5299 68/push "var1"/imm32 -5300 89/<- %ecx 4/r32/esp -5301 # var var-var2/edx : var -5302 68/push 0/imm32/no-register -5303 68/push 8/imm32/stack-offset -5304 68/push 1/imm32/block-depth -5305 ff 6/subop/push *(ecx+4) # Var-type -5306 68/push "var2"/imm32 -5307 89/<- %edx 4/r32/esp -5308 # var inouts/esi : (list var2) -5309 68/push 0/imm32/next -5310 52/push-edx/var-var2 -5311 89/<- %esi 4/r32/esp -5312 # var outputs/edi : (list var1) -5313 68/push 0/imm32/next -5314 51/push-ecx/var-var1 -5315 89/<- %edi 4/r32/esp -5316 # var stmt/esi : statement +5284 # There's a variable on the var stack as follows: +5285 # name: 'foo' +5286 # type: int +5287 # register: 'eax' +5288 # +5289 # There's two primitives, as follows: +5290 # - name: 'increment' +5291 # out: int/reg +5292 # value: 'ff 0/subop/increment' +5293 # - name: 'increment' +5294 # inout: int/mem +5295 # value: 'ff 0/subop/increment' +5296 # +5297 # There's nothing in functions. +5298 # +5299 # . prologue +5300 55/push-ebp +5301 89/<- %ebp 4/r32/esp +5302 # setup +5303 (clear-stream _test-output-stream) +5304 (clear-stream $_test-output-buffered-file->buffer) +5305 # var type/ecx : (handle tree type-id) = int +5306 68/push 0/imm32/right/null +5307 68/push 1/imm32/left/int +5308 89/<- %ecx 4/r32/esp +5309 # var var-foo/ecx : var in eax +5310 68/push "eax"/imm32/register +5311 68/push 0/imm32/no-stack-offset +5312 68/push 1/imm32/block-depth +5313 51/push-ecx +5314 68/push "foo"/imm32 +5315 89/<- %ecx 4/r32/esp +5316 # var inouts/edi : (list var) 5317 68/push 0/imm32/next -5318 57/push-edi/outputs -5319 56/push-esi/inouts -5320 68/push "add"/imm32/operation -5321 68/push 1/imm32 -5322 89/<- %esi 4/r32/esp -5323 # convert -5324 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5325 (flush _test-output-buffered-file) -5326 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5332 # check output -5333 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") -5334 # . epilogue -5335 89/<- %esp 5/r32/ebp -5336 5d/pop-to-ebp -5337 c3/return -5338 -5339 test-add-literal-to-eax: -5340 # var1/eax <- add 0x34 -5341 # => -5342 # 05/add-to-eax 0x34/imm32 -5343 # -5344 # . prologue -5345 55/push-ebp -5346 89/<- %ebp 4/r32/esp -5347 # setup -5348 (clear-stream _test-output-stream) -5349 (clear-stream $_test-output-buffered-file->buffer) -5350 # var type/ecx : (handle tree type-id) = int -5351 68/push 0/imm32/right/null -5352 68/push 1/imm32/left/int -5353 89/<- %ecx 4/r32/esp -5354 # var var-var1/ecx : var in eax -5355 68/push "eax"/imm32/register -5356 68/push 0/imm32/no-stack-offset -5357 68/push 1/imm32/block-depth -5358 51/push-ecx -5359 68/push "var1"/imm32 -5360 89/<- %ecx 4/r32/esp -5361 # var type/edx : (handle tree type-id) = literal -5362 68/push 0/imm32/right/null -5363 68/push 0/imm32/left/literal -5364 89/<- %edx 4/r32/esp -5365 # var var-var2/edx : var literal -5366 68/push 0/imm32/no-register -5367 68/push 0/imm32/no-stack-offset -5368 68/push 1/imm32/block-depth -5369 52/push-edx -5370 68/push "0x34"/imm32 -5371 89/<- %edx 4/r32/esp -5372 # var inouts/esi : (list var2) -5373 68/push 0/imm32/next -5374 52/push-edx/var-var2 -5375 89/<- %esi 4/r32/esp -5376 # var outputs/edi : (list var1) -5377 68/push 0/imm32/next -5378 51/push-ecx/var-var1 -5379 89/<- %edi 4/r32/esp -5380 # var stmt/esi : statement -5381 68/push 0/imm32/next -5382 57/push-edi/outputs -5383 56/push-esi/inouts -5384 68/push "add"/imm32/operation -5385 68/push 1/imm32 -5386 89/<- %esi 4/r32/esp -5387 # convert -5388 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5389 (flush _test-output-buffered-file) -5390 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5396 # check output -5397 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") -5398 # . epilogue -5399 89/<- %esp 5/r32/ebp -5400 5d/pop-to-ebp -5401 c3/return -5402 -5403 test-add-literal-to-reg: -5404 # var1/ecx <- add 0x34 -5405 # => -5406 # 81 0/subop/add %ecx 0x34/imm32 -5407 # -5408 # . prologue -5409 55/push-ebp -5410 89/<- %ebp 4/r32/esp -5411 # setup -5412 (clear-stream _test-output-stream) -5413 (clear-stream $_test-output-buffered-file->buffer) -5414 # var type/ecx : (handle tree type-id) = int -5415 68/push 0/imm32/right/null -5416 68/push 1/imm32/left/int -5417 89/<- %ecx 4/r32/esp -5418 # var var-var1/ecx : var in ecx -5419 68/push "ecx"/imm32/register -5420 68/push 0/imm32/no-stack-offset -5421 68/push 1/imm32/block-depth -5422 51/push-ecx -5423 68/push "var1"/imm32 -5424 89/<- %ecx 4/r32/esp -5425 # var type/edx : (handle tree type-id) = literal -5426 68/push 0/imm32/right/null -5427 68/push 0/imm32/left/literal -5428 89/<- %edx 4/r32/esp -5429 # var var-var2/edx : var literal -5430 68/push 0/imm32/no-register -5431 68/push 0/imm32/no-stack-offset -5432 68/push 1/imm32/block-depth -5433 52/push-edx -5434 68/push "0x34"/imm32 -5435 89/<- %edx 4/r32/esp -5436 # var inouts/esi : (list var2) -5437 68/push 0/imm32/next -5438 52/push-edx/var-var2 -5439 89/<- %esi 4/r32/esp -5440 # var outputs/edi : (list var1) -5441 68/push 0/imm32/next -5442 51/push-ecx/var-var1 -5443 89/<- %edi 4/r32/esp -5444 # var stmt/esi : statement -5445 68/push 0/imm32/next -5446 57/push-edi/outputs -5447 56/push-esi/inouts -5448 68/push "add"/imm32/operation -5449 68/push 1/imm32 -5450 89/<- %esi 4/r32/esp -5451 # convert -5452 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5453 (flush _test-output-buffered-file) -5454 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5460 # check output -5461 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") -5462 # . epilogue -5463 89/<- %esp 5/r32/ebp -5464 5d/pop-to-ebp -5465 c3/return -5466 -5467 test-add-literal-to-mem: -5468 # add-to var1, 0x34 -5469 # => -5470 # 81 0/subop/add %eax 0x34/imm32 -5471 # -5472 # . prologue -5473 55/push-ebp -5474 89/<- %ebp 4/r32/esp -5475 # setup -5476 (clear-stream _test-output-stream) -5477 (clear-stream $_test-output-buffered-file->buffer) -5478 # var type/ecx : (handle tree type-id) = int -5479 68/push 0/imm32/right/null -5480 68/push 1/imm32/left/int -5481 89/<- %ecx 4/r32/esp -5482 # var var-var1/ecx : var -5483 68/push 0/imm32/no-register -5484 68/push 8/imm32/stack-offset -5485 68/push 1/imm32/block-depth -5486 51/push-ecx -5487 68/push "var1"/imm32 -5488 89/<- %ecx 4/r32/esp -5489 # var type/edx : (handle tree type-id) = literal -5490 68/push 0/imm32/right/null -5491 68/push 0/imm32/left/literal -5492 89/<- %edx 4/r32/esp -5493 # var var-var2/edx : var literal -5494 68/push 0/imm32/no-register -5495 68/push 0/imm32/no-stack-offset -5496 68/push 1/imm32/block-depth -5497 52/push-edx -5498 68/push "0x34"/imm32 -5499 89/<- %edx 4/r32/esp -5500 # var inouts/esi : (list var2) -5501 68/push 0/imm32/next -5502 52/push-edx/var-var2 -5503 89/<- %esi 4/r32/esp -5504 # var inouts = (list var1 inouts) -5505 56/push-esi/next -5506 51/push-ecx/var-var1 -5507 89/<- %esi 4/r32/esp -5508 # var stmt/esi : statement -5509 68/push 0/imm32/next -5510 68/push 0/imm32/outputs -5511 56/push-esi/inouts -5512 68/push "add-to"/imm32/operation -5513 68/push 1/imm32 -5514 89/<- %esi 4/r32/esp -5515 # convert -5516 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5517 (flush _test-output-buffered-file) -5518 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5524 # check output -5525 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") -5526 # . epilogue -5527 89/<- %esp 5/r32/ebp -5528 5d/pop-to-ebp -5529 c3/return -5530 -5531 test-emit-subx-statement-function-call: -5532 # Call a function on a variable on the stack. -5533 # f foo -5534 # => -5535 # (f2 *(ebp-8)) -5536 # (Changing the function name supports overloading in general, but here it -5537 # just serves to help disambiguate things.) -5538 # -5539 # There's a variable on the var stack as follows: -5540 # name: 'foo' -5541 # type: int -5542 # stack-offset: -8 -5543 # -5544 # There's nothing in primitives. -5545 # -5546 # There's a function with this info: -5547 # name: 'f' -5548 # inout: int/mem -5549 # value: 'f2' -5550 # -5551 # . prologue -5552 55/push-ebp -5553 89/<- %ebp 4/r32/esp -5554 # setup -5555 (clear-stream _test-output-stream) -5556 (clear-stream $_test-output-buffered-file->buffer) -5557 # var type/ecx : (handle tree type-id) = int -5558 68/push 0/imm32/right/null -5559 68/push 1/imm32/left/int -5560 89/<- %ecx 4/r32/esp -5561 # var var-foo/ecx : var -5562 68/push 0/imm32/no-register -5563 68/push -8/imm32/stack-offset -5564 68/push 0/imm32/block-depth -5565 51/push-ecx -5566 68/push "foo"/imm32 -5567 89/<- %ecx 4/r32/esp -5568 # var operands/esi : (list var) -5569 68/push 0/imm32/next -5570 51/push-ecx/var-foo -5571 89/<- %esi 4/r32/esp -5572 # var stmt/esi : statement -5573 68/push 0/imm32/next -5574 68/push 0/imm32/outputs -5575 56/push-esi/inouts -5576 68/push "f"/imm32/operation -5577 68/push 1/imm32 -5578 89/<- %esi 4/r32/esp -5579 # var functions/ebx : function -5580 68/push 0/imm32/next -5581 68/push 0/imm32/body -5582 68/push 0/imm32/outputs -5583 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -5584 68/push "f2"/imm32/subx-name -5585 68/push "f"/imm32/name -5586 89/<- %ebx 4/r32/esp -5587 # convert -5588 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -5589 (flush _test-output-buffered-file) -5590 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5596 # check output -5597 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") -5598 # . epilogue -5599 89/<- %esp 5/r32/ebp -5600 5d/pop-to-ebp -5601 c3/return -5602 -5603 test-emit-subx-statement-function-call-with-literal-arg: -5604 # Call a function on a literal. -5605 # f 34 -5606 # => -5607 # (f2 34) -5608 # -5609 # . prologue -5610 55/push-ebp -5611 89/<- %ebp 4/r32/esp -5612 # setup -5613 (clear-stream _test-output-stream) -5614 (clear-stream $_test-output-buffered-file->buffer) -5615 # var type/ecx : (handle tree type-id) = literal -5616 68/push 0/imm32/right/null -5617 68/push 0/imm32/left/literal -5618 89/<- %ecx 4/r32/esp -5619 # var var-foo/ecx : var literal -5620 68/push 0/imm32/no-register -5621 68/push 0/imm32/no-stack-offset -5622 68/push 0/imm32/block-depth -5623 51/push-ecx -5624 68/push "34"/imm32 -5625 89/<- %ecx 4/r32/esp -5626 # var operands/esi : (list var) -5627 68/push 0/imm32/next -5628 51/push-ecx/var-foo -5629 89/<- %esi 4/r32/esp -5630 # var stmt/esi : statement -5631 68/push 0/imm32/next -5632 68/push 0/imm32/outputs -5633 56/push-esi/inouts -5634 68/push "f"/imm32/operation -5635 68/push 1/imm32 -5636 89/<- %esi 4/r32/esp -5637 # var functions/ebx : function -5638 68/push 0/imm32/next -5639 68/push 0/imm32/body -5640 68/push 0/imm32/outputs -5641 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -5642 68/push "f2"/imm32/subx-name -5643 68/push "f"/imm32/name -5644 89/<- %ebx 4/r32/esp -5645 # convert -5646 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -5647 (flush _test-output-buffered-file) -5648 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5654 # check output -5655 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") -5656 # . epilogue -5657 89/<- %esp 5/r32/ebp -5658 5d/pop-to-ebp -5659 c3/return -5660 -5661 emit-subx-prologue: # out : (addr buffered-file) -5662 # . prologue -5663 55/push-ebp -5664 89/<- %ebp 4/r32/esp -5665 # -5666 (write-buffered *(ebp+8) "# . prologue\n") -5667 (write-buffered *(ebp+8) "55/push-ebp\n") -5668 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") -5669 $emit-subx-prologue:end: -5670 # . epilogue -5671 89/<- %esp 5/r32/ebp -5672 5d/pop-to-ebp -5673 c3/return -5674 -5675 emit-subx-epilogue: # out : (addr buffered-file) -5676 # . prologue -5677 55/push-ebp -5678 89/<- %ebp 4/r32/esp -5679 # -5680 (write-buffered *(ebp+8) "# . epilogue\n") -5681 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") -5682 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") -5683 (write-buffered *(ebp+8) "c3/return\n") -5684 $emit-subx-epilogue:end: -5685 # . epilogue -5686 89/<- %esp 5/r32/ebp -5687 5d/pop-to-ebp -5688 c3/return +5318 51/push-ecx/var-foo +5319 89/<- %edi 4/r32/esp +5320 # var stmt/esi : statement +5321 68/push 0/imm32/next +5322 68/push 0/imm32/outputs +5323 57/push-edi/inouts +5324 68/push "increment"/imm32/operation +5325 68/push 1/imm32 +5326 89/<- %esi 4/r32/esp +5327 # var formal-var/ebx : var in any register +5328 68/push Any-register/imm32 +5329 68/push 0/imm32/no-stack-offset +5330 68/push 1/imm32/block-depth +5331 ff 6/subop/push *(ecx+4) # Var-type +5332 68/push "dummy"/imm32 +5333 89/<- %ebx 4/r32/esp +5334 # var operand/ebx : (list var) +5335 68/push 0/imm32/next +5336 53/push-ebx/formal-var +5337 89/<- %ebx 4/r32/esp +5338 # var primitive1/ebx : primitive +5339 68/push 0/imm32/next +5340 68/push 0/imm32/output-is-write-only +5341 68/push 0/imm32/no-imm32 +5342 68/push 0/imm32/no-r32 +5343 68/push 3/imm32/rm32-in-first-output +5344 68/push "ff 0/subop/increment"/imm32/subx-name +5345 53/push-ebx/outputs/formal-outputs +5346 68/push 0/imm32/inouts +5347 68/push "increment"/imm32/name +5348 89/<- %ebx 4/r32/esp +5349 # var primitives/ebx : primitive +5350 53/push-ebx/next +5351 68/push 0/imm32/output-is-write-only +5352 68/push 0/imm32/no-imm32 +5353 68/push 0/imm32/no-r32 +5354 68/push 1/imm32/rm32-is-first-inout +5355 68/push "ff 0/subop/increment"/imm32/subx-name +5356 68/push 0/imm32/outputs +5357 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +5358 68/push "increment"/imm32/name +5359 89/<- %ebx 4/r32/esp +5360 # convert +5361 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5362 (flush _test-output-buffered-file) +5363 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5369 # check output +5370 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") +5371 # . epilogue +5372 89/<- %esp 5/r32/ebp +5373 5d/pop-to-ebp +5374 c3/return +5375 +5376 test-increment-register: +5377 # Select the right primitive between overloads. +5378 # foo <- increment +5379 # => +5380 # 50/increment-eax +5381 # +5382 # There's a variable on the var stack as follows: +5383 # name: 'foo' +5384 # type: int +5385 # register: 'eax' +5386 # +5387 # Primitives are the global definitions. +5388 # +5389 # There are no functions defined. +5390 # +5391 # . prologue +5392 55/push-ebp +5393 89/<- %ebp 4/r32/esp +5394 # setup +5395 (clear-stream _test-output-stream) +5396 (clear-stream $_test-output-buffered-file->buffer) +5397 # var type/ecx : (handle tree type-id) = int +5398 68/push 0/imm32/right/null +5399 68/push 1/imm32/left/int +5400 89/<- %ecx 4/r32/esp +5401 # var var-foo/ecx : var in eax +5402 68/push "eax"/imm32/register +5403 68/push 0/imm32/no-stack-offset +5404 68/push 1/imm32/block-depth +5405 51/push-ecx +5406 68/push "foo"/imm32 +5407 89/<- %ecx 4/r32/esp +5408 # var real-outputs/edi : (list var) +5409 68/push 0/imm32/next +5410 51/push-ecx/var-foo +5411 89/<- %edi 4/r32/esp +5412 # var stmt/esi : statement +5413 68/push 0/imm32/next +5414 57/push-edi/outputs +5415 68/push 0/imm32/inouts +5416 68/push "increment"/imm32/operation +5417 68/push 1/imm32/regular-statement +5418 89/<- %esi 4/r32/esp +5419 # convert +5420 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5421 (flush _test-output-buffered-file) +5422 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5428 # check output +5429 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") +5430 # . epilogue +5431 89/<- %esp 5/r32/ebp +5432 5d/pop-to-ebp +5433 c3/return +5434 +5435 test-increment-var: +5436 # Select the right primitive between overloads. +5437 # foo <- increment +5438 # => +5439 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5440 # +5441 # There's a variable on the var stack as follows: +5442 # name: 'foo' +5443 # type: int +5444 # register: 'eax' +5445 # +5446 # Primitives are the global definitions. +5447 # +5448 # There are no functions defined. +5449 # +5450 # . prologue +5451 55/push-ebp +5452 89/<- %ebp 4/r32/esp +5453 # setup +5454 (clear-stream _test-output-stream) +5455 (clear-stream $_test-output-buffered-file->buffer) +5456 # var type/ecx : (handle tree type-id) = int +5457 68/push 0/imm32/right/null +5458 68/push 1/imm32/left/int +5459 89/<- %ecx 4/r32/esp +5460 # var var-foo/ecx : var in eax +5461 68/push "eax"/imm32/register +5462 68/push 0/imm32/no-stack-offset +5463 68/push 1/imm32/block-depth +5464 51/push-ecx +5465 68/push "foo"/imm32 +5466 89/<- %ecx 4/r32/esp +5467 # var inouts/edi : (list var) +5468 68/push 0/imm32/next +5469 51/push-ecx/var-foo +5470 89/<- %edi 4/r32/esp +5471 # var stmt/esi : statement +5472 68/push 0/imm32/next +5473 68/push 0/imm32/outputs +5474 57/push-edi/inouts +5475 68/push "increment"/imm32/operation +5476 68/push 1/imm32 +5477 89/<- %esi 4/r32/esp +5478 # convert +5479 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5480 (flush _test-output-buffered-file) +5481 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5487 # check output +5488 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") +5489 # . epilogue +5490 89/<- %esp 5/r32/ebp +5491 5d/pop-to-ebp +5492 c3/return +5493 +5494 test-add-reg-to-reg: +5495 # var1/reg <- add var2/reg +5496 # => +5497 # 01/add %var1 var2 +5498 # +5499 # . prologue +5500 55/push-ebp +5501 89/<- %ebp 4/r32/esp +5502 # setup +5503 (clear-stream _test-output-stream) +5504 (clear-stream $_test-output-buffered-file->buffer) +5505 # var type/ecx : (handle tree type-id) = int +5506 68/push 0/imm32/right/null +5507 68/push 1/imm32/left/int +5508 89/<- %ecx 4/r32/esp +5509 # var var-var1/ecx : var in eax +5510 68/push "eax"/imm32/register +5511 68/push 0/imm32/no-stack-offset +5512 68/push 1/imm32/block-depth +5513 51/push-ecx +5514 68/push "var1"/imm32 +5515 89/<- %ecx 4/r32/esp +5516 # var var-var2/edx : var in ecx +5517 68/push "ecx"/imm32/register +5518 68/push 0/imm32/no-stack-offset +5519 68/push 1/imm32/block-depth +5520 ff 6/subop/push *(ecx+4) # Var-type +5521 68/push "var2"/imm32 +5522 89/<- %edx 4/r32/esp +5523 # var inouts/esi : (list var2) +5524 68/push 0/imm32/next +5525 52/push-edx/var-var2 +5526 89/<- %esi 4/r32/esp +5527 # var outputs/edi : (list var1) +5528 68/push 0/imm32/next +5529 51/push-ecx/var-var1 +5530 89/<- %edi 4/r32/esp +5531 # var stmt/esi : statement +5532 68/push 0/imm32/next +5533 57/push-edi/outputs +5534 56/push-esi/inouts +5535 68/push "add"/imm32/operation +5536 68/push 1/imm32 +5537 89/<- %esi 4/r32/esp +5538 # convert +5539 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5540 (flush _test-output-buffered-file) +5541 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5547 # check output +5548 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") +5549 # . epilogue +5550 89/<- %esp 5/r32/ebp +5551 5d/pop-to-ebp +5552 c3/return +5553 +5554 test-add-reg-to-mem: +5555 # add-to var1 var2/reg +5556 # => +5557 # 01/add *(ebp+__) var2 +5558 # +5559 # . prologue +5560 55/push-ebp +5561 89/<- %ebp 4/r32/esp +5562 # setup +5563 (clear-stream _test-output-stream) +5564 (clear-stream $_test-output-buffered-file->buffer) +5565 # var type/ecx : (handle tree type-id) = int +5566 68/push 0/imm32/right/null +5567 68/push 1/imm32/left/int +5568 89/<- %ecx 4/r32/esp +5569 # var var-var1/ecx : var +5570 68/push 0/imm32/no-register +5571 68/push 8/imm32/stack-offset +5572 68/push 1/imm32/block-depth +5573 51/push-ecx +5574 68/push "var1"/imm32 +5575 89/<- %ecx 4/r32/esp +5576 # var var-var2/edx : var in ecx +5577 68/push "ecx"/imm32/register +5578 68/push 0/imm32/no-stack-offset +5579 68/push 1/imm32/block-depth +5580 ff 6/subop/push *(ecx+4) # Var-type +5581 68/push "var2"/imm32 +5582 89/<- %edx 4/r32/esp +5583 # var inouts/esi : (list var2) +5584 68/push 0/imm32/next +5585 52/push-edx/var-var2 +5586 89/<- %esi 4/r32/esp +5587 # var inouts = (list var1 var2) +5588 56/push-esi/next +5589 51/push-ecx/var-var1 +5590 89/<- %esi 4/r32/esp +5591 # var stmt/esi : statement +5592 68/push 0/imm32/next +5593 68/push 0/imm32/outputs +5594 56/push-esi/inouts +5595 68/push "add-to"/imm32/operation +5596 68/push 1/imm32 +5597 89/<- %esi 4/r32/esp +5598 # convert +5599 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5600 (flush _test-output-buffered-file) +5601 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5607 # check output +5608 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") +5609 # . epilogue +5610 89/<- %esp 5/r32/ebp +5611 5d/pop-to-ebp +5612 c3/return +5613 +5614 test-add-mem-to-reg: +5615 # var1/reg <- add var2 +5616 # => +5617 # 03/add *(ebp+__) var1 +5618 # +5619 # . prologue +5620 55/push-ebp +5621 89/<- %ebp 4/r32/esp +5622 # setup +5623 (clear-stream _test-output-stream) +5624 (clear-stream $_test-output-buffered-file->buffer) +5625 # var type/ecx : (handle tree type-id) = int +5626 68/push 0/imm32/right/null +5627 68/push 1/imm32/left/int +5628 89/<- %ecx 4/r32/esp +5629 # var var-var1/ecx : var in eax +5630 68/push "eax"/imm32/register +5631 68/push 0/imm32/no-stack-offset +5632 68/push 1/imm32/block-depth +5633 51/push-ecx +5634 68/push "var1"/imm32 +5635 89/<- %ecx 4/r32/esp +5636 # var var-var2/edx : var +5637 68/push 0/imm32/no-register +5638 68/push 8/imm32/stack-offset +5639 68/push 1/imm32/block-depth +5640 ff 6/subop/push *(ecx+4) # Var-type +5641 68/push "var2"/imm32 +5642 89/<- %edx 4/r32/esp +5643 # var inouts/esi : (list var2) +5644 68/push 0/imm32/next +5645 52/push-edx/var-var2 +5646 89/<- %esi 4/r32/esp +5647 # var outputs/edi : (list var1) +5648 68/push 0/imm32/next +5649 51/push-ecx/var-var1 +5650 89/<- %edi 4/r32/esp +5651 # var stmt/esi : statement +5652 68/push 0/imm32/next +5653 57/push-edi/outputs +5654 56/push-esi/inouts +5655 68/push "add"/imm32/operation +5656 68/push 1/imm32 +5657 89/<- %esi 4/r32/esp +5658 # convert +5659 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5660 (flush _test-output-buffered-file) +5661 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5667 # check output +5668 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") +5669 # . epilogue +5670 89/<- %esp 5/r32/ebp +5671 5d/pop-to-ebp +5672 c3/return +5673 +5674 test-add-literal-to-eax: +5675 # var1/eax <- add 0x34 +5676 # => +5677 # 05/add-to-eax 0x34/imm32 +5678 # +5679 # . prologue +5680 55/push-ebp +5681 89/<- %ebp 4/r32/esp +5682 # setup +5683 (clear-stream _test-output-stream) +5684 (clear-stream $_test-output-buffered-file->buffer) +5685 # var type/ecx : (handle tree type-id) = int +5686 68/push 0/imm32/right/null +5687 68/push 1/imm32/left/int +5688 89/<- %ecx 4/r32/esp +5689 # var var-var1/ecx : var in eax +5690 68/push "eax"/imm32/register +5691 68/push 0/imm32/no-stack-offset +5692 68/push 1/imm32/block-depth +5693 51/push-ecx +5694 68/push "var1"/imm32 +5695 89/<- %ecx 4/r32/esp +5696 # var type/edx : (handle tree type-id) = literal +5697 68/push 0/imm32/right/null +5698 68/push 0/imm32/left/literal +5699 89/<- %edx 4/r32/esp +5700 # var var-var2/edx : var literal +5701 68/push 0/imm32/no-register +5702 68/push 0/imm32/no-stack-offset +5703 68/push 1/imm32/block-depth +5704 52/push-edx +5705 68/push "0x34"/imm32 +5706 89/<- %edx 4/r32/esp +5707 # var inouts/esi : (list var2) +5708 68/push 0/imm32/next +5709 52/push-edx/var-var2 +5710 89/<- %esi 4/r32/esp +5711 # var outputs/edi : (list var1) +5712 68/push 0/imm32/next +5713 51/push-ecx/var-var1 +5714 89/<- %edi 4/r32/esp +5715 # var stmt/esi : statement +5716 68/push 0/imm32/next +5717 57/push-edi/outputs +5718 56/push-esi/inouts +5719 68/push "add"/imm32/operation +5720 68/push 1/imm32 +5721 89/<- %esi 4/r32/esp +5722 # convert +5723 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5724 (flush _test-output-buffered-file) +5725 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5731 # check output +5732 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") +5733 # . epilogue +5734 89/<- %esp 5/r32/ebp +5735 5d/pop-to-ebp +5736 c3/return +5737 +5738 test-add-literal-to-reg: +5739 # var1/ecx <- add 0x34 +5740 # => +5741 # 81 0/subop/add %ecx 0x34/imm32 +5742 # +5743 # . prologue +5744 55/push-ebp +5745 89/<- %ebp 4/r32/esp +5746 # setup +5747 (clear-stream _test-output-stream) +5748 (clear-stream $_test-output-buffered-file->buffer) +5749 # var type/ecx : (handle tree type-id) = int +5750 68/push 0/imm32/right/null +5751 68/push 1/imm32/left/int +5752 89/<- %ecx 4/r32/esp +5753 # var var-var1/ecx : var in ecx +5754 68/push "ecx"/imm32/register +5755 68/push 0/imm32/no-stack-offset +5756 68/push 1/imm32/block-depth +5757 51/push-ecx +5758 68/push "var1"/imm32 +5759 89/<- %ecx 4/r32/esp +5760 # var type/edx : (handle tree type-id) = literal +5761 68/push 0/imm32/right/null +5762 68/push 0/imm32/left/literal +5763 89/<- %edx 4/r32/esp +5764 # var var-var2/edx : var literal +5765 68/push 0/imm32/no-register +5766 68/push 0/imm32/no-stack-offset +5767 68/push 1/imm32/block-depth +5768 52/push-edx +5769 68/push "0x34"/imm32 +5770 89/<- %edx 4/r32/esp +5771 # var inouts/esi : (list var2) +5772 68/push 0/imm32/next +5773 52/push-edx/var-var2 +5774 89/<- %esi 4/r32/esp +5775 # var outputs/edi : (list var1) +5776 68/push 0/imm32/next +5777 51/push-ecx/var-var1 +5778 89/<- %edi 4/r32/esp +5779 # var stmt/esi : statement +5780 68/push 0/imm32/next +5781 57/push-edi/outputs +5782 56/push-esi/inouts +5783 68/push "add"/imm32/operation +5784 68/push 1/imm32 +5785 89/<- %esi 4/r32/esp +5786 # convert +5787 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5788 (flush _test-output-buffered-file) +5789 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5795 # check output +5796 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") +5797 # . epilogue +5798 89/<- %esp 5/r32/ebp +5799 5d/pop-to-ebp +5800 c3/return +5801 +5802 test-add-literal-to-mem: +5803 # add-to var1, 0x34 +5804 # => +5805 # 81 0/subop/add %eax 0x34/imm32 +5806 # +5807 # . prologue +5808 55/push-ebp +5809 89/<- %ebp 4/r32/esp +5810 # setup +5811 (clear-stream _test-output-stream) +5812 (clear-stream $_test-output-buffered-file->buffer) +5813 # var type/ecx : (handle tree type-id) = int +5814 68/push 0/imm32/right/null +5815 68/push 1/imm32/left/int +5816 89/<- %ecx 4/r32/esp +5817 # var var-var1/ecx : var +5818 68/push 0/imm32/no-register +5819 68/push 8/imm32/stack-offset +5820 68/push 1/imm32/block-depth +5821 51/push-ecx +5822 68/push "var1"/imm32 +5823 89/<- %ecx 4/r32/esp +5824 # var type/edx : (handle tree type-id) = literal +5825 68/push 0/imm32/right/null +5826 68/push 0/imm32/left/literal +5827 89/<- %edx 4/r32/esp +5828 # var var-var2/edx : var literal +5829 68/push 0/imm32/no-register +5830 68/push 0/imm32/no-stack-offset +5831 68/push 1/imm32/block-depth +5832 52/push-edx +5833 68/push "0x34"/imm32 +5834 89/<- %edx 4/r32/esp +5835 # var inouts/esi : (list var2) +5836 68/push 0/imm32/next +5837 52/push-edx/var-var2 +5838 89/<- %esi 4/r32/esp +5839 # var inouts = (list var1 inouts) +5840 56/push-esi/next +5841 51/push-ecx/var-var1 +5842 89/<- %esi 4/r32/esp +5843 # var stmt/esi : statement +5844 68/push 0/imm32/next +5845 68/push 0/imm32/outputs +5846 56/push-esi/inouts +5847 68/push "add-to"/imm32/operation +5848 68/push 1/imm32 +5849 89/<- %esi 4/r32/esp +5850 # convert +5851 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5852 (flush _test-output-buffered-file) +5853 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5859 # check output +5860 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") +5861 # . epilogue +5862 89/<- %esp 5/r32/ebp +5863 5d/pop-to-ebp +5864 c3/return +5865 +5866 test-emit-subx-statement-function-call: +5867 # Call a function on a variable on the stack. +5868 # f foo +5869 # => +5870 # (f2 *(ebp-8)) +5871 # (Changing the function name supports overloading in general, but here it +5872 # just serves to help disambiguate things.) +5873 # +5874 # There's a variable on the var stack as follows: +5875 # name: 'foo' +5876 # type: int +5877 # stack-offset: -8 +5878 # +5879 # There's nothing in primitives. +5880 # +5881 # There's a function with this info: +5882 # name: 'f' +5883 # inout: int/mem +5884 # value: 'f2' +5885 # +5886 # . prologue +5887 55/push-ebp +5888 89/<- %ebp 4/r32/esp +5889 # setup +5890 (clear-stream _test-output-stream) +5891 (clear-stream $_test-output-buffered-file->buffer) +5892 # var type/ecx : (handle tree type-id) = int +5893 68/push 0/imm32/right/null +5894 68/push 1/imm32/left/int +5895 89/<- %ecx 4/r32/esp +5896 # var var-foo/ecx : var +5897 68/push 0/imm32/no-register +5898 68/push -8/imm32/stack-offset +5899 68/push 0/imm32/block-depth +5900 51/push-ecx +5901 68/push "foo"/imm32 +5902 89/<- %ecx 4/r32/esp +5903 # var operands/esi : (list var) +5904 68/push 0/imm32/next +5905 51/push-ecx/var-foo +5906 89/<- %esi 4/r32/esp +5907 # var stmt/esi : statement +5908 68/push 0/imm32/next +5909 68/push 0/imm32/outputs +5910 56/push-esi/inouts +5911 68/push "f"/imm32/operation +5912 68/push 1/imm32 +5913 89/<- %esi 4/r32/esp +5914 # var functions/ebx : function +5915 68/push 0/imm32/next +5916 68/push 0/imm32/body +5917 68/push 0/imm32/outputs +5918 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +5919 68/push "f2"/imm32/subx-name +5920 68/push "f"/imm32/name +5921 89/<- %ebx 4/r32/esp +5922 # convert +5923 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +5924 (flush _test-output-buffered-file) +5925 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5931 # check output +5932 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") +5933 # . epilogue +5934 89/<- %esp 5/r32/ebp +5935 5d/pop-to-ebp +5936 c3/return +5937 +5938 test-emit-subx-statement-function-call-with-literal-arg: +5939 # Call a function on a literal. +5940 # f 34 +5941 # => +5942 # (f2 34) +5943 # +5944 # . prologue +5945 55/push-ebp +5946 89/<- %ebp 4/r32/esp +5947 # setup +5948 (clear-stream _test-output-stream) +5949 (clear-stream $_test-output-buffered-file->buffer) +5950 # var type/ecx : (handle tree type-id) = literal +5951 68/push 0/imm32/right/null +5952 68/push 0/imm32/left/literal +5953 89/<- %ecx 4/r32/esp +5954 # var var-foo/ecx : var literal +5955 68/push 0/imm32/no-register +5956 68/push 0/imm32/no-stack-offset +5957 68/push 0/imm32/block-depth +5958 51/push-ecx +5959 68/push "34"/imm32 +5960 89/<- %ecx 4/r32/esp +5961 # var operands/esi : (list var) +5962 68/push 0/imm32/next +5963 51/push-ecx/var-foo +5964 89/<- %esi 4/r32/esp +5965 # var stmt/esi : statement +5966 68/push 0/imm32/next +5967 68/push 0/imm32/outputs +5968 56/push-esi/inouts +5969 68/push "f"/imm32/operation +5970 68/push 1/imm32 +5971 89/<- %esi 4/r32/esp +5972 # var functions/ebx : function +5973 68/push 0/imm32/next +5974 68/push 0/imm32/body +5975 68/push 0/imm32/outputs +5976 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +5977 68/push "f2"/imm32/subx-name +5978 68/push "f"/imm32/name +5979 89/<- %ebx 4/r32/esp +5980 # convert +5981 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +5982 (flush _test-output-buffered-file) +5983 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5989 # check output +5990 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") +5991 # . epilogue +5992 89/<- %esp 5/r32/ebp +5993 5d/pop-to-ebp +5994 c3/return +5995 +5996 emit-subx-prologue: # out : (addr buffered-file) +5997 # . prologue +5998 55/push-ebp +5999 89/<- %ebp 4/r32/esp +6000 # +6001 (write-buffered *(ebp+8) "# . prologue\n") +6002 (write-buffered *(ebp+8) "55/push-ebp\n") +6003 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") +6004 $emit-subx-prologue:end: +6005 # . epilogue +6006 89/<- %esp 5/r32/ebp +6007 5d/pop-to-ebp +6008 c3/return +6009 +6010 emit-subx-epilogue: # out : (addr buffered-file) +6011 # . prologue +6012 55/push-ebp +6013 89/<- %ebp 4/r32/esp +6014 # +6015 (write-buffered *(ebp+8) "# . epilogue\n") +6016 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") +6017 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") +6018 (write-buffered *(ebp+8) "c3/return\n") +6019 $emit-subx-epilogue:end: +6020 # . epilogue +6021 89/<- %esp 5/r32/ebp +6022 5d/pop-to-ebp +6023 c3/return -- cgit 1.4.1-2-gfad0