From f25f2e98f9a35a275b5dc31ea80cbbb26fe88c92 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sat, 30 Nov 2019 14:17:13 -0800 Subject: 5786 --- html/apps/mu.subx.html | 4676 ++++++++++++++++++++++++------------------------ 1 file changed, 2356 insertions(+), 2320 deletions(-) (limited to 'html/apps/mu.subx.html') diff --git a/html/apps/mu.subx.html b/html/apps/mu.subx.html index 3ea38715..624a7384 100644 --- a/html/apps/mu.subx.html +++ b/html/apps/mu.subx.html @@ -429,8 +429,8 @@ if ('onhashchange' in window) { 367 89/<- %ebp 4/r32/esp 368 # 369 (parse-mu *(ebp+8)) - 370 (check-mu-types) - 371 (emit-subx *(ebp+0xc)) + 370 (check-mu-types) + 371 (emit-subx *(ebp+0xc)) 372 $convert-mu:end: 373 # . epilogue 374 89/<- %esp 5/r32/ebp @@ -728,7 +728,7 @@ if ('onhashchange' in window) { 691 3d/compare-eax-and 0/imm32 692 0f 84/jump-if-equal break/disp32 693 # var new-function/eax : (address function) = populate-mu-function() - 694 (allocate Heap *Function-size) # => eax + 694 (allocate Heap *Function-size) # => eax 695 (populate-mu-function-header %ecx %eax) 696 (populate-mu-function-body *(ebp+8) %eax) 697 # *curr-function = new-function @@ -847,7 +847,7 @@ if ('onhashchange' in window) { 810 0f 85/jump-if-not-equal $populate-mu-function-header:abort/disp32 811 # 812 (parse-var-with-type %ecx *(ebp+8)) - 813 (append-list Heap %eax *(edi+8)) # Function-inouts => eax + 813 (append-list Heap %eax *(edi+8)) # Function-inouts => eax 814 89/<- *(edi+8) 0/r32/eax # Function-inouts 815 e9/jump loop/disp32 816 } @@ -868,12 +868,12 @@ if ('onhashchange' in window) { 831 0f 85/jump-if-not-equal $populate-mu-function-header:abort/disp32 832 # 833 (parse-var-with-type %ecx *(ebp+8)) - 834 (append-list Heap %eax *(edi+0xc)) # Function-outputs + 834 (append-list Heap %eax *(edi+0xc)) # Function-outputs 835 89/<- *(edi+0xc) 0/r32/eax # Function-outputs 836 e9/jump loop/disp32 837 } 838 $populate-mu-function-header:done: - 839 (check-no-tokens-left *(ebp+8)) + 839 (check-no-tokens-left *(ebp+8)) 840 $populate-mu-function-header:end: 841 # . reclaim locals 842 81 0/subop/add %esp 8/imm32 @@ -1064,7 +1064,7 @@ if ('onhashchange' in window) { 1027 56/push-esi 1028 57/push-edi 1029 # var result/edi : (address var) = allocate(Heap, Var-size) -1030 (allocate Heap *Var-size) +1030 (allocate Heap *Var-size) 1031 89/<- %edi 0/r32/eax 1032 # esi = name 1033 8b/-> *(ebp+8) 6/r32/esi @@ -1642,2336 +1642,2372 @@ if ('onhashchange' in window) { 1605 # . save registers 1606 50/push-eax 1607 56/push-esi -1608 # esi = in -1609 8b/-> *(ebp+8) 6/r32/esi -1610 # var eax : (address block) = parse-mu-block(in) -1611 (parse-mu-block %esi) -1612 # out->body = eax -1613 89/<- *(eax+0x10) 0/r32/eax # Function-body -1614 $populate-mu-function-body:end: -1615 # . restore registers -1616 5e/pop-to-esi -1617 58/pop-to-eax -1618 # . epilogue -1619 89/<- %esp 5/r32/ebp -1620 5d/pop-to-ebp -1621 c3/return -1622 -1623 # parses a block, assuming that the leading '{' has already been read by the caller -1624 parse-mu-block: # in : (address buffered-file) -> result/eax : (address block) -1625 # pseudocode: -1626 # var line : (stream byte 512) -1627 # var word-slice : slice -1628 # result/eax = allocate(Heap, Stmt-size) -1629 # result->tag = 0/Block -1630 # while true # line loop -1631 # clear-stream(line) -1632 # read-line-buffered(in, line) -1633 # if (line->write == 0) break # end of file -1634 # word-slice = next-word(line) -1635 # if slice-empty?(word-slice) # end of line -1636 # continue -1637 # else if slice-starts-with?(word-slice, "#") -1638 # continue -1639 # else if slice-equal?(word-slice, "{") -1640 # assert(no-tokens-in(line)) -1641 # block = parse-mu-block(in) -1642 # append-to-block(result, block) -1643 # else if slice-equal?(word-slice, "}") -1644 # break -1645 # else if slice-ends-with?(word-slice, ":") -1646 # named-block = parse-mu-named-block(word-slice, line, in) -1647 # append-to-block(result, named-block) -1648 # else if slice-equal?(word-slice, "var") -1649 # var-def = parse-mu-var-def(line) -1650 # append-to-block(result, var-def) -1651 # else -1652 # stmt = parse-mu-stmt(line) -1653 # append-to-block(result, stmt) -1654 # return result -1655 # -1656 # . prologue -1657 55/push-ebp -1658 89/<- %ebp 4/r32/esp -1659 # . save registers -1660 50/push-eax -1661 51/push-ecx -1662 52/push-edx -1663 53/push-ebx -1664 56/push-esi -1665 57/pop-edi -1666 # var line/ecx : (stream byte 512) -1667 81 5/subop/subtract %esp 0x200/imm32 -1668 68/push 0x200/imm32/length -1669 68/push 0/imm32/read -1670 68/push 0/imm32/write -1671 89/<- %ecx 4/r32/esp -1672 # var word-slice/edx : slice -1673 68/push 0/imm32/end -1674 68/push 0/imm32/start -1675 89/<- %edx 4/r32/esp -1676 # edi = out -1677 (allocate Heap *Stmt-size) # => eax -1678 89/<- %edi 0/r32/eax -1679 { # line loop -1680 $parse-mu-block:line-loop: -1681 # line = read-line-buffered(in) -1682 (clear-stream %ecx) -1683 (read-line-buffered *(ebp+8) %ecx) -1684 #? (write-buffered Stderr "line: ") -1685 #? (write-stream-data Stderr %ecx) -1686 #? (write-buffered Stderr Newline) -1687 #? (flush Stderr) -1688 # if (line->write == 0) break -1689 81 7/subop/compare *ecx 0/imm32 -1690 0f 84/jump-if-equal break/disp32 -1691 # word-slice = next-word(line) -1692 (next-word %ecx %edx) -1693 #? (write-buffered Stderr "word: ") -1694 #? (write-slice-buffered Stderr %edx) -1695 #? (write-buffered Stderr Newline) -1696 #? (flush Stderr) -1697 # if slice-empty?(word-slice) continue -1698 (slice-empty? %edx) -1699 3d/compare-eax-and 0/imm32 -1700 0f 85/jump-if-not-equal loop/disp32 -1701 # if (slice-starts-with?(word-slice, '#') continue -1702 # . eax = *word-slice->start -1703 8b/-> *edx 0/r32/eax -1704 8a/copy-byte *eax 0/r32/AL -1705 81 4/subop/and %eax 0xff/imm32 -1706 # . if (eax == '#') continue -1707 3d/compare-eax-and 0x23/imm32/hash -1708 0f 84/jump-if-equal loop/disp32 -1709 # if slice-equal?(word-slice, "{") -1710 { -1711 $parse-mu-block:check-for-block: -1712 (slice-equal? %edx "{") -1713 3d/compare-eax-and 0/imm32 -1714 74/jump-if-equal break/disp8 -1715 (check-no-tokens-left %ecx) -1716 # parse new block and append -1717 (parse-mu-block *(ebp+8)) # => eax -1718 (append-to-block %edi %eax) -1719 e9/jump $parse-mu-block:line-loop/disp32 -1720 } -1721 # if slice-equal?(word-slice, "}") break -1722 $parse-mu-block:check-for-end: -1723 (slice-equal? %edx "}") -1724 3d/compare-eax-and 0/imm32 -1725 0f 85/jump-if-not-equal break/disp32 -1726 # if slice-ends-with?(word-slice, ":") parse named block and append -1727 { -1728 $parse-mu-block:check-for-named-block: -1729 # . eax = *word-slice->end -1730 8b/-> *(edx+4) 0/r32/eax -1731 8a/copy-byte *eax 0/r32/AL -1732 81 4/subop/and %eax 0xff/imm32 -1733 # . if (eax != ':') break -1734 3d/compare-eax-and 0x23/imm32/hash -1735 0f 85/jump-if-not-equal break/disp32 -1736 # -1737 (parse-mu-named-block %edx %ecx *(ebp+8)) # => eax -1738 (append-to-block %edi %eax) -1739 e9/jump $parse-mu-block:line-loop/disp32 -1740 } -1741 # if slice-equal?(word-slice, "var") -1742 { -1743 $parse-mu-block:check-for-var: -1744 (slice-equal? %edx "var") -1745 3d/compare-eax-and 0/imm32 -1746 74/jump-if-equal break/disp8 -1747 # -1748 (parse-mu-var-def %ecx) # => eax -1749 (append-to-block %edi %eax) -1750 e9/jump $parse-mu-block:line-loop/disp32 -1751 } -1752 $parse-mu-block:regular-stmt: -1753 # otherwise -1754 (parse-mu-stmt %ecx) # => eax -1755 (append-to-block %edi %eax) -1756 e9/jump loop/disp32 -1757 } # end line loop -1758 $parse-mu-block:end: -1759 # . reclaim locals -1760 81 0/subop/add %esp 0x214/imm32 -1761 # . restore registers -1762 5f/pop-to-edi -1763 5e/pop-to-esi -1764 5b/pop-to-ebx -1765 5a/pop-to-edx -1766 59/pop-to-ecx -1767 58/pop-to-eax -1768 # . epilogue -1769 89/<- %esp 5/r32/ebp -1770 5d/pop-to-ebp -1771 c3/return -1772 -1773 $parse-mu-block:abort: -1774 # error("'{' or '}' should be on its own line, but got '") -1775 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -1776 (rewind-stream %ecx) -1777 (write-stream 2 %ecx) -1778 (write-buffered Stderr "'\n") -1779 (flush Stderr) -1780 # . syscall(exit, 1) -1781 bb/copy-to-ebx 1/imm32 -1782 b8/copy-to-eax 1/imm32/exit -1783 cd/syscall 0x80/imm8 -1784 # never gets here -1785 -1786 check-no-tokens-left: # line : (address stream) -1787 # . prologue -1788 55/push-ebp -1789 89/<- %ebp 4/r32/esp -1790 # . save registers -1791 50/push-eax -1792 51/push-ecx -1793 # var s/ecx : slice = next-word(line) -1794 68/push 0/imm32/end -1795 68/push 0/imm32/start -1796 89/<- %ecx 4/r32/esp -1797 # -1798 (next-word *(ebp+8) %ecx) -1799 # if slice-empty?(s) return -1800 (slice-empty? %ecx) -1801 3d/compare-eax-and 0/imm32 -1802 75/jump-if-not-equal $check-no-tokens-left:end/disp8 -1803 # if (slice-starts-with?(s, '#') return -1804 # . eax = *s->start -1805 8b/-> *edx 0/r32/eax -1806 8a/copy-byte *eax 0/r32/AL -1807 81 4/subop/and %eax 0xff/imm32 -1808 # . if (eax == '#') continue -1809 3d/compare-eax-and 0x23/imm32/hash -1810 74/jump-if-equal $check-no-tokens-left:end/disp8 -1811 # abort -1812 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -1813 (rewind-stream %ecx) -1814 (write-stream 2 %ecx) -1815 (write-buffered Stderr "'\n") -1816 (flush Stderr) -1817 # . syscall(exit, 1) -1818 bb/copy-to-ebx 1/imm32 -1819 b8/copy-to-eax 1/imm32/exit -1820 cd/syscall 0x80/imm8 -1821 # never gets here -1822 $check-no-tokens-left:end: -1823 # . reclaim locals -1824 81 0/subop/add %esp 8/imm32 -1825 # . restore registers -1826 59/pop-to-ecx -1827 58/pop-to-eax -1828 # . epilogue -1829 89/<- %esp 5/r32/ebp -1830 5d/pop-to-ebp -1831 c3/return -1832 -1833 parse-mu-named-block: # name : (address slice), first-line : (address stream), in : (address buffered-file) -> result/eax : (address stmt) -1834 # pseudocode: -1835 # var line : (stream byte 512) -1836 # var word-slice : slice -1837 # result/eax = allocate(Heap, Stmt-size) -1838 # result->tag = 4/Named-block -1839 # result->name = name -1840 # assert(next-word(first-line) == "{") -1841 # assert(no-tokens-in(first-line)) -1842 # while true # line loop -1843 # clear-stream(line) -1844 # read-line-buffered(in, line) -1845 # if (line->write == 0) break # end of file -1846 # word-slice = next-word(line) -1847 # if slice-empty?(word-slice) # end of line -1848 # break -1849 # else if slice-equal?(word-slice, "{") -1850 # block = parse-mu-block(in) -1851 # append-to-block(result, block) -1852 # else if slice-equal?(word-slice, "}") -1853 # break -1854 # else if slice-ends-with?(word-slice, ":") -1855 # named-block = parse-mu-named-block(word-slice, in) -1856 # append-to-block(result, named-block) -1857 # else if slice-equal?(word-slice, "var") -1858 # var-def = parse-mu-var-def(line) -1859 # append-to-block(result, var-def) -1860 # else -1861 # stmt = parse-mu-stmt(line) -1862 # append-to-block(result, stmt) -1863 # return result -1864 # -1865 # . prologue -1866 55/push-ebp -1867 89/<- %ebp 4/r32/esp -1868 # . save registers -1869 $parse-mu-named-block:end: -1870 # . reclaim locals -1871 # . restore registers -1872 # . epilogue -1873 89/<- %esp 5/r32/ebp -1874 5d/pop-to-ebp -1875 c3/return -1876 -1877 parse-mu-var-def: # line : (address stream) -> result/eax : (address stmt) -1878 # pseudocode: -1879 # -1880 # . prologue -1881 55/push-ebp -1882 89/<- %ebp 4/r32/esp -1883 # . save registers -1884 $parse-mu-var-def:end: -1885 # . reclaim locals -1886 # . restore registers -1887 # . epilogue -1888 89/<- %esp 5/r32/ebp -1889 5d/pop-to-ebp -1890 c3/return -1891 -1892 parse-mu-stmt: # line : (address stream) -> result/eax : (address stmt) -1893 # pseudocode: -1894 # var name : slice -1895 # var v : (address var) -1896 # result = allocate(Heap, Stmt-size) -1897 # if stmt-has-outputs?(line) -1898 # while true -1899 # name = next-word(line) -1900 # if (name == '<-') break -1901 # assert(is-identifier?(name)) -1902 # v = parse-var(name) -1903 # result->outputs = append(result->outputs, v) -1904 # result->name = slice-to-string(next-word(line)) -1905 # while true -1906 # name = next-word-or-string(line) -1907 # v = parse-var-or-literal(name) -1908 # result->inouts = append(result->inouts, v) -1909 # -1910 # . prologue -1911 55/push-ebp -1912 89/<- %ebp 4/r32/esp -1913 # . save registers -1914 51/push-ecx -1915 57/push-edi -1916 # var name/ecx : (address slice) -1917 68/push 0/imm32/end -1918 68/push 0/imm32/start -1919 89/<- %ecx 4/r32/esp -1920 # var result/edi : (address stmt) -1921 (allocate Heap *Stmt-size) -1922 89/<- %edi 0/r32/eax -1923 { -1924 (stmt-has-outputs? *(ebp+8)) -1925 3d/compare-eax-and 0/imm32 -1926 0f 84/jump-if-equal break/disp32 -1927 { -1928 $parse-mu-stmt:read-outputs: -1929 # name = next-word(line) -1930 (next-word *(ebp+8) %ecx) -1931 # if slice-empty?(word-slice) break -1932 (slice-empty? %ecx) -1933 3d/compare-eax-and 0/imm32 -1934 0f 85/jump-if-not-equal break/disp32 -1935 # if (name == "<-") break -1936 (slice-equal? %ecx "<-") -1937 3d/compare-eax-and 0/imm32 -1938 75/jump-if-not-equal break/disp8 -1939 # assert(is-identifier?(name)) -1940 (is-identifier? %ecx) -1941 3d/compare-eax-and 0/imm32 -1942 0f 84/jump-if-equal $parse-mu-stmt:abort/disp32 -1943 # -1944 (parse-var Heap %ecx) # => eax -1945 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax -1946 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs -1947 e9/jump loop/disp32 -1948 } -1949 } -1950 $parse-mu-stmt:read-operation: -1951 (next-word *(ebp+8) %ecx) -1952 (slice-to-string Heap %ecx) -1953 89/<- *(edi+4) 0/r32/eax # Stmt1-operation -1954 { -1955 $parse-mu-stmt:read-inouts: -1956 # name = next-word-or-string(line) -1957 (next-word-or-string *(ebp+8) %ecx) -1958 # if slice-empty?(word-slice) break -1959 (slice-empty? %ecx) -1960 3d/compare-eax-and 0/imm32 -1961 0f 85/jump-if-not-equal break/disp32 -1962 # if (name == "<-") abort -1963 (slice-equal? %ecx "<-") -1964 3d/compare-eax-and 0/imm32 -1965 0f 85/jump-if-not-equal $parse-mu-stmt:abort2/disp32 -1966 # -1967 (parse-var Heap %ecx) # => eax # TODO: parse-var-or-literal -1968 (append-list Heap %eax *(edi+8)) # Stmt1-inouts => eax -1969 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts -1970 e9/jump loop/disp32 -1971 } -1972 $parse-mu-stmt:end: -1973 # return result -1974 89/<- %eax 7/r32/edi -1975 # . reclaim locals -1976 81 0/subop/add %esp 8/imm32 -1977 # . restore registers -1978 5f/pop-to-edi -1979 59/pop-to-ecx -1980 # . epilogue -1981 89/<- %esp 5/r32/ebp -1982 5d/pop-to-ebp -1983 c3/return -1984 -1985 $parse-mu-stmt:abort: -1986 # error("invalid identifier '" name "'\n") -1987 (write-buffered Stderr "invalid identifier '") -1988 (write-slice-buffered Stderr %ecx) -1989 (write-buffered Stderr "'\n") -1990 (flush Stderr) -1991 # . syscall(exit, 1) -1992 bb/copy-to-ebx 1/imm32 -1993 b8/copy-to-eax 1/imm32/exit -1994 cd/syscall 0x80/imm8 -1995 # never gets here -1996 -1997 $parse-mu-stmt:abort2: -1998 # error("invalid statement '" line "'\n") -1999 (rewind-stream *(ebp+8)) -2000 (write-buffered Stderr "invalid identifier '") -2001 (write-stream Stderr *(ebp+8)) -2002 (write-buffered Stderr "'\n") -2003 (flush Stderr) -2004 # . syscall(exit, 1) -2005 bb/copy-to-ebx 1/imm32 -2006 b8/copy-to-eax 1/imm32/exit -2007 cd/syscall 0x80/imm8 -2008 # never gets here -2009 -2010 stmt-has-outputs?: # line : (address stream) -> result/eax : boolean -2011 # . prologue -2012 55/push-ebp -2013 89/<- %ebp 4/r32/esp -2014 # . save registers -2015 51/push-ecx -2016 # var word-slice/ecx : slice -2017 68/push 0/imm32/end -2018 68/push 0/imm32/start -2019 89/<- %ecx 4/r32/esp -2020 # result = false -2021 b8/copy-to-eax 0/imm32/false -2022 (rewind-stream *(ebp+8)) -2023 { -2024 (next-word-or-string *(ebp+8) %ecx) -2025 # if slice-empty?(word-slice) break -2026 (slice-empty? %ecx) -2027 3d/compare-eax-and 0/imm32 -2028 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -2029 0f 85/jump-if-not-equal break/disp32 -2030 # if slice-starts-with?(word-slice, '#') break -2031 # . eax = *word-slice->start -2032 8b/-> *ecx 0/r32/eax -2033 8a/copy-byte *eax 0/r32/AL -2034 81 4/subop/and %eax 0xff/imm32 -2035 # . if (eax == '#') break -2036 3d/compare-eax-and 0x23/imm32/hash -2037 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -2038 0f 84/jump-if-equal break/disp32 -2039 # if slice-equal?(word-slice, '<-') return true -2040 (slice-equal? %ecx "<-") -2041 3d/compare-eax-and 0/imm32 -2042 74/jump-if-equal loop/disp8 -2043 b8/copy-to-eax 1/imm32/true -2044 } -2045 $stmt-has-outputs:end: -2046 (rewind-stream *(ebp+8)) -2047 # . reclaim locals -2048 81 0/subop/add %esp 8/imm32 -2049 # . restore registers -2050 59/pop-to-ecx -2051 # . epilogue -2052 89/<- %esp 5/r32/ebp -2053 5d/pop-to-ebp -2054 c3/return -2055 -2056 parse-var: # ad: allocation-descriptor, name: (address slice) -> result/eax: (address var) -2057 # . prologue -2058 55/push-ebp -2059 89/<- %ebp 4/r32/esp -2060 # . save registers -2061 51/push-ecx -2062 # ecx = slice-to-string(name) -2063 8b/-> *(ebp+0xc) 1/r32/ecx -2064 (slice-to-string Heap %ecx) # => eax -2065 89/<- %ecx 0/r32/eax -2066 (allocate *(ebp+8) *Var-size) # => eax -2067 89/<- *eax 1/r32/ecx # Var-name -2068 $parse-var:end: -2069 # . restore registers -2070 59/pop-to-ecx -2071 # . epilogue -2072 89/<- %esp 5/r32/ebp -2073 5d/pop-to-ebp -2074 c3/return -2075 -2076 test-parse-mu-stmt: -2077 # 'increment n' -2078 # . prologue -2079 55/push-ebp -2080 89/<- %ebp 4/r32/esp -2081 # setup -2082 (clear-stream _test-input-stream) -2083 (write _test-input-stream "increment n\n") -2084 # convert -2085 (parse-mu-stmt _test-input-stream) -2086 # check result -2087 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation -2088 # edx : (address list var) = result->inouts -2089 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts -2090 # ebx : (address var) = result->inouts->value -2091 8b/-> *edx 3/r32/ebx # List-value -2092 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name -2093 # . epilogue -2094 89/<- %esp 5/r32/ebp -2095 5d/pop-to-ebp -2096 c3/return -2097 -2098 new-function: # ad: allocation-descriptor, name: string, subx-name: string, inouts: (address list var), outputs: (address list var), body: (address block), next: (address function) -> result/eax: (address function) -2099 # . prologue -2100 55/push-ebp -2101 89/<- %ebp 4/r32/esp -2102 # . save registers -2103 51/push-ecx -2104 # -2105 (allocate *(ebp+8) *Function-size) # => eax -2106 8b/-> *(ebp+0xc) 1/r32/ecx -2107 89/<- *eax 1/r32/ecx # Function-name -2108 8b/-> *(ebp+0x10) 1/r32/ecx -2109 89/<- *(eax+4) 1/r32/ecx # Function-subx-name -2110 8b/-> *(ebp+0x14) 1/r32/ecx -2111 89/<- *(eax+8) 1/r32/ecx # Function-inouts -2112 8b/-> *(ebp+0x18) 1/r32/ecx -2113 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs -2114 8b/-> *(ebp+0x1c) 1/r32/ecx -2115 89/<- *(eax+0x10) 1/r32/ecx # Function-body -2116 8b/-> *(ebp+0x20) 1/r32/ecx -2117 89/<- *(eax+0x14) 1/r32/ecx # Function-next -2118 $new-function:end: -2119 # . restore registers -2120 59/pop-to-ecx -2121 # . epilogue -2122 89/<- %esp 5/r32/ebp -2123 5d/pop-to-ebp -2124 c3/return -2125 -2126 new-var: # ad: allocation-descriptor, name: string, type: int, block: int, stack-offset: int, register: string -> result/eax: (address var) -2127 # . prologue -2128 55/push-ebp -2129 89/<- %ebp 4/r32/esp -2130 # . save registers -2131 51/push-ecx -2132 # -2133 (allocate *(ebp+8) *Var-size) # => eax -2134 8b/-> *(ebp+0xc) 1/r32/ecx -2135 89/<- *eax 1/r32/ecx # Var-name -2136 8b/-> *(ebp+0x10) 1/r32/ecx -2137 89/<- *(eax+4) 1/r32/ecx # Var-type -2138 8b/-> *(ebp+0x14) 1/r32/ecx -2139 89/<- *(eax+8) 1/r32/ecx # Var-block -2140 8b/-> *(ebp+0x18) 1/r32/ecx -2141 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset -2142 8b/-> *(ebp+0x1c) 1/r32/ecx -2143 89/<- *(eax+0x10) 1/r32/ecx # Var-register -2144 $new-var:end: -2145 # . restore registers -2146 59/pop-to-ecx -2147 # . epilogue -2148 89/<- %esp 5/r32/ebp -2149 5d/pop-to-ebp -2150 c3/return -2151 -2152 new-block: # ad: allocation-descriptor, data: (address list statement) -> result/eax: (address statement) -2153 # . prologue -2154 55/push-ebp -2155 89/<- %ebp 4/r32/esp -2156 # . save registers -2157 51/push-ecx -2158 # -2159 (allocate *(ebp+8) *Stmt-size) # => eax -2160 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag -2161 8b/-> *(ebp+0xc) 1/r32/ecx -2162 89/<- *(eax+4) 1/r32/ecx # Block-statements -2163 $new-block:end: -2164 # . restore registers -2165 59/pop-to-ecx -2166 # . epilogue -2167 89/<- %esp 5/r32/ebp -2168 5d/pop-to-ebp -2169 c3/return -2170 -2171 new-stmt: # ad: allocation-descriptor, operation: string, inouts: (address list var), outputs: (address list var) -> result/eax: (address statement) -2172 # . prologue -2173 55/push-ebp -2174 89/<- %ebp 4/r32/esp -2175 # . save registers -2176 51/push-ecx -2177 # -2178 (allocate *(ebp+8) *Stmt-size) # => eax -2179 c7 0/subop/copy *eax 1/imm32/tag/regular-stmt # Stmt-tag -2180 8b/-> *(ebp+0xc) 1/r32/ecx -2181 89/<- *(eax+4) 1/r32/ecx # Stmt1-operation -2182 8b/-> *(ebp+0x10) 1/r32/ecx -2183 89/<- *(eax+8) 1/r32/ecx # Stmt1-inouts -2184 8b/-> *(ebp+0x14) 1/r32/ecx -2185 89/<- *(eax+0xc) 1/r32/ecx # Stmt1-outputs -2186 $new-stmt:end: -2187 # . restore registers -2188 59/pop-to-ecx -2189 # . epilogue -2190 89/<- %esp 5/r32/ebp -2191 5d/pop-to-ebp -2192 c3/return -2193 -2194 new-vardef: # ad: allocation-descriptor, name: string, type: int -> result/eax: (address statement) -2195 # . prologue -2196 55/push-ebp -2197 89/<- %ebp 4/r32/esp -2198 # . save registers -2199 51/push-ecx -2200 # -2201 (allocate *(ebp+8) *Stmt-size) # => eax -2202 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag -2203 8b/-> *(ebp+0xc) 1/r32/ecx -2204 89/<- *(eax+4) 1/r32/ecx # Vardef-name -2205 8b/-> *(ebp+0x10) 1/r32/ecx -2206 89/<- *(eax+8) 1/r32/ecx # Vardef-type -2207 $new-vardef:end: -2208 # . restore registers -2209 59/pop-to-ecx -2210 # . epilogue -2211 89/<- %esp 5/r32/ebp -2212 5d/pop-to-ebp -2213 c3/return -2214 -2215 new-regvardef: # ad: allocation-descriptor, name: string, type: int, register: string -> result/eax: (address statement) -2216 # . prologue -2217 55/push-ebp -2218 89/<- %ebp 4/r32/esp -2219 # . save registers -2220 51/push-ecx -2221 # -2222 (allocate *(ebp+8) *Stmt-size) # => eax -2223 c7 0/subop/copy *eax 3/imm32/tag/var-in-register -2224 8b/-> *(ebp+0xc) 1/r32/ecx -2225 89/<- *(eax+4) 1/r32/ecx # Regvardef-name -2226 8b/-> *(ebp+0x10) 1/r32/ecx -2227 89/<- *(eax+8) 1/r32/ecx # Regvardef-type -2228 8b/-> *(ebp+0x14) 1/r32/ecx -2229 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-register -2230 $new-regvardef:end: -2231 # . restore registers -2232 59/pop-to-ecx -2233 # . epilogue -2234 89/<- %esp 5/r32/ebp -2235 5d/pop-to-ebp -2236 c3/return -2237 -2238 new-named-block: # ad: allocation-descriptor, name: string, data: (address list statement) -> result/eax: (address statement) -2239 # . prologue -2240 55/push-ebp -2241 89/<- %ebp 4/r32/esp -2242 # . save registers -2243 51/push-ecx -2244 # -2245 (allocate *(ebp+8) *Stmt-size) # => eax -2246 c7 0/subop/copy *eax 4/imm32/tag/named-block -2247 8b/-> *(ebp+0xc) 1/r32/ecx -2248 89/<- *(eax+4) 1/r32/ecx # Named-block-name -2249 8b/-> *(ebp+0x10) 1/r32/ecx -2250 89/<- *(eax+8) 1/r32/ecx # Named-block-statements -2251 $new-named-block:end: -2252 # . restore registers -2253 59/pop-to-ecx -2254 # . epilogue -2255 89/<- %esp 5/r32/ebp -2256 5d/pop-to-ebp -2257 c3/return -2258 -2259 new-list: # ad: allocation-descriptor, value: _type, next: (address list _type) -> result/eax : (address list _type) -2260 # . prologue -2261 55/push-ebp -2262 89/<- %ebp 4/r32/esp -2263 # . save registers -2264 51/push-ecx -2265 # -2266 (allocate *(ebp+8) *List-size) # => eax -2267 8b/-> *(ebp+0xc) 1/r32/ecx -2268 89/<- *eax 1/r32/ecx # List-value -2269 8b/-> *(ebp+0x10) 1/r32/ecx -2270 89/<- *(eax+4) 1/r32/ecx # List-next -2271 $new-list:end: -2272 # . restore registers -2273 59/pop-to-ecx -2274 # . epilogue -2275 89/<- %esp 5/r32/ebp -2276 5d/pop-to-ebp -2277 c3/return -2278 -2279 append-list: # ad: allocation-descriptor, value: _type, list: (address list _type) -> result/eax : (address list _type) -2280 # . prologue -2281 55/push-ebp -2282 89/<- %ebp 4/r32/esp -2283 # . save registers -2284 51/push-ecx -2285 # -2286 (allocate *(ebp+8) *List-size) # => eax -2287 8b/-> *(ebp+0xc) 1/r32/ecx -2288 89/<- *eax 1/r32/ecx # List-value -2289 # if (list == null) return result -2290 81 7/subop/compare *(ebp+0x10) 0/imm32 -2291 74/jump-if-equal $new-list:end/disp8 -2292 # otherwise append -2293 # var curr/ecx = list -2294 8b/-> *(ebp+0x10) 1/r32/ecx -2295 # while (curr->next != null) curr = curr->next -2296 { -2297 81 7/subop/compare *(ecx+4) 0/imm32 # List-next -2298 74/jump-if-equal break/disp8 -2299 # curr = curr->next -2300 8b/-> *(ecx+4) 1/r32/ecx -2301 eb/jump loop/disp8 -2302 } -2303 # curr->next = result -2304 89/<- *(ecx+4) 0/r32/eax -2305 # return list -2306 8b/-> *(ebp+0x10) 0/r32/eax -2307 $append-list:end: -2308 # . restore registers -2309 59/pop-to-ecx -2310 # . epilogue -2311 89/<- %esp 5/r32/ebp -2312 5d/pop-to-ebp -2313 c3/return -2314 -2315 append-to-block: # ad: allocation-descriptor, block: (address block), x: (address stmt) -2316 # . prologue -2317 55/push-ebp -2318 89/<- %ebp 4/r32/esp -2319 # . save registers -2320 $append-to-block:end: -2321 # . restore registers -2322 # . epilogue -2323 89/<- %esp 5/r32/ebp -2324 5d/pop-to-ebp -2325 c3/return -2326 -2327 ####################################################### -2328 # Type-checking -2329 ####################################################### -2330 -2331 check-mu-types: -2332 # . prologue -2333 55/push-ebp -2334 89/<- %ebp 4/r32/esp -2335 # -2336 $check-mu-types:end: -2337 # . epilogue -2338 89/<- %esp 5/r32/ebp -2339 5d/pop-to-ebp -2340 c3/return -2341 -2342 ####################################################### -2343 # Code-generation -2344 ####################################################### -2345 -2346 emit-subx: # out : (address buffered-file) -2347 # . prologue -2348 55/push-ebp -2349 89/<- %ebp 4/r32/esp -2350 # . save registers -2351 50/push-eax -2352 51/push-ecx -2353 57/push-edi -2354 # edi = out -2355 8b/-> *(ebp+8) 7/r32/edi -2356 # var curr/ecx : (address function) = Program -2357 8b/-> *Program 1/r32/ecx -2358 { -2359 # if (curr == NULL) break -2360 81 7/subop/compare %ecx 0/imm32 -2361 0f 84/jump-if-equal break/disp32 -2362 (emit-subx-function %edi %ecx) -2363 # curr = curr->next -2364 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -2365 e9/jump loop/disp32 -2366 } -2367 $emit-subx:end: -2368 # . restore registers -2369 5f/pop-to-edi -2370 59/pop-to-ecx -2371 58/pop-to-eax -2372 # . epilogue -2373 89/<- %esp 5/r32/ebp -2374 5d/pop-to-ebp -2375 c3/return -2376 -2377 emit-subx-function: # out : (address buffered-file), f : (address function) -2378 # . prologue -2379 55/push-ebp -2380 89/<- %ebp 4/r32/esp -2381 # . save registers -2382 50/push-eax -2383 51/push-ecx -2384 57/push-edi -2385 # edi = out -2386 8b/-> *(ebp+8) 7/r32/edi -2387 # ecx = f -2388 8b/-> *(ebp+0xc) 1/r32/ecx -2389 # -2390 (write-buffered %edi *ecx) -2391 (write-buffered %edi ":\n") -2392 (emit-subx-prologue %edi) -2393 (emit-subx-block %edi *(ecx+0x10)) # Function-body -2394 (emit-subx-epilogue %edi) -2395 $emit-subx-function:end: -2396 # . restore registers -2397 5f/pop-to-edi -2398 59/pop-to-ecx -2399 58/pop-to-eax -2400 # . epilogue -2401 89/<- %esp 5/r32/ebp -2402 5d/pop-to-ebp -2403 c3/return -2404 -2405 emit-subx-block: # out : (address buffered-file), block : (address block) -2406 # . prologue -2407 55/push-ebp -2408 89/<- %ebp 4/r32/esp -2409 # -2410 $emit-subx-block:end: -2411 # . epilogue -2412 89/<- %esp 5/r32/ebp -2413 5d/pop-to-ebp -2414 c3/return -2415 -2416 emit-subx-statement: # out : (address buffered-file), stmt : (address statement), vars : (stack var), primitives : (address primitive), functions : (address function) -2417 # . prologue -2418 55/push-ebp -2419 89/<- %ebp 4/r32/esp -2420 # . save registers -2421 50/push-eax -2422 51/push-ecx -2423 # if stmt matches a primitive, emit it -2424 { -2425 $emit-subx-statement:primitive: -2426 (find-matching-primitive *(ebp+0x14) *(ebp+0xc)) # primitives, stmt => curr/eax -2427 3d/compare-eax-and 0/imm32 -2428 74/jump-if-equal break/disp8 -2429 (emit-subx-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax) # out, stmt, vars, curr -2430 e9/jump $emit-subx-statement:end/disp32 -2431 } -2432 # else if stmt matches a function, emit a call to it -2433 { -2434 $emit-subx-statement:call: -2435 (find-matching-function *(ebp+0x18) *(ebp+0xc)) # functions, stmt => curr/eax -2436 3d/compare-eax-and 0/imm32 -2437 74/jump-if-equal break/disp8 -2438 (emit-subx-call *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax) # out, stmt, vars, curr -2439 e9/jump $emit-subx-statement:end/disp32 -2440 } -2441 # else abort -2442 e9/jump $emit-subx-statement:abort/disp32 -2443 $emit-subx-statement:end: -2444 # . restore registers -2445 59/pop-to-ecx -2446 58/pop-to-eax -2447 # . epilogue -2448 89/<- %esp 5/r32/ebp -2449 5d/pop-to-ebp -2450 c3/return -2451 -2452 $emit-subx-statement:abort: -2453 # error("couldn't translate '" stmt "'\n") -2454 (write-buffered Stderr "couldn't translate '") -2455 #? (emit-string Stderr *(ebp+0xc)) # TODO -2456 (write-buffered Stderr "'\n") -2457 (flush Stderr) -2458 # . syscall(exit, 1) -2459 bb/copy-to-ebx 1/imm32 -2460 b8/copy-to-eax 1/imm32/exit -2461 cd/syscall 0x80/imm8 -2462 # never gets here -2463 -2464 # Primitives supported -2465 == data -2466 Primitives: -2467 # increment var => ff 0/subop/increment *(ebp+__) -2468 "increment"/imm32/name -2469 Single-int-var-on-stack/imm32/inouts -2470 0/imm32/no-outputs -2471 "ff 0/subop/increment"/imm32/subx-name -2472 1/imm32/rm32-is-first-inout -2473 0/imm32/no-r32 -2474 0/imm32/no-imm32 -2475 _Primitive-inc-reg/imm32/next -2476 _Primitive-inc-reg: -2477 # var/reg <- increment => ff 0/subop/increment %__ -2478 "increment"/imm32/name -2479 0/imm32/no-inouts -2480 Single-int-var-in-some-register/imm32/outputs -2481 "ff 0/subop/increment"/imm32/subx-name -2482 3/imm32/rm32-is-first-output -2483 0/imm32/no-r32 -2484 0/imm32/no-imm32 -2485 _Primitive-add-reg-to-reg/imm32/next -2486 _Primitive-add-reg-to-reg: -2487 # var1/reg <- add var2/reg => 01 var1/rm32 var2/r32 -2488 "add"/imm32/name -2489 Single-int-var-in-some-register/imm32/inouts -2490 Single-int-var-in-some-register/imm32/outputs -2491 "01"/imm32/subx-name -2492 3/imm32/rm32-is-first-output -2493 1/imm32/r32-is-first-inout -2494 0/imm32/no-imm32 -2495 _Primitive-add-reg-to-mem/imm32/next -2496 _Primitive-add-reg-to-mem: -2497 # add-to var1 var2/reg => 01 var1 var2/r32 -2498 "add-to"/imm32/name -2499 Int-var-and-second-int-var-in-some-register/imm32/inouts -2500 0/imm32/outputs -2501 "01"/imm32/subx-name -2502 1/imm32/rm32-is-first-inout -2503 2/imm32/r32-is-second-inout -2504 0/imm32/no-imm32 -2505 _Primitive-add-mem-to-reg/imm32/next -2506 _Primitive-add-mem-to-reg: -2507 # var1/reg <- add var2 => 03 var2/rm32 var1/r32 -2508 "add"/imm32/name -2509 Single-int-var-on-stack/imm32/inouts -2510 Single-int-var-in-some-register/imm32/outputs -2511 "03"/imm32/subx-name -2512 1/imm32/rm32-is-first-inout -2513 3/imm32/r32-is-first-output -2514 0/imm32/no-imm32 -2515 _Primitive-add-lit-to-reg/imm32/next -2516 _Primitive-add-lit-to-reg: -2517 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 -2518 "add"/imm32/name -2519 Single-lit-var/imm32/inouts -2520 Single-int-var-in-some-register/imm32/outputs -2521 "81 0/subop/add"/imm32/subx-name -2522 3/imm32/rm32-is-first-output -2523 0/imm32/no-r32 -2524 1/imm32/imm32-is-first-inout -2525 _Primitive-add-lit-to-mem/imm32/next -2526 _Primitive-add-lit-to-mem: -2527 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 -2528 "add-to"/imm32/name -2529 Int-var-and-literal/imm32/inouts -2530 0/imm32/outputs -2531 "81 0/subop/add"/imm32/subx-name -2532 1/imm32/rm32-is-first-inout -2533 0/imm32/no-r32 -2534 2/imm32/imm32-is-first-inout -2535 0/imm32/next -2536 -2537 Single-int-var-on-stack: -2538 Int-var-on-stack/imm32 -2539 0/imm32/next -2540 -2541 Int-var-on-stack: -2542 "arg1"/imm32/name -2543 1/imm32/type-int -2544 1/imm32/some-block-depth -2545 1/imm32/some-stack-offset -2546 0/imm32/no-register -2547 -2548 Int-var-and-second-int-var-in-some-register: -2549 Int-var-on-stack/imm32 -2550 Single-int-var-in-some-register/imm32/next -2551 -2552 Int-var-and-literal: -2553 Int-var-on-stack/imm32 -2554 Single-lit-var/imm32/next -2555 -2556 Single-int-var-in-some-register: -2557 Int-var-in-some-register/imm32 -2558 0/imm32/next -2559 -2560 Int-var-in-some-register: -2561 "arg1"/imm32/name -2562 1/imm32/type-int -2563 1/imm32/some-block-depth -2564 0/imm32/no-stack-offset -2565 "*"/imm32/register -2566 -2567 Single-lit-var: -2568 Lit-var/imm32 +1608 57/push-edi +1609 # esi = in +1610 8b/-> *(ebp+8) 6/r32/esi +1611 # edi = out +1612 8b/-> *(ebp+0xc) 7/r32/edi +1613 # var eax : (address block) = parse-mu-block(in) +1614 (parse-mu-block %esi) # => eax +1615 # out->body = eax +1616 89/<- *(edi+0x10) 0/r32/eax # Function-body +1617 $populate-mu-function-body:end: +1618 # . restore registers +1619 5f/pop-to-edi +1620 5e/pop-to-esi +1621 58/pop-to-eax +1622 # . epilogue +1623 89/<- %esp 5/r32/ebp +1624 5d/pop-to-ebp +1625 c3/return +1626 +1627 # parses a block, assuming that the leading '{' has already been read by the caller +1628 parse-mu-block: # in : (address buffered-file) -> result/eax : (address block) +1629 # pseudocode: +1630 # var line : (stream byte 512) +1631 # var word-slice : slice +1632 # result/eax = allocate(Heap, Stmt-size) +1633 # result->tag = 0/Block +1634 # while true # line loop +1635 # clear-stream(line) +1636 # read-line-buffered(in, line) +1637 # if (line->write == 0) break # end of file +1638 # word-slice = next-word(line) +1639 # if slice-empty?(word-slice) # end of line +1640 # continue +1641 # else if slice-starts-with?(word-slice, "#") +1642 # continue +1643 # else if slice-equal?(word-slice, "{") +1644 # assert(no-tokens-in(line)) +1645 # block = parse-mu-block(in) +1646 # append-to-block(result, block) +1647 # else if slice-equal?(word-slice, "}") +1648 # break +1649 # else if slice-ends-with?(word-slice, ":") +1650 # named-block = parse-mu-named-block(word-slice, line, in) +1651 # append-to-block(result, named-block) +1652 # else if slice-equal?(word-slice, "var") +1653 # var-def = parse-mu-var-def(line) +1654 # append-to-block(result, var-def) +1655 # else +1656 # stmt = parse-mu-stmt(line) +1657 # append-to-block(result, stmt) +1658 # return result +1659 # +1660 # . prologue +1661 55/push-ebp +1662 89/<- %ebp 4/r32/esp +1663 # . save registers +1664 51/push-ecx +1665 52/push-edx +1666 53/push-ebx +1667 56/push-esi +1668 57/push-edi +1669 # var line/ecx : (stream byte 512) +1670 81 5/subop/subtract %esp 0x200/imm32 +1671 68/push 0x200/imm32/length +1672 68/push 0/imm32/read +1673 68/push 0/imm32/write +1674 89/<- %ecx 4/r32/esp +1675 # var word-slice/edx : slice +1676 68/push 0/imm32/end +1677 68/push 0/imm32/start +1678 89/<- %edx 4/r32/esp +1679 # edi = result +1680 (allocate Heap *Stmt-size) # => eax +1681 89/<- %edi 0/r32/eax +1682 { # line loop +1683 $parse-mu-block:line-loop: +1684 # line = read-line-buffered(in) +1685 (clear-stream %ecx) +1686 (read-line-buffered *(ebp+8) %ecx) +1687 #? (write-buffered Stderr "line: ") +1688 #? (write-stream-data Stderr %ecx) +1689 #? (write-buffered Stderr Newline) +1690 #? (flush Stderr) +1691 # if (line->write == 0) break +1692 81 7/subop/compare *ecx 0/imm32 +1693 0f 84/jump-if-equal break/disp32 +1694 # word-slice = next-word(line) +1695 (next-word %ecx %edx) +1696 #? (write-buffered Stderr "word: ") +1697 #? (write-slice-buffered Stderr %edx) +1698 #? (write-buffered Stderr Newline) +1699 #? (flush Stderr) +1700 # if slice-empty?(word-slice) continue +1701 (slice-empty? %edx) +1702 3d/compare-eax-and 0/imm32 +1703 0f 85/jump-if-not-equal loop/disp32 +1704 # if (slice-starts-with?(word-slice, '#') continue +1705 # . eax = *word-slice->start +1706 8b/-> *edx 0/r32/eax +1707 8a/copy-byte *eax 0/r32/AL +1708 81 4/subop/and %eax 0xff/imm32 +1709 # . if (eax == '#') continue +1710 3d/compare-eax-and 0x23/imm32/hash +1711 0f 84/jump-if-equal loop/disp32 +1712 # if slice-equal?(word-slice, "{") +1713 { +1714 $parse-mu-block:check-for-block: +1715 (slice-equal? %edx "{") +1716 3d/compare-eax-and 0/imm32 +1717 74/jump-if-equal break/disp8 +1718 (check-no-tokens-left %ecx) +1719 # parse new block and append +1720 (parse-mu-block *(ebp+8)) # => eax +1721 (append-to-block %edi %eax) +1722 e9/jump $parse-mu-block:line-loop/disp32 +1723 } +1724 # if slice-equal?(word-slice, "}") break +1725 $parse-mu-block:check-for-end: +1726 (slice-equal? %edx "}") +1727 3d/compare-eax-and 0/imm32 +1728 0f 85/jump-if-not-equal break/disp32 +1729 # if slice-ends-with?(word-slice, ":") parse named block and append +1730 { +1731 $parse-mu-block:check-for-named-block: +1732 # . eax = *word-slice->end +1733 8b/-> *(edx+4) 0/r32/eax +1734 8a/copy-byte *eax 0/r32/AL +1735 81 4/subop/and %eax 0xff/imm32 +1736 # . if (eax != ':') break +1737 3d/compare-eax-and 0x23/imm32/hash +1738 0f 85/jump-if-not-equal break/disp32 +1739 # +1740 (parse-mu-named-block %edx %ecx *(ebp+8)) # => eax +1741 (append-to-block %edi %eax) +1742 e9/jump $parse-mu-block:line-loop/disp32 +1743 } +1744 # if slice-equal?(word-slice, "var") +1745 { +1746 $parse-mu-block:check-for-var: +1747 (slice-equal? %edx "var") +1748 3d/compare-eax-and 0/imm32 +1749 74/jump-if-equal break/disp8 +1750 # +1751 (parse-mu-var-def %ecx) # => eax +1752 (append-to-block %edi %eax) +1753 e9/jump $parse-mu-block:line-loop/disp32 +1754 } +1755 $parse-mu-block:regular-stmt: +1756 # otherwise +1757 (parse-mu-stmt %ecx) # => eax +1758 (append-to-block Heap %edi %eax) +1759 e9/jump loop/disp32 +1760 } # end line loop +1761 # return result +1762 89/<- %eax 7/r32/edi +1763 $parse-mu-block:end: +1764 # . reclaim locals +1765 81 0/subop/add %esp 0x214/imm32 +1766 # . restore registers +1767 5f/pop-to-edi +1768 5e/pop-to-esi +1769 5b/pop-to-ebx +1770 5a/pop-to-edx +1771 59/pop-to-ecx +1772 # . epilogue +1773 89/<- %esp 5/r32/ebp +1774 5d/pop-to-ebp +1775 c3/return +1776 +1777 $parse-mu-block:abort: +1778 # error("'{' or '}' should be on its own line, but got '") +1779 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +1780 (rewind-stream %ecx) +1781 (write-stream 2 %ecx) +1782 (write-buffered Stderr "'\n") +1783 (flush Stderr) +1784 # . syscall(exit, 1) +1785 bb/copy-to-ebx 1/imm32 +1786 b8/copy-to-eax 1/imm32/exit +1787 cd/syscall 0x80/imm8 +1788 # never gets here +1789 +1790 check-no-tokens-left: # line : (address stream) +1791 # . prologue +1792 55/push-ebp +1793 89/<- %ebp 4/r32/esp +1794 # . save registers +1795 50/push-eax +1796 51/push-ecx +1797 # var s/ecx : slice = next-word(line) +1798 68/push 0/imm32/end +1799 68/push 0/imm32/start +1800 89/<- %ecx 4/r32/esp +1801 # +1802 (next-word *(ebp+8) %ecx) +1803 # if slice-empty?(s) return +1804 (slice-empty? %ecx) +1805 3d/compare-eax-and 0/imm32 +1806 75/jump-if-not-equal $check-no-tokens-left:end/disp8 +1807 # if (slice-starts-with?(s, '#') return +1808 # . eax = *s->start +1809 8b/-> *edx 0/r32/eax +1810 8a/copy-byte *eax 0/r32/AL +1811 81 4/subop/and %eax 0xff/imm32 +1812 # . if (eax == '#') continue +1813 3d/compare-eax-and 0x23/imm32/hash +1814 74/jump-if-equal $check-no-tokens-left:end/disp8 +1815 # abort +1816 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +1817 (rewind-stream %ecx) +1818 (write-stream 2 %ecx) +1819 (write-buffered Stderr "'\n") +1820 (flush Stderr) +1821 # . syscall(exit, 1) +1822 bb/copy-to-ebx 1/imm32 +1823 b8/copy-to-eax 1/imm32/exit +1824 cd/syscall 0x80/imm8 +1825 # never gets here +1826 $check-no-tokens-left:end: +1827 # . reclaim locals +1828 81 0/subop/add %esp 8/imm32 +1829 # . restore registers +1830 59/pop-to-ecx +1831 58/pop-to-eax +1832 # . epilogue +1833 89/<- %esp 5/r32/ebp +1834 5d/pop-to-ebp +1835 c3/return +1836 +1837 parse-mu-named-block: # name : (address slice), first-line : (address stream), in : (address buffered-file) -> result/eax : (address stmt) +1838 # pseudocode: +1839 # var line : (stream byte 512) +1840 # var word-slice : slice +1841 # result/eax = allocate(Heap, Stmt-size) +1842 # result->tag = 4/Named-block +1843 # result->name = name +1844 # assert(next-word(first-line) == "{") +1845 # assert(no-tokens-in(first-line)) +1846 # while true # line loop +1847 # clear-stream(line) +1848 # read-line-buffered(in, line) +1849 # if (line->write == 0) break # end of file +1850 # word-slice = next-word(line) +1851 # if slice-empty?(word-slice) # end of line +1852 # break +1853 # else if slice-equal?(word-slice, "{") +1854 # block = parse-mu-block(in) +1855 # append-to-block(result, block) +1856 # else if slice-equal?(word-slice, "}") +1857 # break +1858 # else if slice-ends-with?(word-slice, ":") +1859 # named-block = parse-mu-named-block(word-slice, in) +1860 # append-to-block(result, named-block) +1861 # else if slice-equal?(word-slice, "var") +1862 # var-def = parse-mu-var-def(line) +1863 # append-to-block(result, var-def) +1864 # else +1865 # stmt = parse-mu-stmt(line) +1866 # append-to-block(result, stmt) +1867 # return result +1868 # +1869 # . prologue +1870 55/push-ebp +1871 89/<- %ebp 4/r32/esp +1872 # . save registers +1873 $parse-mu-named-block:end: +1874 # . reclaim locals +1875 # . restore registers +1876 # . epilogue +1877 89/<- %esp 5/r32/ebp +1878 5d/pop-to-ebp +1879 c3/return +1880 +1881 parse-mu-var-def: # line : (address stream) -> result/eax : (address stmt) +1882 # pseudocode: +1883 # +1884 # . prologue +1885 55/push-ebp +1886 89/<- %ebp 4/r32/esp +1887 # . save registers +1888 $parse-mu-var-def:end: +1889 # . reclaim locals +1890 # . restore registers +1891 # . epilogue +1892 89/<- %esp 5/r32/ebp +1893 5d/pop-to-ebp +1894 c3/return +1895 +1896 parse-mu-stmt: # line : (address stream) -> result/eax : (address stmt) +1897 # pseudocode: +1898 # var name : slice +1899 # var v : (address var) +1900 # result = allocate(Heap, Stmt-size) +1901 # if stmt-has-outputs?(line) +1902 # while true +1903 # name = next-word(line) +1904 # if (name == '<-') break +1905 # assert(is-identifier?(name)) +1906 # v = parse-var(name) +1907 # result->outputs = append(result->outputs, v) +1908 # result->name = slice-to-string(next-word(line)) +1909 # while true +1910 # name = next-word-or-string(line) +1911 # v = parse-var-or-literal(name) +1912 # result->inouts = append(result->inouts, v) +1913 # +1914 # . prologue +1915 55/push-ebp +1916 89/<- %ebp 4/r32/esp +1917 # . save registers +1918 51/push-ecx +1919 57/push-edi +1920 # var name/ecx : (address slice) +1921 68/push 0/imm32/end +1922 68/push 0/imm32/start +1923 89/<- %ecx 4/r32/esp +1924 # var result/edi : (address stmt) +1925 (allocate Heap *Stmt-size) +1926 89/<- %edi 0/r32/eax +1927 # result->tag = 1/stmt +1928 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag +1929 { +1930 (stmt-has-outputs? *(ebp+8)) +1931 3d/compare-eax-and 0/imm32 +1932 0f 84/jump-if-equal break/disp32 +1933 { +1934 $parse-mu-stmt:read-outputs: +1935 # name = next-word(line) +1936 (next-word *(ebp+8) %ecx) +1937 # if slice-empty?(word-slice) break +1938 (slice-empty? %ecx) +1939 3d/compare-eax-and 0/imm32 +1940 0f 85/jump-if-not-equal break/disp32 +1941 # if (name == "<-") break +1942 (slice-equal? %ecx "<-") +1943 3d/compare-eax-and 0/imm32 +1944 75/jump-if-not-equal break/disp8 +1945 # assert(is-identifier?(name)) +1946 (is-identifier? %ecx) +1947 3d/compare-eax-and 0/imm32 +1948 0f 84/jump-if-equal $parse-mu-stmt:abort/disp32 +1949 # +1950 (parse-var Heap %ecx) # => eax +1951 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax +1952 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs +1953 e9/jump loop/disp32 +1954 } +1955 } +1956 $parse-mu-stmt:read-operation: +1957 (next-word *(ebp+8) %ecx) +1958 (slice-to-string Heap %ecx) +1959 89/<- *(edi+4) 0/r32/eax # Stmt1-operation +1960 { +1961 $parse-mu-stmt:read-inouts: +1962 # name = next-word-or-string(line) +1963 (next-word-or-string *(ebp+8) %ecx) +1964 # if slice-empty?(word-slice) break +1965 (slice-empty? %ecx) +1966 3d/compare-eax-and 0/imm32 +1967 0f 85/jump-if-not-equal break/disp32 +1968 # if (name == "<-") abort +1969 (slice-equal? %ecx "<-") +1970 3d/compare-eax-and 0/imm32 +1971 0f 85/jump-if-not-equal $parse-mu-stmt:abort2/disp32 +1972 # +1973 (parse-var Heap %ecx) # => eax # TODO: parse-var-or-literal +1974 (append-list Heap %eax *(edi+8)) # Stmt1-inouts => eax +1975 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts +1976 e9/jump loop/disp32 +1977 } +1978 $parse-mu-stmt:end: +1979 # return result +1980 89/<- %eax 7/r32/edi +1981 # . reclaim locals +1982 81 0/subop/add %esp 8/imm32 +1983 # . restore registers +1984 5f/pop-to-edi +1985 59/pop-to-ecx +1986 # . epilogue +1987 89/<- %esp 5/r32/ebp +1988 5d/pop-to-ebp +1989 c3/return +1990 +1991 $parse-mu-stmt:abort: +1992 # error("invalid identifier '" name "'\n") +1993 (write-buffered Stderr "invalid identifier '") +1994 (write-slice-buffered Stderr %ecx) +1995 (write-buffered Stderr "'\n") +1996 (flush Stderr) +1997 # . syscall(exit, 1) +1998 bb/copy-to-ebx 1/imm32 +1999 b8/copy-to-eax 1/imm32/exit +2000 cd/syscall 0x80/imm8 +2001 # never gets here +2002 +2003 $parse-mu-stmt:abort2: +2004 # error("invalid statement '" line "'\n") +2005 (rewind-stream *(ebp+8)) +2006 (write-buffered Stderr "invalid identifier '") +2007 (write-stream Stderr *(ebp+8)) +2008 (write-buffered Stderr "'\n") +2009 (flush Stderr) +2010 # . syscall(exit, 1) +2011 bb/copy-to-ebx 1/imm32 +2012 b8/copy-to-eax 1/imm32/exit +2013 cd/syscall 0x80/imm8 +2014 # never gets here +2015 +2016 stmt-has-outputs?: # line : (address stream) -> result/eax : boolean +2017 # . prologue +2018 55/push-ebp +2019 89/<- %ebp 4/r32/esp +2020 # . save registers +2021 51/push-ecx +2022 # var word-slice/ecx : slice +2023 68/push 0/imm32/end +2024 68/push 0/imm32/start +2025 89/<- %ecx 4/r32/esp +2026 # result = false +2027 b8/copy-to-eax 0/imm32/false +2028 (rewind-stream *(ebp+8)) +2029 { +2030 (next-word-or-string *(ebp+8) %ecx) +2031 # if slice-empty?(word-slice) break +2032 (slice-empty? %ecx) +2033 3d/compare-eax-and 0/imm32 +2034 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +2035 0f 85/jump-if-not-equal break/disp32 +2036 # if slice-starts-with?(word-slice, '#') break +2037 # . eax = *word-slice->start +2038 8b/-> *ecx 0/r32/eax +2039 8a/copy-byte *eax 0/r32/AL +2040 81 4/subop/and %eax 0xff/imm32 +2041 # . if (eax == '#') break +2042 3d/compare-eax-and 0x23/imm32/hash +2043 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +2044 0f 84/jump-if-equal break/disp32 +2045 # if slice-equal?(word-slice, '<-') return true +2046 (slice-equal? %ecx "<-") +2047 3d/compare-eax-and 0/imm32 +2048 74/jump-if-equal loop/disp8 +2049 b8/copy-to-eax 1/imm32/true +2050 } +2051 $stmt-has-outputs:end: +2052 (rewind-stream *(ebp+8)) +2053 # . reclaim locals +2054 81 0/subop/add %esp 8/imm32 +2055 # . restore registers +2056 59/pop-to-ecx +2057 # . epilogue +2058 89/<- %esp 5/r32/ebp +2059 5d/pop-to-ebp +2060 c3/return +2061 +2062 parse-var: # ad: allocation-descriptor, name: (address slice) -> result/eax: (address var) +2063 # . prologue +2064 55/push-ebp +2065 89/<- %ebp 4/r32/esp +2066 # . save registers +2067 51/push-ecx +2068 # ecx = slice-to-string(name) +2069 8b/-> *(ebp+0xc) 1/r32/ecx +2070 (slice-to-string Heap %ecx) # => eax +2071 89/<- %ecx 0/r32/eax +2072 (allocate *(ebp+8) *Var-size) # => eax +2073 89/<- *eax 1/r32/ecx # Var-name +2074 # var->type = int +2075 c7 0/subop/copy *(eax+4) 1/imm32/int-type # Var-type +2076 # var->stack-offset = 8 +2077 c7 0/subop/copy *(eax+0xc) 8/imm32 # Var-stack-offset +2078 $parse-var:end: +2079 # . restore registers +2080 59/pop-to-ecx +2081 # . epilogue +2082 89/<- %esp 5/r32/ebp +2083 5d/pop-to-ebp +2084 c3/return +2085 +2086 test-parse-mu-stmt: +2087 # 'increment n' +2088 # . prologue +2089 55/push-ebp +2090 89/<- %ebp 4/r32/esp +2091 # setup +2092 (clear-stream _test-input-stream) +2093 (write _test-input-stream "increment n\n") +2094 # convert +2095 (parse-mu-stmt _test-input-stream) +2096 # check result +2097 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation +2098 # edx : (address list var) = result->inouts +2099 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts +2100 # ebx : (address var) = result->inouts->value +2101 8b/-> *edx 3/r32/ebx # List-value +2102 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name +2103 # . epilogue +2104 89/<- %esp 5/r32/ebp +2105 5d/pop-to-ebp +2106 c3/return +2107 +2108 new-function: # ad: allocation-descriptor, name: string, subx-name: string, inouts: (address list var), outputs: (address list var), body: (address block), next: (address function) -> result/eax: (address function) +2109 # . prologue +2110 55/push-ebp +2111 89/<- %ebp 4/r32/esp +2112 # . save registers +2113 51/push-ecx +2114 # +2115 (allocate *(ebp+8) *Function-size) # => eax +2116 8b/-> *(ebp+0xc) 1/r32/ecx +2117 89/<- *eax 1/r32/ecx # Function-name +2118 8b/-> *(ebp+0x10) 1/r32/ecx +2119 89/<- *(eax+4) 1/r32/ecx # Function-subx-name +2120 8b/-> *(ebp+0x14) 1/r32/ecx +2121 89/<- *(eax+8) 1/r32/ecx # Function-inouts +2122 8b/-> *(ebp+0x18) 1/r32/ecx +2123 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs +2124 8b/-> *(ebp+0x1c) 1/r32/ecx +2125 89/<- *(eax+0x10) 1/r32/ecx # Function-body +2126 8b/-> *(ebp+0x20) 1/r32/ecx +2127 89/<- *(eax+0x14) 1/r32/ecx # Function-next +2128 $new-function:end: +2129 # . restore registers +2130 59/pop-to-ecx +2131 # . epilogue +2132 89/<- %esp 5/r32/ebp +2133 5d/pop-to-ebp +2134 c3/return +2135 +2136 new-var: # ad: allocation-descriptor, name: string, type: int, block: int, stack-offset: int, register: string -> result/eax: (address var) +2137 # . prologue +2138 55/push-ebp +2139 89/<- %ebp 4/r32/esp +2140 # . save registers +2141 51/push-ecx +2142 # +2143 (allocate *(ebp+8) *Var-size) # => eax +2144 8b/-> *(ebp+0xc) 1/r32/ecx +2145 89/<- *eax 1/r32/ecx # Var-name +2146 8b/-> *(ebp+0x10) 1/r32/ecx +2147 89/<- *(eax+4) 1/r32/ecx # Var-type +2148 8b/-> *(ebp+0x14) 1/r32/ecx +2149 89/<- *(eax+8) 1/r32/ecx # Var-block +2150 8b/-> *(ebp+0x18) 1/r32/ecx +2151 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset +2152 8b/-> *(ebp+0x1c) 1/r32/ecx +2153 89/<- *(eax+0x10) 1/r32/ecx # Var-register +2154 $new-var:end: +2155 # . restore registers +2156 59/pop-to-ecx +2157 # . epilogue +2158 89/<- %esp 5/r32/ebp +2159 5d/pop-to-ebp +2160 c3/return +2161 +2162 new-block: # ad: allocation-descriptor, data: (address list statement) -> result/eax: (address statement) +2163 # . prologue +2164 55/push-ebp +2165 89/<- %ebp 4/r32/esp +2166 # . save registers +2167 51/push-ecx +2168 # +2169 (allocate *(ebp+8) *Stmt-size) # => eax +2170 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag +2171 8b/-> *(ebp+0xc) 1/r32/ecx +2172 89/<- *(eax+4) 1/r32/ecx # Block-statements +2173 $new-block:end: +2174 # . restore registers +2175 59/pop-to-ecx +2176 # . epilogue +2177 89/<- %esp 5/r32/ebp +2178 5d/pop-to-ebp +2179 c3/return +2180 +2181 new-stmt: # ad: allocation-descriptor, operation: string, inouts: (address list var), outputs: (address list var) -> result/eax: (address statement) +2182 # . prologue +2183 55/push-ebp +2184 89/<- %ebp 4/r32/esp +2185 # . save registers +2186 51/push-ecx +2187 # +2188 (allocate *(ebp+8) *Stmt-size) # => eax +2189 c7 0/subop/copy *eax 1/imm32/tag/regular-stmt # Stmt-tag +2190 8b/-> *(ebp+0xc) 1/r32/ecx +2191 89/<- *(eax+4) 1/r32/ecx # Stmt1-operation +2192 8b/-> *(ebp+0x10) 1/r32/ecx +2193 89/<- *(eax+8) 1/r32/ecx # Stmt1-inouts +2194 8b/-> *(ebp+0x14) 1/r32/ecx +2195 89/<- *(eax+0xc) 1/r32/ecx # Stmt1-outputs +2196 $new-stmt:end: +2197 # . restore registers +2198 59/pop-to-ecx +2199 # . epilogue +2200 89/<- %esp 5/r32/ebp +2201 5d/pop-to-ebp +2202 c3/return +2203 +2204 new-vardef: # ad: allocation-descriptor, name: string, type: int -> result/eax: (address statement) +2205 # . prologue +2206 55/push-ebp +2207 89/<- %ebp 4/r32/esp +2208 # . save registers +2209 51/push-ecx +2210 # +2211 (allocate *(ebp+8) *Stmt-size) # => eax +2212 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag +2213 8b/-> *(ebp+0xc) 1/r32/ecx +2214 89/<- *(eax+4) 1/r32/ecx # Vardef-name +2215 8b/-> *(ebp+0x10) 1/r32/ecx +2216 89/<- *(eax+8) 1/r32/ecx # Vardef-type +2217 $new-vardef:end: +2218 # . restore registers +2219 59/pop-to-ecx +2220 # . epilogue +2221 89/<- %esp 5/r32/ebp +2222 5d/pop-to-ebp +2223 c3/return +2224 +2225 new-regvardef: # ad: allocation-descriptor, name: string, type: int, register: string -> result/eax: (address statement) +2226 # . prologue +2227 55/push-ebp +2228 89/<- %ebp 4/r32/esp +2229 # . save registers +2230 51/push-ecx +2231 # +2232 (allocate *(ebp+8) *Stmt-size) # => eax +2233 c7 0/subop/copy *eax 3/imm32/tag/var-in-register +2234 8b/-> *(ebp+0xc) 1/r32/ecx +2235 89/<- *(eax+4) 1/r32/ecx # Regvardef-name +2236 8b/-> *(ebp+0x10) 1/r32/ecx +2237 89/<- *(eax+8) 1/r32/ecx # Regvardef-type +2238 8b/-> *(ebp+0x14) 1/r32/ecx +2239 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-register +2240 $new-regvardef:end: +2241 # . restore registers +2242 59/pop-to-ecx +2243 # . epilogue +2244 89/<- %esp 5/r32/ebp +2245 5d/pop-to-ebp +2246 c3/return +2247 +2248 new-named-block: # ad: allocation-descriptor, name: string, data: (address list statement) -> result/eax: (address statement) +2249 # . prologue +2250 55/push-ebp +2251 89/<- %ebp 4/r32/esp +2252 # . save registers +2253 51/push-ecx +2254 # +2255 (allocate *(ebp+8) *Stmt-size) # => eax +2256 c7 0/subop/copy *eax 4/imm32/tag/named-block +2257 8b/-> *(ebp+0xc) 1/r32/ecx +2258 89/<- *(eax+4) 1/r32/ecx # Named-block-name +2259 8b/-> *(ebp+0x10) 1/r32/ecx +2260 89/<- *(eax+8) 1/r32/ecx # Named-block-statements +2261 $new-named-block:end: +2262 # . restore registers +2263 59/pop-to-ecx +2264 # . epilogue +2265 89/<- %esp 5/r32/ebp +2266 5d/pop-to-ebp +2267 c3/return +2268 +2269 new-list: # ad: allocation-descriptor, value: _type, next: (address list _type) -> result/eax : (address list _type) +2270 # . prologue +2271 55/push-ebp +2272 89/<- %ebp 4/r32/esp +2273 # . save registers +2274 51/push-ecx +2275 # +2276 (allocate *(ebp+8) *List-size) # => eax +2277 8b/-> *(ebp+0xc) 1/r32/ecx +2278 89/<- *eax 1/r32/ecx # List-value +2279 8b/-> *(ebp+0x10) 1/r32/ecx +2280 89/<- *(eax+4) 1/r32/ecx # List-next +2281 $new-list:end: +2282 # . restore registers +2283 59/pop-to-ecx +2284 # . epilogue +2285 89/<- %esp 5/r32/ebp +2286 5d/pop-to-ebp +2287 c3/return +2288 +2289 append-list: # ad: allocation-descriptor, value: _type, list: (address list _type) -> result/eax : (address list _type) +2290 # . prologue +2291 55/push-ebp +2292 89/<- %ebp 4/r32/esp +2293 # . save registers +2294 51/push-ecx +2295 # +2296 (allocate *(ebp+8) *List-size) # => eax +2297 8b/-> *(ebp+0xc) 1/r32/ecx +2298 89/<- *eax 1/r32/ecx # List-value +2299 # if (list == null) return result +2300 81 7/subop/compare *(ebp+0x10) 0/imm32 +2301 74/jump-if-equal $new-list:end/disp8 +2302 # otherwise append +2303 # var curr/ecx = list +2304 8b/-> *(ebp+0x10) 1/r32/ecx +2305 # while (curr->next != null) curr = curr->next +2306 { +2307 81 7/subop/compare *(ecx+4) 0/imm32 # List-next +2308 74/jump-if-equal break/disp8 +2309 # curr = curr->next +2310 8b/-> *(ecx+4) 1/r32/ecx +2311 eb/jump loop/disp8 +2312 } +2313 # curr->next = result +2314 89/<- *(ecx+4) 0/r32/eax +2315 # return list +2316 8b/-> *(ebp+0x10) 0/r32/eax +2317 $append-list:end: +2318 # . restore registers +2319 59/pop-to-ecx +2320 # . epilogue +2321 89/<- %esp 5/r32/ebp +2322 5d/pop-to-ebp +2323 c3/return +2324 +2325 append-to-block: # ad: allocation-descriptor, block: (address block), x: (address stmt) +2326 # . prologue +2327 55/push-ebp +2328 89/<- %ebp 4/r32/esp +2329 # . save registers +2330 56/push-esi +2331 # esi = block +2332 8b/-> *(ebp+0xc) 6/r32/esi +2333 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements +2334 89/<- *(esi+4) 0/r32/eax # Block-statements +2335 $append-to-block:end: +2336 # . restore registers +2337 5e/pop-to-esi +2338 # . epilogue +2339 89/<- %esp 5/r32/ebp +2340 5d/pop-to-ebp +2341 c3/return +2342 +2343 ####################################################### +2344 # Type-checking +2345 ####################################################### +2346 +2347 check-mu-types: +2348 # . prologue +2349 55/push-ebp +2350 89/<- %ebp 4/r32/esp +2351 # +2352 $check-mu-types:end: +2353 # . epilogue +2354 89/<- %esp 5/r32/ebp +2355 5d/pop-to-ebp +2356 c3/return +2357 +2358 ####################################################### +2359 # Code-generation +2360 ####################################################### +2361 +2362 emit-subx: # out : (address buffered-file) +2363 # . prologue +2364 55/push-ebp +2365 89/<- %ebp 4/r32/esp +2366 # . save registers +2367 50/push-eax +2368 51/push-ecx +2369 57/push-edi +2370 # edi = out +2371 8b/-> *(ebp+8) 7/r32/edi +2372 # var curr/ecx : (address function) = Program +2373 8b/-> *Program 1/r32/ecx +2374 { +2375 # if (curr == NULL) break +2376 81 7/subop/compare %ecx 0/imm32 +2377 0f 84/jump-if-equal break/disp32 +2378 (emit-subx-function %edi %ecx) +2379 # curr = curr->next +2380 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +2381 e9/jump loop/disp32 +2382 } +2383 $emit-subx:end: +2384 # . restore registers +2385 5f/pop-to-edi +2386 59/pop-to-ecx +2387 58/pop-to-eax +2388 # . epilogue +2389 89/<- %esp 5/r32/ebp +2390 5d/pop-to-ebp +2391 c3/return +2392 +2393 emit-subx-function: # out : (address buffered-file), f : (address function) +2394 # . prologue +2395 55/push-ebp +2396 89/<- %ebp 4/r32/esp +2397 # . save registers +2398 50/push-eax +2399 51/push-ecx +2400 57/push-edi +2401 # edi = out +2402 8b/-> *(ebp+8) 7/r32/edi +2403 # ecx = f +2404 8b/-> *(ebp+0xc) 1/r32/ecx +2405 # +2406 (write-buffered %edi *ecx) +2407 (write-buffered %edi ":\n") +2408 (emit-subx-prologue %edi) +2409 (emit-subx-block %edi *(ecx+0x10)) # Function-body +2410 (emit-subx-epilogue %edi) +2411 $emit-subx-function:end: +2412 # . restore registers +2413 5f/pop-to-edi +2414 59/pop-to-ecx +2415 58/pop-to-eax +2416 # . epilogue +2417 89/<- %esp 5/r32/ebp +2418 5d/pop-to-ebp +2419 c3/return +2420 +2421 emit-subx-block: # out : (address buffered-file), block : (address block) +2422 # . prologue +2423 55/push-ebp +2424 89/<- %ebp 4/r32/esp +2425 # curr/esi : (address list statement) = block->statements +2426 8b/-> *(ebp+0xc) 6/r32/esi +2427 8b/-> *(esi+4) 6/r32/esi # Block-statements +2428 # +2429 { +2430 $emit-subx-block:stmt: +2431 81 7/subop/compare %esi 0/imm32 +2432 0f 84/jump-if-equal break/disp32 +2433 (write-buffered *(ebp+8) "{\n") +2434 { +2435 81 7/subop/compare %esi 0/imm32 +2436 74/jump-if-equal break/disp8 +2437 (emit-subx-statement *(ebp+8) *esi 0 Primitives 0) # TODO: initialize vars and functions +2438 (write-buffered *(ebp+8) Newline) +2439 8b/-> *(esi+4) 6/r32/esi # List-next +2440 eb/jump loop/disp8 +2441 } +2442 (write-buffered *(ebp+8) "}\n") +2443 } +2444 $emit-subx-block:end: +2445 # . epilogue +2446 89/<- %esp 5/r32/ebp +2447 5d/pop-to-ebp +2448 c3/return +2449 +2450 emit-subx-statement: # out : (address buffered-file), stmt : (address statement), vars : (stack var), primitives : (address primitive), functions : (address function) +2451 # . prologue +2452 55/push-ebp +2453 89/<- %ebp 4/r32/esp +2454 # . save registers +2455 50/push-eax +2456 51/push-ecx +2457 # if stmt matches a primitive, emit it +2458 { +2459 $emit-subx-statement:primitive: +2460 (find-matching-primitive *(ebp+0x14) *(ebp+0xc)) # primitives, stmt => curr/eax +2461 3d/compare-eax-and 0/imm32 +2462 74/jump-if-equal break/disp8 +2463 (emit-subx-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax) # out, stmt, vars, curr +2464 e9/jump $emit-subx-statement:end/disp32 +2465 } +2466 # else if stmt matches a function, emit a call to it +2467 { +2468 $emit-subx-statement:call: +2469 (find-matching-function *(ebp+0x18) *(ebp+0xc)) # functions, stmt => curr/eax +2470 3d/compare-eax-and 0/imm32 +2471 74/jump-if-equal break/disp8 +2472 (emit-subx-call *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax) # out, stmt, vars, curr +2473 e9/jump $emit-subx-statement:end/disp32 +2474 } +2475 # else abort +2476 e9/jump $emit-subx-statement:abort/disp32 +2477 $emit-subx-statement:end: +2478 # . restore registers +2479 59/pop-to-ecx +2480 58/pop-to-eax +2481 # . epilogue +2482 89/<- %esp 5/r32/ebp +2483 5d/pop-to-ebp +2484 c3/return +2485 +2486 $emit-subx-statement:abort: +2487 # error("couldn't translate '" stmt "'\n") +2488 (write-buffered Stderr "couldn't translate '") +2489 #? (emit-string Stderr *(ebp+0xc)) # TODO +2490 (write-buffered Stderr "'\n") +2491 (flush Stderr) +2492 # . syscall(exit, 1) +2493 bb/copy-to-ebx 1/imm32 +2494 b8/copy-to-eax 1/imm32/exit +2495 cd/syscall 0x80/imm8 +2496 # never gets here +2497 +2498 # Primitives supported +2499 == data +2500 Primitives: +2501 # increment var => ff 0/subop/increment *(ebp+__) +2502 "increment"/imm32/name +2503 Single-int-var-on-stack/imm32/inouts +2504 0/imm32/no-outputs +2505 "ff 0/subop/increment"/imm32/subx-name +2506 1/imm32/rm32-is-first-inout +2507 0/imm32/no-r32 +2508 0/imm32/no-imm32 +2509 _Primitive-inc-reg/imm32/next +2510 _Primitive-inc-reg: +2511 # var/reg <- increment => ff 0/subop/increment %__ +2512 "increment"/imm32/name +2513 0/imm32/no-inouts +2514 Single-int-var-in-some-register/imm32/outputs +2515 "ff 0/subop/increment"/imm32/subx-name +2516 3/imm32/rm32-is-first-output +2517 0/imm32/no-r32 +2518 0/imm32/no-imm32 +2519 _Primitive-add-reg-to-reg/imm32/next +2520 _Primitive-add-reg-to-reg: +2521 # var1/reg <- add var2/reg => 01 var1/rm32 var2/r32 +2522 "add"/imm32/name +2523 Single-int-var-in-some-register/imm32/inouts +2524 Single-int-var-in-some-register/imm32/outputs +2525 "01"/imm32/subx-name +2526 3/imm32/rm32-is-first-output +2527 1/imm32/r32-is-first-inout +2528 0/imm32/no-imm32 +2529 _Primitive-add-reg-to-mem/imm32/next +2530 _Primitive-add-reg-to-mem: +2531 # add-to var1 var2/reg => 01 var1 var2/r32 +2532 "add-to"/imm32/name +2533 Int-var-and-second-int-var-in-some-register/imm32/inouts +2534 0/imm32/outputs +2535 "01"/imm32/subx-name +2536 1/imm32/rm32-is-first-inout +2537 2/imm32/r32-is-second-inout +2538 0/imm32/no-imm32 +2539 _Primitive-add-mem-to-reg/imm32/next +2540 _Primitive-add-mem-to-reg: +2541 # var1/reg <- add var2 => 03 var2/rm32 var1/r32 +2542 "add"/imm32/name +2543 Single-int-var-on-stack/imm32/inouts +2544 Single-int-var-in-some-register/imm32/outputs +2545 "03"/imm32/subx-name +2546 1/imm32/rm32-is-first-inout +2547 3/imm32/r32-is-first-output +2548 0/imm32/no-imm32 +2549 _Primitive-add-lit-to-reg/imm32/next +2550 _Primitive-add-lit-to-reg: +2551 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 +2552 "add"/imm32/name +2553 Single-lit-var/imm32/inouts +2554 Single-int-var-in-some-register/imm32/outputs +2555 "81 0/subop/add"/imm32/subx-name +2556 3/imm32/rm32-is-first-output +2557 0/imm32/no-r32 +2558 1/imm32/imm32-is-first-inout +2559 _Primitive-add-lit-to-mem/imm32/next +2560 _Primitive-add-lit-to-mem: +2561 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 +2562 "add-to"/imm32/name +2563 Int-var-and-literal/imm32/inouts +2564 0/imm32/outputs +2565 "81 0/subop/add"/imm32/subx-name +2566 1/imm32/rm32-is-first-inout +2567 0/imm32/no-r32 +2568 2/imm32/imm32-is-first-inout 2569 0/imm32/next 2570 -2571 Lit-var: -2572 "literal"/imm32/name -2573 0/imm32/type-literal -2574 1/imm32/some-block-depth -2575 0/imm32/no-stack-offset -2576 0/imm32/no-register -2577 -2578 == code -2579 emit-subx-primitive: # out : (address buffered-file), stmt : (address statement), vars : (address variable), primitive : (address function) -2580 # . prologue -2581 55/push-ebp -2582 89/<- %ebp 4/r32/esp -2583 # . save registers -2584 50/push-eax -2585 51/push-ecx -2586 # ecx = primitive -2587 8b/-> *(ebp+0x14) 1/r32/ecx -2588 # emit primitive name -2589 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name -2590 # emit rm32 if necessary -2591 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt -2592 # emit r32 if necessary -2593 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt -2594 # emit imm32 if necessary -2595 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt -2596 $emit-subx-primitive:end: -2597 # . restore registers -2598 59/pop-to-ecx -2599 58/pop-to-eax -2600 # . epilogue -2601 89/<- %esp 5/r32/ebp -2602 5d/pop-to-ebp -2603 c3/return +2571 Single-int-var-on-stack: +2572 Int-var-on-stack/imm32 +2573 0/imm32/next +2574 +2575 Int-var-on-stack: +2576 "arg1"/imm32/name +2577 1/imm32/type-int +2578 1/imm32/some-block-depth +2579 1/imm32/some-stack-offset +2580 0/imm32/no-register +2581 +2582 Int-var-and-second-int-var-in-some-register: +2583 Int-var-on-stack/imm32 +2584 Single-int-var-in-some-register/imm32/next +2585 +2586 Int-var-and-literal: +2587 Int-var-on-stack/imm32 +2588 Single-lit-var/imm32/next +2589 +2590 Single-int-var-in-some-register: +2591 Int-var-in-some-register/imm32 +2592 0/imm32/next +2593 +2594 Int-var-in-some-register: +2595 "arg1"/imm32/name +2596 1/imm32/type-int +2597 1/imm32/some-block-depth +2598 0/imm32/no-stack-offset +2599 "*"/imm32/register +2600 +2601 Single-lit-var: +2602 Lit-var/imm32 +2603 0/imm32/next 2604 -2605 emit-subx-rm32: # out : (address buffered-file), l : arg-location, stmt : (address statement) -2606 # . prologue -2607 55/push-ebp -2608 89/<- %ebp 4/r32/esp -2609 # . save registers -2610 50/push-eax -2611 # if (l == 0) return -2612 81 7/subop/compare *(ebp+0xc) 0/imm32 -2613 74/jump-if-equal $emit-subx-rm32:end/disp8 -2614 # -2615 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -2616 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var -2617 $emit-subx-rm32:end: -2618 # . restore registers -2619 58/pop-to-eax -2620 # . epilogue -2621 89/<- %esp 5/r32/ebp -2622 5d/pop-to-ebp -2623 c3/return -2624 -2625 get-stmt-operand-from-arg-location: # stmt : (address statement), l : arg-location -> var/eax : (address variable) -2626 # . prologue -2627 55/push-ebp -2628 89/<- %ebp 4/r32/esp -2629 # . save registers -2630 51/push-ecx -2631 # eax = l -2632 8b/-> *(ebp+0xc) 0/r32/eax -2633 # ecx = stmt -2634 8b/-> *(ebp+8) 1/r32/ecx -2635 # if (l == 1) return stmt->inouts->var -2636 { -2637 3d/compare-eax-and 1/imm32 -2638 75/jump-if-not-equal break/disp8 -2639 $get-stmt-operand-from-arg-location:1: -2640 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -2641 8b/-> *eax 0/r32/eax # Operand-var -2642 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -2643 } -2644 # if (l == 2) return stmt->inouts->next->var -2645 { -2646 3d/compare-eax-and 2/imm32 -2647 75/jump-if-not-equal break/disp8 -2648 $get-stmt-operand-from-arg-location:2: -2649 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -2650 8b/-> *(eax+4) 0/r32/eax # Operand-next -2651 8b/-> *eax 0/r32/eax # Operand-var -2652 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -2653 } -2654 # if (l == 3) return stmt->outputs -2655 { -2656 3d/compare-eax-and 3/imm32 -2657 75/jump-if-not-equal break/disp8 -2658 $get-stmt-operand-from-arg-location:3: -2659 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs -2660 8b/-> *eax 0/r32/eax # Operand-var -2661 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -2662 } -2663 # abort -2664 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 -2665 $get-stmt-operand-from-arg-location:end: -2666 # . restore registers -2667 59/pop-to-ecx -2668 # . epilogue -2669 89/<- %esp 5/r32/ebp -2670 5d/pop-to-ebp -2671 c3/return -2672 -2673 $get-stmt-operand-from-arg-location:abort: -2674 # error("invalid arg-location " eax) -2675 (write-buffered Stderr "invalid arg-location ") -2676 (print-int32-buffered Stderr %eax) -2677 (write-buffered Stderr "\n") -2678 (flush Stderr) -2679 # . syscall(exit, 1) -2680 bb/copy-to-ebx 1/imm32 -2681 b8/copy-to-eax 1/imm32/exit -2682 cd/syscall 0x80/imm8 -2683 # never gets here -2684 -2685 emit-subx-r32: # out : (address buffered-file), l : arg-location, stmt : (address statement) -2686 # . prologue -2687 55/push-ebp -2688 89/<- %ebp 4/r32/esp -2689 # . save registers -2690 50/push-eax -2691 51/push-ecx -2692 # if (location == 0) return -2693 81 7/subop/compare *(ebp+0xc) 0/imm32 -2694 0f 84/jump-if-equal $emit-subx-r32:end/disp32 -2695 # -2696 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -2697 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (address register-index) -2698 (write-buffered *(ebp+8) Space) -2699 (print-int32-buffered *(ebp+8) *eax) -2700 (write-buffered *(ebp+8) "/r32") -2701 $emit-subx-r32:end: -2702 # . restore registers -2703 59/pop-to-ecx -2704 58/pop-to-eax -2705 # . epilogue -2706 89/<- %esp 5/r32/ebp -2707 5d/pop-to-ebp -2708 c3/return -2709 -2710 emit-subx-imm32: # out : (address buffered-file), l : arg-location, stmt : (address statement) -2711 # . prologue -2712 55/push-ebp -2713 89/<- %ebp 4/r32/esp -2714 # . save registers -2715 50/push-eax -2716 51/push-ecx -2717 # if (location == 0) return -2718 81 7/subop/compare *(ebp+0xc) 0/imm32 -2719 74/jump-if-equal $emit-subx-imm32:end/disp8 -2720 # -2721 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -2722 (write-buffered *(ebp+8) Space) -2723 (write-buffered *(ebp+8) *eax) # Var-name -2724 (write-buffered *(ebp+8) "/imm32") -2725 $emit-subx-imm32:end: -2726 # . restore registers -2727 59/pop-to-ecx -2728 58/pop-to-eax -2729 # . epilogue -2730 89/<- %esp 5/r32/ebp -2731 5d/pop-to-ebp -2732 c3/return -2733 -2734 emit-subx-call: # out : (address buffered-file), stmt : (address statement), vars : (address variable), callee : (address function) -2735 # . prologue -2736 55/push-ebp -2737 89/<- %ebp 4/r32/esp -2738 # . save registers -2739 50/push-eax -2740 51/push-ecx -2741 # -2742 (write-buffered *(ebp+8) "(") -2743 # - emit function name -2744 8b/-> *(ebp+0x14) 1/r32/ecx -2745 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name -2746 # - emit arguments -2747 # var curr/ecx : (list var) = stmt->inouts -2748 8b/-> *(ebp+0xc) 1/r32/ecx -2749 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts -2750 { -2751 # if (curr == null) break -2752 81 7/subop/compare %ecx 0/imm32 -2753 74/jump-if-equal break/disp8 -2754 # -2755 (emit-subx-call-operand *(ebp+8) *ecx) -2756 # curr = curr->next -2757 8b/-> *(ecx+4) 1/r32/ecx -2758 } -2759 # -2760 (write-buffered *(ebp+8) ")") -2761 $emit-subx-call:end: -2762 # . restore registers -2763 59/pop-to-ecx -2764 58/pop-to-eax -2765 # . epilogue -2766 89/<- %esp 5/r32/ebp -2767 5d/pop-to-ebp -2768 c3/return -2769 -2770 emit-subx-call-operand: # out : (address buffered-file), operand : (address variable) -2771 # . prologue -2772 55/push-ebp -2773 89/<- %ebp 4/r32/esp -2774 # . save registers -2775 50/push-eax -2776 # eax = operand -2777 8b/-> *(ebp+0xc) 0/r32/eax -2778 # if non-literal, emit appropriately -2779 (emit-subx-var-as-rm32 *(ebp+8) %eax) -2780 # else if (operand->type == literal) emit "__" -2781 { -2782 81 7/subop/compare *(eax+4) 0/imm32 # Var-type -2783 75/jump-if-not-equal break/disp8 -2784 $emit-subx-call-operand:literal: -2785 (write-buffered *(ebp+8) Space) -2786 (write-buffered *(ebp+8) *eax) -2787 } -2788 $emit-subx-call-operand:end: -2789 # . restore registers -2790 58/pop-to-eax -2791 # . epilogue -2792 89/<- %esp 5/r32/ebp -2793 5d/pop-to-ebp -2794 c3/return -2795 -2796 emit-subx-var-as-rm32: # out : (address buffered-file), operand : (address variable) -2797 # . prologue -2798 55/push-ebp -2799 89/<- %ebp 4/r32/esp -2800 # . save registers -2801 50/push-eax -2802 # eax = operand -2803 8b/-> *(ebp+0xc) 0/r32/eax -2804 # if (operand->register) emit "%__" -2805 { -2806 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -2807 74/jump-if-equal break/disp8 -2808 $emit-subx-var-as-rm32:register: -2809 (write-buffered *(ebp+8) " %") -2810 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -2811 } -2812 # else if (operand->stack-offset) emit "*(ebp+__)" -2813 { -2814 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -2815 74/jump-if-equal break/disp8 -2816 $emit-subx-var-as-rm32:stack: -2817 (write-buffered *(ebp+8) Space) -2818 (write-buffered *(ebp+8) "*(ebp+") -2819 8b/-> *(ebp+0xc) 0/r32/eax -2820 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -2821 (write-buffered *(ebp+8) ")") -2822 } -2823 $emit-subx-var-as-rm32:end: -2824 # . restore registers -2825 58/pop-to-eax -2826 # . epilogue -2827 89/<- %esp 5/r32/ebp -2828 5d/pop-to-ebp -2829 c3/return -2830 -2831 find-matching-function: # functions : (address function), stmt : (address statement) -> result/eax : (address function) -2832 # . prologue -2833 55/push-ebp -2834 89/<- %ebp 4/r32/esp -2835 # . save registers -2836 51/push-ecx -2837 # var curr/ecx : (address function) = functions -2838 8b/-> *(ebp+8) 1/r32/ecx +2605 Lit-var: +2606 "literal"/imm32/name +2607 0/imm32/type-literal +2608 1/imm32/some-block-depth +2609 0/imm32/no-stack-offset +2610 0/imm32/no-register +2611 +2612 == code +2613 emit-subx-primitive: # out : (address buffered-file), stmt : (address statement), vars : (address variable), primitive : (address function) +2614 # . prologue +2615 55/push-ebp +2616 89/<- %ebp 4/r32/esp +2617 # . save registers +2618 50/push-eax +2619 51/push-ecx +2620 # ecx = primitive +2621 8b/-> *(ebp+0x14) 1/r32/ecx +2622 # emit primitive name +2623 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name +2624 # emit rm32 if necessary +2625 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt +2626 # emit r32 if necessary +2627 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt +2628 # emit imm32 if necessary +2629 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt +2630 $emit-subx-primitive:end: +2631 # . restore registers +2632 59/pop-to-ecx +2633 58/pop-to-eax +2634 # . epilogue +2635 89/<- %esp 5/r32/ebp +2636 5d/pop-to-ebp +2637 c3/return +2638 +2639 emit-subx-rm32: # out : (address buffered-file), l : arg-location, stmt : (address statement) +2640 # . prologue +2641 55/push-ebp +2642 89/<- %ebp 4/r32/esp +2643 # . save registers +2644 50/push-eax +2645 # if (l == 0) return +2646 81 7/subop/compare *(ebp+0xc) 0/imm32 +2647 74/jump-if-equal $emit-subx-rm32:end/disp8 +2648 # +2649 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +2650 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var +2651 $emit-subx-rm32:end: +2652 # . restore registers +2653 58/pop-to-eax +2654 # . epilogue +2655 89/<- %esp 5/r32/ebp +2656 5d/pop-to-ebp +2657 c3/return +2658 +2659 get-stmt-operand-from-arg-location: # stmt : (address statement), l : arg-location -> var/eax : (address variable) +2660 # . prologue +2661 55/push-ebp +2662 89/<- %ebp 4/r32/esp +2663 # . save registers +2664 51/push-ecx +2665 # eax = l +2666 8b/-> *(ebp+0xc) 0/r32/eax +2667 # ecx = stmt +2668 8b/-> *(ebp+8) 1/r32/ecx +2669 # if (l == 1) return stmt->inouts->var +2670 { +2671 3d/compare-eax-and 1/imm32 +2672 75/jump-if-not-equal break/disp8 +2673 $get-stmt-operand-from-arg-location:1: +2674 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +2675 8b/-> *eax 0/r32/eax # Operand-var +2676 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +2677 } +2678 # if (l == 2) return stmt->inouts->next->var +2679 { +2680 3d/compare-eax-and 2/imm32 +2681 75/jump-if-not-equal break/disp8 +2682 $get-stmt-operand-from-arg-location:2: +2683 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +2684 8b/-> *(eax+4) 0/r32/eax # Operand-next +2685 8b/-> *eax 0/r32/eax # Operand-var +2686 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +2687 } +2688 # if (l == 3) return stmt->outputs +2689 { +2690 3d/compare-eax-and 3/imm32 +2691 75/jump-if-not-equal break/disp8 +2692 $get-stmt-operand-from-arg-location:3: +2693 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs +2694 8b/-> *eax 0/r32/eax # Operand-var +2695 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +2696 } +2697 # abort +2698 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 +2699 $get-stmt-operand-from-arg-location:end: +2700 # . restore registers +2701 59/pop-to-ecx +2702 # . epilogue +2703 89/<- %esp 5/r32/ebp +2704 5d/pop-to-ebp +2705 c3/return +2706 +2707 $get-stmt-operand-from-arg-location:abort: +2708 # error("invalid arg-location " eax) +2709 (write-buffered Stderr "invalid arg-location ") +2710 (print-int32-buffered Stderr %eax) +2711 (write-buffered Stderr "\n") +2712 (flush Stderr) +2713 # . syscall(exit, 1) +2714 bb/copy-to-ebx 1/imm32 +2715 b8/copy-to-eax 1/imm32/exit +2716 cd/syscall 0x80/imm8 +2717 # never gets here +2718 +2719 emit-subx-r32: # out : (address buffered-file), l : arg-location, stmt : (address statement) +2720 # . prologue +2721 55/push-ebp +2722 89/<- %ebp 4/r32/esp +2723 # . save registers +2724 50/push-eax +2725 51/push-ecx +2726 # if (location == 0) return +2727 81 7/subop/compare *(ebp+0xc) 0/imm32 +2728 0f 84/jump-if-equal $emit-subx-r32:end/disp32 +2729 # +2730 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +2731 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (address register-index) +2732 (write-buffered *(ebp+8) Space) +2733 (print-int32-buffered *(ebp+8) *eax) +2734 (write-buffered *(ebp+8) "/r32") +2735 $emit-subx-r32:end: +2736 # . restore registers +2737 59/pop-to-ecx +2738 58/pop-to-eax +2739 # . epilogue +2740 89/<- %esp 5/r32/ebp +2741 5d/pop-to-ebp +2742 c3/return +2743 +2744 emit-subx-imm32: # out : (address buffered-file), l : arg-location, stmt : (address statement) +2745 # . prologue +2746 55/push-ebp +2747 89/<- %ebp 4/r32/esp +2748 # . save registers +2749 50/push-eax +2750 51/push-ecx +2751 # if (location == 0) return +2752 81 7/subop/compare *(ebp+0xc) 0/imm32 +2753 74/jump-if-equal $emit-subx-imm32:end/disp8 +2754 # +2755 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +2756 (write-buffered *(ebp+8) Space) +2757 (write-buffered *(ebp+8) *eax) # Var-name +2758 (write-buffered *(ebp+8) "/imm32") +2759 $emit-subx-imm32:end: +2760 # . restore registers +2761 59/pop-to-ecx +2762 58/pop-to-eax +2763 # . epilogue +2764 89/<- %esp 5/r32/ebp +2765 5d/pop-to-ebp +2766 c3/return +2767 +2768 emit-subx-call: # out : (address buffered-file), stmt : (address statement), vars : (address variable), callee : (address function) +2769 # . prologue +2770 55/push-ebp +2771 89/<- %ebp 4/r32/esp +2772 # . save registers +2773 50/push-eax +2774 51/push-ecx +2775 # +2776 (write-buffered *(ebp+8) "(") +2777 # - emit function name +2778 8b/-> *(ebp+0x14) 1/r32/ecx +2779 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name +2780 # - emit arguments +2781 # var curr/ecx : (list var) = stmt->inouts +2782 8b/-> *(ebp+0xc) 1/r32/ecx +2783 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts +2784 { +2785 # if (curr == null) break +2786 81 7/subop/compare %ecx 0/imm32 +2787 74/jump-if-equal break/disp8 +2788 # +2789 (emit-subx-call-operand *(ebp+8) *ecx) +2790 # curr = curr->next +2791 8b/-> *(ecx+4) 1/r32/ecx +2792 } +2793 # +2794 (write-buffered *(ebp+8) ")") +2795 $emit-subx-call:end: +2796 # . restore registers +2797 59/pop-to-ecx +2798 58/pop-to-eax +2799 # . epilogue +2800 89/<- %esp 5/r32/ebp +2801 5d/pop-to-ebp +2802 c3/return +2803 +2804 emit-subx-call-operand: # out : (address buffered-file), operand : (address variable) +2805 # . prologue +2806 55/push-ebp +2807 89/<- %ebp 4/r32/esp +2808 # . save registers +2809 50/push-eax +2810 # eax = operand +2811 8b/-> *(ebp+0xc) 0/r32/eax +2812 # if non-literal, emit appropriately +2813 (emit-subx-var-as-rm32 *(ebp+8) %eax) +2814 # else if (operand->type == literal) emit "__" +2815 { +2816 81 7/subop/compare *(eax+4) 0/imm32 # Var-type +2817 75/jump-if-not-equal break/disp8 +2818 $emit-subx-call-operand:literal: +2819 (write-buffered *(ebp+8) Space) +2820 (write-buffered *(ebp+8) *eax) +2821 } +2822 $emit-subx-call-operand:end: +2823 # . restore registers +2824 58/pop-to-eax +2825 # . epilogue +2826 89/<- %esp 5/r32/ebp +2827 5d/pop-to-ebp +2828 c3/return +2829 +2830 emit-subx-var-as-rm32: # out : (address buffered-file), operand : (address variable) +2831 # . prologue +2832 55/push-ebp +2833 89/<- %ebp 4/r32/esp +2834 # . save registers +2835 50/push-eax +2836 # eax = operand +2837 8b/-> *(ebp+0xc) 0/r32/eax +2838 # if (operand->register) emit "%__" 2839 { -2840 # if (curr == null) break -2841 81 7/subop/compare %ecx 0/imm32 -2842 74/jump-if-equal break/disp8 -2843 # if match(curr, stmt) return curr -2844 { -2845 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax -2846 3d/compare-eax-and 0/imm32 -2847 74/jump-if-equal break/disp8 -2848 89/<- %eax 1/r32/ecx -2849 eb/jump $find-matching-function:end/disp8 -2850 } -2851 # curr = curr->next -2852 8b/-> *(ecx+0x10) 1/r32/ecx # Function-next -2853 eb/jump loop/disp8 -2854 } -2855 # return null -2856 b8/copy-to-eax 0/imm32 -2857 $find-matching-function:end: +2840 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +2841 74/jump-if-equal break/disp8 +2842 $emit-subx-var-as-rm32:register: +2843 (write-buffered *(ebp+8) " %") +2844 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +2845 } +2846 # else if (operand->stack-offset) emit "*(ebp+__)" +2847 { +2848 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +2849 74/jump-if-equal break/disp8 +2850 $emit-subx-var-as-rm32:stack: +2851 (write-buffered *(ebp+8) Space) +2852 (write-buffered *(ebp+8) "*(ebp+") +2853 8b/-> *(ebp+0xc) 0/r32/eax +2854 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +2855 (write-buffered *(ebp+8) ")") +2856 } +2857 $emit-subx-var-as-rm32:end: 2858 # . restore registers -2859 59/pop-to-ecx +2859 58/pop-to-eax 2860 # . epilogue 2861 89/<- %esp 5/r32/ebp 2862 5d/pop-to-ebp 2863 c3/return 2864 -2865 find-matching-primitive: # primitives : (address primitive), stmt : (address statement) -> result/eax : (address primitive) +2865 find-matching-function: # functions : (address function), stmt : (address statement) -> result/eax : (address function) 2866 # . prologue 2867 55/push-ebp 2868 89/<- %ebp 4/r32/esp 2869 # . save registers 2870 51/push-ecx -2871 # var curr/ecx : (address primitive) = primitives +2871 # var curr/ecx : (address function) = functions 2872 8b/-> *(ebp+8) 1/r32/ecx 2873 { -2874 $find-matching-primitive:loop: -2875 # if (curr == null) break -2876 81 7/subop/compare %ecx 0/imm32 -2877 74/jump-if-equal break/disp8 -2878 # if match(curr, stmt) return curr -2879 { -2880 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax -2881 3d/compare-eax-and 0/imm32 -2882 74/jump-if-equal break/disp8 -2883 89/<- %eax 1/r32/ecx -2884 eb/jump $find-matching-function:end/disp8 -2885 } -2886 $find-matching-primitive:next-primitive: -2887 # curr = curr->next -2888 8b/-> *(ecx+0x1c) 1/r32/ecx # Primitive-next -2889 eb/jump loop/disp8 -2890 } -2891 # return null -2892 b8/copy-to-eax 0/imm32 -2893 $find-matching-primitive:end: -2894 # . restore registers -2895 59/pop-to-ecx -2896 # . epilogue -2897 89/<- %esp 5/r32/ebp -2898 5d/pop-to-ebp -2899 c3/return -2900 -2901 mu-stmt-matches-function?: # stmt : (address statement), function : (address opcode-info) => result/eax : boolean -2902 # . prologue -2903 55/push-ebp -2904 89/<- %ebp 4/r32/esp -2905 # . save registers -2906 51/push-ecx -2907 # return primitive->name == stmt->operation -2908 8b/-> *(ebp+8) 1/r32/ecx -2909 8b/-> *(ebp+0xc) 0/r32/eax -2910 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Primitive-name => eax -2911 $mu-stmt-matches-function?:end: -2912 # . restore registers -2913 59/pop-to-ecx -2914 # . epilogue -2915 89/<- %esp 5/r32/ebp -2916 5d/pop-to-ebp -2917 c3/return -2918 -2919 mu-stmt-matches-primitive?: # stmt : (address statement), primitive : (address primitive) => result/eax : boolean -2920 # A mu stmt matches a primitive if the name matches, all the inout vars -2921 # match, and all the output vars match. -2922 # Vars match if types match and registers match. -2923 # In addition, a stmt output matches a primitive's output if types match -2924 # and the primitive has a wildcard register. -2925 # . prologue -2926 55/push-ebp -2927 89/<- %ebp 4/r32/esp -2928 # . save registers -2929 51/push-ecx -2930 52/push-edx -2931 53/push-ebx -2932 56/push-esi -2933 57/push-edi -2934 # ecx = stmt -2935 8b/-> *(ebp+8) 1/r32/ecx -2936 # edx = primitive -2937 8b/-> *(ebp+0xc) 2/r32/edx -2938 { -2939 $mu-stmt-matches-primitive?:check-name: -2940 # if (primitive->name != stmt->operation) return false -2941 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax -2942 3d/compare-eax-and 0/imm32 -2943 75/jump-if-not-equal break/disp8 -2944 b8/copy-to-eax 0/imm32 -2945 e9/jump $mu-stmt-matches-primitive?:end/disp32 -2946 } -2947 $mu-stmt-matches-primitive?:check-inouts: -2948 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) -2949 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts -2950 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts -2951 { -2952 # if (curr == 0) return (curr2 == 0) -2953 { -2954 81 7/subop/compare %esi 0/imm32 -2955 75/jump-if-not-equal break/disp8 -2956 { -2957 81 7/subop/compare %edi 0/imm32 -2958 75/jump-if-not-equal break/disp8 -2959 # return true -2960 b8/copy-to-eax 1/imm32 -2961 e9/jump $mu-stmt-matches-primitive?:end/disp32 -2962 } -2963 # return false -2964 b8/copy-to-eax 0/imm32 -2965 e9/jump $mu-stmt-matches-primitive?:end/disp32 -2966 } -2967 # if (curr2 == 0) return false -2968 { -2969 81 7/subop/compare %edi 0/imm32 -2970 75/jump-if-not-equal break/disp8 -2971 b8/copy-to-eax 0/imm32 -2972 e9/jump $mu-stmt-matches-primitive?:end/disp32 -2973 } -2974 # if (curr != curr2) return false -2975 { -2976 (operand-matches-primitive? *esi *edi) # => eax -2977 3d/compare-eax-and 0/imm32 -2978 75/jump-if-not-equal break/disp8 -2979 b8/copy-to-eax 0/imm32 -2980 e9/jump $mu-stmt-matches-primitive?:end/disp32 -2981 } -2982 # curr=curr->next -2983 8b/-> *(esi+4) 6/r32/esi # Operand-next -2984 # curr2=curr2->next -2985 8b/-> *(edi+4) 7/r32/edi # Operand-next -2986 eb/jump loop/disp8 -2987 } -2988 $mu-stmt-matches-primitive?:check-outputs: -2989 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) -2990 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs -2991 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs -2992 { -2993 # if (curr == 0) return (curr2 == 0) -2994 { -2995 81 7/subop/compare %esi 0/imm32 -2996 75/jump-if-not-equal break/disp8 -2997 { -2998 81 7/subop/compare %edi 0/imm32 -2999 75/jump-if-not-equal break/disp8 -3000 # return true -3001 b8/copy-to-eax 1/imm32 -3002 e9/jump $mu-stmt-matches-primitive?:end/disp32 -3003 } -3004 # return false -3005 b8/copy-to-eax 0/imm32 -3006 e9/jump $mu-stmt-matches-primitive?:end/disp32 -3007 } -3008 # if (curr2 == 0) return false -3009 { -3010 81 7/subop/compare %edi 0/imm32 -3011 75/jump-if-not-equal break/disp8 -3012 b8/copy-to-eax 0/imm32 -3013 e9/jump $mu-stmt-matches-primitive?:end/disp32 -3014 } -3015 # if (curr != curr2) return false -3016 { -3017 (operand-matches-primitive? *esi *edi) # => eax -3018 3d/compare-eax-and 0/imm32 -3019 75/jump-if-not-equal break/disp8 -3020 b8/copy-to-eax 0/imm32 -3021 e9/jump $mu-stmt-matches-primitive?:end/disp32 -3022 } -3023 # curr=curr->next -3024 8b/-> *(ecx+4) 1/r32/ecx # Operand-next -3025 # curr2=curr2->next -3026 8b/-> *(edx+4) 2/r32/edx # Operand-next -3027 eb/jump loop/disp8 -3028 } -3029 $mu-stmt-matches-primitive?:return-true: -3030 b8/copy-to-eax 1/imm32 -3031 $mu-stmt-matches-primitive?:end: -3032 # . restore registers -3033 5f/pop-to-edi -3034 5e/pop-to-esi -3035 5b/pop-to-ebx -3036 5a/pop-to-edx -3037 59/pop-to-ecx -3038 # . epilogue -3039 89/<- %esp 5/r32/ebp -3040 5d/pop-to-ebp -3041 c3/return -3042 -3043 operand-matches-primitive?: # var : (address var), primout-var : (address var) => result/eax : boolean -3044 # . prologue -3045 55/push-ebp -3046 89/<- %ebp 4/r32/esp -3047 # . save registers -3048 56/push-esi -3049 57/push-edi -3050 # esi = var -3051 8b/-> *(ebp+8) 6/r32/esi -3052 # edi = primout-var -3053 8b/-> *(ebp+0xc) 7/r32/edi -3054 # if (var->type != primout-var->type) return false -3055 8b/-> *(esi+4) 0/r32/eax # Var-type -3056 39/compare *(edi+4) 0/r32/eax # Var-type -3057 b8/copy-to-eax 0/imm32/false -3058 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 -3059 # return false if var->register doesn't match primout-var->register -3060 { -3061 # if addresses are equal, don't return here -3062 8b/-> *(esi+0x10) 0/r32/eax -3063 39/compare *(edi+0x10) 0/r32/eax -3064 74/jump-if-equal break/disp8 -3065 # if either address is 0, return false -3066 3d/compare-eax-and 0/imm32 -3067 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -3068 81 7/subop/compare *(edi+0x10) 0/imm32 -3069 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -3070 # if primout-var->register is "*", return true -3071 (string-equal? *(edi+0x10) "*") # Var-register -3072 3d/compare-eax-and 0/imm32 -3073 b8/copy-to-eax 1/imm32/true -3074 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 -3075 # if string contents don't match, return false -3076 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register -3077 3d/compare-eax-and 0/imm32 -3078 b8/copy-to-eax 0/imm32/false -3079 74/jump-if-equal $operand-matches-primitive?:end/disp8 -3080 } -3081 # return true -3082 b8/copy-to-eax 1/imm32/true -3083 $operand-matches-primitive?:end: -3084 # . restore registers -3085 5f/pop-to-edi -3086 5e/pop-to-esi -3087 # . epilogue -3088 89/<- %esp 5/r32/ebp -3089 5d/pop-to-ebp -3090 c3/return -3091 -3092 test-emit-subx-statement-primitive: -3093 # Primitive operation on a variable on the stack. -3094 # increment foo -3095 # => -3096 # ff 0/subop/increment *(ebp-8) -3097 # -3098 # There's a variable on the var stack as follows: -3099 # name: 'foo' -3100 # type: int -3101 # stack-offset: -8 -3102 # -3103 # There's a primitive with this info: -3104 # name: 'increment' -3105 # inouts: int/mem -3106 # value: 'ff 0/subop/increment' -3107 # -3108 # There's nothing in functions. -3109 # -3110 # . prologue -3111 55/push-ebp -3112 89/<- %ebp 4/r32/esp -3113 # setup -3114 (clear-stream _test-output-stream) -3115 (clear-stream _test-output-buffered-file->buffer) -3116 # var-foo/ecx : var -3117 68/push 0/imm32/no-register -3118 68/push -8/imm32/stack-offset -3119 68/push 1/imm32/block-depth -3120 68/push 1/imm32/type-int -3121 68/push "foo"/imm32 -3122 89/<- %ecx 4/r32/esp -3123 # vars/edx : (stack 1) -3124 51/push-ecx/var-foo -3125 68/push 1/imm32/data-length -3126 68/push 1/imm32/top -3127 89/<- %edx 4/r32/esp -3128 # operand/ebx : (list var) -3129 68/push 0/imm32/next -3130 51/push-ecx/var-foo -3131 89/<- %ebx 4/r32/esp -3132 # stmt/esi : statement -3133 68/push 0/imm32/next -3134 68/push 0/imm32/outputs -3135 53/push-ebx/operands -3136 68/push "increment"/imm32/operation -3137 68/push 1/imm32 -3138 89/<- %esi 4/r32/esp -3139 # primitives/ebx : primitive -3140 68/push 0/imm32/next -3141 68/push 0/imm32/no-imm32 -3142 68/push 0/imm32/no-r32 -3143 68/push 1/imm32/rm32-is-first-inout -3144 68/push "ff 0/subop/increment"/imm32/subx-name -3145 68/push 0/imm32/outputs -3146 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call -3147 68/push "increment"/imm32/name -3148 89/<- %ebx 4/r32/esp -3149 # convert -3150 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) -3151 (flush _test-output-buffered-file) -3152 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3158 # check output -3159 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") -3160 # . epilogue -3161 89/<- %esp 5/r32/ebp -3162 5d/pop-to-ebp -3163 c3/return -3164 -3165 test-emit-subx-statement-primitive-register: -3166 # Primitive operation on a variable in a register. -3167 # foo <- increment -3168 # => -3169 # ff 0/subop/increment %eax # sub-optimal, but should suffice -3170 # -3171 # There's a variable on the var stack as follows: -3172 # name: 'foo' -3173 # type: int -3174 # register: 'eax' -3175 # -3176 # There's a primitive with this info: -3177 # name: 'increment' -3178 # out: int/reg -3179 # value: 'ff 0/subop/increment' -3180 # -3181 # There's nothing in functions. -3182 # -3183 # . prologue -3184 55/push-ebp -3185 89/<- %ebp 4/r32/esp -3186 # setup -3187 (clear-stream _test-output-stream) -3188 (clear-stream _test-output-buffered-file->buffer) -3189 # var-foo/ecx : var in eax -3190 68/push "eax"/imm32/register -3191 68/push 0/imm32/no-stack-offset -3192 68/push 1/imm32/block-depth -3193 68/push 1/imm32/type-int -3194 68/push "foo"/imm32 -3195 89/<- %ecx 4/r32/esp -3196 # vars/edx : (stack 1) -3197 51/push-ecx/var-foo -3198 68/push 1/imm32/data-length -3199 68/push 1/imm32/top -3200 89/<- %edx 4/r32/esp -3201 # operand/ebx : (list var) -3202 68/push 0/imm32/next -3203 51/push-ecx/var-foo -3204 89/<- %ebx 4/r32/esp -3205 # stmt/esi : statement -3206 68/push 0/imm32/next -3207 53/push-ebx/outputs -3208 68/push 0/imm32/inouts -3209 68/push "increment"/imm32/operation -3210 68/push 1/imm32 -3211 89/<- %esi 4/r32/esp -3212 # formal-var/ebx : var in any register -3213 68/push Any-register/imm32 -3214 68/push 0/imm32/no-stack-offset -3215 68/push 1/imm32/block-depth -3216 68/push 1/imm32/type-int -3217 68/push "dummy"/imm32 -3218 89/<- %ebx 4/r32/esp -3219 # operand/ebx : (list var) -3220 68/push 0/imm32/next -3221 53/push-ebx/formal-var -3222 89/<- %ebx 4/r32/esp -3223 # primitives/ebx : primitive -3224 68/push 0/imm32/next -3225 68/push 0/imm32/no-imm32 -3226 68/push 0/imm32/no-r32 -3227 68/push 3/imm32/rm32-in-first-output -3228 68/push "ff 0/subop/increment"/imm32/subx-name -3229 53/push-ebx/outputs -3230 68/push 0/imm32/inouts -3231 68/push "increment"/imm32/name -3232 89/<- %ebx 4/r32/esp -3233 # convert -3234 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) -3235 (flush _test-output-buffered-file) -3236 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3242 # check output -3243 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") -3244 # . epilogue -3245 89/<- %esp 5/r32/ebp -3246 5d/pop-to-ebp -3247 c3/return -3248 -3249 test-emit-subx-statement-select-primitive: -3250 # Select the right primitive between overloads. -3251 # foo <- increment -3252 # => -3253 # ff 0/subop/increment %eax # sub-optimal, but should suffice -3254 # -3255 # There's a variable on the var stack as follows: -3256 # name: 'foo' -3257 # type: int -3258 # register: 'eax' -3259 # -3260 # There's two primitives, as follows: -3261 # - name: 'increment' -3262 # out: int/reg -3263 # value: 'ff 0/subop/increment' -3264 # - name: 'increment' -3265 # inout: int/mem -3266 # value: 'ff 0/subop/increment' -3267 # -3268 # There's nothing in functions. -3269 # -3270 # . prologue -3271 55/push-ebp -3272 89/<- %ebp 4/r32/esp -3273 # setup -3274 (clear-stream _test-output-stream) -3275 (clear-stream _test-output-buffered-file->buffer) -3276 # var-foo/ecx : var in eax -3277 68/push "eax"/imm32/register -3278 68/push 0/imm32/no-stack-offset -3279 68/push 1/imm32/block-depth -3280 68/push 1/imm32/type-int -3281 68/push "foo"/imm32 -3282 89/<- %ecx 4/r32/esp -3283 # vars/edx : (stack 1) -3284 51/push-ecx/var-foo -3285 68/push 1/imm32/data-length -3286 68/push 1/imm32/top -3287 89/<- %edx 4/r32/esp -3288 # real-outputs/edi : (list var) -3289 68/push 0/imm32/next -3290 51/push-ecx/var-foo -3291 89/<- %edi 4/r32/esp -3292 # stmt/esi : statement -3293 68/push 0/imm32/next -3294 57/push-edi/outputs -3295 68/push 0/imm32/inouts -3296 68/push "increment"/imm32/operation -3297 68/push 1/imm32 -3298 89/<- %esi 4/r32/esp -3299 # formal-var/ebx : var in any register -3300 68/push Any-register/imm32 -3301 68/push 0/imm32/no-stack-offset -3302 68/push 1/imm32/block-depth -3303 68/push 1/imm32/type-int -3304 68/push "dummy"/imm32 -3305 89/<- %ebx 4/r32/esp -3306 # formal-outputs/ebx : (list var) -3307 68/push 0/imm32/next -3308 53/push-ebx/formal-var -3309 89/<- %ebx 4/r32/esp -3310 # primitive1/ebx : primitive -3311 68/push 0/imm32/next -3312 68/push 0/imm32/no-imm32 -3313 68/push 0/imm32/no-r32 -3314 68/push 3/imm32/rm32-in-first-output -3315 68/push "ff 0/subop/increment"/imm32/subx-name -3316 53/push-ebx/outputs/formal-outputs -3317 68/push 0/imm32/inouts -3318 68/push "increment"/imm32/name -3319 89/<- %ebx 4/r32/esp -3320 # primitives/ebx : primitive -3321 53/push-ebx/next -3322 68/push 0/imm32/no-imm32 -3323 68/push 0/imm32/no-r32 -3324 68/push 1/imm32/rm32-is-first-inout -3325 68/push "ff 0/subop/increment"/imm32/subx-name -3326 68/push 0/imm32/outputs -3327 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -3328 68/push "increment"/imm32/name -3329 89/<- %ebx 4/r32/esp -3330 # convert -3331 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) -3332 (flush _test-output-buffered-file) -3333 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3339 # check output -3340 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") -3341 # . epilogue -3342 89/<- %esp 5/r32/ebp -3343 5d/pop-to-ebp -3344 c3/return -3345 -3346 test-emit-subx-statement-select-primitive-2: -3347 # Select the right primitive between overloads. -3348 # foo <- increment -3349 # => -3350 # ff 0/subop/increment %eax # sub-optimal, but should suffice -3351 # -3352 # There's a variable on the var stack as follows: -3353 # name: 'foo' -3354 # type: int -3355 # register: 'eax' -3356 # -3357 # There's two primitives, as follows: -3358 # - name: 'increment' -3359 # out: int/reg -3360 # value: 'ff 0/subop/increment' -3361 # - name: 'increment' -3362 # inout: int/mem -3363 # value: 'ff 0/subop/increment' -3364 # -3365 # There's nothing in functions. -3366 # -3367 # . prologue -3368 55/push-ebp -3369 89/<- %ebp 4/r32/esp -3370 # setup -3371 (clear-stream _test-output-stream) -3372 (clear-stream _test-output-buffered-file->buffer) -3373 # var-foo/ecx : var in eax -3374 68/push "eax"/imm32/register -3375 68/push 0/imm32/no-stack-offset -3376 68/push 1/imm32/block-depth -3377 68/push 1/imm32/type-int -3378 68/push "foo"/imm32 -3379 89/<- %ecx 4/r32/esp -3380 # vars/edx : (stack 1) -3381 51/push-ecx/var-foo -3382 68/push 1/imm32/data-length -3383 68/push 1/imm32/top -3384 89/<- %edx 4/r32/esp -3385 # inouts/edi : (list var) -3386 68/push 0/imm32/next -3387 51/push-ecx/var-foo -3388 89/<- %edi 4/r32/esp -3389 # stmt/esi : statement -3390 68/push 0/imm32/next -3391 68/push 0/imm32/outputs -3392 57/push-edi/inouts -3393 68/push "increment"/imm32/operation -3394 68/push 1/imm32 -3395 89/<- %esi 4/r32/esp -3396 # formal-var/ebx : var in any register -3397 68/push Any-register/imm32 -3398 68/push 0/imm32/no-stack-offset -3399 68/push 1/imm32/block-depth -3400 68/push 1/imm32/type-int -3401 68/push "dummy"/imm32 -3402 89/<- %ebx 4/r32/esp -3403 # operand/ebx : (list var) -3404 68/push 0/imm32/next -3405 53/push-ebx/formal-var -3406 89/<- %ebx 4/r32/esp -3407 # primitive1/ebx : primitive -3408 68/push 0/imm32/next -3409 68/push 0/imm32/no-imm32 -3410 68/push 0/imm32/no-r32 -3411 68/push 3/imm32/rm32-in-first-output -3412 68/push "ff 0/subop/increment"/imm32/subx-name -3413 53/push-ebx/outputs/formal-outputs -3414 68/push 0/imm32/inouts -3415 68/push "increment"/imm32/name -3416 89/<- %ebx 4/r32/esp -3417 # primitives/ebx : primitive -3418 53/push-ebx/next -3419 68/push 0/imm32/no-imm32 -3420 68/push 0/imm32/no-r32 -3421 68/push 1/imm32/rm32-is-first-inout -3422 68/push "ff 0/subop/increment"/imm32/subx-name -3423 68/push 0/imm32/outputs -3424 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -3425 68/push "increment"/imm32/name -3426 89/<- %ebx 4/r32/esp -3427 # convert -3428 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) -3429 (flush _test-output-buffered-file) -3430 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3436 # check output -3437 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") -3438 # . epilogue -3439 89/<- %esp 5/r32/ebp -3440 5d/pop-to-ebp -3441 c3/return -3442 -3443 test-increment-register: -3444 # Select the right primitive between overloads. -3445 # foo <- increment -3446 # => -3447 # ff 0/subop/increment %eax # sub-optimal, but should suffice -3448 # -3449 # There's a variable on the var stack as follows: -3450 # name: 'foo' -3451 # type: int -3452 # register: 'eax' -3453 # -3454 # Primitives are the global definitions. -3455 # -3456 # There are no functions defined. -3457 # -3458 # . prologue -3459 55/push-ebp -3460 89/<- %ebp 4/r32/esp -3461 # setup -3462 (clear-stream _test-output-stream) -3463 (clear-stream _test-output-buffered-file->buffer) -3464 # var-foo/ecx : var in eax -3465 68/push "eax"/imm32/register -3466 68/push 0/imm32/no-stack-offset -3467 68/push 1/imm32/block-depth -3468 68/push 1/imm32/type-int -3469 68/push "foo"/imm32 -3470 89/<- %ecx 4/r32/esp -3471 # vars/edx : (stack 1) -3472 51/push-ecx/var-foo -3473 68/push 1/imm32/data-length -3474 68/push 1/imm32/top -3475 89/<- %edx 4/r32/esp -3476 # real-outputs/edi : (list var) -3477 68/push 0/imm32/next -3478 51/push-ecx/var-foo -3479 89/<- %edi 4/r32/esp -3480 # stmt/esi : statement -3481 68/push 0/imm32/next -3482 57/push-edi/outputs -3483 68/push 0/imm32/inouts -3484 68/push "increment"/imm32/operation -3485 68/push 1/imm32 -3486 89/<- %esi 4/r32/esp -3487 # convert -3488 (emit-subx-statement _test-output-buffered-file %esi %edx Primitives 0) -3489 (flush _test-output-buffered-file) -3490 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3496 # check output -3497 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-register") -3498 # . epilogue -3499 89/<- %esp 5/r32/ebp -3500 5d/pop-to-ebp -3501 c3/return -3502 -3503 test-increment-var: -3504 # Select the right primitive between overloads. -3505 # foo <- increment -3506 # => -3507 # ff 0/subop/increment %eax # sub-optimal, but should suffice -3508 # -3509 # There's a variable on the var stack as follows: -3510 # name: 'foo' -3511 # type: int -3512 # register: 'eax' -3513 # -3514 # Primitives are the global definitions. -3515 # -3516 # There are no functions defined. -3517 # -3518 # . prologue -3519 55/push-ebp -3520 89/<- %ebp 4/r32/esp -3521 # setup -3522 (clear-stream _test-output-stream) -3523 (clear-stream _test-output-buffered-file->buffer) -3524 # var-foo/ecx : var in eax -3525 68/push "eax"/imm32/register -3526 68/push 0/imm32/no-stack-offset -3527 68/push 1/imm32/block-depth -3528 68/push 1/imm32/type-int -3529 68/push "foo"/imm32 -3530 89/<- %ecx 4/r32/esp -3531 # vars/edx : (stack 1) -3532 51/push-ecx/var-foo -3533 68/push 1/imm32/data-length -3534 68/push 1/imm32/top -3535 89/<- %edx 4/r32/esp -3536 # inouts/edi : (list var) -3537 68/push 0/imm32/next -3538 51/push-ecx/var-foo -3539 89/<- %edi 4/r32/esp -3540 # stmt/esi : statement -3541 68/push 0/imm32/next -3542 68/push 0/imm32/outputs -3543 57/push-edi/inouts -3544 68/push "increment"/imm32/operation -3545 68/push 1/imm32 -3546 89/<- %esi 4/r32/esp -3547 # convert -3548 (emit-subx-statement _test-output-buffered-file %esi %edx Primitives 0) -3549 (flush _test-output-buffered-file) -3550 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3556 # check output -3557 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") -3558 # . epilogue -3559 89/<- %esp 5/r32/ebp -3560 5d/pop-to-ebp -3561 c3/return -3562 -3563 test-add-reg-to-reg: -3564 # var1/reg <- add var2/reg -3565 # => -3566 # 01 %var1 var2 -3567 # -3568 # . prologue -3569 55/push-ebp -3570 89/<- %ebp 4/r32/esp -3571 # setup -3572 (clear-stream _test-output-stream) -3573 (clear-stream _test-output-buffered-file->buffer) -3574 # var-var1/ecx : var in eax -3575 68/push "eax"/imm32/register -3576 68/push 0/imm32/no-stack-offset -3577 68/push 1/imm32/block-depth -3578 68/push 1/imm32/type-int -3579 68/push "var1"/imm32 -3580 89/<- %ecx 4/r32/esp -3581 # var-var2/edx : var in ecx -3582 68/push "ecx"/imm32/register -3583 68/push 0/imm32/no-stack-offset -3584 68/push 1/imm32/block-depth -3585 68/push 1/imm32/type-int -3586 68/push "var2"/imm32 -3587 89/<- %edx 4/r32/esp -3588 # inouts/esi : (list var2) -3589 68/push 0/imm32/next -3590 52/push-edx/var-var2 -3591 89/<- %esi 4/r32/esp -3592 # outputs/edi : (list var1) -3593 68/push 0/imm32/next -3594 51/push-ecx/var-var1 -3595 89/<- %edi 4/r32/esp -3596 # stmt/esi : statement -3597 68/push 0/imm32/next -3598 57/push-edi/outputs -3599 56/push-esi/inouts -3600 68/push "add"/imm32/operation -3601 68/push 1/imm32 -3602 89/<- %esi 4/r32/esp -3603 # convert -3604 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) -3605 (flush _test-output-buffered-file) -3606 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3612 # check output -3613 (check-next-stream-line-equal _test-output-stream "01 %eax 0x00000001/r32" "F - test-add-reg-to-reg") -3614 # . epilogue -3615 89/<- %esp 5/r32/ebp -3616 5d/pop-to-ebp -3617 c3/return -3618 -3619 test-add-reg-to-mem: -3620 # add-to var1 var2/reg -3621 # => -3622 # 01 *(ebp+__) var2 -3623 # -3624 # . prologue -3625 55/push-ebp -3626 89/<- %ebp 4/r32/esp -3627 # setup -3628 (clear-stream _test-output-stream) -3629 (clear-stream _test-output-buffered-file->buffer) -3630 # var-var1/ecx : var -3631 68/push 0/imm32/no-register -3632 68/push 8/imm32/stack-offset -3633 68/push 1/imm32/block-depth -3634 68/push 1/imm32/type-int -3635 68/push "var1"/imm32 -3636 89/<- %ecx 4/r32/esp -3637 # var-var2/edx : var in ecx -3638 68/push "ecx"/imm32/register -3639 68/push 0/imm32/no-stack-offset -3640 68/push 1/imm32/block-depth -3641 68/push 1/imm32/type-int -3642 68/push "var2"/imm32 -3643 89/<- %edx 4/r32/esp -3644 # inouts/esi : (list var2) -3645 68/push 0/imm32/next -3646 52/push-edx/var-var2 -3647 89/<- %esi 4/r32/esp -3648 # inouts = (list var1 var2) -3649 56/push-esi/next -3650 51/push-ecx/var-var1 -3651 89/<- %esi 4/r32/esp -3652 # stmt/esi : statement -3653 68/push 0/imm32/next -3654 68/push 0/imm32/outputs -3655 56/push-esi/inouts -3656 68/push "add-to"/imm32/operation -3657 68/push 1/imm32 -3658 89/<- %esi 4/r32/esp -3659 # convert -3660 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) -3661 (flush _test-output-buffered-file) -3662 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3668 # check output -3669 (check-next-stream-line-equal _test-output-stream "01 *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") -3670 # . epilogue -3671 89/<- %esp 5/r32/ebp -3672 5d/pop-to-ebp -3673 c3/return -3674 -3675 test-add-mem-to-reg: -3676 # var1/reg <- add var2 -3677 # => -3678 # 03 *(ebp+__) var1 -3679 # -3680 # . prologue -3681 55/push-ebp -3682 89/<- %ebp 4/r32/esp -3683 # setup -3684 (clear-stream _test-output-stream) -3685 (clear-stream _test-output-buffered-file->buffer) -3686 # var-var1/ecx : var in eax -3687 68/push "eax"/imm32/register -3688 68/push 0/imm32/no-stack-offset -3689 68/push 1/imm32/block-depth -3690 68/push 1/imm32/type-int -3691 68/push "var1"/imm32 -3692 89/<- %ecx 4/r32/esp -3693 # var-var2/edx : var -3694 68/push 0/imm32/no-register -3695 68/push 8/imm32/stack-offset -3696 68/push 1/imm32/block-depth -3697 68/push 1/imm32/type-int -3698 68/push "var2"/imm32 -3699 89/<- %edx 4/r32/esp -3700 # inouts/esi : (list var2) -3701 68/push 0/imm32/next -3702 52/push-edx/var-var2 -3703 89/<- %esi 4/r32/esp -3704 # outputs/edi : (list var1) -3705 68/push 0/imm32/next -3706 51/push-ecx/var-var1 -3707 89/<- %edi 4/r32/esp -3708 # stmt/esi : statement -3709 68/push 0/imm32/next -3710 57/push-edi/outputs -3711 56/push-esi/inouts -3712 68/push "add"/imm32/operation -3713 68/push 1/imm32 -3714 89/<- %esi 4/r32/esp -3715 # convert -3716 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) -3717 (flush _test-output-buffered-file) -3718 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3724 # check output -3725 (check-next-stream-line-equal _test-output-stream "03 *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") -3726 # . epilogue -3727 89/<- %esp 5/r32/ebp -3728 5d/pop-to-ebp -3729 c3/return -3730 -3731 test-add-literal-to-reg: -3732 # var1/eax <- add 0x34 -3733 # => -3734 # 81 0/subop/add %eax 0x34/imm32 -3735 # -3736 # . prologue -3737 55/push-ebp -3738 89/<- %ebp 4/r32/esp -3739 # setup -3740 (clear-stream _test-output-stream) -3741 (clear-stream _test-output-buffered-file->buffer) -3742 # var-var1/ecx : var in eax -3743 68/push "eax"/imm32/register -3744 68/push 0/imm32/no-stack-offset -3745 68/push 1/imm32/block-depth -3746 68/push 1/imm32/type-int -3747 68/push "var1"/imm32 -3748 89/<- %ecx 4/r32/esp -3749 # var-var2/edx : var literal -3750 68/push 0/imm32/no-register -3751 68/push 0/imm32/no-stack-offset -3752 68/push 1/imm32/block-depth -3753 68/push 0/imm32/type-literal -3754 68/push "0x34"/imm32 -3755 89/<- %edx 4/r32/esp -3756 # inouts/esi : (list var2) -3757 68/push 0/imm32/next -3758 52/push-edx/var-var2 -3759 89/<- %esi 4/r32/esp -3760 # outputs/edi : (list var1) -3761 68/push 0/imm32/next -3762 51/push-ecx/var-var1 -3763 89/<- %edi 4/r32/esp -3764 # stmt/esi : statement -3765 68/push 0/imm32/next -3766 57/push-edi/outputs -3767 56/push-esi/inouts -3768 68/push "add"/imm32/operation -3769 68/push 1/imm32 -3770 89/<- %esi 4/r32/esp -3771 # convert -3772 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) -3773 (flush _test-output-buffered-file) -3774 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3780 # check output -3781 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %eax 0x34/imm32" "F - test-add-literal-to-reg") -3782 # . epilogue -3783 89/<- %esp 5/r32/ebp -3784 5d/pop-to-ebp -3785 c3/return -3786 -3787 test-add-literal-to-mem: -3788 # add-to var1, 0x34 -3789 # => -3790 # 81 0/subop/add %eax 0x34/imm32 -3791 # -3792 # . prologue -3793 55/push-ebp -3794 89/<- %ebp 4/r32/esp -3795 # setup -3796 (clear-stream _test-output-stream) -3797 (clear-stream _test-output-buffered-file->buffer) -3798 # var-var1/ecx : var -3799 68/push 0/imm32/no-register -3800 68/push 8/imm32/stack-offset -3801 68/push 1/imm32/block-depth -3802 68/push 1/imm32/type-int -3803 68/push "var1"/imm32 -3804 89/<- %ecx 4/r32/esp -3805 # var-var2/edx : var literal -3806 68/push 0/imm32/no-register -3807 68/push 0/imm32/no-stack-offset -3808 68/push 1/imm32/block-depth -3809 68/push 0/imm32/type-literal -3810 68/push "0x34"/imm32 -3811 89/<- %edx 4/r32/esp -3812 # inouts/esi : (list var2) -3813 68/push 0/imm32/next -3814 52/push-edx/var-var2 -3815 89/<- %esi 4/r32/esp -3816 # inouts = (list var1 inouts) -3817 56/push-esi/next -3818 51/push-ecx/var-var1 -3819 89/<- %esi 4/r32/esp -3820 # stmt/esi : statement -3821 68/push 0/imm32/next -3822 68/push 0/imm32/outputs -3823 56/push-esi/inouts -3824 68/push "add-to"/imm32/operation -3825 68/push 1/imm32 -3826 89/<- %esi 4/r32/esp -3827 # convert -3828 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) -3829 (flush _test-output-buffered-file) -3830 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3836 # check output -3837 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") -3838 # . epilogue -3839 89/<- %esp 5/r32/ebp -3840 5d/pop-to-ebp -3841 c3/return -3842 -3843 test-emit-subx-statement-function-call: -3844 # Call a function on a variable on the stack. -3845 # f foo -3846 # => -3847 # (f2 *(ebp-8)) -3848 # (Changing the function name supports overloading in general, but here it -3849 # just serves to help disambiguate things.) -3850 # -3851 # There's a variable on the var stack as follows: -3852 # name: 'foo' -3853 # type: int -3854 # stack-offset: -8 -3855 # -3856 # There's nothing in primitives. -3857 # -3858 # There's a function with this info: -3859 # name: 'f' -3860 # inout: int/mem -3861 # value: 'f2' -3862 # -3863 # . prologue -3864 55/push-ebp -3865 89/<- %ebp 4/r32/esp -3866 # setup -3867 (clear-stream _test-output-stream) -3868 (clear-stream _test-output-buffered-file->buffer) -3869 # var-foo/ecx : var -3870 68/push 0/imm32/no-register -3871 68/push -8/imm32/stack-offset -3872 68/push 0/imm32/block-depth -3873 68/push 1/imm32/type-int -3874 68/push "foo"/imm32 -3875 89/<- %ecx 4/r32/esp -3876 # vars/edx = (stack 1) -3877 51/push-ecx/var-foo -3878 68/push 1/imm32/data-length -3879 68/push 1/imm32/top -3880 89/<- %edx 4/r32/esp -3881 # operands/esi : (list var) -3882 68/push 0/imm32/next -3883 51/push-ecx/var-foo -3884 89/<- %esi 4/r32/esp -3885 # stmt/esi : statement -3886 68/push 0/imm32/next -3887 68/push 0/imm32/outputs -3888 56/push-esi/inouts -3889 68/push "f"/imm32/operation -3890 68/push 1/imm32 -3891 89/<- %esi 4/r32/esp -3892 # functions/ebx : function -3893 68/push 0/imm32/next -3894 68/push 0/imm32/body -3895 68/push 0/imm32/outputs -3896 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -3897 68/push "f2"/imm32/subx-name -3898 68/push "f"/imm32/name -3899 89/<- %ebx 4/r32/esp -3900 # convert -3901 (emit-subx-statement _test-output-buffered-file %esi %edx 0 %ebx) -3902 (flush _test-output-buffered-file) -3903 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3909 # check output -3910 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") -3911 # . epilogue -3912 89/<- %esp 5/r32/ebp -3913 5d/pop-to-ebp -3914 c3/return -3915 -3916 test-emit-subx-statement-function-call-with-literal-arg: -3917 # Call a function on a literal. -3918 # f 34 -3919 # => -3920 # (f2 34) -3921 # -3922 # . prologue -3923 55/push-ebp -3924 89/<- %ebp 4/r32/esp -3925 # setup -3926 (clear-stream _test-output-stream) -3927 (clear-stream _test-output-buffered-file->buffer) -3928 # var-foo/ecx : literal -3929 68/push 0/imm32/no-register -3930 68/push 0/imm32/no-stack-offset -3931 68/push 0/imm32/block-depth -3932 68/push 0/imm32/type-literal -3933 68/push "34"/imm32 -3934 89/<- %ecx 4/r32/esp -3935 # vars/edx = (stack 1) -3936 51/push-ecx/var-foo -3937 68/push 1/imm32/data-length -3938 68/push 1/imm32/top -3939 89/<- %edx 4/r32/esp -3940 # operands/esi : (list var) -3941 68/push 0/imm32/next -3942 51/push-ecx/var-foo -3943 89/<- %esi 4/r32/esp -3944 # stmt/esi : statement -3945 68/push 0/imm32/next -3946 68/push 0/imm32/outputs -3947 56/push-esi/inouts -3948 68/push "f"/imm32/operation -3949 68/push 1/imm32 -3950 89/<- %esi 4/r32/esp -3951 # functions/ebx : function -3952 68/push 0/imm32/next -3953 68/push 0/imm32/body -3954 68/push 0/imm32/outputs -3955 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -3956 68/push "f2"/imm32/subx-name -3957 68/push "f"/imm32/name -3958 89/<- %ebx 4/r32/esp -3959 # convert -3960 (emit-subx-statement _test-output-buffered-file %esi %edx 0 %ebx) -3961 (flush _test-output-buffered-file) -3962 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -3968 # check output -3969 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") -3970 # . epilogue -3971 89/<- %esp 5/r32/ebp -3972 5d/pop-to-ebp -3973 c3/return -3974 -3975 emit-subx-prologue: # out : (address buffered-file) -3976 # . prologue -3977 55/push-ebp -3978 89/<- %ebp 4/r32/esp -3979 # -3980 (write-buffered *(ebp+8) "# . prologue\n") -3981 (write-buffered *(ebp+8) "55/push-ebp\n") -3982 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") -3983 $emit-subx-prologue:end: -3984 # . epilogue -3985 89/<- %esp 5/r32/ebp -3986 5d/pop-to-ebp -3987 c3/return -3988 -3989 emit-subx-epilogue: # out : (address buffered-file) -3990 # . prologue -3991 55/push-ebp -3992 89/<- %ebp 4/r32/esp -3993 # -3994 (write-buffered *(ebp+8) "# . epilogue\n") -3995 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") -3996 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") -3997 (write-buffered *(ebp+8) "c3/return\n") -3998 $emit-subx-epilogue:end: -3999 # . epilogue -4000 89/<- %esp 5/r32/ebp -4001 5d/pop-to-ebp -4002 c3/return +2874 # if (curr == null) break +2875 81 7/subop/compare %ecx 0/imm32 +2876 74/jump-if-equal break/disp8 +2877 # if match(curr, stmt) return curr +2878 { +2879 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax +2880 3d/compare-eax-and 0/imm32 +2881 74/jump-if-equal break/disp8 +2882 89/<- %eax 1/r32/ecx +2883 eb/jump $find-matching-function:end/disp8 +2884 } +2885 # curr = curr->next +2886 8b/-> *(ecx+0x10) 1/r32/ecx # Function-next +2887 eb/jump loop/disp8 +2888 } +2889 # return null +2890 b8/copy-to-eax 0/imm32 +2891 $find-matching-function:end: +2892 # . restore registers +2893 59/pop-to-ecx +2894 # . epilogue +2895 89/<- %esp 5/r32/ebp +2896 5d/pop-to-ebp +2897 c3/return +2898 +2899 find-matching-primitive: # primitives : (address primitive), stmt : (address statement) -> result/eax : (address primitive) +2900 # . prologue +2901 55/push-ebp +2902 89/<- %ebp 4/r32/esp +2903 # . save registers +2904 51/push-ecx +2905 # var curr/ecx : (address primitive) = primitives +2906 8b/-> *(ebp+8) 1/r32/ecx +2907 { +2908 $find-matching-primitive:loop: +2909 # if (curr == null) break +2910 81 7/subop/compare %ecx 0/imm32 +2911 74/jump-if-equal break/disp8 +2912 # if match(curr, stmt) return curr +2913 { +2914 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax +2915 3d/compare-eax-and 0/imm32 +2916 74/jump-if-equal break/disp8 +2917 89/<- %eax 1/r32/ecx +2918 eb/jump $find-matching-function:end/disp8 +2919 } +2920 $find-matching-primitive:next-primitive: +2921 # curr = curr->next +2922 8b/-> *(ecx+0x1c) 1/r32/ecx # Primitive-next +2923 eb/jump loop/disp8 +2924 } +2925 # return null +2926 b8/copy-to-eax 0/imm32 +2927 $find-matching-primitive:end: +2928 # . restore registers +2929 59/pop-to-ecx +2930 # . epilogue +2931 89/<- %esp 5/r32/ebp +2932 5d/pop-to-ebp +2933 c3/return +2934 +2935 mu-stmt-matches-function?: # stmt : (address statement), function : (address opcode-info) => result/eax : boolean +2936 # . prologue +2937 55/push-ebp +2938 89/<- %ebp 4/r32/esp +2939 # . save registers +2940 51/push-ecx +2941 # return primitive->name == stmt->operation +2942 8b/-> *(ebp+8) 1/r32/ecx +2943 8b/-> *(ebp+0xc) 0/r32/eax +2944 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Primitive-name => eax +2945 $mu-stmt-matches-function?:end: +2946 # . restore registers +2947 59/pop-to-ecx +2948 # . epilogue +2949 89/<- %esp 5/r32/ebp +2950 5d/pop-to-ebp +2951 c3/return +2952 +2953 mu-stmt-matches-primitive?: # stmt : (address statement), primitive : (address primitive) => result/eax : boolean +2954 # A mu stmt matches a primitive if the name matches, all the inout vars +2955 # match, and all the output vars match. +2956 # Vars match if types match and registers match. +2957 # In addition, a stmt output matches a primitive's output if types match +2958 # and the primitive has a wildcard register. +2959 # . prologue +2960 55/push-ebp +2961 89/<- %ebp 4/r32/esp +2962 # . save registers +2963 51/push-ecx +2964 52/push-edx +2965 53/push-ebx +2966 56/push-esi +2967 57/push-edi +2968 # ecx = stmt +2969 8b/-> *(ebp+8) 1/r32/ecx +2970 # edx = primitive +2971 8b/-> *(ebp+0xc) 2/r32/edx +2972 { +2973 $mu-stmt-matches-primitive?:check-name: +2974 # if (primitive->name != stmt->operation) return false +2975 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax +2976 3d/compare-eax-and 0/imm32 +2977 75/jump-if-not-equal break/disp8 +2978 b8/copy-to-eax 0/imm32 +2979 e9/jump $mu-stmt-matches-primitive?:end/disp32 +2980 } +2981 $mu-stmt-matches-primitive?:check-inouts: +2982 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) +2983 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts +2984 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts +2985 { +2986 # if (curr == 0) return (curr2 == 0) +2987 { +2988 81 7/subop/compare %esi 0/imm32 +2989 75/jump-if-not-equal break/disp8 +2990 $mu-stmt-matches-primitive?:stmt-inout-is-null: +2991 { +2992 81 7/subop/compare %edi 0/imm32 +2993 75/jump-if-not-equal break/disp8 +2994 # return true +2995 b8/copy-to-eax 1/imm32/true +2996 e9/jump $mu-stmt-matches-primitive?:end/disp32 +2997 } +2998 # return false +2999 b8/copy-to-eax 0/imm32/false +3000 e9/jump $mu-stmt-matches-primitive?:end/disp32 +3001 } +3002 # if (curr2 == 0) return false +3003 { +3004 81 7/subop/compare %edi 0/imm32 +3005 75/jump-if-not-equal break/disp8 +3006 $mu-stmt-matches-primitive?:prim-inout-is-null: +3007 b8/copy-to-eax 0/imm32/false +3008 e9/jump $mu-stmt-matches-primitive?:end/disp32 +3009 } +3010 # if (curr != curr2) return false +3011 { +3012 (operand-matches-primitive? *esi *edi) # => eax +3013 3d/compare-eax-and 0/imm32 +3014 75/jump-if-not-equal break/disp8 +3015 b8/copy-to-eax 0/imm32/false +3016 e9/jump $mu-stmt-matches-primitive?:end/disp32 +3017 } +3018 # curr=curr->next +3019 8b/-> *(esi+4) 6/r32/esi # Operand-next +3020 # curr2=curr2->next +3021 8b/-> *(edi+4) 7/r32/edi # Operand-next +3022 eb/jump loop/disp8 +3023 } +3024 $mu-stmt-matches-primitive?:check-outputs: +3025 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) +3026 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs +3027 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs +3028 { +3029 # if (curr == 0) return (curr2 == 0) +3030 { +3031 81 7/subop/compare %esi 0/imm32 +3032 75/jump-if-not-equal break/disp8 +3033 { +3034 81 7/subop/compare %edi 0/imm32 +3035 75/jump-if-not-equal break/disp8 +3036 # return true +3037 b8/copy-to-eax 1/imm32 +3038 e9/jump $mu-stmt-matches-primitive?:end/disp32 +3039 } +3040 # return false +3041 b8/copy-to-eax 0/imm32 +3042 e9/jump $mu-stmt-matches-primitive?:end/disp32 +3043 } +3044 # if (curr2 == 0) return false +3045 { +3046 81 7/subop/compare %edi 0/imm32 +3047 75/jump-if-not-equal break/disp8 +3048 b8/copy-to-eax 0/imm32 +3049 e9/jump $mu-stmt-matches-primitive?:end/disp32 +3050 } +3051 # if (curr != curr2) return false +3052 { +3053 (operand-matches-primitive? *esi *edi) # => eax +3054 3d/compare-eax-and 0/imm32 +3055 75/jump-if-not-equal break/disp8 +3056 b8/copy-to-eax 0/imm32 +3057 e9/jump $mu-stmt-matches-primitive?:end/disp32 +3058 } +3059 # curr=curr->next +3060 8b/-> *(ecx+4) 1/r32/ecx # Operand-next +3061 # curr2=curr2->next +3062 8b/-> *(edx+4) 2/r32/edx # Operand-next +3063 eb/jump loop/disp8 +3064 } +3065 $mu-stmt-matches-primitive?:return-true: +3066 b8/copy-to-eax 1/imm32 +3067 $mu-stmt-matches-primitive?:end: +3068 # . restore registers +3069 5f/pop-to-edi +3070 5e/pop-to-esi +3071 5b/pop-to-ebx +3072 5a/pop-to-edx +3073 59/pop-to-ecx +3074 # . epilogue +3075 89/<- %esp 5/r32/ebp +3076 5d/pop-to-ebp +3077 c3/return +3078 +3079 operand-matches-primitive?: # var : (address var), primout-var : (address var) => result/eax : boolean +3080 # . prologue +3081 55/push-ebp +3082 89/<- %ebp 4/r32/esp +3083 # . save registers +3084 56/push-esi +3085 57/push-edi +3086 # esi = var +3087 8b/-> *(ebp+8) 6/r32/esi +3088 # edi = primout-var +3089 8b/-> *(ebp+0xc) 7/r32/edi +3090 # if (var->type != primout-var->type) return false +3091 8b/-> *(esi+4) 0/r32/eax # Var-type +3092 39/compare *(edi+4) 0/r32/eax # Var-type +3093 b8/copy-to-eax 0/imm32/false +3094 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 +3095 # return false if var->register doesn't match primout-var->register +3096 { +3097 # if addresses are equal, don't return here +3098 8b/-> *(esi+0x10) 0/r32/eax +3099 39/compare *(edi+0x10) 0/r32/eax +3100 74/jump-if-equal break/disp8 +3101 # if either address is 0, return false +3102 3d/compare-eax-and 0/imm32 +3103 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +3104 81 7/subop/compare *(edi+0x10) 0/imm32 +3105 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +3106 # if primout-var->register is "*", return true +3107 (string-equal? *(edi+0x10) "*") # Var-register +3108 3d/compare-eax-and 0/imm32 +3109 b8/copy-to-eax 1/imm32/true +3110 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 +3111 # if string contents don't match, return false +3112 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register +3113 3d/compare-eax-and 0/imm32 +3114 b8/copy-to-eax 0/imm32/false +3115 74/jump-if-equal $operand-matches-primitive?:end/disp8 +3116 } +3117 # return true +3118 b8/copy-to-eax 1/imm32/true +3119 $operand-matches-primitive?:end: +3120 # . restore registers +3121 5f/pop-to-edi +3122 5e/pop-to-esi +3123 # . epilogue +3124 89/<- %esp 5/r32/ebp +3125 5d/pop-to-ebp +3126 c3/return +3127 +3128 test-emit-subx-statement-primitive: +3129 # Primitive operation on a variable on the stack. +3130 # increment foo +3131 # => +3132 # ff 0/subop/increment *(ebp-8) +3133 # +3134 # There's a variable on the var stack as follows: +3135 # name: 'foo' +3136 # type: int +3137 # stack-offset: -8 +3138 # +3139 # There's a primitive with this info: +3140 # name: 'increment' +3141 # inouts: int/mem +3142 # value: 'ff 0/subop/increment' +3143 # +3144 # There's nothing in functions. +3145 # +3146 # . prologue +3147 55/push-ebp +3148 89/<- %ebp 4/r32/esp +3149 # setup +3150 (clear-stream _test-output-stream) +3151 (clear-stream _test-output-buffered-file->buffer) +3152 # var-foo/ecx : var +3153 68/push 0/imm32/no-register +3154 68/push -8/imm32/stack-offset +3155 68/push 1/imm32/block-depth +3156 68/push 1/imm32/type-int +3157 68/push "foo"/imm32 +3158 89/<- %ecx 4/r32/esp +3159 # vars/edx : (stack 1) +3160 51/push-ecx/var-foo +3161 68/push 1/imm32/data-length +3162 68/push 1/imm32/top +3163 89/<- %edx 4/r32/esp +3164 # operand/ebx : (list var) +3165 68/push 0/imm32/next +3166 51/push-ecx/var-foo +3167 89/<- %ebx 4/r32/esp +3168 # stmt/esi : statement +3169 68/push 0/imm32/next +3170 68/push 0/imm32/outputs +3171 53/push-ebx/operands +3172 68/push "increment"/imm32/operation +3173 68/push 1/imm32 +3174 89/<- %esi 4/r32/esp +3175 # primitives/ebx : primitive +3176 68/push 0/imm32/next +3177 68/push 0/imm32/no-imm32 +3178 68/push 0/imm32/no-r32 +3179 68/push 1/imm32/rm32-is-first-inout +3180 68/push "ff 0/subop/increment"/imm32/subx-name +3181 68/push 0/imm32/outputs +3182 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call +3183 68/push "increment"/imm32/name +3184 89/<- %ebx 4/r32/esp +3185 # convert +3186 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) +3187 (flush _test-output-buffered-file) +3188 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3194 # check output +3195 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") +3196 # . epilogue +3197 89/<- %esp 5/r32/ebp +3198 5d/pop-to-ebp +3199 c3/return +3200 +3201 test-emit-subx-statement-primitive-register: +3202 # Primitive operation on a variable in a register. +3203 # foo <- increment +3204 # => +3205 # ff 0/subop/increment %eax # sub-optimal, but should suffice +3206 # +3207 # There's a variable on the var stack as follows: +3208 # name: 'foo' +3209 # type: int +3210 # register: 'eax' +3211 # +3212 # There's a primitive with this info: +3213 # name: 'increment' +3214 # out: int/reg +3215 # value: 'ff 0/subop/increment' +3216 # +3217 # There's nothing in functions. +3218 # +3219 # . prologue +3220 55/push-ebp +3221 89/<- %ebp 4/r32/esp +3222 # setup +3223 (clear-stream _test-output-stream) +3224 (clear-stream _test-output-buffered-file->buffer) +3225 # var-foo/ecx : var in eax +3226 68/push "eax"/imm32/register +3227 68/push 0/imm32/no-stack-offset +3228 68/push 1/imm32/block-depth +3229 68/push 1/imm32/type-int +3230 68/push "foo"/imm32 +3231 89/<- %ecx 4/r32/esp +3232 # vars/edx : (stack 1) +3233 51/push-ecx/var-foo +3234 68/push 1/imm32/data-length +3235 68/push 1/imm32/top +3236 89/<- %edx 4/r32/esp +3237 # operand/ebx : (list var) +3238 68/push 0/imm32/next +3239 51/push-ecx/var-foo +3240 89/<- %ebx 4/r32/esp +3241 # stmt/esi : statement +3242 68/push 0/imm32/next +3243 53/push-ebx/outputs +3244 68/push 0/imm32/inouts +3245 68/push "increment"/imm32/operation +3246 68/push 1/imm32 +3247 89/<- %esi 4/r32/esp +3248 # formal-var/ebx : var in any register +3249 68/push Any-register/imm32 +3250 68/push 0/imm32/no-stack-offset +3251 68/push 1/imm32/block-depth +3252 68/push 1/imm32/type-int +3253 68/push "dummy"/imm32 +3254 89/<- %ebx 4/r32/esp +3255 # operand/ebx : (list var) +3256 68/push 0/imm32/next +3257 53/push-ebx/formal-var +3258 89/<- %ebx 4/r32/esp +3259 # primitives/ebx : primitive +3260 68/push 0/imm32/next +3261 68/push 0/imm32/no-imm32 +3262 68/push 0/imm32/no-r32 +3263 68/push 3/imm32/rm32-in-first-output +3264 68/push "ff 0/subop/increment"/imm32/subx-name +3265 53/push-ebx/outputs +3266 68/push 0/imm32/inouts +3267 68/push "increment"/imm32/name +3268 89/<- %ebx 4/r32/esp +3269 # convert +3270 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) +3271 (flush _test-output-buffered-file) +3272 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3278 # check output +3279 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") +3280 # . epilogue +3281 89/<- %esp 5/r32/ebp +3282 5d/pop-to-ebp +3283 c3/return +3284 +3285 test-emit-subx-statement-select-primitive: +3286 # Select the right primitive between overloads. +3287 # foo <- increment +3288 # => +3289 # ff 0/subop/increment %eax # sub-optimal, but should suffice +3290 # +3291 # There's a variable on the var stack as follows: +3292 # name: 'foo' +3293 # type: int +3294 # register: 'eax' +3295 # +3296 # There's two primitives, as follows: +3297 # - name: 'increment' +3298 # out: int/reg +3299 # value: 'ff 0/subop/increment' +3300 # - name: 'increment' +3301 # inout: int/mem +3302 # value: 'ff 0/subop/increment' +3303 # +3304 # There's nothing in functions. +3305 # +3306 # . prologue +3307 55/push-ebp +3308 89/<- %ebp 4/r32/esp +3309 # setup +3310 (clear-stream _test-output-stream) +3311 (clear-stream _test-output-buffered-file->buffer) +3312 # var-foo/ecx : var in eax +3313 68/push "eax"/imm32/register +3314 68/push 0/imm32/no-stack-offset +3315 68/push 1/imm32/block-depth +3316 68/push 1/imm32/type-int +3317 68/push "foo"/imm32 +3318 89/<- %ecx 4/r32/esp +3319 # vars/edx : (stack 1) +3320 51/push-ecx/var-foo +3321 68/push 1/imm32/data-length +3322 68/push 1/imm32/top +3323 89/<- %edx 4/r32/esp +3324 # real-outputs/edi : (list var) +3325 68/push 0/imm32/next +3326 51/push-ecx/var-foo +3327 89/<- %edi 4/r32/esp +3328 # stmt/esi : statement +3329 68/push 0/imm32/next +3330 57/push-edi/outputs +3331 68/push 0/imm32/inouts +3332 68/push "increment"/imm32/operation +3333 68/push 1/imm32 +3334 89/<- %esi 4/r32/esp +3335 # formal-var/ebx : var in any register +3336 68/push Any-register/imm32 +3337 68/push 0/imm32/no-stack-offset +3338 68/push 1/imm32/block-depth +3339 68/push 1/imm32/type-int +3340 68/push "dummy"/imm32 +3341 89/<- %ebx 4/r32/esp +3342 # formal-outputs/ebx : (list var) +3343 68/push 0/imm32/next +3344 53/push-ebx/formal-var +3345 89/<- %ebx 4/r32/esp +3346 # primitive1/ebx : primitive +3347 68/push 0/imm32/next +3348 68/push 0/imm32/no-imm32 +3349 68/push 0/imm32/no-r32 +3350 68/push 3/imm32/rm32-in-first-output +3351 68/push "ff 0/subop/increment"/imm32/subx-name +3352 53/push-ebx/outputs/formal-outputs +3353 68/push 0/imm32/inouts +3354 68/push "increment"/imm32/name +3355 89/<- %ebx 4/r32/esp +3356 # primitives/ebx : primitive +3357 53/push-ebx/next +3358 68/push 0/imm32/no-imm32 +3359 68/push 0/imm32/no-r32 +3360 68/push 1/imm32/rm32-is-first-inout +3361 68/push "ff 0/subop/increment"/imm32/subx-name +3362 68/push 0/imm32/outputs +3363 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +3364 68/push "increment"/imm32/name +3365 89/<- %ebx 4/r32/esp +3366 # convert +3367 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) +3368 (flush _test-output-buffered-file) +3369 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3375 # check output +3376 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") +3377 # . epilogue +3378 89/<- %esp 5/r32/ebp +3379 5d/pop-to-ebp +3380 c3/return +3381 +3382 test-emit-subx-statement-select-primitive-2: +3383 # Select the right primitive between overloads. +3384 # foo <- increment +3385 # => +3386 # ff 0/subop/increment %eax # sub-optimal, but should suffice +3387 # +3388 # There's a variable on the var stack as follows: +3389 # name: 'foo' +3390 # type: int +3391 # register: 'eax' +3392 # +3393 # There's two primitives, as follows: +3394 # - name: 'increment' +3395 # out: int/reg +3396 # value: 'ff 0/subop/increment' +3397 # - name: 'increment' +3398 # inout: int/mem +3399 # value: 'ff 0/subop/increment' +3400 # +3401 # There's nothing in functions. +3402 # +3403 # . prologue +3404 55/push-ebp +3405 89/<- %ebp 4/r32/esp +3406 # setup +3407 (clear-stream _test-output-stream) +3408 (clear-stream _test-output-buffered-file->buffer) +3409 # var-foo/ecx : var in eax +3410 68/push "eax"/imm32/register +3411 68/push 0/imm32/no-stack-offset +3412 68/push 1/imm32/block-depth +3413 68/push 1/imm32/type-int +3414 68/push "foo"/imm32 +3415 89/<- %ecx 4/r32/esp +3416 # vars/edx : (stack 1) +3417 51/push-ecx/var-foo +3418 68/push 1/imm32/data-length +3419 68/push 1/imm32/top +3420 89/<- %edx 4/r32/esp +3421 # inouts/edi : (list var) +3422 68/push 0/imm32/next +3423 51/push-ecx/var-foo +3424 89/<- %edi 4/r32/esp +3425 # stmt/esi : statement +3426 68/push 0/imm32/next +3427 68/push 0/imm32/outputs +3428 57/push-edi/inouts +3429 68/push "increment"/imm32/operation +3430 68/push 1/imm32 +3431 89/<- %esi 4/r32/esp +3432 # formal-var/ebx : var in any register +3433 68/push Any-register/imm32 +3434 68/push 0/imm32/no-stack-offset +3435 68/push 1/imm32/block-depth +3436 68/push 1/imm32/type-int +3437 68/push "dummy"/imm32 +3438 89/<- %ebx 4/r32/esp +3439 # operand/ebx : (list var) +3440 68/push 0/imm32/next +3441 53/push-ebx/formal-var +3442 89/<- %ebx 4/r32/esp +3443 # primitive1/ebx : primitive +3444 68/push 0/imm32/next +3445 68/push 0/imm32/no-imm32 +3446 68/push 0/imm32/no-r32 +3447 68/push 3/imm32/rm32-in-first-output +3448 68/push "ff 0/subop/increment"/imm32/subx-name +3449 53/push-ebx/outputs/formal-outputs +3450 68/push 0/imm32/inouts +3451 68/push "increment"/imm32/name +3452 89/<- %ebx 4/r32/esp +3453 # primitives/ebx : primitive +3454 53/push-ebx/next +3455 68/push 0/imm32/no-imm32 +3456 68/push 0/imm32/no-r32 +3457 68/push 1/imm32/rm32-is-first-inout +3458 68/push "ff 0/subop/increment"/imm32/subx-name +3459 68/push 0/imm32/outputs +3460 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +3461 68/push "increment"/imm32/name +3462 89/<- %ebx 4/r32/esp +3463 # convert +3464 (emit-subx-statement _test-output-buffered-file %esi %edx %ebx 0) +3465 (flush _test-output-buffered-file) +3466 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3472 # check output +3473 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") +3474 # . epilogue +3475 89/<- %esp 5/r32/ebp +3476 5d/pop-to-ebp +3477 c3/return +3478 +3479 test-increment-register: +3480 # Select the right primitive between overloads. +3481 # foo <- increment +3482 # => +3483 # ff 0/subop/increment %eax # sub-optimal, but should suffice +3484 # +3485 # There's a variable on the var stack as follows: +3486 # name: 'foo' +3487 # type: int +3488 # register: 'eax' +3489 # +3490 # Primitives are the global definitions. +3491 # +3492 # There are no functions defined. +3493 # +3494 # . prologue +3495 55/push-ebp +3496 89/<- %ebp 4/r32/esp +3497 # setup +3498 (clear-stream _test-output-stream) +3499 (clear-stream _test-output-buffered-file->buffer) +3500 # var-foo/ecx : var in eax +3501 68/push "eax"/imm32/register +3502 68/push 0/imm32/no-stack-offset +3503 68/push 1/imm32/block-depth +3504 68/push 1/imm32/type-int +3505 68/push "foo"/imm32 +3506 89/<- %ecx 4/r32/esp +3507 # vars/edx : (stack 1) +3508 51/push-ecx/var-foo +3509 68/push 1/imm32/data-length +3510 68/push 1/imm32/top +3511 89/<- %edx 4/r32/esp +3512 # real-outputs/edi : (list var) +3513 68/push 0/imm32/next +3514 51/push-ecx/var-foo +3515 89/<- %edi 4/r32/esp +3516 # stmt/esi : statement +3517 68/push 0/imm32/next +3518 57/push-edi/outputs +3519 68/push 0/imm32/inouts +3520 68/push "increment"/imm32/operation +3521 68/push 1/imm32 +3522 89/<- %esi 4/r32/esp +3523 # convert +3524 (emit-subx-statement _test-output-buffered-file %esi %edx Primitives 0) +3525 (flush _test-output-buffered-file) +3526 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3532 # check output +3533 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-register") +3534 # . epilogue +3535 89/<- %esp 5/r32/ebp +3536 5d/pop-to-ebp +3537 c3/return +3538 +3539 test-increment-var: +3540 # Select the right primitive between overloads. +3541 # foo <- increment +3542 # => +3543 # ff 0/subop/increment %eax # sub-optimal, but should suffice +3544 # +3545 # There's a variable on the var stack as follows: +3546 # name: 'foo' +3547 # type: int +3548 # register: 'eax' +3549 # +3550 # Primitives are the global definitions. +3551 # +3552 # There are no functions defined. +3553 # +3554 # . prologue +3555 55/push-ebp +3556 89/<- %ebp 4/r32/esp +3557 # setup +3558 (clear-stream _test-output-stream) +3559 (clear-stream _test-output-buffered-file->buffer) +3560 # var-foo/ecx : var in eax +3561 68/push "eax"/imm32/register +3562 68/push 0/imm32/no-stack-offset +3563 68/push 1/imm32/block-depth +3564 68/push 1/imm32/type-int +3565 68/push "foo"/imm32 +3566 89/<- %ecx 4/r32/esp +3567 # vars/edx : (stack 1) +3568 51/push-ecx/var-foo +3569 68/push 1/imm32/data-length +3570 68/push 1/imm32/top +3571 89/<- %edx 4/r32/esp +3572 # inouts/edi : (list var) +3573 68/push 0/imm32/next +3574 51/push-ecx/var-foo +3575 89/<- %edi 4/r32/esp +3576 # stmt/esi : statement +3577 68/push 0/imm32/next +3578 68/push 0/imm32/outputs +3579 57/push-edi/inouts +3580 68/push "increment"/imm32/operation +3581 68/push 1/imm32 +3582 89/<- %esi 4/r32/esp +3583 # convert +3584 (emit-subx-statement _test-output-buffered-file %esi %edx Primitives 0) +3585 (flush _test-output-buffered-file) +3586 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3592 # check output +3593 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") +3594 # . epilogue +3595 89/<- %esp 5/r32/ebp +3596 5d/pop-to-ebp +3597 c3/return +3598 +3599 test-add-reg-to-reg: +3600 # var1/reg <- add var2/reg +3601 # => +3602 # 01 %var1 var2 +3603 # +3604 # . prologue +3605 55/push-ebp +3606 89/<- %ebp 4/r32/esp +3607 # setup +3608 (clear-stream _test-output-stream) +3609 (clear-stream _test-output-buffered-file->buffer) +3610 # var-var1/ecx : var in eax +3611 68/push "eax"/imm32/register +3612 68/push 0/imm32/no-stack-offset +3613 68/push 1/imm32/block-depth +3614 68/push 1/imm32/type-int +3615 68/push "var1"/imm32 +3616 89/<- %ecx 4/r32/esp +3617 # var-var2/edx : var in ecx +3618 68/push "ecx"/imm32/register +3619 68/push 0/imm32/no-stack-offset +3620 68/push 1/imm32/block-depth +3621 68/push 1/imm32/type-int +3622 68/push "var2"/imm32 +3623 89/<- %edx 4/r32/esp +3624 # inouts/esi : (list var2) +3625 68/push 0/imm32/next +3626 52/push-edx/var-var2 +3627 89/<- %esi 4/r32/esp +3628 # outputs/edi : (list var1) +3629 68/push 0/imm32/next +3630 51/push-ecx/var-var1 +3631 89/<- %edi 4/r32/esp +3632 # stmt/esi : statement +3633 68/push 0/imm32/next +3634 57/push-edi/outputs +3635 56/push-esi/inouts +3636 68/push "add"/imm32/operation +3637 68/push 1/imm32 +3638 89/<- %esi 4/r32/esp +3639 # convert +3640 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) +3641 (flush _test-output-buffered-file) +3642 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3648 # check output +3649 (check-next-stream-line-equal _test-output-stream "01 %eax 0x00000001/r32" "F - test-add-reg-to-reg") +3650 # . epilogue +3651 89/<- %esp 5/r32/ebp +3652 5d/pop-to-ebp +3653 c3/return +3654 +3655 test-add-reg-to-mem: +3656 # add-to var1 var2/reg +3657 # => +3658 # 01 *(ebp+__) var2 +3659 # +3660 # . prologue +3661 55/push-ebp +3662 89/<- %ebp 4/r32/esp +3663 # setup +3664 (clear-stream _test-output-stream) +3665 (clear-stream _test-output-buffered-file->buffer) +3666 # var-var1/ecx : var +3667 68/push 0/imm32/no-register +3668 68/push 8/imm32/stack-offset +3669 68/push 1/imm32/block-depth +3670 68/push 1/imm32/type-int +3671 68/push "var1"/imm32 +3672 89/<- %ecx 4/r32/esp +3673 # var-var2/edx : var in ecx +3674 68/push "ecx"/imm32/register +3675 68/push 0/imm32/no-stack-offset +3676 68/push 1/imm32/block-depth +3677 68/push 1/imm32/type-int +3678 68/push "var2"/imm32 +3679 89/<- %edx 4/r32/esp +3680 # inouts/esi : (list var2) +3681 68/push 0/imm32/next +3682 52/push-edx/var-var2 +3683 89/<- %esi 4/r32/esp +3684 # inouts = (list var1 var2) +3685 56/push-esi/next +3686 51/push-ecx/var-var1 +3687 89/<- %esi 4/r32/esp +3688 # stmt/esi : statement +3689 68/push 0/imm32/next +3690 68/push 0/imm32/outputs +3691 56/push-esi/inouts +3692 68/push "add-to"/imm32/operation +3693 68/push 1/imm32 +3694 89/<- %esi 4/r32/esp +3695 # convert +3696 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) +3697 (flush _test-output-buffered-file) +3698 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3704 # check output +3705 (check-next-stream-line-equal _test-output-stream "01 *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") +3706 # . epilogue +3707 89/<- %esp 5/r32/ebp +3708 5d/pop-to-ebp +3709 c3/return +3710 +3711 test-add-mem-to-reg: +3712 # var1/reg <- add var2 +3713 # => +3714 # 03 *(ebp+__) var1 +3715 # +3716 # . prologue +3717 55/push-ebp +3718 89/<- %ebp 4/r32/esp +3719 # setup +3720 (clear-stream _test-output-stream) +3721 (clear-stream _test-output-buffered-file->buffer) +3722 # var-var1/ecx : var in eax +3723 68/push "eax"/imm32/register +3724 68/push 0/imm32/no-stack-offset +3725 68/push 1/imm32/block-depth +3726 68/push 1/imm32/type-int +3727 68/push "var1"/imm32 +3728 89/<- %ecx 4/r32/esp +3729 # var-var2/edx : var +3730 68/push 0/imm32/no-register +3731 68/push 8/imm32/stack-offset +3732 68/push 1/imm32/block-depth +3733 68/push 1/imm32/type-int +3734 68/push "var2"/imm32 +3735 89/<- %edx 4/r32/esp +3736 # inouts/esi : (list var2) +3737 68/push 0/imm32/next +3738 52/push-edx/var-var2 +3739 89/<- %esi 4/r32/esp +3740 # outputs/edi : (list var1) +3741 68/push 0/imm32/next +3742 51/push-ecx/var-var1 +3743 89/<- %edi 4/r32/esp +3744 # stmt/esi : statement +3745 68/push 0/imm32/next +3746 57/push-edi/outputs +3747 56/push-esi/inouts +3748 68/push "add"/imm32/operation +3749 68/push 1/imm32 +3750 89/<- %esi 4/r32/esp +3751 # convert +3752 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) +3753 (flush _test-output-buffered-file) +3754 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3760 # check output +3761 (check-next-stream-line-equal _test-output-stream "03 *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") +3762 # . epilogue +3763 89/<- %esp 5/r32/ebp +3764 5d/pop-to-ebp +3765 c3/return +3766 +3767 test-add-literal-to-reg: +3768 # var1/eax <- add 0x34 +3769 # => +3770 # 81 0/subop/add %eax 0x34/imm32 +3771 # +3772 # . prologue +3773 55/push-ebp +3774 89/<- %ebp 4/r32/esp +3775 # setup +3776 (clear-stream _test-output-stream) +3777 (clear-stream _test-output-buffered-file->buffer) +3778 # var-var1/ecx : var in eax +3779 68/push "eax"/imm32/register +3780 68/push 0/imm32/no-stack-offset +3781 68/push 1/imm32/block-depth +3782 68/push 1/imm32/type-int +3783 68/push "var1"/imm32 +3784 89/<- %ecx 4/r32/esp +3785 # var-var2/edx : var literal +3786 68/push 0/imm32/no-register +3787 68/push 0/imm32/no-stack-offset +3788 68/push 1/imm32/block-depth +3789 68/push 0/imm32/type-literal +3790 68/push "0x34"/imm32 +3791 89/<- %edx 4/r32/esp +3792 # inouts/esi : (list var2) +3793 68/push 0/imm32/next +3794 52/push-edx/var-var2 +3795 89/<- %esi 4/r32/esp +3796 # outputs/edi : (list var1) +3797 68/push 0/imm32/next +3798 51/push-ecx/var-var1 +3799 89/<- %edi 4/r32/esp +3800 # stmt/esi : statement +3801 68/push 0/imm32/next +3802 57/push-edi/outputs +3803 56/push-esi/inouts +3804 68/push "add"/imm32/operation +3805 68/push 1/imm32 +3806 89/<- %esi 4/r32/esp +3807 # convert +3808 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) +3809 (flush _test-output-buffered-file) +3810 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3816 # check output +3817 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %eax 0x34/imm32" "F - test-add-literal-to-reg") +3818 # . epilogue +3819 89/<- %esp 5/r32/ebp +3820 5d/pop-to-ebp +3821 c3/return +3822 +3823 test-add-literal-to-mem: +3824 # add-to var1, 0x34 +3825 # => +3826 # 81 0/subop/add %eax 0x34/imm32 +3827 # +3828 # . prologue +3829 55/push-ebp +3830 89/<- %ebp 4/r32/esp +3831 # setup +3832 (clear-stream _test-output-stream) +3833 (clear-stream _test-output-buffered-file->buffer) +3834 # var-var1/ecx : var +3835 68/push 0/imm32/no-register +3836 68/push 8/imm32/stack-offset +3837 68/push 1/imm32/block-depth +3838 68/push 1/imm32/type-int +3839 68/push "var1"/imm32 +3840 89/<- %ecx 4/r32/esp +3841 # var-var2/edx : var literal +3842 68/push 0/imm32/no-register +3843 68/push 0/imm32/no-stack-offset +3844 68/push 1/imm32/block-depth +3845 68/push 0/imm32/type-literal +3846 68/push "0x34"/imm32 +3847 89/<- %edx 4/r32/esp +3848 # inouts/esi : (list var2) +3849 68/push 0/imm32/next +3850 52/push-edx/var-var2 +3851 89/<- %esi 4/r32/esp +3852 # inouts = (list var1 inouts) +3853 56/push-esi/next +3854 51/push-ecx/var-var1 +3855 89/<- %esi 4/r32/esp +3856 # stmt/esi : statement +3857 68/push 0/imm32/next +3858 68/push 0/imm32/outputs +3859 56/push-esi/inouts +3860 68/push "add-to"/imm32/operation +3861 68/push 1/imm32 +3862 89/<- %esi 4/r32/esp +3863 # convert +3864 (emit-subx-statement _test-output-buffered-file %esi 0 Primitives 0) +3865 (flush _test-output-buffered-file) +3866 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3872 # check output +3873 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") +3874 # . epilogue +3875 89/<- %esp 5/r32/ebp +3876 5d/pop-to-ebp +3877 c3/return +3878 +3879 test-emit-subx-statement-function-call: +3880 # Call a function on a variable on the stack. +3881 # f foo +3882 # => +3883 # (f2 *(ebp-8)) +3884 # (Changing the function name supports overloading in general, but here it +3885 # just serves to help disambiguate things.) +3886 # +3887 # There's a variable on the var stack as follows: +3888 # name: 'foo' +3889 # type: int +3890 # stack-offset: -8 +3891 # +3892 # There's nothing in primitives. +3893 # +3894 # There's a function with this info: +3895 # name: 'f' +3896 # inout: int/mem +3897 # value: 'f2' +3898 # +3899 # . prologue +3900 55/push-ebp +3901 89/<- %ebp 4/r32/esp +3902 # setup +3903 (clear-stream _test-output-stream) +3904 (clear-stream _test-output-buffered-file->buffer) +3905 # var-foo/ecx : var +3906 68/push 0/imm32/no-register +3907 68/push -8/imm32/stack-offset +3908 68/push 0/imm32/block-depth +3909 68/push 1/imm32/type-int +3910 68/push "foo"/imm32 +3911 89/<- %ecx 4/r32/esp +3912 # vars/edx = (stack 1) +3913 51/push-ecx/var-foo +3914 68/push 1/imm32/data-length +3915 68/push 1/imm32/top +3916 89/<- %edx 4/r32/esp +3917 # operands/esi : (list var) +3918 68/push 0/imm32/next +3919 51/push-ecx/var-foo +3920 89/<- %esi 4/r32/esp +3921 # stmt/esi : statement +3922 68/push 0/imm32/next +3923 68/push 0/imm32/outputs +3924 56/push-esi/inouts +3925 68/push "f"/imm32/operation +3926 68/push 1/imm32 +3927 89/<- %esi 4/r32/esp +3928 # functions/ebx : function +3929 68/push 0/imm32/next +3930 68/push 0/imm32/body +3931 68/push 0/imm32/outputs +3932 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +3933 68/push "f2"/imm32/subx-name +3934 68/push "f"/imm32/name +3935 89/<- %ebx 4/r32/esp +3936 # convert +3937 (emit-subx-statement _test-output-buffered-file %esi %edx 0 %ebx) +3938 (flush _test-output-buffered-file) +3939 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +3945 # check output +3946 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") +3947 # . epilogue +3948 89/<- %esp 5/r32/ebp +3949 5d/pop-to-ebp +3950 c3/return +3951 +3952 test-emit-subx-statement-function-call-with-literal-arg: +3953 # Call a function on a literal. +3954 # f 34 +3955 # => +3956 # (f2 34) +3957 # +3958 # . prologue +3959 55/push-ebp +3960 89/<- %ebp 4/r32/esp +3961 # setup +3962 (clear-stream _test-output-stream) +3963 (clear-stream _test-output-buffered-file->buffer) +3964 # var-foo/ecx : literal +3965 68/push 0/imm32/no-register +3966 68/push 0/imm32/no-stack-offset +3967 68/push 0/imm32/block-depth +3968 68/push 0/imm32/type-literal +3969 68/push "34"/imm32 +3970 89/<- %ecx 4/r32/esp +3971 # vars/edx = (stack 1) +3972 51/push-ecx/var-foo +3973 68/push 1/imm32/data-length +3974 68/push 1/imm32/top +3975 89/<- %edx 4/r32/esp +3976 # operands/esi : (list var) +3977 68/push 0/imm32/next +3978 51/push-ecx/var-foo +3979 89/<- %esi 4/r32/esp +3980 # stmt/esi : statement +3981 68/push 0/imm32/next +3982 68/push 0/imm32/outputs +3983 56/push-esi/inouts +3984 68/push "f"/imm32/operation +3985 68/push 1/imm32 +3986 89/<- %esi 4/r32/esp +3987 # functions/ebx : function +3988 68/push 0/imm32/next +3989 68/push 0/imm32/body +3990 68/push 0/imm32/outputs +3991 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +3992 68/push "f2"/imm32/subx-name +3993 68/push "f"/imm32/name +3994 89/<- %ebx 4/r32/esp +3995 # convert +3996 (emit-subx-statement _test-output-buffered-file %esi %edx 0 %ebx) +3997 (flush _test-output-buffered-file) +3998 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +4004 # check output +4005 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") +4006 # . epilogue +4007 89/<- %esp 5/r32/ebp +4008 5d/pop-to-ebp +4009 c3/return +4010 +4011 emit-subx-prologue: # out : (address buffered-file) +4012 # . prologue +4013 55/push-ebp +4014 89/<- %ebp 4/r32/esp +4015 # +4016 (write-buffered *(ebp+8) "# . prologue\n") +4017 (write-buffered *(ebp+8) "55/push-ebp\n") +4018 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") +4019 $emit-subx-prologue:end: +4020 # . epilogue +4021 89/<- %esp 5/r32/ebp +4022 5d/pop-to-ebp +4023 c3/return +4024 +4025 emit-subx-epilogue: # out : (address buffered-file) +4026 # . prologue +4027 55/push-ebp +4028 89/<- %ebp 4/r32/esp +4029 # +4030 (write-buffered *(ebp+8) "# . epilogue\n") +4031 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") +4032 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") +4033 (write-buffered *(ebp+8) "c3/return\n") +4034 $emit-subx-epilogue:end: +4035 # . epilogue +4036 89/<- %esp 5/r32/ebp +4037 5d/pop-to-ebp +4038 c3/return -- cgit 1.4.1-2-gfad0