From 8fa32599bb288f9e51ebcf6f7c00339692c2a5b5 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Tue, 14 Jan 2020 01:24:54 -0800 Subject: [PATCH] 5889 --- ....html => 085next-word-or-string.subx.html} | 34 +- ....subx.html => 090register-names.subx.html} | 4 +- ...e-int.subx.html => 091write-int.subx.html} | 10 +- ...{095stack.subx.html => 092stack.subx.html} | 42 +- html/093array-equal.subx.html | 670 -- html/100array-equal.subx.html | 663 ++ html/apps/assort.subx.html | 4 +- html/apps/braces.subx.html | 10 +- html/apps/calls.subx.html | 4 +- html/apps/dquotes.subx.html | 2 +- html/apps/mu.subx.html | 8403 +++++++++-------- html/apps/sigils.subx.html | 10 +- 12 files changed, 5009 insertions(+), 4847 deletions(-) rename html/{094next-word-or-string.subx.html => 085next-word-or-string.subx.html} (98%) rename html/{085register-names.subx.html => 090register-names.subx.html} (94%) rename html/{092write-int.subx.html => 091write-int.subx.html} (98%) rename html/{095stack.subx.html => 092stack.subx.html} (97%) delete mode 100644 html/093array-equal.subx.html create mode 100644 html/100array-equal.subx.html diff --git a/html/094next-word-or-string.subx.html b/html/085next-word-or-string.subx.html similarity index 98% rename from html/094next-word-or-string.subx.html rename to html/085next-word-or-string.subx.html index 05b8855a..640b2745 100644 --- a/html/094next-word-or-string.subx.html +++ b/html/085next-word-or-string.subx.html @@ -2,7 +2,7 @@ -Mu - 094next-word-or-string.subx +Mu - 085next-word-or-string.subx @@ -55,7 +55,7 @@ if ('onhashchange' in window) { -https://github.com/akkartik/mu/blob/master/094next-word-or-string.subx +https://github.com/akkartik/mu/blob/master/085next-word-or-string.subx
   1 == code
   2 #   instruction                     effective address                                                   register    displacement    immediate
@@ -187,12 +187,12 @@ if ('onhashchange' in window) {
 128     51/push-ecx
 129     68/push  _test-input-stream/imm32
 130     # . . call
-131     e8/call  next-word-or-string/disp32
+131     e8/call  next-word-or-string/disp32
 132     # . . discard args
 133     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 134     # check-ints-equal(_test-input-stream->read, 4, msg)
 135     # . . push args
-136     68/push  "F - test-next-word-or-string/updates-stream-read-correctly"/imm32
+136     68/push  "F - test-next-word-or-string/updates-stream-read-correctly"/imm32
 137     68/push  4/imm32
 138     b8/copy-to-eax  _test-input-stream/imm32
 139     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
@@ -203,7 +203,7 @@ if ('onhashchange' in window) {
 144     # check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
 145     # . check-ints-equal(slice->start - _test-input-stream, 14, msg)
 146     # . . push args
-147     68/push  "F - test-next-word-or-string: start"/imm32
+147     68/push  "F - test-next-word-or-string: start"/imm32
 148     68/push  0xe/imm32
 149     # . . push slice->start - _test-input-stream
 150     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
@@ -216,7 +216,7 @@ if ('onhashchange' in window) {
 157     # check-ints-equal(slice->end - _test-input-stream->data, 4, msg)
 158     # . check-ints-equal(slice->end - _test-input-stream, 16, msg)
 159     # . . push args
-160     68/push  "F - test-next-word-or-string: end"/imm32
+160     68/push  "F - test-next-word-or-string: end"/imm32
 161     68/push  0x10/imm32
 162     # . . push slice->end - _test-input-stream
 163     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
@@ -260,12 +260,12 @@ if ('onhashchange' in window) {
 201     51/push-ecx
 202     68/push  _test-input-stream/imm32
 203     # . . call
-204     e8/call  next-word-or-string/disp32
+204     e8/call  next-word-or-string/disp32
 205     # . . discard args
 206     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 207     # check-ints-equal(_test-input-stream->read, 5, msg)
 208     # . . push args
-209     68/push  "F - test-next-word-or-string-returns-whole-comment/updates-stream-read-correctly"/imm32
+209     68/push  "F - test-next-word-or-string-returns-whole-comment/updates-stream-read-correctly"/imm32
 210     68/push  5/imm32
 211     b8/copy-to-eax  _test-input-stream/imm32
 212     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
@@ -276,7 +276,7 @@ if ('onhashchange' in window) {
 217     # check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
 218     # . check-ints-equal(slice->start - _test-input-stream, 14, msg)
 219     # . . push args
-220     68/push  "F - test-next-word-or-string-returns-whole-comment: start"/imm32
+220     68/push  "F - test-next-word-or-string-returns-whole-comment: start"/imm32
 221     68/push  0xe/imm32
 222     # . . push slice->start - _test-input-stream
 223     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
@@ -289,7 +289,7 @@ if ('onhashchange' in window) {
 230     # check-ints-equal(slice->end - _test-input-stream->data, 5, msg)
 231     # . check-ints-equal(slice->end - _test-input-stream, 17, msg)
 232     # . . push args
-233     68/push  "F - test-next-word-or-string-returns-whole-comment: end"/imm32
+233     68/push  "F - test-next-word-or-string-returns-whole-comment: end"/imm32
 234     68/push  0x11/imm32
 235     # . . push slice->end - _test-input-stream
 236     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
@@ -326,7 +326,7 @@ if ('onhashchange' in window) {
 267     51/push-ecx
 268     68/push  _test-input-stream/imm32
 269     # . . call
-270     e8/call  next-word-or-string/disp32
+270     e8/call  next-word-or-string/disp32
 271     # . . discard args
 272     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 273     # check-ints-equal(slice->end - slice->start, 0, msg)
@@ -375,13 +375,13 @@ if ('onhashchange' in window) {
 316     51/push-ecx
 317     68/push  _test-input-stream/imm32
 318     # . . call
-319     e8/call  next-word-or-string/disp32
+319     e8/call  next-word-or-string/disp32
 320     # . . discard args
 321     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 322     # check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
 323     # . check-ints-equal(slice->start - _test-input-stream, 13, msg)
 324     # . . push args
-325     68/push  "F - test-next-word-or-string-returns-string-literal: start"/imm32
+325     68/push  "F - test-next-word-or-string-returns-string-literal: start"/imm32
 326     68/push  0xd/imm32
 327     # . . push slice->start - _test-input-stream
 328     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
@@ -394,7 +394,7 @@ if ('onhashchange' in window) {
 335     # check-ints-equal(slice->end - _test-input-stream->data, 12, msg)
 336     # . check-ints-equal(slice->end - _test-input-stream, 24, msg)
 337     # . . push args
-338     68/push  "F - test-next-word-or-string-returns-string-literal: end"/imm32
+338     68/push  "F - test-next-word-or-string-returns-string-literal: end"/imm32
 339     68/push  0x18/imm32
 340     # . . push slice->end - _test-input-stream
 341     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
@@ -438,13 +438,13 @@ if ('onhashchange' in window) {
 379     51/push-ecx
 380     68/push  _test-input-stream/imm32
 381     # . . call
-382     e8/call  next-word-or-string/disp32
+382     e8/call  next-word-or-string/disp32
 383     # . . discard args
 384     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 385     # check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
 386     # . check-ints-equal(slice->start - _test-input-stream, 13, msg)
 387     # . . push args
-388     68/push  "F - test-next-word-or-string-returns-string-with-escapes: start"/imm32
+388     68/push  "F - test-next-word-or-string-returns-string-with-escapes: start"/imm32
 389     68/push  0xd/imm32
 390     # . . push slice->start - _test-input-stream
 391     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
@@ -457,7 +457,7 @@ if ('onhashchange' in window) {
 398     # check-ints-equal(slice->end - _test-input-stream->data, 9, msg)
 399     # . check-ints-equal(slice->end - _test-input-stream, 21, msg)
 400     # . . push args
-401     68/push  "F - test-next-word-or-string-returns-string-with-escapes: end"/imm32
+401     68/push  "F - test-next-word-or-string-returns-string-with-escapes: end"/imm32
 402     68/push  0x15/imm32
 403     # . . push slice->end - _test-input-stream
 404     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
diff --git a/html/085register-names.subx.html b/html/090register-names.subx.html
similarity index 94%
rename from html/085register-names.subx.html
rename to html/090register-names.subx.html
index eaf9a9e5..46e18826 100644
--- a/html/085register-names.subx.html
+++ b/html/090register-names.subx.html
@@ -2,7 +2,7 @@
 
 
 
-Mu - 085register-names.subx
+Mu - 090register-names.subx
 
 
 
@@ -51,7 +51,7 @@ if ('onhashchange' in window) {
 
 
 
-https://github.com/akkartik/mu/blob/master/085register-names.subx
+https://github.com/akkartik/mu/blob/master/090register-names.subx
 
  1 == data
  2 Registers:  # (table string int)
diff --git a/html/092write-int.subx.html b/html/091write-int.subx.html
similarity index 98%
rename from html/092write-int.subx.html
rename to html/091write-int.subx.html
index f8deb37c..d69537e4 100644
--- a/html/092write-int.subx.html
+++ b/html/091write-int.subx.html
@@ -2,7 +2,7 @@
 
 
 
-Mu - 092write-int.subx
+Mu - 091write-int.subx
 
 
 
@@ -56,7 +56,7 @@ if ('onhashchange' in window) {
 
 
 
-https://github.com/akkartik/mu/blob/master/092write-int.subx
+https://github.com/akkartik/mu/blob/master/091write-int.subx
 
   1 # write-int: add a single int to a stream
   2 
@@ -126,7 +126,7 @@ if ('onhashchange' in window) {
  66     68/push  0x64636261/imm32
  67     68/push  _test-stream/imm32
  68     # . . call
- 69     e8/call  write-int/disp32
+ 69     e8/call  write-int/disp32
  70     # . . discard args
  71     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
  72     # check-stream-equal(_test-stream, "abcd", msg)
@@ -156,7 +156,7 @@ if ('onhashchange' in window) {
  96     68/push  0x64636261/imm32
  97     68/push  _test-stream/imm32
  98     # . . call
- 99     e8/call  write-int/disp32
+ 99     e8/call  write-int/disp32
 100     # . . discard args
 101     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 102     # write-int(_test-stream, "efgh")
@@ -164,7 +164,7 @@ if ('onhashchange' in window) {
 104     68/push  0x68676665/imm32
 105     68/push  _test-stream/imm32
 106     # . . call
-107     e8/call  write-int/disp32
+107     e8/call  write-int/disp32
 108     # . . discard args
 109     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 110     # check-stream-equal(_test-stream, "abcdefgh", msg)
diff --git a/html/095stack.subx.html b/html/092stack.subx.html
similarity index 97%
rename from html/095stack.subx.html
rename to html/092stack.subx.html
index 29c47744..1b0e6fe7 100644
--- a/html/095stack.subx.html
+++ b/html/092stack.subx.html
@@ -2,7 +2,7 @@
 
 
 
-Mu - 095stack.subx
+Mu - 092stack.subx
 
 
 
@@ -56,7 +56,7 @@ if ('onhashchange' in window) {
 
 
 
-https://github.com/akkartik/mu/blob/master/095stack.subx
+https://github.com/akkartik/mu/blob/master/092stack.subx
 
   1 # A stack looks like this:
   2 #   top: int
@@ -115,14 +115,14 @@ if ('onhashchange' in window) {
  55     # . . push args
  56     51/push-ecx
  57     # . . call
- 58     e8/call  clear-stack/disp32
+ 58     e8/call  clear-stack/disp32
  59     # . . discard args
  60     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
  61     # top should be 0
  62     58/pop-to-eax
  63     # . check-ints-equal(eax, 0, msg)
  64     # . . push args
- 65     68/push  "F - test-clear-stack: top"/imm32
+ 65     68/push  "F - test-clear-stack: top"/imm32
  66     68/push  0/imm32
  67     50/push-eax
  68     # . . call
@@ -133,7 +133,7 @@ if ('onhashchange' in window) {
  73     58/pop-to-eax
  74     # . check-ints-equal(eax, 8, msg)
  75     # . . push args
- 76     68/push  "F - test-clear-stack: length"/imm32
+ 76     68/push  "F - test-clear-stack: length"/imm32
  77     68/push  8/imm32
  78     50/push-eax
  79     # . . call
@@ -144,7 +144,7 @@ if ('onhashchange' in window) {
  84     58/pop-to-eax
  85     # . check-ints-equal(eax, 0, msg)
  86     # . . push args
- 87     68/push  "F - test-clear-stack: data[0..3]"/imm32
+ 87     68/push  "F - test-clear-stack: data[0..3]"/imm32
  88     68/push  0/imm32
  89     50/push-eax
  90     # . . call
@@ -155,7 +155,7 @@ if ('onhashchange' in window) {
  95     58/pop-to-eax
  96     # . check-ints-equal(eax, 0, msg)
  97     # . . push args
- 98     68/push  "F - test-clear-stack: data[4..7]"/imm32
+ 98     68/push  "F - test-clear-stack: data[4..7]"/imm32
  99     68/push  0/imm32
 100     50/push-eax
 101     # . . call
@@ -201,7 +201,7 @@ if ('onhashchange' in window) {
 141     # print(stderr, "error: push: no space left")
 142     # . write-buffered(Stderr, "error: push: no space left")
 143     # . . push args
-144     68/push  "error: push: no space left"/imm32
+144     68/push  "error: push: no space left"/imm32
 145     68/push  Stderr/imm32
 146     # . . call
 147     e8/call  write-buffered/disp32
@@ -235,14 +235,14 @@ if ('onhashchange' in window) {
 175     68/push  0x42/imm32
 176     51/push-ecx
 177     # . . call
-178     e8/call  push/disp32
+178     e8/call  push/disp32
 179     # . . discard args
 180     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 181     # check top
 182     58/pop-to-eax
 183     # . check-ints-equal(eax, 4, msg)
 184     # . . push args
-185     68/push  "F - test-push: top"/imm32
+185     68/push  "F - test-push: top"/imm32
 186     68/push  4/imm32
 187     50/push-eax
 188     # . . call
@@ -253,7 +253,7 @@ if ('onhashchange' in window) {
 193     58/pop-to-eax
 194     # . check-ints-equal(eax, 8, msg)
 195     # . . push args
-196     68/push  "F - test-push: length"/imm32
+196     68/push  "F - test-push: length"/imm32
 197     68/push  8/imm32
 198     50/push-eax
 199     # . . call
@@ -264,7 +264,7 @@ if ('onhashchange' in window) {
 204     58/pop-to-eax
 205     # . check-ints-equal(eax, 0x42, msg)
 206     # . . push args
-207     68/push  "F - test-push: data[0..3]"/imm32
+207     68/push  "F - test-push: data[0..3]"/imm32
 208     68/push  0x42/imm32
 209     50/push-eax
 210     # . . call
@@ -275,7 +275,7 @@ if ('onhashchange' in window) {
 215     58/pop-to-eax
 216     # . check-ints-equal(eax, 0, msg)
 217     # . . push args
-218     68/push  "F - test-push: data[4..7]"/imm32
+218     68/push  "F - test-push: data[4..7]"/imm32
 219     68/push  0/imm32
 220     50/push-eax
 221     # . . call
@@ -319,7 +319,7 @@ if ('onhashchange' in window) {
 259     # print(stderr, "error: pop: nothing left in stack")
 260     # . write-buffered(Stderr, "error: pop: nothing left in stack")
 261     # . . push args
-262     68/push  "error: pop: nothing left in stack"/imm32
+262     68/push  "error: pop: nothing left in stack"/imm32
 263     68/push  Stderr/imm32
 264     # . . call
 265     e8/call  write-buffered/disp32
@@ -352,12 +352,12 @@ if ('onhashchange' in window) {
 292     # . . push args
 293     51/push-ecx
 294     # . . call
-295     e8/call  pop/disp32
+295     e8/call  pop/disp32
 296     # . . discard args
 297     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
 298     # check-ints-equal(eax, 0x42, msg)
 299     # . . push args
-300     68/push  "F - test-pop: result"/imm32
+300     68/push  "F - test-pop: result"/imm32
 301     68/push  0x42/imm32
 302     50/push-eax
 303     # . . call
@@ -368,7 +368,7 @@ if ('onhashchange' in window) {
 308     58/pop-to-eax
 309     # . check-ints-equal(eax, 0, msg)
 310     # . . push args
-311     68/push  "F - test-pop: top"/imm32
+311     68/push  "F - test-pop: top"/imm32
 312     68/push  0/imm32
 313     50/push-eax
 314     # . . call
@@ -379,7 +379,7 @@ if ('onhashchange' in window) {
 319     58/pop-to-eax
 320     # . check-ints-equal(eax, 8, msg)
 321     # . . push args
-322     68/push  "F - test-pop: length"/imm32
+322     68/push  "F - test-pop: length"/imm32
 323     68/push  8/imm32
 324     50/push-eax
 325     # . . call
@@ -420,7 +420,7 @@ if ('onhashchange' in window) {
 360     # print(stderr, "error: top: nothing left in stack")
 361     # . write-buffered(Stderr, "error: top: nothing left in stack")
 362     # . . push args
-363     68/push  "error: top: nothing left in stack"/imm32
+363     68/push  "error: top: nothing left in stack"/imm32
 364     68/push  Stderr/imm32
 365     # . . call
 366     e8/call  write-buffered/disp32
@@ -453,12 +453,12 @@ if ('onhashchange' in window) {
 393     # . . push args
 394     51/push-ecx
 395     # . . call
-396     e8/call  top/disp32
+396     e8/call  top/disp32
 397     # . . discard args
 398     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
 399     # check-ints-equal(eax, 42, msg")
 400     # . . push args
-401     68/push  "F - test-top: result"/imm32
+401     68/push  "F - test-top: result"/imm32
 402     68/push  0x42/imm32
 403     50/push-eax
 404     # . . call
diff --git a/html/093array-equal.subx.html b/html/093array-equal.subx.html
deleted file mode 100644
index 75de8313..00000000
--- a/html/093array-equal.subx.html
+++ /dev/null
@@ -1,670 +0,0 @@
-
-
-
-
-Mu - 093array-equal.subx
-
-
-
-
-
-
-
-
-
-
-https://github.com/akkartik/mu/blob/master/093array-equal.subx
-
-  1 # Comparing arrays of numbers.
-  2 
-  3 == code
-  4 #   instruction                     effective address                                                   register    displacement    immediate
-  5 # . op          subop               mod             rm32          base        index         scale       r32
-  6 # . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
-  7 
-  8 array-equal?:  # a : (addr array int), b : (addr array int) -> eax : boolean
-  9     # pseudocode:
- 10     #   lena = a->length
- 11     #   if (lena != b->length) return false
- 12     #   i = 0
- 13     #   curra = a->data
- 14     #   currb = b->data
- 15     #   while i < lena
- 16     #     i1 = *curra
- 17     #     i2 = *currb
- 18     #     if (c1 != c2) return false
- 19     #     i+=4, curra+=4, currb+=4
- 20     #   return true
- 21     #
- 22     # registers:
- 23     #   i: ecx
- 24     #   lena: edx
- 25     #   curra: esi
- 26     #   currb: edi
- 27     #   i1: eax
- 28     #   i2: ebx
- 29     #
- 30     # . prologue
- 31     55/push-ebp
- 32     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 33     # . save registers
- 34     51/push-ecx
- 35     52/push-edx
- 36     53/push-ebx
- 37     56/push-esi
- 38     57/push-edi
- 39     # esi = a
- 40     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
- 41     # edi = b
- 42     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
- 43     # var lena/edx : int = a->length
- 44     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
- 45 $array-equal?:lengths:
- 46     # if (lena != b->length) return false
- 47     39/compare                      0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare *edi and edx
- 48     75/jump-if-not-equal  $array-equal?:false/disp8
- 49     # var curra/esi : (addr byte) = a->data
- 50     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
- 51     # var currb/edi : (addr byte) = b->data
- 52     81          0/subop/add         3/mod/direct    7/rm32/edi    .           .             .           .           .               4/imm32           # add to edi
- 53     # var i/ecx : int = 0
- 54     31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
- 55     # var vala/eax : int
- 56     # var valb/ebx : int
- 57 $array-equal?:loop:
- 58     # if (i >= lena) return true
- 59     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
- 60     7d/jump-if-greater-or-equal  $array-equal?:true/disp8
- 61     # vala = *curra
- 62     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
- 63     # valb = *currb
- 64     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           3/r32/ebx   .               .                 # copy *edi to ebx
- 65     # if (vala != valb) return false
- 66     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
- 67     75/jump-if-not-equal  $array-equal?:false/disp8
- 68     # i += 4
- 69     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
- 70     # currs += 4
- 71     81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               4/imm32           # add to esi
- 72     # currb += 4
- 73     81          0/subop/add         3/mod/direct    7/rm32/edi    .           .             .           .           .               4/imm32           # add to edi
- 74     eb/jump  $array-equal?:loop/disp8
- 75 $array-equal?:true:
- 76     b8/copy-to-eax  1/imm32
- 77     eb/jump  $array-equal?:end/disp8
- 78 $array-equal?:false:
- 79     b8/copy-to-eax  0/imm32
- 80 $array-equal?:end:
- 81     # . restore registers
- 82     5f/pop-to-edi
- 83     5e/pop-to-esi
- 84     5b/pop-to-ebx
- 85     5a/pop-to-edx
- 86     59/pop-to-ecx
- 87     # . epilogue
- 88     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
- 89     5d/pop-to-ebp
- 90     c3/return
- 91 
- 92 test-compare-empty-with-empty-array:
- 93     # . prologue
- 94     55/push-ebp
- 95     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
- 96     # var ecx : (array _) = []
- 97     68/push  0/imm32/size
- 98     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
- 99     # var edx : (array _) = []
-100     68/push  0/imm32/size
-101     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-102     # eax = array-equal?(ecx, edx)
-103     # . . push args
-104     52/push-edx
-105     51/push-ecx
-106     # . . call
-107     e8/call  array-equal?/disp32
-108     # . . discard args
-109     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-110     # check-ints-equal(eax, 1, msg)
-111     # . . push args
-112     68/push  "F - test-compare-empty-with-empty-array"/imm32
-113     68/push  1/imm32/true
-114     50/push-eax
-115     # . . call
-116     e8/call  check-ints-equal/disp32
-117     # . . discard args
-118     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-119     # . epilogue
-120     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-121     5d/pop-to-ebp
-122     c3/return
-123 
-124 test-compare-empty-with-non-empty-array:  # also checks length-mismatch code path
-125     # . prologue
-126     55/push-ebp
-127     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-128     # var ecx : (array int) = [1]
-129     68/push  1/imm32
-130     68/push  4/imm32/size
-131     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-132     # var edx : (array int) = []
-133     68/push  0/imm32/size
-134     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-135     # eax = array-equal?(ecx, edx)
-136     # . . push args
-137     52/push-edx
-138     51/push-ecx
-139     # . . call
-140     e8/call  array-equal?/disp32
-141     # . . discard args
-142     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-143     # check-ints-equal(eax, 0, msg)
-144     # . . push args
-145     68/push  "F - test-compare-empty-with-non-empty-array"/imm32
-146     68/push  0/imm32/false
-147     50/push-eax
-148     # . . call
-149     e8/call  check-ints-equal/disp32
-150     # . . discard args
-151     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-152     # . epilogue
-153     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-154     5d/pop-to-ebp
-155     c3/return
-156 
-157 test-compare-equal-arrays:
-158     # . prologue
-159     55/push-ebp
-160     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-161     # var ecx : (array int) = [1, 2, 3]
-162     68/push  3/imm32
-163     68/push  2/imm32
-164     68/push  1/imm32
-165     68/push  0xc/imm32/size
-166     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-167     # var edx : (array int) = [1, 2, 3]
-168     68/push  3/imm32
-169     68/push  2/imm32
-170     68/push  1/imm32
-171     68/push  0xc/imm32/size
-172     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-173     # eax = array-equal?(ecx, edx)
-174     # . . push args
-175     52/push-edx
-176     51/push-ecx
-177     # . . call
-178     e8/call  array-equal?/disp32
-179     # . . discard args
-180     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-181     # check-ints-equal(eax, 1, msg)
-182     # . . push args
-183     68/push  "F - test-compare-equal-arrays"/imm32
-184     68/push  1/imm32/true
-185     50/push-eax
-186     # . . call
-187     e8/call  check-ints-equal/disp32
-188     # . . discard args
-189     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-190     # . epilogue
-191     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-192     5d/pop-to-ebp
-193     c3/return
-194 
-195 test-compare-inequal-arrays-equal-lengths:
-196     # . prologue
-197     55/push-ebp
-198     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-199     # var ecx : (array int) = [1, 4, 3]
-200     68/push  3/imm32
-201     68/push  4/imm32
-202     68/push  1/imm32
-203     68/push  0xc/imm32/size
-204     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-205     # var edx : (array int) = [1, 2, 3]
-206     68/push  3/imm32
-207     68/push  2/imm32
-208     68/push  1/imm32
-209     68/push  0xc/imm32/size
-210     89/copy                         3/mod/direct    2/rm32/edx    .           .             .           4/r32/esp   .               .                 # copy esp to edx
-211     # eax = array-equal?(ecx, edx)
-212     # . . push args
-213     52/push-edx
-214     51/push-ecx
-215     # . . call
-216     e8/call  array-equal?/disp32
-217     # . . discard args
-218     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-219     # check-ints-equal(eax, 0, msg)
-220     # . . push args
-221     68/push  "F - test-compare-inequal-arrays-equal-lengths"/imm32
-222     68/push  0/imm32/false
-223     50/push-eax
-224     # . . call
-225     e8/call  check-ints-equal/disp32
-226     # . . discard args
-227     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-228     # . epilogue
-229     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-230     5d/pop-to-ebp
-231     c3/return
-232 
-233 parse-array-of-ints:  # ad : (addr allocation-descriptor), s : (addr string) -> result/eax : (handle array int)
-234     # pseudocode
-235     #   end = &s->data[s->length]
-236     #   curr = s->data
-237     #   size = 0
-238     #   while true
-239     #     if (curr >= end) break
-240     #     curr = skip-chars-matching-in-slice(curr, end, ' ')
-241     #     if (curr >= end) break
-242     #     curr = skip-chars-not-matching-in-slice(curr, end, ' ')
-243     #     ++size
-244     #   result = allocate(ad, (size+1)*4)
-245     #   result->size = (size+1)*4
-246     #   var slice : slice = {s->data, 0}
-247     #   out = result->data
-248     #   while true
-249     #     if (slice->start >= end) break
-250     #     slice->start = skip-chars-matching-in-slice(slice->start, end, ' ')
-251     #     if (slice->start >= end) break
-252     #     slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ')
-253     #     *out = parse-hex-int(slice)
-254     #     out += 4
-255     #     slice->start = slice->end
-256     #   return result
-257     #
-258     # . prologue
-259     55/push-ebp
-260     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-261     # . save registers
-262     51/push-ecx
-263     52/push-edx
-264     53/push-ebx
-265     56/push-esi
-266     57/push-edi
-267     # esi = s
-268     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   0xc/disp8       .                 # copy *(ebp+12) to esi
-269     # var curr/ecx : (addr byte) = s->data
-270     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy esi+4 to ecx
-271     # var end/edx : (addr byte) = &s->data[s->length]
-272     # . edx = s->length
-273     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           2/r32/edx   .               .                 # copy *esi to edx
-274     # . edx += curr
-275     01/add                          3/mod/direct    2/rm32/edx    .           .             .           1/r32/ecx   .               .                 # add ecx to edx
-276     # var size/ebx : int = 0
-277     31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
-278 $parse-array-of-ints:loop1:
-279     # if (curr >= end) break
-280     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
-281     73/jump-if-greater-or-equal-unsigned  $parse-array-of-ints:break1/disp8
-282     # curr = skip-chars-matching-in-slice(curr, end, ' ')
-283     # . eax = skip-chars-matching-in-slice(curr, end, ' ')
-284     # . . push args
-285     68/push  0x20/imm32/space
-286     52/push-edx
-287     51/push-ecx
-288     # . . call
-289     e8/call  skip-chars-matching-in-slice/disp32
-290     # . . discard args
-291     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-292     # . ecx = eax
-293     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to ecx
-294     # if (curr >= end) break
-295     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
-296     73/jump-if-greater-or-equal-unsigned  $parse-array-of-ints:break1/disp8
-297     # curr = skip-chars-not-matching-in-slice(curr, end, ' ')
-298     # . eax = skip-chars-not-matching-in-slice(curr, end, ' ')
-299     # . . push args
-300     68/push  0x20/imm32/space
-301     52/push-edx
-302     51/push-ecx
-303     # . . call
-304     e8/call  skip-chars-not-matching-in-slice/disp32
-305     # . . discard args
-306     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-307     # . ecx = eax
-308     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to ecx
-309     # size += 4
-310     81          0/subop/add         3/mod/direct    3/rm32/ebx    .           .             .           .           .               4/imm32           # add to ebx
-311     eb/jump  $parse-array-of-ints:loop1/disp8
-312 $parse-array-of-ints:break1:
-313     # var result/edi : (handle array int) = allocate(ad, size+4)
-314     # . eax = allocate(ad, size+4)
-315     # . . push args
-316     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # copy ebx to eax
-317     05/add-to-eax  4/imm32
-318     50/push-eax
-319     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-320     # . . call
-321     e8/call  allocate/disp32
-322     # . . discard args
-323     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-324     # . edi = eax
-325     89/copy                         3/mod/direct    7/rm32/edi    .           .             .           0/r32/eax   .               .                 # copy eax to edi
-326     # result->size = size
-327     89/copy                         0/mod/indirect  0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # copy ebx to *eax
-328 $parse-array-of-ints:pass2:
-329     # var slice/ecx : slice = {s->data, 0}
-330     # . push 0
-331     68/push  0/imm32/end
-332     # . push s->data
-333     8d/copy-address                 1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy esi+4 to ecx
-334     51/push-ecx
-335     # . bookmark
-336     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-337     # var out/ebx : (addr byte) = result->data
-338     8d/copy-address                 1/mod/*+disp8   0/rm32/eax    .           .             .           3/r32/ebx   4/disp8         .                 # copy eax+4 to ebx
-339 $parse-array-of-ints:loop2:
-340     # if (slice->start >= end) break
-341     39/compare                      0/mod/indirect  1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare *ecx with edx
-342     73/jump-if-greater-or-equal-unsigned  $parse-array-of-ints:end/disp8
-343     # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ')
-344     # . eax = skip-chars-matching-in-slice(slice->start, end, ' ')
-345     # . . push args
-346     68/push  0x20/imm32/space
-347     52/push-edx
-348     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
-349     # . . call
-350     e8/call  skip-chars-matching-in-slice/disp32
-351     # . . discard args
-352     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-353     # . slice->start = eax
-354     89/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to *ecx
-355     # if (slice->start >= end) break
-356     39/compare                      0/mod/indirect  1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare *ecx with edx
-357     73/jump-if-greater-or-equal-unsigned  $parse-array-of-ints:end/disp8
-358     # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ')
-359     # . eax = skip-chars-not-matching-in-slice(curr, end, ' ')
-360     # . . push args
-361     68/push  0x20/imm32/space
-362     52/push-edx
-363     50/push-eax
-364     # . . call
-365     e8/call  skip-chars-not-matching-in-slice/disp32
-366     # . . discard args
-367     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-368     # . slice->end = eax
-369     89/copy                         1/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(ecx+4)
-370     # *out = parse-hex-int(slice)
-371     # . eax = parse-hex-int(slice)
-372     # . . push args
-373     51/push-ecx
-374     # . . call
-375     e8/call  parse-hex-int/disp32
-376     # . . discard args
-377     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
-378     # . *out = eax
-379     89/copy                         0/mod/indirect  3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to *ebx
-380     # out += 4
-381     81          0/subop/add         3/mod/direct    3/rm32/ebx    .           .             .           .           .               4/imm32           # add to ebx
-382     # slice->start = slice->end
-383     8b/copy                         1/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
-384     89/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to *ecx
-385     81          0/subop/add         3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm32           # add to ecx
-386     eb/jump  $parse-array-of-ints:loop2/disp8
-387 $parse-array-of-ints:end:
-388     # return edi
-389     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           7/r32/edi   .               .                 # copy edi to eax
-390     # . reclaim locals
-391     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-392     # . restore registers
-393     5f/pop-to-edi
-394     5e/pop-to-esi
-395     5b/pop-to-ebx
-396     5a/pop-to-edx
-397     59/pop-to-ecx
-398     # . epilogue
-399     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-400     5d/pop-to-ebp
-401     c3/return
-402 
-403 test-parse-array-of-ints:
-404     # . prologue
-405     55/push-ebp
-406     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-407     # var ecx : (array int) = [1, 2, 3]
-408     68/push  3/imm32
-409     68/push  2/imm32
-410     68/push  1/imm32
-411     68/push  0xc/imm32/size
-412     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-413     # eax = parse-array-of-ints(Heap, "1 2 3")
-414     # . . push args
-415     68/push  "1 2 3"/imm32
-416     68/push  Heap/imm32
-417     # . . call
-418     e8/call  parse-array-of-ints/disp32
-419     # . . discard args
-420     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-421     # eax = array-equal?(ecx, eax)
-422     # . . push args
-423     50/push-eax
-424     51/push-ecx
-425     # . . call
-426     e8/call  array-equal?/disp32
-427     # . . discard args
-428     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-429     # check-ints-equal(eax, 1, msg)
-430     # . . push args
-431     68/push  "F - test-parse-array-of-ints"/imm32
-432     68/push  1/imm32/true
-433     50/push-eax
-434     # . . call
-435     e8/call  check-ints-equal/disp32
-436     # . . discard args
-437     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-438     # . epilogue
-439     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-440     5d/pop-to-ebp
-441     c3/return
-442 
-443 test-parse-array-of-ints-empty:
-444     # - empty string = empty array
-445     # . prologue
-446     55/push-ebp
-447     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-448     # eax = parse-array-of-ints(Heap, "")
-449     # . . push args
-450     68/push  ""/imm32
-451     68/push  Heap/imm32
-452     # . . call
-453     e8/call  parse-array-of-ints/disp32
-454     # . . discard args
-455     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-456     # check-ints-equal(*eax, 0, msg)
-457     # . . push args
-458     68/push  "F - test-parse-array-of-ints-empty"/imm32
-459     68/push  0/imm32/size
-460     ff          6/subop/push        0/mod/indirect  0/rm32/eax    .           .             .           .           .               .                 # push *eax
-461     # . . call
-462     e8/call  check-ints-equal/disp32
-463     # . . discard args
-464     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-465     # . epilogue
-466     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-467     5d/pop-to-ebp
-468     c3/return
-469 
-470 test-parse-array-of-ints-just-whitespace:
-471     # - just whitespace = empty array
-472     # . prologue
-473     55/push-ebp
-474     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-475     # eax = parse-array-of-ints(Heap, " ")
-476     # . . push args
-477     68/push  Space/imm32
-478     68/push  Heap/imm32
-479     # . . call
-480     e8/call  parse-array-of-ints/disp32
-481     # . . discard args
-482     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-483     # check-ints-equal(*eax, 0, msg)
-484     # . . push args
-485     68/push  "F - test-parse-array-of-ints-empty"/imm32
-486     68/push  0/imm32/size
-487     ff          6/subop/push        0/mod/indirect  0/rm32/eax    .           .             .           .           .               .                 # push *eax
-488     # . . call
-489     e8/call  check-ints-equal/disp32
-490     # . . discard args
-491     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-492     # . epilogue
-493     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-494     5d/pop-to-ebp
-495     c3/return
-496 
-497 test-parse-array-of-ints-extra-whitespace:
-498     # . prologue
-499     55/push-ebp
-500     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-501     # var ecx : (array int) = [1, 2, 3]
-502     68/push  3/imm32
-503     68/push  2/imm32
-504     68/push  1/imm32
-505     68/push  0xc/imm32/size
-506     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-507     # eax = parse-array-of-ints(Heap, " 1 2  3  ")
-508     # . . push args
-509     68/push  " 1 2  3  "/imm32
-510     68/push  Heap/imm32
-511     # . . call
-512     e8/call  parse-array-of-ints/disp32
-513     # . . discard args
-514     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-515     # eax = array-equal?(ecx, eax)
-516     # . . push args
-517     50/push-eax
-518     51/push-ecx
-519     # . . call
-520     e8/call  array-equal?/disp32
-521     # . . discard args
-522     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-523     # check-ints-equal(eax, 1, msg)
-524     # . . push args
-525     68/push  "F - test-parse-array-of-ints-extra-whitespace"/imm32
-526     68/push  1/imm32/true
-527     50/push-eax
-528     # . . call
-529     e8/call  check-ints-equal/disp32
-530     # . . discard args
-531     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-532     # . epilogue
-533     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-534     5d/pop-to-ebp
-535     c3/return
-536 
-537 # helper for later tests
-538 # compare an array with a string representation of an array literal
-539 check-array-equal:  # a : (addr array int), expected : (addr string), msg : (addr string)
-540     # . prologue
-541     55/push-ebp
-542     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-543     # . save registers
-544     50/push-eax
-545     # var b/ecx : (handle array int) = parse-array-of-ints(Heap, expected)
-546     # . eax = parse-array-of-ints(Heap, expected)
-547     # . . push args
-548     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
-549     68/push  Heap/imm32
-550     # . . call
-551     e8/call  parse-array-of-ints/disp32
-552     # . . discard args
-553     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-554     # . b = eax
-555     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to ecx
-556     # eax = array-equal?(a, b)
-557     # . . push args
-558     51/push-ecx
-559     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
-560     # . . call
-561     e8/call  array-equal?/disp32
-562     # . . discard args
-563     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-564     # check-ints-equal(eax, 1, msg)
-565     # . . push args
-566     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
-567     68/push  1/imm32
-568     50/push-eax
-569     # . . call
-570     e8/call  check-ints-equal/disp32
-571     # . . discard args
-572     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
-573 $check-array-equal:end:
-574     # . restore registers
-575     58/pop-to-eax
-576     # . epilogue
-577     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-578     5d/pop-to-ebp
-579     c3/return
-580 
-581 test-check-array-equal:
-582     # . prologue
-583     55/push-ebp
-584     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
-585     # var ecx : (array int) = [1, 2, 3]
-586     68/push  3/imm32
-587     68/push  2/imm32
-588     68/push  1/imm32
-589     68/push  0xc/imm32/size
-590     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
-591     # check-array-equal(ecx, "1 2 3", "msg")
-592     # . . push args
-593     68/push  "F - test-check-array-equal"/imm32
-594     68/push  "1 2 3"/imm32
-595     51/push-ecx
-596     # . . call
-597     e8/call  check-array-equal/disp32
-598     # . . discard args
-599     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
-600     # . epilogue
-601     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
-602     5d/pop-to-ebp
-603     c3/return
-604 
-605 # . . vim:nowrap:textwidth=0
-
- - - diff --git a/html/100array-equal.subx.html b/html/100array-equal.subx.html new file mode 100644 index 00000000..89c48e6b --- /dev/null +++ b/html/100array-equal.subx.html @@ -0,0 +1,663 @@ + + + + +Mu - 100array-equal.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/100array-equal.subx +
+  1 # Comparing arrays of numbers.
+  2 
+  3 == code
+  4 
+  5 array-equal?:  # a : (addr array int), b : (addr array int) -> eax : boolean
+  6     # pseudocode:
+  7     #   lena = a->length
+  8     #   if (lena != b->length) return false
+  9     #   i = 0
+ 10     #   curra = a->data
+ 11     #   currb = b->data
+ 12     #   while i < lena
+ 13     #     i1 = *curra
+ 14     #     i2 = *currb
+ 15     #     if (c1 != c2) return false
+ 16     #     i+=4, curra+=4, currb+=4
+ 17     #   return true
+ 18     #
+ 19     # registers:
+ 20     #   i: ecx
+ 21     #   lena: edx
+ 22     #   curra: esi
+ 23     #   currb: edi
+ 24     #   i1: eax
+ 25     #   i2: ebx
+ 26     #
+ 27     # . prologue
+ 28     55/push-ebp
+ 29     89/<- %ebp 4/r32/esp
+ 30     # . save registers
+ 31     51/push-ecx
+ 32     52/push-edx
+ 33     53/push-ebx
+ 34     56/push-esi
+ 35     57/push-edi
+ 36     # esi = a
+ 37     8b/-> *(ebp+8) 6/r32/esi
+ 38     # edi = b
+ 39     8b/-> *(ebp+0xc) 7/r32/edi
+ 40     # var lena/edx : int = a->length
+ 41     8b/-> *esi 2/r32/edx
+ 42 $array-equal?:lengths:
+ 43     # if (lena != b->length) return false
+ 44     39/compare *edi 2/r32/edx
+ 45     75/jump-if-not-equal $array-equal?:false/disp8
+ 46     # var curra/esi : (addr byte) = a->data
+ 47     81 0/subop/add %esi 4/imm32
+ 48     # var currb/edi : (addr byte) = b->data
+ 49     81 0/subop/add %edi 4/imm32
+ 50     # var i/ecx : int = 0
+ 51     31/xor %ecx 1/r32/ecx
+ 52     # var vala/eax : int
+ 53     # var valb/ebx : int
+ 54 $array-equal?:loop:
+ 55     # if (i >= lena) return true
+ 56     39/compare %ecx 2/r32/edx
+ 57     7d/jump-if-greater-or-equal $array-equal?:true/disp8
+ 58     # var vala/eax : int = *curra
+ 59     8b/-> *esi 0/r32/eax
+ 60     # var valb/ebx : int = *currb
+ 61     8b/-> *edi 3/r32/ebx
+ 62     # if (vala != valb) return false
+ 63     39/compare %eax 3/r32/ebx
+ 64     75/jump-if-not-equal $array-equal?:false/disp8
+ 65     # i += 4
+ 66     81 0/subop/add %ecx 4/imm32
+ 67     # currs += 4
+ 68     81 0/subop/add %esi 4/imm32
+ 69     # currb += 4
+ 70     81 0/subop/add %edi 4/imm32
+ 71     eb/jump $array-equal?:loop/disp8
+ 72 $array-equal?:true:
+ 73     b8/copy-to-eax 1/imm32
+ 74     eb/jump $array-equal?:end/disp8
+ 75 $array-equal?:false:
+ 76     b8/copy-to-eax 0/imm32
+ 77 $array-equal?:end:
+ 78     # . restore registers
+ 79     5f/pop-to-edi
+ 80     5e/pop-to-esi
+ 81     5b/pop-to-ebx
+ 82     5a/pop-to-edx
+ 83     59/pop-to-ecx
+ 84     # . epilogue
+ 85     89/<- %esp 5/r32/ebp
+ 86     5d/pop-to-ebp
+ 87     c3/return
+ 88 
+ 89 test-compare-empty-with-empty-array:
+ 90     # . prologue
+ 91     55/push-ebp
+ 92     89/<- %ebp 4/r32/esp
+ 93     # var ecx : (array _) = []
+ 94     68/push 0/imm32/size
+ 95     89/<- %ecx 4/r32/esp
+ 96     # var edx : (array _) = []
+ 97     68/push 0/imm32/size
+ 98     89/<- %edx 4/r32/esp
+ 99     # eax = array-equal?(ecx, edx)
+100     # . . push args
+101     52/push-edx
+102     51/push-ecx
+103     # . . call
+104     e8/call array-equal?/disp32
+105     # . . discard args
+106     81 0/subop/add %esp 8/imm32
+107     # check-ints-equal(eax, 1, msg)
+108     # . . push args
+109     68/push "F - test-compare-empty-with-empty-array"/imm32
+110     68/push 1/imm32/true
+111     50/push-eax
+112     # . . call
+113     e8/call check-ints-equal/disp32
+114     # . . discard args
+115     81 0/subop/add %esp 0xc/imm32
+116     # . epilogue
+117     89/<- %esp 5/r32/ebp
+118     5d/pop-to-ebp
+119     c3/return
+120 
+121 test-compare-empty-with-non-empty-array:  # also checks length-mismatch code path
+122     # . prologue
+123     55/push-ebp
+124     89/<- %ebp 4/r32/esp
+125     # var ecx : (array int) = [1]
+126     68/push 1/imm32
+127     68/push 4/imm32/size
+128     89/<- %ecx 4/r32/esp
+129     # var edx : (array int) = []
+130     68/push 0/imm32/size
+131     89/<- %edx 4/r32/esp
+132     # eax = array-equal?(ecx, edx)
+133     # . . push args
+134     52/push-edx
+135     51/push-ecx
+136     # . . call
+137     e8/call array-equal?/disp32
+138     # . . discard args
+139     81 0/subop/add %esp 8/imm32
+140     # check-ints-equal(eax, 0, msg)
+141     # . . push args
+142     68/push "F - test-compare-empty-with-non-empty-array"/imm32
+143     68/push 0/imm32/false
+144     50/push-eax
+145     # . . call
+146     e8/call check-ints-equal/disp32
+147     # . . discard args
+148     81 0/subop/add %esp 0xc/imm32
+149     # . epilogue
+150     89/<- %esp 5/r32/ebp
+151     5d/pop-to-ebp
+152     c3/return
+153 
+154 test-compare-equal-arrays:
+155     # . prologue
+156     55/push-ebp
+157     89/<- %ebp 4/r32/esp
+158     # var ecx : (array int) = [1, 2, 3]
+159     68/push 3/imm32
+160     68/push 2/imm32
+161     68/push 1/imm32
+162     68/push 0xc/imm32/size
+163     89/<- %ecx 4/r32/esp
+164     # var edx : (array int) = [1, 2, 3]
+165     68/push 3/imm32
+166     68/push 2/imm32
+167     68/push 1/imm32
+168     68/push 0xc/imm32/size
+169     89/<- %edx 4/r32/esp
+170     # eax = array-equal?(ecx, edx)
+171     # . . push args
+172     52/push-edx
+173     51/push-ecx
+174     # . . call
+175     e8/call array-equal?/disp32
+176     # . . discard args
+177     81 0/subop/add %esp 8/imm32
+178     # check-ints-equal(eax, 1, msg)
+179     # . . push args
+180     68/push "F - test-compare-equal-arrays"/imm32
+181     68/push 1/imm32/true
+182     50/push-eax
+183     # . . call
+184     e8/call check-ints-equal/disp32
+185     # . . discard args
+186     81 0/subop/add %esp 0xc/imm32
+187     # . epilogue
+188     89/<- %esp 5/r32/ebp
+189     5d/pop-to-ebp
+190     c3/return
+191 
+192 test-compare-inequal-arrays-equal-lengths:
+193     # . prologue
+194     55/push-ebp
+195     89/<- %ebp 4/r32/esp
+196     # var ecx : (array int) = [1, 4, 3]
+197     68/push 3/imm32
+198     68/push 4/imm32
+199     68/push 1/imm32
+200     68/push 0xc/imm32/size
+201     89/<- %ecx 4/r32/esp
+202     # var edx : (array int) = [1, 2, 3]
+203     68/push 3/imm32
+204     68/push 2/imm32
+205     68/push 1/imm32
+206     68/push 0xc/imm32/size
+207     89/<- %edx 4/r32/esp
+208     # eax = array-equal?(ecx, edx)
+209     # . . push args
+210     52/push-edx
+211     51/push-ecx
+212     # . . call
+213     e8/call array-equal?/disp32
+214     # . . discard args
+215     81 0/subop/add %esp 8/imm32
+216     # check-ints-equal(eax, 0, msg)
+217     # . . push args
+218     68/push "F - test-compare-inequal-arrays-equal-lengths"/imm32
+219     68/push 0/imm32/false
+220     50/push-eax
+221     # . . call
+222     e8/call check-ints-equal/disp32
+223     # . . discard args
+224     81 0/subop/add %esp 0xc/imm32
+225     # . epilogue
+226     89/<- %esp 5/r32/ebp
+227     5d/pop-to-ebp
+228     c3/return
+229 
+230 parse-array-of-ints:  # ad : (addr allocation-descriptor), s : (addr string) -> result/eax : (handle array int)
+231     # pseudocode
+232     #   end = &s->data[s->length]
+233     #   curr = s->data
+234     #   size = 0
+235     #   while true
+236     #     if (curr >= end) break
+237     #     curr = skip-chars-matching-in-slice(curr, end, ' ')
+238     #     if (curr >= end) break
+239     #     curr = skip-chars-not-matching-in-slice(curr, end, ' ')
+240     #     ++size
+241     #   result = allocate(ad, (size+1)*4)
+242     #   result->size = (size+1)*4
+243     #   var slice : slice = {s->data, 0}
+244     #   out = result->data
+245     #   while true
+246     #     if (slice->start >= end) break
+247     #     slice->start = skip-chars-matching-in-slice(slice->start, end, ' ')
+248     #     if (slice->start >= end) break
+249     #     slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ')
+250     #     *out = parse-hex-int(slice)
+251     #     out += 4
+252     #     slice->start = slice->end
+253     #   return result
+254     #
+255     # . prologue
+256     55/push-ebp
+257     89/<- %ebp 4/r32/esp
+258     # . save registers
+259     51/push-ecx
+260     52/push-edx
+261     53/push-ebx
+262     56/push-esi
+263     57/push-edi
+264     # esi = s
+265     8b/-> *(ebp+0xc) 6/r32/esi
+266     # var curr/ecx : (addr byte) = s->data
+267     8d/copy-address *(esi+4) 1/r32/ecx
+268     # var end/edx : (addr byte) = &s->data[s->length]
+269     # . edx = s->length
+270     8b/-> *esi 2/r32/edx
+271     # . edx += curr
+272     01/add %edx 1/r32/ecx
+273     # var size/ebx : int = 0
+274     31/xor %ebx 3/r32/ebx
+275 $parse-array-of-ints:loop1:
+276     # if (curr >= end) break
+277     39/compare %ecx 2/r32/edx
+278     73/jump-if-greater-or-equal-unsigned $parse-array-of-ints:break1/disp8
+279     # curr = skip-chars-matching-in-slice(curr, end, ' ')
+280     # . eax = skip-chars-matching-in-slice(curr, end, ' ')
+281     # . . push args
+282     68/push 0x20/imm32/space
+283     52/push-edx
+284     51/push-ecx
+285     # . . call
+286     e8/call skip-chars-matching-in-slice/disp32
+287     # . . discard args
+288     81 0/subop/add %esp 0xc/imm32
+289     # . ecx = eax
+290     89/<- %ecx 0/r32/eax
+291     # if (curr >= end) break
+292     39/compare %ecx 2/r32/edx
+293     73/jump-if-greater-or-equal-unsigned $parse-array-of-ints:break1/disp8
+294     # curr = skip-chars-not-matching-in-slice(curr, end, ' ')
+295     # . eax = skip-chars-not-matching-in-slice(curr, end, ' ')
+296     # . . push args
+297     68/push 0x20/imm32/space
+298     52/push-edx
+299     51/push-ecx
+300     # . . call
+301     e8/call skip-chars-not-matching-in-slice/disp32
+302     # . . discard args
+303     81 0/subop/add %esp 0xc/imm32
+304     # . ecx = eax
+305     89/<- %ecx 0/r32/eax
+306     # size += 4
+307     81 0/subop/add %ebx 4/imm32
+308     eb/jump $parse-array-of-ints:loop1/disp8
+309 $parse-array-of-ints:break1:
+310     # var result/edi : (handle array int) = allocate(ad, size+4)
+311     # . eax = allocate(ad, size+4)
+312     # . . push args
+313     89/<- %eax 3/r32/ebx
+314     05/add-to-eax 4/imm32
+315     50/push-eax
+316     ff 6/subop/push *(ebp+8)
+317     # . . call
+318     e8/call allocate/disp32
+319     # . . discard args
+320     81 0/subop/add %esp 8/imm32
+321     # . edi = eax
+322     89/<- %edi 0/r32/eax
+323     # result->size = size
+324     89/<- *eax 3/r32/ebx
+325 $parse-array-of-ints:pass2:
+326     # var slice/ecx : slice = {s->data, 0}
+327     68/push 0/imm32/end
+328     8d/copy-address *(esi+4) 1/r32/ecx
+329     51/push-ecx
+330     89/<- %ecx 4/r32/esp
+331     # var out/ebx : (addr byte) = result->data
+332     8d/copy-address *(eax+4) 3/r32/ebx
+333 $parse-array-of-ints:loop2:
+334     # if (slice->start >= end) break
+335     39/compare *ecx 2/r32/edx
+336     73/jump-if-greater-or-equal-unsigned $parse-array-of-ints:end/disp8
+337     # slice->start = skip-chars-matching-in-slice(slice->start, end, ' ')
+338     # . eax = skip-chars-matching-in-slice(slice->start, end, ' ')
+339     # . . push args
+340     68/push 0x20/imm32/space
+341     52/push-edx
+342     ff 6/subop/push *ecx
+343     # . . call
+344     e8/call skip-chars-matching-in-slice/disp32
+345     # . . discard args
+346     81 0/subop/add %esp 0xc/imm32
+347     # . slice->start = eax
+348     89/<- *ecx 0/r32/eax
+349     # if (slice->start >= end) break
+350     39/compare *ecx 2/r32/edx
+351     73/jump-if-greater-or-equal-unsigned $parse-array-of-ints:end/disp8
+352     # slice->end = skip-chars-not-matching-in-slice(slice->start, end, ' ')
+353     # . eax = skip-chars-not-matching-in-slice(curr, end, ' ')
+354     # . . push args
+355     68/push 0x20/imm32/space
+356     52/push-edx
+357     50/push-eax
+358     # . . call
+359     e8/call skip-chars-not-matching-in-slice/disp32
+360     # . . discard args
+361     81 0/subop/add %esp 0xc/imm32
+362     # . slice->end = eax
+363     89/<- *(ecx+4) 0/r32/eax
+364     # *out = parse-hex-int(slice)
+365     # . eax = parse-hex-int(slice)
+366     # . . push args
+367     51/push-ecx
+368     # . . call
+369     e8/call parse-hex-int/disp32
+370     # . . discard args
+371     81 0/subop/add %esp 4/imm32
+372     # . *out = eax
+373     89/<- *ebx 0/r32/eax
+374     # out += 4
+375     81 0/subop/add %ebx 4/imm32
+376     # slice->start = slice->end
+377     8b/-> *(ecx+4) 0/r32/eax
+378     89/<- *ecx 0/r32/eax
+379     81 0/subop/add %ecx 4/imm32
+380     eb/jump $parse-array-of-ints:loop2/disp8
+381 $parse-array-of-ints:end:
+382     # return edi
+383     89/<- %eax 7/r32/edi
+384     # . reclaim locals
+385     81 0/subop/add %esp 8/imm32
+386     # . restore registers
+387     5f/pop-to-edi
+388     5e/pop-to-esi
+389     5b/pop-to-ebx
+390     5a/pop-to-edx
+391     59/pop-to-ecx
+392     # . epilogue
+393     89/<- %esp 5/r32/ebp
+394     5d/pop-to-ebp
+395     c3/return
+396 
+397 test-parse-array-of-ints:
+398     # . prologue
+399     55/push-ebp
+400     89/<- %ebp 4/r32/esp
+401     # var ecx : (array int) = [1, 2, 3]
+402     68/push 3/imm32
+403     68/push 2/imm32
+404     68/push 1/imm32
+405     68/push 0xc/imm32/size
+406     89/<- %ecx 4/r32/esp
+407     # eax = parse-array-of-ints(Heap, "1 2 3")
+408     # . . push args
+409     68/push "1 2 3"/imm32
+410     68/push Heap/imm32
+411     # . . call
+412     e8/call parse-array-of-ints/disp32
+413     # . . discard args
+414     81 0/subop/add %esp 8/imm32
+415     # eax = array-equal?(ecx, eax)
+416     # . . push args
+417     50/push-eax
+418     51/push-ecx
+419     # . . call
+420     e8/call array-equal?/disp32
+421     # . . discard args
+422     81 0/subop/add %esp 8/imm32
+423     # check-ints-equal(eax, 1, msg)
+424     # . . push args
+425     68/push "F - test-parse-array-of-ints"/imm32
+426     68/push 1/imm32/true
+427     50/push-eax
+428     # . . call
+429     e8/call check-ints-equal/disp32
+430     # . . discard args
+431     81 0/subop/add %esp 0xc/imm32
+432     # . epilogue
+433     89/<- %esp 5/r32/ebp
+434     5d/pop-to-ebp
+435     c3/return
+436 
+437 test-parse-array-of-ints-empty:
+438     # - empty string = empty array
+439     # . prologue
+440     55/push-ebp
+441     89/<- %ebp 4/r32/esp
+442     # eax = parse-array-of-ints(Heap, "")
+443     # . . push args
+444     68/push ""/imm32
+445     68/push Heap/imm32
+446     # . . call
+447     e8/call parse-array-of-ints/disp32
+448     # . . discard args
+449     81 0/subop/add %esp 8/imm32
+450     # check-ints-equal(*eax, 0, msg)
+451     # . . push args
+452     68/push "F - test-parse-array-of-ints-empty"/imm32
+453     68/push 0/imm32/size
+454     ff 6/subop/push *eax
+455     # . . call
+456     e8/call check-ints-equal/disp32
+457     # . . discard args
+458     81 0/subop/add %esp 0xc/imm32
+459     # . epilogue
+460     89/<- %esp 5/r32/ebp
+461     5d/pop-to-ebp
+462     c3/return
+463 
+464 test-parse-array-of-ints-just-whitespace:
+465     # - just whitespace = empty array
+466     # . prologue
+467     55/push-ebp
+468     89/<- %ebp 4/r32/esp
+469     # eax = parse-array-of-ints(Heap, " ")
+470     # . . push args
+471     68/push Space/imm32
+472     68/push Heap/imm32
+473     # . . call
+474     e8/call parse-array-of-ints/disp32
+475     # . . discard args
+476     81 0/subop/add %esp 8/imm32
+477     # check-ints-equal(*eax, 0, msg)
+478     # . . push args
+479     68/push "F - test-parse-array-of-ints-empty"/imm32
+480     68/push 0/imm32/size
+481     ff 6/subop/push *eax
+482     # . . call
+483     e8/call check-ints-equal/disp32
+484     # . . discard args
+485     81 0/subop/add %esp 0xc/imm32
+486     # . epilogue
+487     89/<- %esp 5/r32/ebp
+488     5d/pop-to-ebp
+489     c3/return
+490 
+491 test-parse-array-of-ints-extra-whitespace:
+492     # . prologue
+493     55/push-ebp
+494     89/<- %ebp 4/r32/esp
+495     # var ecx : (array int) = [1, 2, 3]
+496     68/push 3/imm32
+497     68/push 2/imm32
+498     68/push 1/imm32
+499     68/push 0xc/imm32/size
+500     89/<- %ecx 4/r32/esp
+501     # eax = parse-array-of-ints(Heap, " 1 2  3  ")
+502     # . . push args
+503     68/push " 1 2  3  "/imm32
+504     68/push Heap/imm32
+505     # . . call
+506     e8/call parse-array-of-ints/disp32
+507     # . . discard args
+508     81 0/subop/add %esp 8/imm32
+509     # eax = array-equal?(ecx, eax)
+510     # . . push args
+511     50/push-eax
+512     51/push-ecx
+513     # . . call
+514     e8/call array-equal?/disp32
+515     # . . discard args
+516     81 0/subop/add %esp 8/imm32
+517     # check-ints-equal(eax, 1, msg)
+518     # . . push args
+519     68/push "F - test-parse-array-of-ints-extra-whitespace"/imm32
+520     68/push 1/imm32/true
+521     50/push-eax
+522     # . . call
+523     e8/call check-ints-equal/disp32
+524     # . . discard args
+525     81 0/subop/add %esp 0xc/imm32
+526     # . epilogue
+527     89/<- %esp 5/r32/ebp
+528     5d/pop-to-ebp
+529     c3/return
+530 
+531 # helper for later tests
+532 # compare an array with a string representation of an array literal
+533 check-array-equal:  # a : (addr array int), expected : (addr string), msg : (addr string)
+534     # . prologue
+535     55/push-ebp
+536     89/<- %ebp 4/r32/esp
+537     # . save registers
+538     50/push-eax
+539     # var b/ecx : (handle array int) = parse-array-of-ints(Heap, expected)
+540     # . eax = parse-array-of-ints(Heap, expected)
+541     # . . push args
+542     ff 6/subop/push *(ebp+0xc)
+543     68/push Heap/imm32
+544     # . . call
+545     e8/call parse-array-of-ints/disp32
+546     # . . discard args
+547     81 0/subop/add %esp 8/imm32
+548     # . b = eax
+549     89/<- %ecx 0/r32/eax
+550     # eax = array-equal?(a, b)
+551     # . . push args
+552     51/push-ecx
+553     ff 6/subop/push *(ebp+8)
+554     # . . call
+555     e8/call array-equal?/disp32
+556     # . . discard args
+557     81 0/subop/add %esp 8/imm32
+558     # check-ints-equal(eax, 1, msg)
+559     # . . push args
+560     ff 6/subop/push *(ebp+0x10)
+561     68/push 1/imm32
+562     50/push-eax
+563     # . . call
+564     e8/call check-ints-equal/disp32
+565     # . . discard args
+566     81 0/subop/add %esp 0xc/imm32
+567 $check-array-equal:end:
+568     # . restore registers
+569     58/pop-to-eax
+570     # . epilogue
+571     89/<- %esp 5/r32/ebp
+572     5d/pop-to-ebp
+573     c3/return
+574 
+575 test-check-array-equal:
+576     # . prologue
+577     55/push-ebp
+578     89/<- %ebp 4/r32/esp
+579     # var ecx : (array int) = [1, 2, 3]
+580     68/push 3/imm32
+581     68/push 2/imm32
+582     68/push 1/imm32
+583     68/push 0xc/imm32/size
+584     89/<- %ecx 4/r32/esp
+585     # check-array-equal(ecx, "1 2 3", "msg")
+586     # . . push args
+587     68/push "F - test-check-array-equal"/imm32
+588     68/push "1 2 3"/imm32
+589     51/push-ecx
+590     # . . call
+591     e8/call check-array-equal/disp32
+592     # . . discard args
+593     81 0/subop/add %esp 8/imm32
+594     # . epilogue
+595     89/<- %esp 5/r32/ebp
+596     5d/pop-to-ebp
+597     c3/return
+598 
+599 # . . vim:nowrap:textwidth=0
+
+ + + diff --git a/html/apps/assort.subx.html b/html/apps/assort.subx.html index 30bb901f..127ccce8 100644 --- a/html/apps/assort.subx.html +++ b/html/apps/assort.subx.html @@ -546,7 +546,7 @@ if ('onhashchange' in window) { 564 52/push-edx 565 51/push-ecx 566 # . . call -567 e8/call next-word-or-string/disp32 +567 e8/call next-word-or-string/disp32 568 # . . discard args 569 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 570 $read-segments:check1: @@ -593,7 +593,7 @@ if ('onhashchange' in window) { 674 52/push-edx 675 51/push-ecx 676 # . . call -677 e8/call next-word-or-string/disp32 +677 e8/call next-word-or-string/disp32 678 # . . discard args 679 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 680 +-- 40 lines: #? # dump segment name --------------------------------------------------------------------------------------------------------------------- diff --git a/html/apps/braces.subx.html b/html/apps/braces.subx.html index e0088910..038eb673 100644 --- a/html/apps/braces.subx.html +++ b/html/apps/braces.subx.html @@ -222,7 +222,7 @@ if ('onhashchange' in window) { 163 (print-int32-buffered *(ebp+0xc) %ebx) 164 (write-buffered *(ebp+0xc) ":") 165 # push(label-stack, next-label-id) -166 (push %edx %ebx) +166 (push %edx %ebx) 167 # ++next-label-id 168 ff 0/subop/increment %ebx 169 # continue @@ -233,7 +233,7 @@ if ('onhashchange' in window) { 174 0f 85/jump-if-equal $subx-braces:word-loop/disp32 175 $subx-braces:emit-curly-closed: 176 # eax = pop(label-stack) -177 (pop %edx) +177 (pop %edx) 178 # print(out, "_break" eax ":") 179 (write-buffered *(ebp+0xc) "_break") 180 (print-int32-buffered *(ebp+0xc) %eax) @@ -241,7 +241,7 @@ if ('onhashchange' in window) { 182 # continue 183 e9/jump $subx-braces:next-line/disp32 184 $subx-braces:word-loop: -185 (next-word-or-string %ecx %edi) +185 (next-word-or-string %ecx %edi) 186 $subx-braces:check1: 187 # if (slice-empty?(word-slice)) break 188 (slice-empty? %edi) @@ -264,7 +264,7 @@ if ('onhashchange' in window) { 205 3d/compare-eax-and 0/imm32/false 206 74/jump-if-equal $subx-braces:check-for-loop/disp8 207 $subx-braces:emit-break: -208 (top %edx) +208 (top %edx) 209 # print(out, "_break" eax) 210 (write-buffered *(ebp+0xc) "_break") 211 (print-int32-buffered *(ebp+0xc) %eax) @@ -280,7 +280,7 @@ if ('onhashchange' in window) { 221 3d/compare-eax-and 0/imm32/false 222 74/jump-if-equal $subx-braces:emit-word-slice/disp8 223 $subx-braces:emit-loop: -224 (top %edx) +224 (top %edx) 225 # print(out, "_loop" eax) 226 (write-buffered *(ebp+0xc) "_loop") 227 (print-int32-buffered *(ebp+0xc) %eax) diff --git a/html/apps/calls.subx.html b/html/apps/calls.subx.html index a135aad8..315eca0e 100644 --- a/html/apps/calls.subx.html +++ b/html/apps/calls.subx.html @@ -339,7 +339,7 @@ if ('onhashchange' in window) { 317 ff 6/subop/push *ecx 318 ff 6/subop/push *(ebp+0xc) 319 # . . call - 320 e8/call write-int/disp32 + 320 e8/call write-int/disp32 321 # . . discard args 322 81 0/subop/add %esp 8/imm32 323 # write-int(words, word-slice->end) @@ -347,7 +347,7 @@ if ('onhashchange' in window) { 325 ff 6/subop/push *(ecx+4) 326 ff 6/subop/push *(ebp+0xc) 327 # . . call - 328 e8/call write-int/disp32 + 328 e8/call write-int/disp32 329 # . . discard args 330 81 0/subop/add %esp 8/imm32 331 # loop diff --git a/html/apps/dquotes.subx.html b/html/apps/dquotes.subx.html index 3114a631..03753533 100644 --- a/html/apps/dquotes.subx.html +++ b/html/apps/dquotes.subx.html @@ -244,7 +244,7 @@ if ('onhashchange' in window) { 181 52/push-edx 182 51/push-ecx 183 # . . call - 184 e8/call next-word-or-string/disp32 + 184 e8/call next-word-or-string/disp32 185 # . . discard args 186 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 187 $subx-dquotes:check1: diff --git a/html/apps/mu.subx.html b/html/apps/mu.subx.html index 494d0088..357c856e 100644 --- a/html/apps/mu.subx.html +++ b/html/apps/mu.subx.html @@ -462,8 +462,8 @@ if ('onhashchange' in window) { 400 89/<- %ebp 4/r32/esp 401 # 402 (parse-mu *(ebp+8)) - 403 (check-mu-types) - 404 (emit-subx *(ebp+0xc)) + 403 (check-mu-types) + 404 (emit-subx *(ebp+0xc)) 405 $convert-mu:end: 406 # . epilogue 407 89/<- %esp 5/r32/ebp @@ -1044,7 +1044,7 @@ if ('onhashchange' in window) { 1027 81 7/subop/compare *ecx 0/imm32 1028 0f 84/jump-if-equal break/disp32 1029 +-- 6 lines: #? # dump line --------------------------------------------------------------------------------------------------------------------------- -1035 (next-word-or-string %ecx %edx) +1035 (next-word-or-string %ecx %edx) 1036 # if slice-empty?(word-slice) continue 1037 (slice-empty? %edx) 1038 3d/compare-eax-and 0/imm32 @@ -1066,9 +1066,9 @@ if ('onhashchange' in window) { 1054 # var new-function/eax : (handle function) = populate-mu-function(in, new-function, vars) 1055 (allocate Heap *Function-size) # => eax 1056 (zero-out %eax *Function-size) -1057 (clear-stack %ebx) +1057 (clear-stack %ebx) 1058 (populate-mu-function-header %ecx %eax %ebx) -1059 (populate-mu-function-body *(ebp+8) %eax %ebx) +1059 (populate-mu-function-body *(ebp+8) %eax %ebx) 1060 # *curr-function = new-function 1061 89/<- *edi 0/r32/eax 1062 # curr-function = &new-function->next @@ -1212,7 +1212,7 @@ if ('onhashchange' in window) { 1200 3d/compare-eax-and 0/imm32 1201 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 1202 # var v/ebx : (handle var) = parse-var-with-type(word-slice, first-line) -1203 (parse-var-with-type %ecx *(ebp+8)) # => eax +1203 (parse-var-with-type %ecx *(ebp+8)) # => eax 1204 89/<- %ebx 0/r32/eax 1205 # assert(v->register == null) 1206 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register @@ -1220,12 +1220,12 @@ if ('onhashchange' in window) { 1208 # v->stack-offset = next-offset 1209 89/<- *(ebx+0xc) 2/r32/edx # Var-stack-offset 1210 # next-offset += size-of(v) -1211 (size-of %ebx) # => eax +1211 (size-of %ebx) # => eax 1212 01/add %edx 0/r32/eax 1213 # -1214 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax +1214 (append-list Heap %ebx *(edi+8)) # Function-inouts => eax 1215 89/<- *(edi+8) 0/r32/eax # Function-inouts -1216 (push *(ebp+0x10) %ebx) +1216 (push *(ebp+0x10) %ebx) 1217 # 1218 e9/jump loop/disp32 1219 } @@ -1246,17 +1246,17 @@ if ('onhashchange' in window) { 1234 3d/compare-eax-and 0/imm32 1235 0f 85/jump-if-not-equal $populate-mu-function-header:error1/disp32 1236 # -1237 (parse-var-with-type %ecx *(ebp+8)) # => eax +1237 (parse-var-with-type %ecx *(ebp+8)) # => eax 1238 89/<- %ebx 0/r32/eax 1239 # assert(var->register != null) 1240 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register 1241 0f 84/jump-if-equal $populate-mu-function-header:error3/disp32 -1242 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax +1242 (append-list Heap %ebx *(edi+0xc)) # Function-outputs => eax 1243 89/<- *(edi+0xc) 0/r32/eax # Function-outputs 1244 e9/jump loop/disp32 1245 } 1246 $populate-mu-function-header:done: -1247 (check-no-tokens-left *(ebp+8)) +1247 (check-no-tokens-left *(ebp+8)) 1248 $populate-mu-function-header:end: 1249 # . reclaim locals 1250 81 0/subop/add %esp 8/imm32 @@ -1339,1371 +1339,1371 @@ if ('onhashchange' in window) { 1327 # ebx : (handle var) = result->inouts->value 1328 8b/-> *edx 3/r32/ebx # List-value 1329 (check-strings-equal *ebx "n" "F - test-function-header-with-arg/inout:0") # Var-name -1330 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:0/type") # Var-type -1331 # . epilogue -1332 89/<- %esp 5/r32/ebp -1333 5d/pop-to-ebp -1334 c3/return -1335 -1336 test-function-header-with-multiple-args: -1337 # 'fn foo a: int, b: int, c: int {' -1338 # . prologue -1339 55/push-ebp -1340 89/<- %ebp 4/r32/esp -1341 # setup -1342 (clear-stream _test-input-stream) -1343 (write _test-input-stream "foo a: int, b: int c: int {\n") -1344 # result/ecx : (handle function) -1345 2b/subtract-> *Function-size 4/r32/esp -1346 89/<- %ecx 4/r32/esp -1347 (zero-out %ecx *Function-size) -1348 # var vars/ebx : (stack (addr var) 16) -1349 81 5/subop/subtract %esp 0x10/imm32 -1350 68/push 0x10/imm32/length -1351 68/push 0/imm32/top -1352 89/<- %ebx 4/r32/esp -1353 # convert -1354 (populate-mu-function-header _test-input-stream %ecx %ebx) -1355 # check result -1356 (check-strings-equal *ecx "foo") # Function-name -1357 # edx : (handle list var) = result->inouts -1358 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1359 $test-function-header-with-multiple-args:inout0: -1360 # ebx : (handle var) = result->inouts->value -1361 8b/-> *edx 3/r32/ebx # List-value -1362 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name -1363 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:0/type") # Var-type -1364 # edx = result->inouts->next -1365 8b/-> *(edx+4) 2/r32/edx # List-next -1366 $test-function-header-with-multiple-args:inout1: -1367 # ebx = result->inouts->next->value -1368 8b/-> *edx 3/r32/ebx # List-value -1369 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name -1370 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:1/type") # Var-type -1371 # edx = result->inouts->next->next -1372 8b/-> *(edx+4) 2/r32/edx # List-next -1373 $test-function-header-with-multiple-args:inout2: -1374 # ebx = result->inouts->next->next->value -1375 8b/-> *edx 3/r32/ebx # List-value -1376 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name -1377 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-multiple-args/inout:2/type") # Var-type -1378 # . epilogue -1379 89/<- %esp 5/r32/ebp -1380 5d/pop-to-ebp -1381 c3/return -1382 -1383 test-function-with-multiple-args-and-outputs: -1384 # fn foo a: int, b: int, c: int -> x: int, y: int { -1385 # . prologue -1386 55/push-ebp -1387 89/<- %ebp 4/r32/esp -1388 # setup -1389 (clear-stream _test-input-stream) -1390 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx : int {\n") -1391 # result/ecx : (handle function) -1392 2b/subtract-> *Function-size 4/r32/esp -1393 89/<- %ecx 4/r32/esp -1394 (zero-out %ecx *Function-size) -1395 # var vars/ebx : (stack (addr var) 16) -1396 81 5/subop/subtract %esp 0x10/imm32 -1397 68/push 0x10/imm32/length -1398 68/push 0/imm32/top -1399 89/<- %ebx 4/r32/esp -1400 # convert -1401 (populate-mu-function-header _test-input-stream %ecx %ebx) -1402 # check result -1403 (check-strings-equal *ecx "foo") # Function-name -1404 # edx : (handle list var) = result->inouts -1405 8b/-> *(ecx+8) 2/r32/edx # Function-inouts -1406 # ebx : (handle var) = result->inouts->value -1407 8b/-> *edx 3/r32/ebx # List-value -1408 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name -1409 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:0/type") # Var-type -1410 # edx = result->inouts->next -1411 8b/-> *(edx+4) 2/r32/edx # List-next -1412 # ebx = result->inouts->next->value -1413 8b/-> *edx 3/r32/ebx # List-value -1414 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name -1415 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:1/type") # Var-type -1416 # edx = result->inouts->next->next -1417 8b/-> *(edx+4) 2/r32/edx # List-next -1418 # ebx = result->inouts->next->next->value -1419 8b/-> *edx 3/r32/ebx # List-value -1420 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name -1421 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/inout:2/type") # Var-type -1422 # edx : (handle list var) = result->outputs -1423 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs -1424 # ebx : (handle var) = result->outputs->value -1425 8b/-> *edx 3/r32/ebx # List-value -1426 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args/output:0") # Var-name -1427 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/output:0/type") # Var-type -1428 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-arg/output:0/register") # Var-register -1429 # edx = result->outputs->next -1430 8b/-> *(edx+4) 2/r32/edx # List-next -1431 # ebx = result->outputs->next->value -1432 8b/-> *edx 3/r32/ebx # List-value -1433 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args/output:1") # Var-name -1434 (check-ints-equal *(ebx+4) 1 "F - test-function-header-with-arg/output:1/type") # Var-type -1435 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-arg/output:0/register") # Var-register -1436 # . epilogue -1437 89/<- %esp 5/r32/ebp -1438 5d/pop-to-ebp -1439 c3/return -1440 -1441 # format for variables with types -1442 # x : int -1443 # x: int -1444 # x: int, -1445 # ignores at most one trailing colon or comma -1446 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte) -> result/eax: (handle var) -1447 # pseudocode: -1448 # var v : (handle var) = allocate(Heap, Var-size) -1449 # var s : slice -1450 # next-token-from-slice(name->start, name->end, '/', s) -1451 # var end : (addr byte) = s->end -1452 # if (slice-ends-with(s, ":")) -1453 # decrement s->end -1454 # if (slice-ends-with(s, ",")) -1455 # decrement s->end -1456 # v->name = slice-to-string(s) -1457 # ## register -1458 # next-token-from-slice(end, name->end, '/', s) -1459 # if (slice-ends-with(s, ":")) -1460 # decrement s->end -1461 # if (slice-ends-with(s, ",")) -1462 # decrement s->end -1463 # if (!slice-empty?(s)) -1464 # v->register = slice-to-string(s) -1465 # ## type -1466 # s = next-mu-token(first-line) -1467 # assert(s not in '{' '}' '->') -1468 # if (slice-empty?(s)) { -1469 # s = next-mu-token(first-line) -1470 # assert(type not in '{' '}' '->') -1471 # } -1472 # type = type-for(s) -1473 # v->type = type -1474 # return v -1475 # -1476 # . prologue -1477 55/push-ebp -1478 89/<- %ebp 4/r32/esp -1479 # . save registers -1480 51/push-ecx -1481 52/push-edx -1482 53/push-ebx -1483 56/push-esi -1484 57/push-edi -1485 # var result/edi : (handle var) = allocate(Heap, Var-size) -1486 (allocate Heap *Var-size) # => eax -1487 (zero-out %eax *Var-size) -1488 89/<- %edi 0/r32/eax -1489 # esi = name -1490 8b/-> *(ebp+8) 6/r32/esi -1491 # var s/ecx : slice -1492 68/push 0/imm32/end -1493 68/push 0/imm32/start -1494 89/<- %ecx 4/r32/esp -1495 $parse-var-with-type:save-name: -1496 # save v->name -1497 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' -1498 # . end/edx = s->end -1499 8b/-> *(ecx+4) 2/r32/edx -1500 # . if s ends with ':', decrement s->end -1501 { -1502 8b/-> *(ecx+4) 0/r32/eax -1503 48/decrement-eax -1504 8a/copy-byte *eax 3/r32/BL -1505 81 4/subop/and %ebx 0xff/imm32 -1506 81 7/subop/compare %ebx 0x3a/imm32/colon -1507 75/jump-if-not-equal break/disp8 -1508 89/<- *(ecx+4) 0/r32/eax -1509 } -1510 # . if s ends with ',', decrement s->end -1511 { -1512 8b/-> *(ecx+4) 0/r32/eax -1513 48/decrement-eax -1514 8a/copy-byte *eax 3/r32/BL -1515 81 4/subop/and %ebx 0xff/imm32 -1516 81 7/subop/compare %ebx 0x2c/imm32/comma -1517 75/jump-if-not-equal break/disp8 -1518 89/<- *(ecx+4) 0/r32/eax -1519 } -1520 $parse-var-with-type:write-name: -1521 (slice-to-string Heap %ecx) # => eax -1522 89/<- *edi 0/r32/eax # Var-name -1523 # save v->register -1524 $parse-var-with-type:save-register: -1525 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' -1526 # . if s ends with ':', decrement s->end -1527 { -1528 8b/-> *(ecx+4) 0/r32/eax -1529 48/decrement-eax -1530 8a/copy-byte *eax 3/r32/BL -1531 81 4/subop/and %ebx 0xff/imm32 -1532 81 7/subop/compare %ebx 0x3a/imm32/colon -1533 75/jump-if-not-equal break/disp8 -1534 89/<- *(ecx+4) 0/r32/eax -1535 } -1536 # . if s ends with ',', decrement s->end -1537 { -1538 8b/-> *(ecx+4) 0/r32/eax -1539 48/decrement-eax -1540 8a/copy-byte *eax 3/r32/BL -1541 81 4/subop/and %ebx 0xff/imm32 -1542 81 7/subop/compare %ebx 0x2c/imm32/comma -1543 75/jump-if-not-equal break/disp8 -1544 89/<- *(ecx+4) 0/r32/eax -1545 } -1546 # if (!slice-empty?(s)) v->register = slice-to-string(s) -1547 { -1548 $parse-var-with-type:write-register: -1549 # HACK: s->end can be less than s->start with all the decrements above -1550 # That's probably a sign we have the wrong algorithm for this function. -1551 8b/-> *ecx 0/r32/eax -1552 39/compare 0/r32/eax *(ecx+4) -1553 76/jump-if-lesser-or-equal break/disp8 -1554 (slice-to-string Heap %ecx) -1555 89/<- *(edi+0x10) 0/r32/eax # Var-register -1556 } -1557 # save v->type -1558 (next-mu-token *(ebp+0xc) %ecx) -1559 # if (word-slice == '{') abort -1560 (slice-equal? %ecx "{") # => eax -1561 3d/compare-eax-and 0/imm32 -1562 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1563 # if (word-slice == '->') abort -1564 (slice-equal? %ecx "->") # => eax -1565 3d/compare-eax-and 0/imm32 -1566 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1567 # if (word-slice == '}') abort -1568 (slice-equal? %ecx "}") # => eax -1569 3d/compare-eax-and 0/imm32 -1570 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1571 # if (slice-empty?(type)) skip -1572 (slice-empty? %ecx) -1573 { -1574 3d/compare-eax-and 0/imm32 -1575 0f 84/jump-if-equal break/disp32 -1576 (next-mu-token *(ebp+0xc) %ecx) -1577 # if (word-slice == '{') abort -1578 (slice-equal? %ecx "{") # => eax -1579 3d/compare-eax-and 0/imm32 -1580 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1581 # if (word-slice == '->') abort -1582 (slice-equal? %ecx "->") # => eax -1583 3d/compare-eax-and 0/imm32 -1584 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1585 # if (word-slice == '}') abort -1586 (slice-equal? %ecx "}") # => eax -1587 3d/compare-eax-and 0/imm32 -1588 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 -1589 } -1590 (type-for %ecx) -1591 89/<- *(edi+4) 0/r32/eax # Var-type -1592 $parse-var-with-type:end: -1593 # return result -1594 89/<- %eax 7/r32/edi -1595 # . reclaim locals -1596 81 0/subop/add %esp 8/imm32 -1597 # . restore registers -1598 5f/pop-to-edi -1599 5e/pop-to-esi -1600 5b/pop-to-ebx -1601 5a/pop-to-edx -1602 59/pop-to-ecx -1603 # . epilogue -1604 89/<- %esp 5/r32/ebp -1605 5d/pop-to-ebp -1606 c3/return -1607 -1608 $parse-var-with-type:abort: -1609 # error("function header not in form 'fn <name> {'") -1610 (write-buffered Stderr "var should have form 'name: type' in '") -1611 (flush Stderr) -1612 (rewind-stream *(ebp+0xc)) -1613 (write-stream 2 *(ebp+0xc)) -1614 (write-buffered Stderr "'\n") -1615 (flush Stderr) -1616 # . syscall(exit, 1) -1617 bb/copy-to-ebx 1/imm32 -1618 b8/copy-to-eax 1/imm32/exit -1619 cd/syscall 0x80/imm8 -1620 # never gets here -1621 -1622 next-mu-token: # in: (addr stream byte), out: (addr slice) -1623 # . prologue -1624 55/push-ebp -1625 89/<- %ebp 4/r32/esp -1626 # . save registers -1627 50/push-eax -1628 57/push-edi -1629 # edi = out -1630 8b/-> *(ebp+0xc) 7/r32/edi -1631 # -1632 (next-word *(ebp+8) %edi) # TODO: support s-expressions -1633 # if out ends with ':', decrement out->end -1634 { -1635 8b/-> *(edi+4) 0/r32/eax -1636 48/decrement-eax -1637 8a/copy-byte *eax 3/r32/BL -1638 81 4/subop/and %ebx 0xff/imm32 -1639 81 7/subop/compare %ebx 0x3a/imm32/colon -1640 75/jump-if-not-equal break/disp8 -1641 89/<- *(edi+4) 0/r32/eax -1642 } -1643 # if out ends with ',', decrement out->end -1644 { -1645 8b/-> *(edi+4) 0/r32/eax -1646 48/decrement-eax -1647 8a/copy-byte *eax 3/r32/BL -1648 81 4/subop/and %ebx 0xff/imm32 -1649 81 7/subop/compare %ebx 0x2c/imm32/comma -1650 75/jump-if-not-equal break/disp8 -1651 89/<- *(edi+4) 0/r32/eax -1652 } -1653 $next-mu-token:end: -1654 b8/copy-to-eax 1/imm32/int -1655 # . restore registers -1656 5f/pop-to-edi -1657 58/pop-to-eax -1658 # . epilogue -1659 89/<- %esp 5/r32/ebp -1660 5d/pop-to-ebp -1661 c3/return -1662 -1663 type-for: # name: (addr slice) -> result/eax: (handle tree type-id) -1664 # . prologue -1665 55/push-ebp -1666 89/<- %ebp 4/r32/esp -1667 # . save registers -1668 (pos-slice Type-id *(ebp+8)) # => eax -1669 $type-for:end: -1670 # . restore registers -1671 # . epilogue -1672 89/<- %esp 5/r32/ebp -1673 5d/pop-to-ebp -1674 c3/return -1675 -1676 # return the index in an array of strings matching 's' -1677 # index is denominated in elements, not bytes -1678 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int -1679 # . prologue -1680 55/push-ebp -1681 89/<- %ebp 4/r32/esp -1682 # . save registers -1683 51/push-ecx -1684 52/push-edx -1685 53/push-ebx -1686 56/push-esi -1687 # esi = arr -1688 8b/-> *(ebp+8) 6/r32/esi -1689 # var index/ecx: int = 0 -1690 b9/copy-to-ecx 0/imm32 -1691 # var curr/edx: (addr (addr array byte)) = arr->data -1692 8d/copy-address *(esi+0xc) 2/r32/edx -1693 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] -1694 8b/-> *esi 3/r32/ebx -1695 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx -1696 { -1697 # if (curr >= max) return -1 -1698 39/compare %edx 3/r32/ebx -1699 { -1700 72/jump-if-lesser-unsigned break/disp8 -1701 b8/copy-to-eax 1/imm32 -1702 eb/jump $pos-slice:end/disp8 -1703 } -1704 # if (slice-equal?(s, *curr)) break -1705 (slice-equal? *(ebp+0xc) *edx) # => eax -1706 3d/compare-eax-and 0/imm32 -1707 75/jump-if-not-equal break/disp8 -1708 # ++index -1709 41/increment-ecx -1710 # curr += 4 -1711 81 0/subop/add %edx 4/imm32 -1712 } -1713 89/<- %eax 1/r32/ecx -1714 $pos-slice:end: -1715 # . restore registers -1716 5e/pop-to-esi -1717 5b/pop-to-ebx -1718 5a/pop-to-edx -1719 59/pop-to-ecx -1720 # . epilogue -1721 89/<- %esp 5/r32/ebp -1722 5d/pop-to-ebp -1723 c3/return -1724 -1725 == data -1726 -1727 Type-id: # (stream (address array byte)) -1728 0x1c/imm32/write -1729 0/imm32/read -1730 0x100/imm32/length -1731 # data -1732 "literal"/imm32 # 0 -1733 "int"/imm32 # 1 -1734 "ref"/imm32 # 2 -1735 "addr"/imm32 # 3 -1736 "array"/imm32 # 4 -1737 "handle"/imm32 # 5 -1738 "bool"/imm32 # 6 -1739 0/imm32 -1740 # 0x20 -1741 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1742 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1743 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1744 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1745 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1746 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1747 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 -1748 -1749 == code -1750 -1751 test-parse-var-with-type: -1752 # . prologue -1753 55/push-ebp -1754 89/<- %ebp 4/r32/esp -1755 # (eax..ecx) = "x:" -1756 b8/copy-to-eax "x:"/imm32 -1757 8b/-> *eax 1/r32/ecx -1758 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1759 05/add-to-eax 4/imm32 -1760 # var slice/ecx : slice = {eax, ecx} -1761 51/push-ecx -1762 50/push-eax -1763 89/<- %ecx 4/r32/esp -1764 # _test-input-stream contains "int" -1765 (clear-stream _test-input-stream) -1766 (write _test-input-stream "int") -1767 # -1768 (parse-var-with-type %ecx _test-input-stream) -1769 8b/-> *eax 2/r32/edx # Var-name -1770 (check-strings-equal %edx "x" "F - test-var-with-type/name") -1771 8b/-> *(eax+4) 2/r32/edx # Var-type -1772 (check-ints-equal %edx 1 "F - test-var-with-type/type") -1773 # . epilogue -1774 89/<- %esp 5/r32/ebp -1775 5d/pop-to-ebp -1776 c3/return -1777 -1778 test-parse-var-with-type-and-register: -1779 # . prologue -1780 55/push-ebp -1781 89/<- %ebp 4/r32/esp -1782 # (eax..ecx) = "x/eax" -1783 b8/copy-to-eax "x/eax"/imm32 -1784 8b/-> *eax 1/r32/ecx -1785 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1786 05/add-to-eax 4/imm32 -1787 # var slice/ecx : slice = {eax, ecx} -1788 51/push-ecx -1789 50/push-eax -1790 89/<- %ecx 4/r32/esp -1791 # _test-input-stream contains ": int" -1792 (clear-stream _test-input-stream) -1793 (write _test-input-stream ": int") -1794 # -1795 (parse-var-with-type %ecx _test-input-stream) -1796 8b/-> *eax 2/r32/edx # Var-name -1797 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") -1798 8b/-> *(eax+0x10) 2/r32/edx # Var-register -1799 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") -1800 8b/-> *(eax+4) 2/r32/edx # Var-type -1801 (check-ints-equal %edx 1 "F - test-var-with-type-and-register/type") -1802 # . epilogue -1803 89/<- %esp 5/r32/ebp -1804 5d/pop-to-ebp -1805 c3/return -1806 -1807 test-parse-var-with-trailing-characters: -1808 # . prologue -1809 55/push-ebp -1810 89/<- %ebp 4/r32/esp -1811 # (eax..ecx) = "x:" -1812 b8/copy-to-eax "x:"/imm32 -1813 8b/-> *eax 1/r32/ecx -1814 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1815 05/add-to-eax 4/imm32 -1816 # var slice/ecx : slice = {eax, ecx} -1817 51/push-ecx -1818 50/push-eax -1819 89/<- %ecx 4/r32/esp -1820 # _test-input-stream contains "int," -1821 (clear-stream _test-input-stream) -1822 (write _test-input-stream "int,") -1823 # -1824 (parse-var-with-type %ecx _test-input-stream) -1825 8b/-> *eax 2/r32/edx # Var-name -1826 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") -1827 8b/-> *(eax+0x10) 2/r32/edx # Var-register -1828 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") -1829 8b/-> *(eax+4) 2/r32/edx # Var-type -1830 (check-ints-equal %edx 1 "F - test-var-with-trailing-characters/type") -1831 # . epilogue -1832 89/<- %esp 5/r32/ebp -1833 5d/pop-to-ebp -1834 c3/return -1835 -1836 test-parse-var-with-register-and-trailing-characters: -1837 # . prologue -1838 55/push-ebp -1839 89/<- %ebp 4/r32/esp -1840 # (eax..ecx) = "x/eax:" -1841 b8/copy-to-eax "x/eax:"/imm32 -1842 8b/-> *eax 1/r32/ecx -1843 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1844 05/add-to-eax 4/imm32 -1845 # var slice/ecx : slice = {eax, ecx} -1846 51/push-ecx -1847 50/push-eax -1848 89/<- %ecx 4/r32/esp -1849 # _test-input-stream contains "int," -1850 (clear-stream _test-input-stream) -1851 (write _test-input-stream "int,") -1852 # -1853 (parse-var-with-type %ecx _test-input-stream) -1854 8b/-> *eax 2/r32/edx # Var-name -1855 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") -1856 8b/-> *(eax+0x10) 2/r32/edx # Var-register -1857 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") -1858 8b/-> *(eax+4) 2/r32/edx # Var-type -1859 (check-ints-equal %edx 1 "F - test-var-with-register-and-trailing-characters/type") -1860 # . epilogue -1861 89/<- %esp 5/r32/ebp -1862 5d/pop-to-ebp -1863 c3/return -1864 -1865 # identifier starts with a letter or '$' or '_' -1866 # no constraints at the moment on later letters -1867 # all we really want to do so far is exclude '{', '}' and '->' -1868 is-identifier?: # in : (addr slice) -> result/eax : boolean -1869 # . prologue -1870 55/push-ebp -1871 89/<- %ebp 4/r32/esp -1872 # if (slice-empty?(in)) return false -1873 (slice-empty? *(ebp+8)) # => eax -1874 3d/compare-eax-and 0/imm32 -1875 75/jump-if-not-equal $is-identifier?:false/disp8 -1876 # var c/eax : byte = *in->start -1877 8b/-> *(ebp+8) 0/r32/eax -1878 8b/-> *eax 0/r32/eax -1879 8a/copy-byte *eax 0/r32/AL -1880 81 4/subop/and %eax 0xff/imm32 -1881 # if (c == '$') return true -1882 3d/compare-eax-and 0x24/imm32/$ -1883 74/jump-if-equal $is-identifier?:true/disp8 -1884 # if (c == '_') return true -1885 3d/compare-eax-and 0x5f/imm32/_ -1886 74/jump-if-equal $is-identifier?:true/disp8 -1887 # drop case -1888 25/and-eax-with 0x5f/imm32 -1889 # if (c < 'A') return false -1890 3d/compare-eax-and 0x41/imm32/A -1891 7c/jump-if-lesser $is-identifier?:false/disp8 -1892 # if (c > 'Z') return false -1893 3d/compare-eax-and 0x5a/imm32/Z -1894 7f/jump-if-greater $is-identifier?:false/disp8 -1895 # otherwise return true -1896 $is-identifier?:true: -1897 b8/copy-to-eax 1/imm32/true -1898 eb/jump $is-identifier?:end/disp8 -1899 $is-identifier?:false: -1900 b8/copy-to-eax 0/imm32/false -1901 $is-identifier?:end: -1902 # . epilogue -1903 89/<- %esp 5/r32/ebp -1904 5d/pop-to-ebp -1905 c3/return -1906 -1907 test-is-identifier-dollar: -1908 # . prologue -1909 55/push-ebp -1910 89/<- %ebp 4/r32/esp -1911 # (eax..ecx) = "$a" -1912 b8/copy-to-eax "$a"/imm32 -1913 8b/-> *eax 1/r32/ecx -1914 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1915 05/add-to-eax 4/imm32 -1916 # var slice/ecx : slice = {eax, ecx} -1917 51/push-ecx -1918 50/push-eax -1919 89/<- %ecx 4/r32/esp -1920 # -1921 (is-identifier? %ecx) -1922 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") -1923 # . epilogue -1924 89/<- %esp 5/r32/ebp -1925 5d/pop-to-ebp -1926 c3/return -1927 -1928 test-is-identifier-underscore: -1929 # . prologue -1930 55/push-ebp -1931 89/<- %ebp 4/r32/esp -1932 # (eax..ecx) = "_a" -1933 b8/copy-to-eax "_a"/imm32 -1934 8b/-> *eax 1/r32/ecx -1935 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1936 05/add-to-eax 4/imm32 -1937 # var slice/ecx : slice = {eax, ecx} -1938 51/push-ecx -1939 50/push-eax -1940 89/<- %ecx 4/r32/esp -1941 # -1942 (is-identifier? %ecx) -1943 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") -1944 # . epilogue -1945 89/<- %esp 5/r32/ebp -1946 5d/pop-to-ebp -1947 c3/return -1948 -1949 test-is-identifier-a: -1950 # . prologue -1951 55/push-ebp -1952 89/<- %ebp 4/r32/esp -1953 # (eax..ecx) = "a$" -1954 b8/copy-to-eax "a$"/imm32 -1955 8b/-> *eax 1/r32/ecx -1956 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1957 05/add-to-eax 4/imm32 -1958 # var slice/ecx : slice = {eax, ecx} -1959 51/push-ecx -1960 50/push-eax -1961 89/<- %ecx 4/r32/esp -1962 # -1963 (is-identifier? %ecx) -1964 (check-ints-equal %eax 1 "F - test-is-identifier-a") -1965 # . epilogue -1966 89/<- %esp 5/r32/ebp -1967 5d/pop-to-ebp -1968 c3/return -1969 -1970 test-is-identifier-z: -1971 # . prologue -1972 55/push-ebp -1973 89/<- %ebp 4/r32/esp -1974 # (eax..ecx) = "z$" -1975 b8/copy-to-eax "z$"/imm32 -1976 8b/-> *eax 1/r32/ecx -1977 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1978 05/add-to-eax 4/imm32 -1979 # var slice/ecx : slice = {eax, ecx} -1980 51/push-ecx -1981 50/push-eax -1982 89/<- %ecx 4/r32/esp -1983 # -1984 (is-identifier? %ecx) -1985 (check-ints-equal %eax 1 "F - test-is-identifier-z") -1986 # . epilogue -1987 89/<- %esp 5/r32/ebp -1988 5d/pop-to-ebp -1989 c3/return -1990 -1991 test-is-identifier-A: -1992 # . prologue -1993 55/push-ebp -1994 89/<- %ebp 4/r32/esp -1995 # (eax..ecx) = "A$" -1996 b8/copy-to-eax "A$"/imm32 -1997 8b/-> *eax 1/r32/ecx -1998 8d/copy-address *(eax+ecx+4) 1/r32/ecx -1999 05/add-to-eax 4/imm32 -2000 # var slice/ecx : slice = {eax, ecx} -2001 51/push-ecx -2002 50/push-eax -2003 89/<- %ecx 4/r32/esp -2004 # -2005 (is-identifier? %ecx) -2006 (check-ints-equal %eax 1 "F - test-is-identifier-A") -2007 # . epilogue -2008 89/<- %esp 5/r32/ebp -2009 5d/pop-to-ebp -2010 c3/return -2011 -2012 test-is-identifier-Z: -2013 # . prologue -2014 55/push-ebp -2015 89/<- %ebp 4/r32/esp -2016 # (eax..ecx) = "Z$" -2017 b8/copy-to-eax "Z$"/imm32 -2018 8b/-> *eax 1/r32/ecx -2019 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2020 05/add-to-eax 4/imm32 -2021 # var slice/ecx : slice = {eax, ecx} -2022 51/push-ecx -2023 50/push-eax -2024 89/<- %ecx 4/r32/esp -2025 # -2026 (is-identifier? %ecx) -2027 (check-ints-equal %eax 1 "F - test-is-identifier-Z") -2028 # . epilogue -2029 89/<- %esp 5/r32/ebp -2030 5d/pop-to-ebp -2031 c3/return -2032 -2033 test-is-identifier-@: -2034 # character before 'A' is invalid -2035 # . prologue -2036 55/push-ebp -2037 89/<- %ebp 4/r32/esp -2038 # (eax..ecx) = "@a" -2039 b8/copy-to-eax "@a"/imm32 -2040 8b/-> *eax 1/r32/ecx -2041 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2042 05/add-to-eax 4/imm32 -2043 # var slice/ecx : slice = {eax, ecx} -2044 51/push-ecx -2045 50/push-eax -2046 89/<- %ecx 4/r32/esp -2047 # -2048 (is-identifier? %ecx) -2049 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2050 # . epilogue -2051 89/<- %esp 5/r32/ebp -2052 5d/pop-to-ebp -2053 c3/return -2054 -2055 test-is-identifier-square-bracket: -2056 # character after 'Z' is invalid -2057 # . prologue -2058 55/push-ebp -2059 89/<- %ebp 4/r32/esp -2060 # (eax..ecx) = "[a" -2061 b8/copy-to-eax "[a"/imm32 -2062 8b/-> *eax 1/r32/ecx -2063 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2064 05/add-to-eax 4/imm32 -2065 # var slice/ecx : slice = {eax, ecx} -2066 51/push-ecx -2067 50/push-eax -2068 89/<- %ecx 4/r32/esp -2069 # -2070 (is-identifier? %ecx) -2071 (check-ints-equal %eax 0 "F - test-is-identifier-@") -2072 # . epilogue -2073 89/<- %esp 5/r32/ebp -2074 5d/pop-to-ebp -2075 c3/return -2076 -2077 test-is-identifier-backtick: -2078 # character before 'a' is invalid -2079 # . prologue -2080 55/push-ebp -2081 89/<- %ebp 4/r32/esp -2082 # (eax..ecx) = "`a" -2083 b8/copy-to-eax "`a"/imm32 -2084 8b/-> *eax 1/r32/ecx -2085 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2086 05/add-to-eax 4/imm32 -2087 # var slice/ecx : slice = {eax, ecx} -2088 51/push-ecx -2089 50/push-eax -2090 89/<- %ecx 4/r32/esp -2091 # -2092 (is-identifier? %ecx) -2093 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") -2094 # . epilogue -2095 89/<- %esp 5/r32/ebp -2096 5d/pop-to-ebp -2097 c3/return -2098 -2099 test-is-identifier-curly-brace-open: -2100 # character after 'z' is invalid; also used for blocks -2101 # . prologue -2102 55/push-ebp -2103 89/<- %ebp 4/r32/esp -2104 # (eax..ecx) = "{a" -2105 b8/copy-to-eax "{a"/imm32 -2106 8b/-> *eax 1/r32/ecx -2107 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2108 05/add-to-eax 4/imm32 -2109 # var slice/ecx : slice = {eax, ecx} -2110 51/push-ecx -2111 50/push-eax -2112 89/<- %ecx 4/r32/esp -2113 # -2114 (is-identifier? %ecx) -2115 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") -2116 # . epilogue -2117 89/<- %esp 5/r32/ebp -2118 5d/pop-to-ebp -2119 c3/return -2120 -2121 test-is-identifier-curly-brace-close: -2122 # . prologue -2123 55/push-ebp -2124 89/<- %ebp 4/r32/esp -2125 # (eax..ecx) = "}a" -2126 b8/copy-to-eax "}a"/imm32 -2127 8b/-> *eax 1/r32/ecx -2128 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2129 05/add-to-eax 4/imm32 -2130 # var slice/ecx : slice = {eax, ecx} -2131 51/push-ecx -2132 50/push-eax -2133 89/<- %ecx 4/r32/esp -2134 # -2135 (is-identifier? %ecx) -2136 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") -2137 # . epilogue -2138 89/<- %esp 5/r32/ebp -2139 5d/pop-to-ebp -2140 c3/return -2141 -2142 test-is-identifier-hyphen: -2143 # disallow leading '-' since '->' has special meaning -2144 # . prologue -2145 55/push-ebp -2146 89/<- %ebp 4/r32/esp -2147 # (eax..ecx) = "-a" -2148 b8/copy-to-eax "-a"/imm32 -2149 8b/-> *eax 1/r32/ecx -2150 8d/copy-address *(eax+ecx+4) 1/r32/ecx -2151 05/add-to-eax 4/imm32 -2152 # var slice/ecx : slice = {eax, ecx} -2153 51/push-ecx -2154 50/push-eax -2155 89/<- %ecx 4/r32/esp -2156 # -2157 (is-identifier? %ecx) -2158 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") -2159 # . epilogue -2160 89/<- %esp 5/r32/ebp -2161 5d/pop-to-ebp -2162 c3/return -2163 -2164 populate-mu-function-body: # in : (addr buffered-file), out : (handle function), vars : (addr stack (handle var)) -2165 # . prologue -2166 55/push-ebp -2167 89/<- %ebp 4/r32/esp -2168 # . save registers -2169 50/push-eax -2170 56/push-esi -2171 57/push-edi -2172 # esi = in -2173 8b/-> *(ebp+8) 6/r32/esi -2174 # edi = out -2175 8b/-> *(ebp+0xc) 7/r32/edi -2176 # var eax : (handle block) = parse-mu-block(in, vars) -2177 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax -2178 # out->body = eax -2179 89/<- *(edi+0x10) 0/r32/eax # Function-body -2180 $populate-mu-function-body:end: -2181 # . restore registers -2182 5f/pop-to-edi -2183 5e/pop-to-esi -2184 58/pop-to-eax -2185 # . epilogue -2186 89/<- %esp 5/r32/ebp -2187 5d/pop-to-ebp -2188 c3/return -2189 -2190 # parses a block, assuming that the leading '{' has already been read by the caller -2191 parse-mu-block: # in : (addr buffered-file), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle block) -2192 # pseudocode: -2193 # var line : (stream byte 512) -2194 # var word-slice : slice -2195 # result/eax = allocate(Heap, Stmt-size) -2196 # result->tag = 0/Block -2197 # while true # line loop -2198 # clear-stream(line) -2199 # read-line-buffered(in, line) -2200 # if (line->write == 0) break # end of file -2201 # word-slice = next-word(line) -2202 # if slice-empty?(word-slice) # end of line -2203 # continue -2204 # else if slice-starts-with?(word-slice, "#") -2205 # continue -2206 # else if slice-equal?(word-slice, "{") -2207 # assert(no-tokens-in(line)) -2208 # block = parse-mu-block(in, vars, fn) -2209 # append-to-block(result, block) -2210 # else if slice-equal?(word-slice, "}") -2211 # break -2212 # else if slice-ends-with?(word-slice, ":") -2213 # named-block = parse-mu-named-block(word-slice, line, in, vars, fn) -2214 # append-to-block(result, named-block) -2215 # else if slice-equal?(word-slice, "var") -2216 # var-def = parse-mu-var-def(line, vars) -2217 # append-to-block(result, var-def) -2218 # else -2219 # stmt = parse-mu-stmt(line, vars, fn) -2220 # append-to-block(result, stmt) -2221 # return result -2222 # -2223 # . prologue -2224 55/push-ebp -2225 89/<- %ebp 4/r32/esp -2226 # . save registers -2227 51/push-ecx -2228 52/push-edx -2229 53/push-ebx -2230 57/push-edi -2231 # var line/ecx : (stream byte 512) -2232 81 5/subop/subtract %esp 0x200/imm32 -2233 68/push 0x200/imm32/length -2234 68/push 0/imm32/read -2235 68/push 0/imm32/write -2236 89/<- %ecx 4/r32/esp -2237 # var word-slice/edx : slice -2238 68/push 0/imm32/end -2239 68/push 0/imm32/start -2240 89/<- %edx 4/r32/esp -2241 # edi = result -2242 (allocate Heap *Stmt-size) # => eax -2243 (zero-out %eax *Stmt-size) -2244 89/<- %edi 0/r32/eax -2245 { # line loop -2246 $parse-mu-block:line-loop: -2247 # line = read-line-buffered(in) -2248 (clear-stream %ecx) -2249 (read-line-buffered *(ebp+8) %ecx) -2250 #? (write-buffered Stderr "line: ") -2251 #? (write-stream-data Stderr %ecx) -2252 #? (write-buffered Stderr Newline) -2253 #? (flush Stderr) -2254 # if (line->write == 0) break -2255 81 7/subop/compare *ecx 0/imm32 -2256 0f 84/jump-if-equal break/disp32 -2257 # word-slice = next-word(line) -2258 (next-word %ecx %edx) -2259 #? (write-buffered Stderr "word: ") -2260 #? (write-slice-buffered Stderr %edx) -2261 #? (write-buffered Stderr Newline) -2262 #? (flush Stderr) -2263 # if slice-empty?(word-slice) continue -2264 (slice-empty? %edx) -2265 3d/compare-eax-and 0/imm32 -2266 0f 85/jump-if-not-equal loop/disp32 -2267 # if (slice-starts-with?(word-slice, '#') continue -2268 # . eax = *word-slice->start -2269 8b/-> *edx 0/r32/eax -2270 8a/copy-byte *eax 0/r32/AL -2271 81 4/subop/and %eax 0xff/imm32 -2272 # . if (eax == '#') continue -2273 3d/compare-eax-and 0x23/imm32/hash -2274 0f 84/jump-if-equal loop/disp32 -2275 # if slice-equal?(word-slice, "{") -2276 { -2277 $parse-mu-block:check-for-block: -2278 (slice-equal? %edx "{") -2279 3d/compare-eax-and 0/imm32 -2280 74/jump-if-equal break/disp8 -2281 (check-no-tokens-left %ecx) -2282 # parse new block and append -2283 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -2284 (append-to-block %edi %eax) -2285 e9/jump $parse-mu-block:line-loop/disp32 -2286 } -2287 # if slice-equal?(word-slice, "}") break -2288 $parse-mu-block:check-for-end: -2289 (slice-equal? %edx "}") -2290 3d/compare-eax-and 0/imm32 -2291 0f 85/jump-if-not-equal break/disp32 -2292 # if slice-ends-with?(word-slice, ":") parse named block and append -2293 { -2294 $parse-mu-block:check-for-named-block: -2295 # . eax = *word-slice->end -2296 8b/-> *(edx+4) 0/r32/eax -2297 8a/copy-byte *eax 0/r32/AL -2298 81 4/subop/and %eax 0xff/imm32 -2299 # . if (eax != ':') break -2300 3d/compare-eax-and 0x23/imm32/hash -2301 0f 85/jump-if-not-equal break/disp32 -2302 # -2303 (parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax -2304 (append-to-block %edi %eax) -2305 e9/jump $parse-mu-block:line-loop/disp32 -2306 } -2307 # if slice-equal?(word-slice, "var") -2308 { -2309 $parse-mu-block:check-for-var: -2310 (slice-equal? %edx "var") -2311 3d/compare-eax-and 0/imm32 -2312 74/jump-if-equal break/disp8 -2313 # -2314 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax -2315 (append-to-block %edi %eax) -2316 e9/jump $parse-mu-block:line-loop/disp32 -2317 } -2318 $parse-mu-block:regular-stmt: -2319 # otherwise -2320 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -2321 (append-to-block Heap %edi %eax) -2322 e9/jump loop/disp32 -2323 } # end line loop -2324 # return result -2325 89/<- %eax 7/r32/edi -2326 $parse-mu-block:end: -2327 # . reclaim locals -2328 81 0/subop/add %esp 0x214/imm32 -2329 # . restore registers -2330 5f/pop-to-edi -2331 5b/pop-to-ebx -2332 5a/pop-to-edx -2333 59/pop-to-ecx -2334 # . epilogue -2335 89/<- %esp 5/r32/ebp -2336 5d/pop-to-ebp -2337 c3/return -2338 -2339 $parse-mu-block:abort: -2340 # error("'{' or '}' should be on its own line, but got '") -2341 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2342 (rewind-stream %ecx) -2343 (write-stream 2 %ecx) -2344 (write-buffered Stderr "'\n") -2345 (flush Stderr) -2346 # . syscall(exit, 1) -2347 bb/copy-to-ebx 1/imm32 -2348 b8/copy-to-eax 1/imm32/exit -2349 cd/syscall 0x80/imm8 -2350 # never gets here -2351 -2352 check-no-tokens-left: # line : (addr stream byte) -2353 # . prologue -2354 55/push-ebp -2355 89/<- %ebp 4/r32/esp -2356 # . save registers -2357 50/push-eax -2358 51/push-ecx -2359 # var s/ecx : slice -2360 68/push 0/imm32/end -2361 68/push 0/imm32/start -2362 89/<- %ecx 4/r32/esp -2363 # -2364 (next-word *(ebp+8) %ecx) -2365 # if slice-empty?(s) return -2366 (slice-empty? %ecx) -2367 3d/compare-eax-and 0/imm32 -2368 75/jump-if-not-equal $check-no-tokens-left:end/disp8 -2369 # if (slice-starts-with?(s, '#') return -2370 # . eax = *s->start -2371 8b/-> *edx 0/r32/eax -2372 8a/copy-byte *eax 0/r32/AL -2373 81 4/subop/and %eax 0xff/imm32 -2374 # . if (eax == '#') continue -2375 3d/compare-eax-and 0x23/imm32/hash -2376 74/jump-if-equal $check-no-tokens-left:end/disp8 -2377 # abort -2378 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") -2379 (rewind-stream %ecx) -2380 (write-stream 2 %ecx) -2381 (write-buffered Stderr "'\n") -2382 (flush Stderr) -2383 # . syscall(exit, 1) -2384 bb/copy-to-ebx 1/imm32 -2385 b8/copy-to-eax 1/imm32/exit -2386 cd/syscall 0x80/imm8 -2387 # never gets here -2388 $check-no-tokens-left:end: -2389 # . reclaim locals -2390 81 0/subop/add %esp 8/imm32 -2391 # . restore registers -2392 59/pop-to-ecx -2393 58/pop-to-eax -2394 # . epilogue -2395 89/<- %esp 5/r32/ebp -2396 5d/pop-to-ebp -2397 c3/return -2398 -2399 parse-mu-named-block: # name : (addr slice), first-line : (addr stream byte), in : (addr buffered-file), vars : (addr stack (handle var)) -> result/eax : (handle stmt) -2400 # pseudocode: -2401 # var line : (stream byte 512) -2402 # var word-slice : slice -2403 # result/eax = allocate(Heap, Stmt-size) -2404 # result->tag = 4/Named-block -2405 # result->name = name -2406 # assert(next-word(first-line) == "{") -2407 # assert(no-tokens-in(first-line)) -2408 # while true # line loop -2409 # clear-stream(line) -2410 # read-line-buffered(in, line) -2411 # if (line->write == 0) break # end of file -2412 # word-slice = next-word(line) -2413 # if slice-empty?(word-slice) # end of line -2414 # break -2415 # else if slice-equal?(word-slice, "{") -2416 # block = parse-mu-block(in, vars) -2417 # append-to-block(result, block) -2418 # else if slice-equal?(word-slice, "}") -2419 # break -2420 # else if slice-ends-with?(word-slice, ":") -2421 # named-block = parse-mu-named-block(word-slice, in, vars) -2422 # append-to-block(result, named-block) -2423 # else if slice-equal?(word-slice, "var") -2424 # var-def = parse-mu-var-def(line, vars) -2425 # append-to-block(result, var-def) -2426 # else -2427 # stmt = parse-mu-stmt(line, vars, fn) -2428 # append-to-block(result, stmt) -2429 # return result -2430 # -2431 # . prologue -2432 55/push-ebp -2433 89/<- %ebp 4/r32/esp -2434 # . save registers -2435 $parse-mu-named-block:end: -2436 # . reclaim locals -2437 # . restore registers -2438 # . epilogue -2439 89/<- %esp 5/r32/ebp -2440 5d/pop-to-ebp -2441 c3/return -2442 -2443 parse-mu-var-def: # line : (addr stream byte), vars : (addr stack (handle var)) -> result/eax : (handle stmt) -2444 # pseudocode: -2445 # -2446 # . prologue -2447 55/push-ebp -2448 89/<- %ebp 4/r32/esp -2449 # . save registers -2450 $parse-mu-var-def:end: -2451 # . reclaim locals -2452 # . restore registers -2453 # . epilogue -2454 89/<- %esp 5/r32/ebp -2455 5d/pop-to-ebp -2456 c3/return -2457 -2458 parse-mu-stmt: # line : (addr stream byte), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle stmt) -2459 # pseudocode: -2460 # var name : slice -2461 # result = allocate(Heap, Stmt-size) -2462 # if stmt-has-outputs?(line) -2463 # while true -2464 # name = next-word(line) -2465 # if (name == '<-') break -2466 # assert(is-identifier?(name)) -2467 # var v : (handle var) = lookup-or-define-var(name, vars) -2468 # result->outputs = append(result->outputs, v) -2469 # result->name = slice-to-string(next-word(line)) -2470 # while true -2471 # name = next-word-or-string(line) -2472 # v = lookup-var-or-literal(name) -2473 # result->inouts = append(result->inouts, v) +1330 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1331 (check-ints-equal *ebx 1 "F - test-function-header-with-arg/inout:0/type:0") # Tree-left +1332 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-arg/inout:0/type:1") # Tree-right +1333 # . epilogue +1334 89/<- %esp 5/r32/ebp +1335 5d/pop-to-ebp +1336 c3/return +1337 +1338 test-function-header-with-multiple-args: +1339 # 'fn foo a: int, b: int, c: int {' +1340 # . prologue +1341 55/push-ebp +1342 89/<- %ebp 4/r32/esp +1343 # setup +1344 (clear-stream _test-input-stream) +1345 (write _test-input-stream "foo a: int, b: int c: int {\n") +1346 # result/ecx : (handle function) +1347 2b/subtract-> *Function-size 4/r32/esp +1348 89/<- %ecx 4/r32/esp +1349 (zero-out %ecx *Function-size) +1350 # var vars/ebx : (stack (addr var) 16) +1351 81 5/subop/subtract %esp 0x10/imm32 +1352 68/push 0x10/imm32/length +1353 68/push 0/imm32/top +1354 89/<- %ebx 4/r32/esp +1355 # convert +1356 (populate-mu-function-header _test-input-stream %ecx %ebx) +1357 # check result +1358 (check-strings-equal *ecx "foo") # Function-name +1359 # edx : (handle list var) = result->inouts +1360 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1361 $test-function-header-with-multiple-args:inout0: +1362 # ebx : (handle var) = result->inouts->value +1363 8b/-> *edx 3/r32/ebx # List-value +1364 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args/inout:0") # Var-name +1365 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1366 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:0/type:0") # Tree-left +1367 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:0/type:1") # Tree-right +1368 # edx = result->inouts->next +1369 8b/-> *(edx+4) 2/r32/edx # List-next +1370 $test-function-header-with-multiple-args:inout1: +1371 # ebx = result->inouts->next->value +1372 8b/-> *edx 3/r32/ebx # List-value +1373 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args/inout:1") # Var-name +1374 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1375 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:1/type:0") # Tree-left +1376 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:1/type:1") # Tree-right +1377 # edx = result->inouts->next->next +1378 8b/-> *(edx+4) 2/r32/edx # List-next +1379 $test-function-header-with-multiple-args:inout2: +1380 # ebx = result->inouts->next->next->value +1381 8b/-> *edx 3/r32/ebx # List-value +1382 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args/inout:2") # Var-name +1383 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1384 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args/inout:2/type:0") # Tree-left +1385 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args/inout:2/type:1") # Tree-right +1386 # . epilogue +1387 89/<- %esp 5/r32/ebp +1388 5d/pop-to-ebp +1389 c3/return +1390 +1391 test-function-with-multiple-args-and-outputs: +1392 # fn foo a: int, b: int, c: int -> x: int, y: int { +1393 # . prologue +1394 55/push-ebp +1395 89/<- %ebp 4/r32/esp +1396 # setup +1397 (clear-stream _test-input-stream) +1398 (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx : int {\n") +1399 # result/ecx : (handle function) +1400 2b/subtract-> *Function-size 4/r32/esp +1401 89/<- %ecx 4/r32/esp +1402 (zero-out %ecx *Function-size) +1403 # var vars/ebx : (stack (addr var) 16) +1404 81 5/subop/subtract %esp 0x10/imm32 +1405 68/push 0x10/imm32/length +1406 68/push 0/imm32/top +1407 89/<- %ebx 4/r32/esp +1408 # convert +1409 (populate-mu-function-header _test-input-stream %ecx %ebx) +1410 # check result +1411 (check-strings-equal *ecx "foo") # Function-name +1412 # edx : (handle list var) = result->inouts +1413 8b/-> *(ecx+8) 2/r32/edx # Function-inouts +1414 # ebx : (handle var) = result->inouts->value +1415 8b/-> *edx 3/r32/ebx # List-value +1416 (check-strings-equal *ebx "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0") # Var-name +1417 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1418 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0") # Tree-left +1419 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1") # Tree-right +1420 # edx = result->inouts->next +1421 8b/-> *(edx+4) 2/r32/edx # List-next +1422 # ebx = result->inouts->next->value +1423 8b/-> *edx 3/r32/ebx # List-value +1424 (check-strings-equal *ebx "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1") # Var-name +1425 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1426 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0") # Tree-left +1427 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1") # Tree-right +1428 # edx = result->inouts->next->next +1429 8b/-> *(edx+4) 2/r32/edx # List-next +1430 # ebx = result->inouts->next->next->value +1431 8b/-> *edx 3/r32/ebx # List-value +1432 (check-strings-equal *ebx "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2") # Var-name +1433 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1434 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0") # Tree-left +1435 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1") # Tree-right +1436 # edx : (handle list var) = result->outputs +1437 8b/-> *(ecx+0xc) 2/r32/edx # Function-outputs +1438 # ebx : (handle var) = result->outputs->value +1439 8b/-> *edx 3/r32/ebx # List-value +1440 (check-strings-equal *ebx "x" "F - test-function-header-with-multiple-args-and-outputs/output:0") # Var-name +1441 (check-strings-equal *(ebx+0x10) "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register +1442 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1443 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-left +1444 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1") # Tree-right +1445 # edx = result->outputs->next +1446 8b/-> *(edx+4) 2/r32/edx # List-next +1447 # ebx = result->outputs->next->value +1448 8b/-> *edx 3/r32/ebx # List-value +1449 (check-strings-equal *ebx "y" "F - test-function-header-with-multiple-args-and-outputs/output:1") # Var-name +1450 (check-strings-equal *(ebx+0x10) "edx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register") # Var-register +1451 8b/-> *(ebx+4) 3/r32/ebx # Var-type +1452 (check-ints-equal *ebx 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-left +1453 (check-ints-equal *(ebx+4) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1") # Tree-right +1454 # . epilogue +1455 89/<- %esp 5/r32/ebp +1456 5d/pop-to-ebp +1457 c3/return +1458 +1459 # format for variables with types +1460 # x : int +1461 # x: int +1462 # x: int, +1463 # ignores at most one trailing colon or comma +1464 parse-var-with-type: # name: (addr slice), first-line: (addr stream byte) -> result/eax: (handle var) +1465 # pseudocode: +1466 # var v : (handle var) = allocate(Heap, Var-size) +1467 # var s : slice +1468 # next-token-from-slice(name->start, name->end, '/', s) +1469 # var end : (addr byte) = s->end +1470 # if (slice-ends-with(s, ":")) +1471 # decrement s->end +1472 # if (slice-ends-with(s, ",")) +1473 # decrement s->end +1474 # v->name = slice-to-string(s) +1475 # ## register +1476 # next-token-from-slice(end, name->end, '/', s) +1477 # if (slice-ends-with(s, ":")) +1478 # decrement s->end +1479 # if (slice-ends-with(s, ",")) +1480 # decrement s->end +1481 # if (!slice-empty?(s)) +1482 # v->register = slice-to-string(s) +1483 # ## type +1484 # s = next-mu-token(first-line) +1485 # assert(s not in '{' '}' '->') +1486 # if (slice-empty?(s)) { +1487 # s = next-mu-token(first-line) +1488 # assert(type not in '{' '}' '->') +1489 # } +1490 # type = type-for(s) +1491 # v->type = type +1492 # return v +1493 # +1494 # . prologue +1495 55/push-ebp +1496 89/<- %ebp 4/r32/esp +1497 # . save registers +1498 51/push-ecx +1499 52/push-edx +1500 53/push-ebx +1501 56/push-esi +1502 57/push-edi +1503 # var result/edi : (handle var) = allocate(Heap, Var-size) +1504 (allocate Heap *Var-size) # => eax +1505 (zero-out %eax *Var-size) +1506 89/<- %edi 0/r32/eax +1507 # esi = name +1508 8b/-> *(ebp+8) 6/r32/esi +1509 # var s/ecx : slice +1510 68/push 0/imm32/end +1511 68/push 0/imm32/start +1512 89/<- %ecx 4/r32/esp +1513 $parse-var-with-type:save-name: +1514 # save v->name +1515 (next-token-from-slice *esi *(esi+4) 0x2f %ecx) # Slice-start, Slice-end, '/' +1516 # . end/edx = s->end +1517 8b/-> *(ecx+4) 2/r32/edx +1518 # . if s ends with ':', decrement s->end +1519 { +1520 8b/-> *(ecx+4) 0/r32/eax +1521 48/decrement-eax +1522 8a/copy-byte *eax 3/r32/BL +1523 81 4/subop/and %ebx 0xff/imm32 +1524 81 7/subop/compare %ebx 0x3a/imm32/colon +1525 75/jump-if-not-equal break/disp8 +1526 89/<- *(ecx+4) 0/r32/eax +1527 } +1528 # . if s ends with ',', decrement s->end +1529 { +1530 8b/-> *(ecx+4) 0/r32/eax +1531 48/decrement-eax +1532 8a/copy-byte *eax 3/r32/BL +1533 81 4/subop/and %ebx 0xff/imm32 +1534 81 7/subop/compare %ebx 0x2c/imm32/comma +1535 75/jump-if-not-equal break/disp8 +1536 89/<- *(ecx+4) 0/r32/eax +1537 } +1538 $parse-var-with-type:write-name: +1539 (slice-to-string Heap %ecx) # => eax +1540 89/<- *edi 0/r32/eax # Var-name +1541 # save v->register +1542 $parse-var-with-type:save-register: +1543 (next-token-from-slice %edx *(esi+4) 0x2f %ecx) # end, name->end, '/' +1544 # . if s ends with ':', decrement s->end +1545 { +1546 8b/-> *(ecx+4) 0/r32/eax +1547 48/decrement-eax +1548 8a/copy-byte *eax 3/r32/BL +1549 81 4/subop/and %ebx 0xff/imm32 +1550 81 7/subop/compare %ebx 0x3a/imm32/colon +1551 75/jump-if-not-equal break/disp8 +1552 89/<- *(ecx+4) 0/r32/eax +1553 } +1554 # . if s ends with ',', decrement s->end +1555 { +1556 8b/-> *(ecx+4) 0/r32/eax +1557 48/decrement-eax +1558 8a/copy-byte *eax 3/r32/BL +1559 81 4/subop/and %ebx 0xff/imm32 +1560 81 7/subop/compare %ebx 0x2c/imm32/comma +1561 75/jump-if-not-equal break/disp8 +1562 89/<- *(ecx+4) 0/r32/eax +1563 } +1564 # if (!slice-empty?(s)) v->register = slice-to-string(s) +1565 { +1566 $parse-var-with-type:write-register: +1567 # HACK: s->end can be less than s->start with all the decrements above +1568 # That's probably a sign we have the wrong algorithm for this function. +1569 8b/-> *ecx 0/r32/eax +1570 39/compare 0/r32/eax *(ecx+4) +1571 76/jump-if-lesser-or-equal break/disp8 +1572 (slice-to-string Heap %ecx) +1573 89/<- *(edi+0x10) 0/r32/eax # Var-register +1574 } +1575 # save v->type +1576 (next-mu-token *(ebp+0xc) %ecx) +1577 # if (word-slice == '{') abort +1578 (slice-equal? %ecx "{") # => eax +1579 3d/compare-eax-and 0/imm32 +1580 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1581 # if (word-slice == '->') abort +1582 (slice-equal? %ecx "->") # => eax +1583 3d/compare-eax-and 0/imm32 +1584 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1585 # if (word-slice == '}') abort +1586 (slice-equal? %ecx "}") # => eax +1587 3d/compare-eax-and 0/imm32 +1588 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1589 # if (slice-empty?(type)) skip +1590 (slice-empty? %ecx) +1591 { +1592 3d/compare-eax-and 0/imm32 +1593 0f 84/jump-if-equal break/disp32 +1594 (next-mu-token *(ebp+0xc) %ecx) +1595 # if (word-slice == '{') abort +1596 (slice-equal? %ecx "{") # => eax +1597 3d/compare-eax-and 0/imm32 +1598 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1599 # if (word-slice == '->') abort +1600 (slice-equal? %ecx "->") # => eax +1601 3d/compare-eax-and 0/imm32 +1602 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1603 # if (word-slice == '}') abort +1604 (slice-equal? %ecx "}") # => eax +1605 3d/compare-eax-and 0/imm32 +1606 0f 85/jump-if-not-equal $parse-var-with-type:abort/disp32 +1607 } +1608 (type-for %ecx) # => eax +1609 89/<- *(edi+4) 0/r32/eax # Var-type +1610 $parse-var-with-type:end: +1611 # return result +1612 89/<- %eax 7/r32/edi +1613 # . reclaim locals +1614 81 0/subop/add %esp 8/imm32 +1615 # . restore registers +1616 5f/pop-to-edi +1617 5e/pop-to-esi +1618 5b/pop-to-ebx +1619 5a/pop-to-edx +1620 59/pop-to-ecx +1621 # . epilogue +1622 89/<- %esp 5/r32/ebp +1623 5d/pop-to-ebp +1624 c3/return +1625 +1626 $parse-var-with-type:abort: +1627 # error("function header not in form 'fn <name> {'") +1628 (write-buffered Stderr "var should have form 'name: type' in '") +1629 (flush Stderr) +1630 (rewind-stream *(ebp+0xc)) +1631 (write-stream 2 *(ebp+0xc)) +1632 (write-buffered Stderr "'\n") +1633 (flush Stderr) +1634 # . syscall(exit, 1) +1635 bb/copy-to-ebx 1/imm32 +1636 b8/copy-to-eax 1/imm32/exit +1637 cd/syscall 0x80/imm8 +1638 # never gets here +1639 +1640 next-mu-token: # in: (addr stream byte), out: (addr slice) +1641 # . prologue +1642 55/push-ebp +1643 89/<- %ebp 4/r32/esp +1644 # . save registers +1645 50/push-eax +1646 57/push-edi +1647 # edi = out +1648 8b/-> *(ebp+0xc) 7/r32/edi +1649 # +1650 (next-word *(ebp+8) %edi) # TODO: support s-expressions +1651 # if out ends with ':', decrement out->end +1652 { +1653 8b/-> *(edi+4) 0/r32/eax +1654 48/decrement-eax +1655 8a/copy-byte *eax 3/r32/BL +1656 81 4/subop/and %ebx 0xff/imm32 +1657 81 7/subop/compare %ebx 0x3a/imm32/colon +1658 75/jump-if-not-equal break/disp8 +1659 89/<- *(edi+4) 0/r32/eax +1660 } +1661 # if out ends with ',', decrement out->end +1662 { +1663 8b/-> *(edi+4) 0/r32/eax +1664 48/decrement-eax +1665 8a/copy-byte *eax 3/r32/BL +1666 81 4/subop/and %ebx 0xff/imm32 +1667 81 7/subop/compare %ebx 0x2c/imm32/comma +1668 75/jump-if-not-equal break/disp8 +1669 89/<- *(edi+4) 0/r32/eax +1670 } +1671 $next-mu-token:end: +1672 b8/copy-to-eax 1/imm32/int +1673 # . restore registers +1674 5f/pop-to-edi +1675 58/pop-to-eax +1676 # . epilogue +1677 89/<- %esp 5/r32/ebp +1678 5d/pop-to-ebp +1679 c3/return +1680 +1681 type-for: # name: (addr slice) -> result/eax: (handle tree type-id) +1682 # . prologue +1683 55/push-ebp +1684 89/<- %ebp 4/r32/esp +1685 # . save registers +1686 51/push-ecx +1687 # +1688 (pos-slice Type-id *(ebp+8)) # => eax +1689 89/<- %ecx 0/r32/eax +1690 (allocate Heap *Tree-size) # => eax +1691 (zero-out %eax *Tree-size) +1692 89/<- *eax 1/r32/ecx # Tree-left +1693 $type-for:end: +1694 # . restore registers +1695 59/pop-to-ecx +1696 # . epilogue +1697 89/<- %esp 5/r32/ebp +1698 5d/pop-to-ebp +1699 c3/return +1700 +1701 # return the index in an array of strings matching 's' +1702 # index is denominated in elements, not bytes +1703 pos-slice: # arr: (addr stream (handle array byte)), s: (addr slice) -> index/eax: int +1704 # . prologue +1705 55/push-ebp +1706 89/<- %ebp 4/r32/esp +1707 # . save registers +1708 51/push-ecx +1709 52/push-edx +1710 53/push-ebx +1711 56/push-esi +1712 # esi = arr +1713 8b/-> *(ebp+8) 6/r32/esi +1714 # var index/ecx: int = 0 +1715 b9/copy-to-ecx 0/imm32 +1716 # var curr/edx: (addr (addr array byte)) = arr->data +1717 8d/copy-address *(esi+0xc) 2/r32/edx +1718 # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write] +1719 8b/-> *esi 3/r32/ebx +1720 8d/copy-address *(esi+ebx+0xc) 3/r32/ebx +1721 { +1722 # if (curr >= max) return -1 +1723 39/compare %edx 3/r32/ebx +1724 { +1725 72/jump-if-lesser-unsigned break/disp8 +1726 b8/copy-to-eax 1/imm32 +1727 eb/jump $pos-slice:end/disp8 +1728 } +1729 # if (slice-equal?(s, *curr)) break +1730 (slice-equal? *(ebp+0xc) *edx) # => eax +1731 3d/compare-eax-and 0/imm32 +1732 75/jump-if-not-equal break/disp8 +1733 # ++index +1734 41/increment-ecx +1735 # curr += 4 +1736 81 0/subop/add %edx 4/imm32 +1737 } +1738 89/<- %eax 1/r32/ecx +1739 $pos-slice:end: +1740 # . restore registers +1741 5e/pop-to-esi +1742 5b/pop-to-ebx +1743 5a/pop-to-edx +1744 59/pop-to-ecx +1745 # . epilogue +1746 89/<- %esp 5/r32/ebp +1747 5d/pop-to-ebp +1748 c3/return +1749 +1750 == data +1751 +1752 Type-id: # (stream (address array byte)) +1753 0x1c/imm32/write +1754 0/imm32/read +1755 0x100/imm32/length +1756 # data +1757 "literal"/imm32 # 0 +1758 "int"/imm32 # 1 +1759 "ref"/imm32 # 2 +1760 "addr"/imm32 # 3 +1761 "array"/imm32 # 4 +1762 "handle"/imm32 # 5 +1763 "bool"/imm32 # 6 +1764 0/imm32 +1765 # 0x20 +1766 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +1767 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +1768 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +1769 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +1770 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +1771 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +1772 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 +1773 +1774 == code +1775 +1776 test-parse-var-with-type: +1777 # . prologue +1778 55/push-ebp +1779 89/<- %ebp 4/r32/esp +1780 # (eax..ecx) = "x:" +1781 b8/copy-to-eax "x:"/imm32 +1782 8b/-> *eax 1/r32/ecx +1783 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1784 05/add-to-eax 4/imm32 +1785 # var slice/ecx : slice = {eax, ecx} +1786 51/push-ecx +1787 50/push-eax +1788 89/<- %ecx 4/r32/esp +1789 # _test-input-stream contains "int" +1790 (clear-stream _test-input-stream) +1791 (write _test-input-stream "int") +1792 # +1793 (parse-var-with-type %ecx _test-input-stream) +1794 8b/-> *eax 2/r32/edx # Var-name +1795 (check-strings-equal %edx "x" "F - test-var-with-type/name") +1796 8b/-> *(eax+4) 2/r32/edx # Var-type +1797 (check-ints-equal *edx 1 "F - test-var-with-type/type") +1798 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") +1799 # . epilogue +1800 89/<- %esp 5/r32/ebp +1801 5d/pop-to-ebp +1802 c3/return +1803 +1804 test-parse-var-with-type-and-register: +1805 # . prologue +1806 55/push-ebp +1807 89/<- %ebp 4/r32/esp +1808 # (eax..ecx) = "x/eax" +1809 b8/copy-to-eax "x/eax"/imm32 +1810 8b/-> *eax 1/r32/ecx +1811 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1812 05/add-to-eax 4/imm32 +1813 # var slice/ecx : slice = {eax, ecx} +1814 51/push-ecx +1815 50/push-eax +1816 89/<- %ecx 4/r32/esp +1817 # _test-input-stream contains ": int" +1818 (clear-stream _test-input-stream) +1819 (write _test-input-stream ": int") +1820 # +1821 (parse-var-with-type %ecx _test-input-stream) +1822 8b/-> *eax 2/r32/edx # Var-name +1823 (check-strings-equal %edx "x" "F - test-var-with-type-and-register/name") +1824 8b/-> *(eax+0x10) 2/r32/edx # Var-register +1825 (check-strings-equal %edx "eax" "F - test-var-with-type-and-register/register") +1826 8b/-> *(eax+4) 2/r32/edx # Var-type +1827 (check-ints-equal *edx 1 "F - test-var-with-type-and-register/type") +1828 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") +1829 # . epilogue +1830 89/<- %esp 5/r32/ebp +1831 5d/pop-to-ebp +1832 c3/return +1833 +1834 test-parse-var-with-trailing-characters: +1835 # . prologue +1836 55/push-ebp +1837 89/<- %ebp 4/r32/esp +1838 # (eax..ecx) = "x:" +1839 b8/copy-to-eax "x:"/imm32 +1840 8b/-> *eax 1/r32/ecx +1841 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1842 05/add-to-eax 4/imm32 +1843 # var slice/ecx : slice = {eax, ecx} +1844 51/push-ecx +1845 50/push-eax +1846 89/<- %ecx 4/r32/esp +1847 # _test-input-stream contains "int," +1848 (clear-stream _test-input-stream) +1849 (write _test-input-stream "int,") +1850 # +1851 (parse-var-with-type %ecx _test-input-stream) +1852 8b/-> *eax 2/r32/edx # Var-name +1853 (check-strings-equal %edx "x" "F - test-var-with-trailing-characters/name") +1854 8b/-> *(eax+0x10) 2/r32/edx # Var-register +1855 (check-ints-equal %edx 0 "F - test-var-with-trailing-characters/register") +1856 8b/-> *(eax+4) 2/r32/edx # Var-type +1857 (check-ints-equal *edx 1 "F - test-var-with-trailing-characters/type") +1858 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") +1859 # . epilogue +1860 89/<- %esp 5/r32/ebp +1861 5d/pop-to-ebp +1862 c3/return +1863 +1864 test-parse-var-with-register-and-trailing-characters: +1865 # . prologue +1866 55/push-ebp +1867 89/<- %ebp 4/r32/esp +1868 # (eax..ecx) = "x/eax:" +1869 b8/copy-to-eax "x/eax:"/imm32 +1870 8b/-> *eax 1/r32/ecx +1871 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1872 05/add-to-eax 4/imm32 +1873 # var slice/ecx : slice = {eax, ecx} +1874 51/push-ecx +1875 50/push-eax +1876 89/<- %ecx 4/r32/esp +1877 # _test-input-stream contains "int," +1878 (clear-stream _test-input-stream) +1879 (write _test-input-stream "int,") +1880 # +1881 (parse-var-with-type %ecx _test-input-stream) +1882 8b/-> *eax 2/r32/edx # Var-name +1883 (check-strings-equal %edx "x" "F - test-var-with-register-and-trailing-characters/name") +1884 8b/-> *(eax+0x10) 2/r32/edx # Var-register +1885 (check-strings-equal %edx "eax" "F - test-var-with-register-and-trailing-characters/register") +1886 8b/-> *(eax+4) 2/r32/edx # Var-type +1887 (check-ints-equal *edx 1 "F - test-var-with-register-and-trailing-characters/type") +1888 (check-ints-equal *(edx+4) 0 "F - test-var-with-register-and-trailing-characters/type") +1889 # . epilogue +1890 89/<- %esp 5/r32/ebp +1891 5d/pop-to-ebp +1892 c3/return +1893 +1894 # identifier starts with a letter or '$' or '_' +1895 # no constraints at the moment on later letters +1896 # all we really want to do so far is exclude '{', '}' and '->' +1897 is-identifier?: # in : (addr slice) -> result/eax : boolean +1898 # . prologue +1899 55/push-ebp +1900 89/<- %ebp 4/r32/esp +1901 # if (slice-empty?(in)) return false +1902 (slice-empty? *(ebp+8)) # => eax +1903 3d/compare-eax-and 0/imm32 +1904 75/jump-if-not-equal $is-identifier?:false/disp8 +1905 # var c/eax : byte = *in->start +1906 8b/-> *(ebp+8) 0/r32/eax +1907 8b/-> *eax 0/r32/eax +1908 8a/copy-byte *eax 0/r32/AL +1909 81 4/subop/and %eax 0xff/imm32 +1910 # if (c == '$') return true +1911 3d/compare-eax-and 0x24/imm32/$ +1912 74/jump-if-equal $is-identifier?:true/disp8 +1913 # if (c == '_') return true +1914 3d/compare-eax-and 0x5f/imm32/_ +1915 74/jump-if-equal $is-identifier?:true/disp8 +1916 # drop case +1917 25/and-eax-with 0x5f/imm32 +1918 # if (c < 'A') return false +1919 3d/compare-eax-and 0x41/imm32/A +1920 7c/jump-if-lesser $is-identifier?:false/disp8 +1921 # if (c > 'Z') return false +1922 3d/compare-eax-and 0x5a/imm32/Z +1923 7f/jump-if-greater $is-identifier?:false/disp8 +1924 # otherwise return true +1925 $is-identifier?:true: +1926 b8/copy-to-eax 1/imm32/true +1927 eb/jump $is-identifier?:end/disp8 +1928 $is-identifier?:false: +1929 b8/copy-to-eax 0/imm32/false +1930 $is-identifier?:end: +1931 # . epilogue +1932 89/<- %esp 5/r32/ebp +1933 5d/pop-to-ebp +1934 c3/return +1935 +1936 test-is-identifier-dollar: +1937 # . prologue +1938 55/push-ebp +1939 89/<- %ebp 4/r32/esp +1940 # (eax..ecx) = "$a" +1941 b8/copy-to-eax "$a"/imm32 +1942 8b/-> *eax 1/r32/ecx +1943 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1944 05/add-to-eax 4/imm32 +1945 # var slice/ecx : slice = {eax, ecx} +1946 51/push-ecx +1947 50/push-eax +1948 89/<- %ecx 4/r32/esp +1949 # +1950 (is-identifier? %ecx) +1951 (check-ints-equal %eax 1 "F - test-is-identifier-dollar") +1952 # . epilogue +1953 89/<- %esp 5/r32/ebp +1954 5d/pop-to-ebp +1955 c3/return +1956 +1957 test-is-identifier-underscore: +1958 # . prologue +1959 55/push-ebp +1960 89/<- %ebp 4/r32/esp +1961 # (eax..ecx) = "_a" +1962 b8/copy-to-eax "_a"/imm32 +1963 8b/-> *eax 1/r32/ecx +1964 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1965 05/add-to-eax 4/imm32 +1966 # var slice/ecx : slice = {eax, ecx} +1967 51/push-ecx +1968 50/push-eax +1969 89/<- %ecx 4/r32/esp +1970 # +1971 (is-identifier? %ecx) +1972 (check-ints-equal %eax 1 "F - test-is-identifier-underscore") +1973 # . epilogue +1974 89/<- %esp 5/r32/ebp +1975 5d/pop-to-ebp +1976 c3/return +1977 +1978 test-is-identifier-a: +1979 # . prologue +1980 55/push-ebp +1981 89/<- %ebp 4/r32/esp +1982 # (eax..ecx) = "a$" +1983 b8/copy-to-eax "a$"/imm32 +1984 8b/-> *eax 1/r32/ecx +1985 8d/copy-address *(eax+ecx+4) 1/r32/ecx +1986 05/add-to-eax 4/imm32 +1987 # var slice/ecx : slice = {eax, ecx} +1988 51/push-ecx +1989 50/push-eax +1990 89/<- %ecx 4/r32/esp +1991 # +1992 (is-identifier? %ecx) +1993 (check-ints-equal %eax 1 "F - test-is-identifier-a") +1994 # . epilogue +1995 89/<- %esp 5/r32/ebp +1996 5d/pop-to-ebp +1997 c3/return +1998 +1999 test-is-identifier-z: +2000 # . prologue +2001 55/push-ebp +2002 89/<- %ebp 4/r32/esp +2003 # (eax..ecx) = "z$" +2004 b8/copy-to-eax "z$"/imm32 +2005 8b/-> *eax 1/r32/ecx +2006 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2007 05/add-to-eax 4/imm32 +2008 # var slice/ecx : slice = {eax, ecx} +2009 51/push-ecx +2010 50/push-eax +2011 89/<- %ecx 4/r32/esp +2012 # +2013 (is-identifier? %ecx) +2014 (check-ints-equal %eax 1 "F - test-is-identifier-z") +2015 # . epilogue +2016 89/<- %esp 5/r32/ebp +2017 5d/pop-to-ebp +2018 c3/return +2019 +2020 test-is-identifier-A: +2021 # . prologue +2022 55/push-ebp +2023 89/<- %ebp 4/r32/esp +2024 # (eax..ecx) = "A$" +2025 b8/copy-to-eax "A$"/imm32 +2026 8b/-> *eax 1/r32/ecx +2027 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2028 05/add-to-eax 4/imm32 +2029 # var slice/ecx : slice = {eax, ecx} +2030 51/push-ecx +2031 50/push-eax +2032 89/<- %ecx 4/r32/esp +2033 # +2034 (is-identifier? %ecx) +2035 (check-ints-equal %eax 1 "F - test-is-identifier-A") +2036 # . epilogue +2037 89/<- %esp 5/r32/ebp +2038 5d/pop-to-ebp +2039 c3/return +2040 +2041 test-is-identifier-Z: +2042 # . prologue +2043 55/push-ebp +2044 89/<- %ebp 4/r32/esp +2045 # (eax..ecx) = "Z$" +2046 b8/copy-to-eax "Z$"/imm32 +2047 8b/-> *eax 1/r32/ecx +2048 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2049 05/add-to-eax 4/imm32 +2050 # var slice/ecx : slice = {eax, ecx} +2051 51/push-ecx +2052 50/push-eax +2053 89/<- %ecx 4/r32/esp +2054 # +2055 (is-identifier? %ecx) +2056 (check-ints-equal %eax 1 "F - test-is-identifier-Z") +2057 # . epilogue +2058 89/<- %esp 5/r32/ebp +2059 5d/pop-to-ebp +2060 c3/return +2061 +2062 test-is-identifier-@: +2063 # character before 'A' is invalid +2064 # . prologue +2065 55/push-ebp +2066 89/<- %ebp 4/r32/esp +2067 # (eax..ecx) = "@a" +2068 b8/copy-to-eax "@a"/imm32 +2069 8b/-> *eax 1/r32/ecx +2070 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2071 05/add-to-eax 4/imm32 +2072 # var slice/ecx : slice = {eax, ecx} +2073 51/push-ecx +2074 50/push-eax +2075 89/<- %ecx 4/r32/esp +2076 # +2077 (is-identifier? %ecx) +2078 (check-ints-equal %eax 0 "F - test-is-identifier-@") +2079 # . epilogue +2080 89/<- %esp 5/r32/ebp +2081 5d/pop-to-ebp +2082 c3/return +2083 +2084 test-is-identifier-square-bracket: +2085 # character after 'Z' is invalid +2086 # . prologue +2087 55/push-ebp +2088 89/<- %ebp 4/r32/esp +2089 # (eax..ecx) = "[a" +2090 b8/copy-to-eax "[a"/imm32 +2091 8b/-> *eax 1/r32/ecx +2092 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2093 05/add-to-eax 4/imm32 +2094 # var slice/ecx : slice = {eax, ecx} +2095 51/push-ecx +2096 50/push-eax +2097 89/<- %ecx 4/r32/esp +2098 # +2099 (is-identifier? %ecx) +2100 (check-ints-equal %eax 0 "F - test-is-identifier-@") +2101 # . epilogue +2102 89/<- %esp 5/r32/ebp +2103 5d/pop-to-ebp +2104 c3/return +2105 +2106 test-is-identifier-backtick: +2107 # character before 'a' is invalid +2108 # . prologue +2109 55/push-ebp +2110 89/<- %ebp 4/r32/esp +2111 # (eax..ecx) = "`a" +2112 b8/copy-to-eax "`a"/imm32 +2113 8b/-> *eax 1/r32/ecx +2114 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2115 05/add-to-eax 4/imm32 +2116 # var slice/ecx : slice = {eax, ecx} +2117 51/push-ecx +2118 50/push-eax +2119 89/<- %ecx 4/r32/esp +2120 # +2121 (is-identifier? %ecx) +2122 (check-ints-equal %eax 0 "F - test-is-identifier-backtick") +2123 # . epilogue +2124 89/<- %esp 5/r32/ebp +2125 5d/pop-to-ebp +2126 c3/return +2127 +2128 test-is-identifier-curly-brace-open: +2129 # character after 'z' is invalid; also used for blocks +2130 # . prologue +2131 55/push-ebp +2132 89/<- %ebp 4/r32/esp +2133 # (eax..ecx) = "{a" +2134 b8/copy-to-eax "{a"/imm32 +2135 8b/-> *eax 1/r32/ecx +2136 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2137 05/add-to-eax 4/imm32 +2138 # var slice/ecx : slice = {eax, ecx} +2139 51/push-ecx +2140 50/push-eax +2141 89/<- %ecx 4/r32/esp +2142 # +2143 (is-identifier? %ecx) +2144 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open") +2145 # . epilogue +2146 89/<- %esp 5/r32/ebp +2147 5d/pop-to-ebp +2148 c3/return +2149 +2150 test-is-identifier-curly-brace-close: +2151 # . prologue +2152 55/push-ebp +2153 89/<- %ebp 4/r32/esp +2154 # (eax..ecx) = "}a" +2155 b8/copy-to-eax "}a"/imm32 +2156 8b/-> *eax 1/r32/ecx +2157 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2158 05/add-to-eax 4/imm32 +2159 # var slice/ecx : slice = {eax, ecx} +2160 51/push-ecx +2161 50/push-eax +2162 89/<- %ecx 4/r32/esp +2163 # +2164 (is-identifier? %ecx) +2165 (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close") +2166 # . epilogue +2167 89/<- %esp 5/r32/ebp +2168 5d/pop-to-ebp +2169 c3/return +2170 +2171 test-is-identifier-hyphen: +2172 # disallow leading '-' since '->' has special meaning +2173 # . prologue +2174 55/push-ebp +2175 89/<- %ebp 4/r32/esp +2176 # (eax..ecx) = "-a" +2177 b8/copy-to-eax "-a"/imm32 +2178 8b/-> *eax 1/r32/ecx +2179 8d/copy-address *(eax+ecx+4) 1/r32/ecx +2180 05/add-to-eax 4/imm32 +2181 # var slice/ecx : slice = {eax, ecx} +2182 51/push-ecx +2183 50/push-eax +2184 89/<- %ecx 4/r32/esp +2185 # +2186 (is-identifier? %ecx) +2187 (check-ints-equal %eax 0 "F - test-is-identifier-hyphen") +2188 # . epilogue +2189 89/<- %esp 5/r32/ebp +2190 5d/pop-to-ebp +2191 c3/return +2192 +2193 populate-mu-function-body: # in : (addr buffered-file), out : (handle function), vars : (addr stack (handle var)) +2194 # . prologue +2195 55/push-ebp +2196 89/<- %ebp 4/r32/esp +2197 # . save registers +2198 50/push-eax +2199 56/push-esi +2200 57/push-edi +2201 # esi = in +2202 8b/-> *(ebp+8) 6/r32/esi +2203 # edi = out +2204 8b/-> *(ebp+0xc) 7/r32/edi +2205 # var eax : (handle block) = parse-mu-block(in, vars) +2206 (parse-mu-block %esi *(ebp+0x10) %edi) # => eax +2207 # out->body = eax +2208 89/<- *(edi+0x10) 0/r32/eax # Function-body +2209 $populate-mu-function-body:end: +2210 # . restore registers +2211 5f/pop-to-edi +2212 5e/pop-to-esi +2213 58/pop-to-eax +2214 # . epilogue +2215 89/<- %esp 5/r32/ebp +2216 5d/pop-to-ebp +2217 c3/return +2218 +2219 # parses a block, assuming that the leading '{' has already been read by the caller +2220 parse-mu-block: # in : (addr buffered-file), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle block) +2221 # pseudocode: +2222 # var line : (stream byte 512) +2223 # var word-slice : slice +2224 # result/eax = allocate(Heap, Stmt-size) +2225 # result->tag = 0/Block +2226 # while true # line loop +2227 # clear-stream(line) +2228 # read-line-buffered(in, line) +2229 # if (line->write == 0) break # end of file +2230 # word-slice = next-word(line) +2231 # if slice-empty?(word-slice) # end of line +2232 # continue +2233 # else if slice-starts-with?(word-slice, "#") +2234 # continue +2235 # else if slice-equal?(word-slice, "{") +2236 # assert(no-tokens-in(line)) +2237 # block = parse-mu-block(in, vars, fn) +2238 # append-to-block(result, block) +2239 # else if slice-equal?(word-slice, "}") +2240 # break +2241 # else if slice-ends-with?(word-slice, ":") +2242 # named-block = parse-mu-named-block(word-slice, line, in, vars, fn) +2243 # append-to-block(result, named-block) +2244 # else if slice-equal?(word-slice, "var") +2245 # var-def = parse-mu-var-def(line, vars) +2246 # append-to-block(result, var-def) +2247 # else +2248 # stmt = parse-mu-stmt(line, vars, fn) +2249 # append-to-block(result, stmt) +2250 # return result +2251 # +2252 # . prologue +2253 55/push-ebp +2254 89/<- %ebp 4/r32/esp +2255 # . save registers +2256 51/push-ecx +2257 52/push-edx +2258 53/push-ebx +2259 57/push-edi +2260 # var line/ecx : (stream byte 512) +2261 81 5/subop/subtract %esp 0x200/imm32 +2262 68/push 0x200/imm32/length +2263 68/push 0/imm32/read +2264 68/push 0/imm32/write +2265 89/<- %ecx 4/r32/esp +2266 # var word-slice/edx : slice +2267 68/push 0/imm32/end +2268 68/push 0/imm32/start +2269 89/<- %edx 4/r32/esp +2270 # edi = result +2271 (allocate Heap *Stmt-size) # => eax +2272 (zero-out %eax *Stmt-size) +2273 89/<- %edi 0/r32/eax +2274 { # line loop +2275 $parse-mu-block:line-loop: +2276 # line = read-line-buffered(in) +2277 (clear-stream %ecx) +2278 (read-line-buffered *(ebp+8) %ecx) +2279 #? (write-buffered Stderr "line: ") +2280 #? (write-stream-data Stderr %ecx) +2281 #? (write-buffered Stderr Newline) +2282 #? (flush Stderr) +2283 # if (line->write == 0) break +2284 81 7/subop/compare *ecx 0/imm32 +2285 0f 84/jump-if-equal break/disp32 +2286 # word-slice = next-word(line) +2287 (next-word %ecx %edx) +2288 #? (write-buffered Stderr "word: ") +2289 #? (write-slice-buffered Stderr %edx) +2290 #? (write-buffered Stderr Newline) +2291 #? (flush Stderr) +2292 # if slice-empty?(word-slice) continue +2293 (slice-empty? %edx) +2294 3d/compare-eax-and 0/imm32 +2295 0f 85/jump-if-not-equal loop/disp32 +2296 # if (slice-starts-with?(word-slice, '#') continue +2297 # . eax = *word-slice->start +2298 8b/-> *edx 0/r32/eax +2299 8a/copy-byte *eax 0/r32/AL +2300 81 4/subop/and %eax 0xff/imm32 +2301 # . if (eax == '#') continue +2302 3d/compare-eax-and 0x23/imm32/hash +2303 0f 84/jump-if-equal loop/disp32 +2304 # if slice-equal?(word-slice, "{") +2305 { +2306 $parse-mu-block:check-for-block: +2307 (slice-equal? %edx "{") +2308 3d/compare-eax-and 0/imm32 +2309 74/jump-if-equal break/disp8 +2310 (check-no-tokens-left %ecx) +2311 # parse new block and append +2312 (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2313 (append-to-block %edi %eax) +2314 e9/jump $parse-mu-block:line-loop/disp32 +2315 } +2316 # if slice-equal?(word-slice, "}") break +2317 $parse-mu-block:check-for-end: +2318 (slice-equal? %edx "}") +2319 3d/compare-eax-and 0/imm32 +2320 0f 85/jump-if-not-equal break/disp32 +2321 # if slice-ends-with?(word-slice, ":") parse named block and append +2322 { +2323 $parse-mu-block:check-for-named-block: +2324 # . eax = *word-slice->end +2325 8b/-> *(edx+4) 0/r32/eax +2326 8a/copy-byte *eax 0/r32/AL +2327 81 4/subop/and %eax 0xff/imm32 +2328 # . if (eax != ':') break +2329 3d/compare-eax-and 0x23/imm32/hash +2330 0f 85/jump-if-not-equal break/disp32 +2331 # +2332 (parse-mu-named-block %edx %ecx *(ebp+8) *(ebp+0xc) *(ebp+0x10)) # => eax +2333 (append-to-block %edi %eax) +2334 e9/jump $parse-mu-block:line-loop/disp32 +2335 } +2336 # if slice-equal?(word-slice, "var") +2337 { +2338 $parse-mu-block:check-for-var: +2339 (slice-equal? %edx "var") +2340 3d/compare-eax-and 0/imm32 +2341 74/jump-if-equal break/disp8 +2342 # +2343 (parse-mu-var-def %ecx *(ebp+0xc)) # => eax +2344 (append-to-block %edi %eax) +2345 e9/jump $parse-mu-block:line-loop/disp32 +2346 } +2347 $parse-mu-block:regular-stmt: +2348 # otherwise +2349 (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +2350 (append-to-block Heap %edi %eax) +2351 e9/jump loop/disp32 +2352 } # end line loop +2353 # return result +2354 89/<- %eax 7/r32/edi +2355 $parse-mu-block:end: +2356 # . reclaim locals +2357 81 0/subop/add %esp 0x214/imm32 +2358 # . restore registers +2359 5f/pop-to-edi +2360 5b/pop-to-ebx +2361 5a/pop-to-edx +2362 59/pop-to-ecx +2363 # . epilogue +2364 89/<- %esp 5/r32/ebp +2365 5d/pop-to-ebp +2366 c3/return +2367 +2368 $parse-mu-block:abort: +2369 # error("'{' or '}' should be on its own line, but got '") +2370 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +2371 (rewind-stream %ecx) +2372 (write-stream 2 %ecx) +2373 (write-buffered Stderr "'\n") +2374 (flush Stderr) +2375 # . syscall(exit, 1) +2376 bb/copy-to-ebx 1/imm32 +2377 b8/copy-to-eax 1/imm32/exit +2378 cd/syscall 0x80/imm8 +2379 # never gets here +2380 +2381 check-no-tokens-left: # line : (addr stream byte) +2382 # . prologue +2383 55/push-ebp +2384 89/<- %ebp 4/r32/esp +2385 # . save registers +2386 50/push-eax +2387 51/push-ecx +2388 # var s/ecx : slice +2389 68/push 0/imm32/end +2390 68/push 0/imm32/start +2391 89/<- %ecx 4/r32/esp +2392 # +2393 (next-word *(ebp+8) %ecx) +2394 # if slice-empty?(s) return +2395 (slice-empty? %ecx) +2396 3d/compare-eax-and 0/imm32 +2397 75/jump-if-not-equal $check-no-tokens-left:end/disp8 +2398 # if (slice-starts-with?(s, '#') return +2399 # . eax = *s->start +2400 8b/-> *edx 0/r32/eax +2401 8a/copy-byte *eax 0/r32/AL +2402 81 4/subop/and %eax 0xff/imm32 +2403 # . if (eax == '#') continue +2404 3d/compare-eax-and 0x23/imm32/hash +2405 74/jump-if-equal $check-no-tokens-left:end/disp8 +2406 # abort +2407 (write-buffered Stderr "'{' or '}' should be on its own line, but got '") +2408 (rewind-stream %ecx) +2409 (write-stream 2 %ecx) +2410 (write-buffered Stderr "'\n") +2411 (flush Stderr) +2412 # . syscall(exit, 1) +2413 bb/copy-to-ebx 1/imm32 +2414 b8/copy-to-eax 1/imm32/exit +2415 cd/syscall 0x80/imm8 +2416 # never gets here +2417 $check-no-tokens-left:end: +2418 # . reclaim locals +2419 81 0/subop/add %esp 8/imm32 +2420 # . restore registers +2421 59/pop-to-ecx +2422 58/pop-to-eax +2423 # . epilogue +2424 89/<- %esp 5/r32/ebp +2425 5d/pop-to-ebp +2426 c3/return +2427 +2428 parse-mu-named-block: # name : (addr slice), first-line : (addr stream byte), in : (addr buffered-file), vars : (addr stack (handle var)) -> result/eax : (handle stmt) +2429 # pseudocode: +2430 # var line : (stream byte 512) +2431 # var word-slice : slice +2432 # result/eax = allocate(Heap, Stmt-size) +2433 # result->tag = 4/Named-block +2434 # result->name = name +2435 # assert(next-word(first-line) == "{") +2436 # assert(no-tokens-in(first-line)) +2437 # while true # line loop +2438 # clear-stream(line) +2439 # read-line-buffered(in, line) +2440 # if (line->write == 0) break # end of file +2441 # word-slice = next-word(line) +2442 # if slice-empty?(word-slice) # end of line +2443 # break +2444 # else if slice-equal?(word-slice, "{") +2445 # block = parse-mu-block(in, vars) +2446 # append-to-block(result, block) +2447 # else if slice-equal?(word-slice, "}") +2448 # break +2449 # else if slice-ends-with?(word-slice, ":") +2450 # named-block = parse-mu-named-block(word-slice, in, vars) +2451 # append-to-block(result, named-block) +2452 # else if slice-equal?(word-slice, "var") +2453 # var-def = parse-mu-var-def(line, vars) +2454 # append-to-block(result, var-def) +2455 # else +2456 # stmt = parse-mu-stmt(line, vars, fn) +2457 # append-to-block(result, stmt) +2458 # return result +2459 # +2460 # . prologue +2461 55/push-ebp +2462 89/<- %ebp 4/r32/esp +2463 # . save registers +2464 $parse-mu-named-block:end: +2465 # . reclaim locals +2466 # . restore registers +2467 # . epilogue +2468 89/<- %esp 5/r32/ebp +2469 5d/pop-to-ebp +2470 c3/return +2471 +2472 parse-mu-var-def: # line : (addr stream byte), vars : (addr stack (handle var)) -> result/eax : (handle stmt) +2473 # pseudocode: 2474 # 2475 # . prologue 2476 55/push-ebp 2477 89/<- %ebp 4/r32/esp 2478 # . save registers -2479 51/push-ecx -2480 57/push-edi -2481 # var name/ecx : slice -2482 68/push 0/imm32/end -2483 68/push 0/imm32/start -2484 89/<- %ecx 4/r32/esp -2485 # result/edi : (handle stmt) -2486 (allocate Heap *Stmt-size) # => eax -2487 (zero-out %eax *Stmt-size) -2488 89/<- %edi 0/r32/eax -2489 # result->tag = 1/stmt -2490 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag -2491 { -2492 (stmt-has-outputs? *(ebp+8)) -2493 3d/compare-eax-and 0/imm32 -2494 0f 84/jump-if-equal break/disp32 -2495 { -2496 $parse-mu-stmt:read-outputs: -2497 # name = next-word(line) -2498 (next-word *(ebp+8) %ecx) -2499 # if slice-empty?(word-slice) break -2500 (slice-empty? %ecx) -2501 3d/compare-eax-and 0/imm32 -2502 0f 85/jump-if-not-equal break/disp32 -2503 # if (name == "<-") break -2504 (slice-equal? %ecx "<-") -2505 3d/compare-eax-and 0/imm32 -2506 75/jump-if-not-equal break/disp8 -2507 # assert(is-identifier?(name)) -2508 (is-identifier? %ecx) -2509 3d/compare-eax-and 0/imm32 -2510 0f 84/jump-if-equal $parse-mu-stmt:abort/disp32 -2511 # -2512 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax -2513 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax -2514 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs -2515 e9/jump loop/disp32 -2516 } -2517 } -2518 $parse-mu-stmt:read-operation: -2519 (next-word *(ebp+8) %ecx) -2520 (slice-to-string Heap %ecx) -2521 89/<- *(edi+4) 0/r32/eax # Stmt1-operation -2522 { -2523 $parse-mu-stmt:read-inouts: -2524 # name = next-word-or-string(line) -2525 (next-word-or-string *(ebp+8) %ecx) -2526 # if slice-empty?(word-slice) break -2527 (slice-empty? %ecx) -2528 3d/compare-eax-and 0/imm32 -2529 0f 85/jump-if-not-equal break/disp32 -2530 # if (name == "<-") abort -2531 (slice-equal? %ecx "<-") -2532 3d/compare-eax-and 0/imm32 -2533 0f 85/jump-if-not-equal $parse-mu-stmt:abort2/disp32 -2534 # -2535 (lookup-var-or-literal %ecx *(ebp+0xc)) # => eax -2536 (append-list Heap %eax *(edi+8)) # Stmt1-inouts => eax -2537 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts -2538 e9/jump loop/disp32 -2539 } -2540 $parse-mu-stmt:end: -2541 # return result -2542 89/<- %eax 7/r32/edi -2543 # . reclaim locals -2544 81 0/subop/add %esp 8/imm32 -2545 # . restore registers -2546 5f/pop-to-edi -2547 59/pop-to-ecx -2548 # . epilogue -2549 89/<- %esp 5/r32/ebp -2550 5d/pop-to-ebp -2551 c3/return -2552 -2553 $parse-mu-stmt:abort: -2554 # error("invalid identifier '" name "'\n") -2555 (write-buffered Stderr "invalid identifier '") -2556 (write-slice-buffered Stderr %ecx) -2557 (write-buffered Stderr "'\n") -2558 (flush Stderr) -2559 # . syscall(exit, 1) -2560 bb/copy-to-ebx 1/imm32 -2561 b8/copy-to-eax 1/imm32/exit -2562 cd/syscall 0x80/imm8 -2563 # never gets here -2564 -2565 $parse-mu-stmt:abort2: -2566 # error("invalid statement '" line "'\n") -2567 (rewind-stream *(ebp+8)) -2568 (write-buffered Stderr "invalid identifier '") -2569 (write-stream Stderr *(ebp+8)) -2570 (write-buffered Stderr "'\n") -2571 (flush Stderr) -2572 # . syscall(exit, 1) -2573 bb/copy-to-ebx 1/imm32 -2574 b8/copy-to-eax 1/imm32/exit -2575 cd/syscall 0x80/imm8 -2576 # never gets here -2577 -2578 stmt-has-outputs?: # line : (addr stream byte) -> result/eax : boolean -2579 # . prologue -2580 55/push-ebp -2581 89/<- %ebp 4/r32/esp -2582 # . save registers -2583 51/push-ecx -2584 # var word-slice/ecx : slice -2585 68/push 0/imm32/end -2586 68/push 0/imm32/start -2587 89/<- %ecx 4/r32/esp -2588 # result = false -2589 b8/copy-to-eax 0/imm32/false -2590 (rewind-stream *(ebp+8)) -2591 { -2592 (next-word-or-string *(ebp+8) %ecx) -2593 # if slice-empty?(word-slice) break -2594 (slice-empty? %ecx) -2595 3d/compare-eax-and 0/imm32 -2596 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -2597 0f 85/jump-if-not-equal break/disp32 -2598 # if slice-starts-with?(word-slice, '#') break -2599 # . eax = *word-slice->start -2600 8b/-> *ecx 0/r32/eax -2601 8a/copy-byte *eax 0/r32/AL -2602 81 4/subop/and %eax 0xff/imm32 -2603 # . if (eax == '#') break -2604 3d/compare-eax-and 0x23/imm32/hash -2605 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) -2606 0f 84/jump-if-equal break/disp32 -2607 # if slice-equal?(word-slice, '<-') return true -2608 (slice-equal? %ecx "<-") -2609 3d/compare-eax-and 0/imm32 -2610 74/jump-if-equal loop/disp8 -2611 b8/copy-to-eax 1/imm32/true -2612 } -2613 $stmt-has-outputs:end: -2614 (rewind-stream *(ebp+8)) -2615 # . reclaim locals -2616 81 0/subop/add %esp 8/imm32 -2617 # . restore registers -2618 59/pop-to-ecx -2619 # . epilogue -2620 89/<- %esp 5/r32/ebp -2621 5d/pop-to-ebp -2622 c3/return -2623 -2624 # if 'name' starts with a digit, create a new literal var for it -2625 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found -2626 lookup-var-or-literal: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) -2627 # . prologue -2628 55/push-ebp -2629 89/<- %ebp 4/r32/esp -2630 # . save registers -2631 51/push-ecx -2632 56/push-esi -2633 # esi = name -2634 8b/-> *(ebp+8) 6/r32/esi -2635 # if slice-empty?(name) abort -2636 (slice-empty? %esi) # => eax -2637 3d/compare-eax-and 0/imm32 -2638 0f 85/jump-if-not-equal $lookup-var-or-literal:abort/disp32 -2639 # var ecx : byte = *name->start -2640 8b/-> *esi 1/r32/ecx -2641 8a/copy-byte *ecx 1/r32/CL -2642 81 4/subop/and %ecx 0xff/imm32 -2643 # if is-decimal-digit?(*name->start) return new var(name) -2644 (is-decimal-digit? %ecx) # => eax -2645 81 7/subop/compare %eax 0/imm32 -2646 { -2647 74/jump-if-equal break/disp8 -2648 (new-literal-integer Heap %esi) # => eax -2649 } -2650 # otherwise return lookup-var(name, vars) -2651 { -2652 75/jump-if-not-equal break/disp8 -2653 (lookup-var %esi *(ebp+0xc)) # => eax -2654 } -2655 $lookup-var-or-literal:end: -2656 # . restore registers -2657 5e/pop-to-esi -2658 59/pop-to-ecx -2659 # . epilogue -2660 89/<- %esp 5/r32/ebp -2661 5d/pop-to-ebp -2662 c3/return -2663 -2664 $lookup-var-or-literal:abort: -2665 (write-buffered Stderr "empty variable!") -2666 (flush Stderr) -2667 # . syscall(exit, 1) -2668 bb/copy-to-ebx 1/imm32 -2669 b8/copy-to-eax 1/imm32/exit -2670 cd/syscall 0x80/imm8 -2671 # never gets here -2672 -2673 # return first 'name' from the top (back) of 'vars' and abort if not found -2674 lookup-var: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) -2675 # . prologue -2676 55/push-ebp -2677 89/<- %ebp 4/r32/esp -2678 # var target/eax : (handle array byte) = slice-to-string(name) -2679 (slice-to-string Heap *(ebp+8)) # => eax -2680 # -2681 (lookup-var-helper %eax *(ebp+0xc)) # => eax -2682 # if (result == 0) abort -2683 3d/compare-eax-and 0/imm32 -2684 74/jump-if-equal $lookup-var:abort/disp8 -2685 $lookup-var:end: -2686 # . epilogue -2687 89/<- %esp 5/r32/ebp -2688 5d/pop-to-ebp -2689 c3/return -2690 -2691 $lookup-var:abort: -2692 (write-buffered Stderr "unknown variable '") -2693 (write-slice-buffered Stderr *(ebp+8)) -2694 (write-buffered Stderr "'\n") +2479 $parse-mu-var-def:end: +2480 # . reclaim locals +2481 # . restore registers +2482 # . epilogue +2483 89/<- %esp 5/r32/ebp +2484 5d/pop-to-ebp +2485 c3/return +2486 +2487 parse-mu-stmt: # line : (addr stream byte), vars : (addr stack (handle var)), fn : (handle function) -> result/eax : (handle stmt) +2488 # pseudocode: +2489 # var name : slice +2490 # result = allocate(Heap, Stmt-size) +2491 # if stmt-has-outputs?(line) +2492 # while true +2493 # name = next-word(line) +2494 # if (name == '<-') break +2495 # assert(is-identifier?(name)) +2496 # var v : (handle var) = lookup-or-define-var(name, vars) +2497 # result->outputs = append(result->outputs, v) +2498 # result->name = slice-to-string(next-word(line)) +2499 # while true +2500 # name = next-word-or-string(line) +2501 # v = lookup-var-or-literal(name) +2502 # result->inouts = append(result->inouts, v) +2503 # +2504 # . prologue +2505 55/push-ebp +2506 89/<- %ebp 4/r32/esp +2507 # . save registers +2508 51/push-ecx +2509 57/push-edi +2510 # var name/ecx : slice +2511 68/push 0/imm32/end +2512 68/push 0/imm32/start +2513 89/<- %ecx 4/r32/esp +2514 # result/edi : (handle stmt) +2515 (allocate Heap *Stmt-size) # => eax +2516 (zero-out %eax *Stmt-size) +2517 89/<- %edi 0/r32/eax +2518 # result->tag = 1/stmt +2519 c7 0/subop/copy *edi 1/imm32/stmt1 # Stmt-tag +2520 { +2521 (stmt-has-outputs? *(ebp+8)) +2522 3d/compare-eax-and 0/imm32 +2523 0f 84/jump-if-equal break/disp32 +2524 { +2525 $parse-mu-stmt:read-outputs: +2526 # name = next-word(line) +2527 (next-word *(ebp+8) %ecx) +2528 # if slice-empty?(word-slice) break +2529 (slice-empty? %ecx) +2530 3d/compare-eax-and 0/imm32 +2531 0f 85/jump-if-not-equal break/disp32 +2532 # if (name == "<-") break +2533 (slice-equal? %ecx "<-") +2534 3d/compare-eax-and 0/imm32 +2535 75/jump-if-not-equal break/disp8 +2536 # assert(is-identifier?(name)) +2537 (is-identifier? %ecx) +2538 3d/compare-eax-and 0/imm32 +2539 0f 84/jump-if-equal $parse-mu-stmt:abort/disp32 +2540 # +2541 (lookup-or-define-var %ecx *(ebp+0xc) *(ebp+0x10)) # => eax +2542 (append-list Heap %eax *(edi+0xc)) # Stmt1-outputs => eax +2543 89/<- *(edi+0xc) 0/r32/eax # Stmt1-outputs +2544 e9/jump loop/disp32 +2545 } +2546 } +2547 $parse-mu-stmt:read-operation: +2548 (next-word *(ebp+8) %ecx) +2549 (slice-to-string Heap %ecx) +2550 89/<- *(edi+4) 0/r32/eax # Stmt1-operation +2551 { +2552 $parse-mu-stmt:read-inouts: +2553 # name = next-word-or-string(line) +2554 (next-word-or-string *(ebp+8) %ecx) +2555 # if slice-empty?(word-slice) break +2556 (slice-empty? %ecx) +2557 3d/compare-eax-and 0/imm32 +2558 0f 85/jump-if-not-equal break/disp32 +2559 # if (name == "<-") abort +2560 (slice-equal? %ecx "<-") +2561 3d/compare-eax-and 0/imm32 +2562 0f 85/jump-if-not-equal $parse-mu-stmt:abort2/disp32 +2563 # +2564 (lookup-var-or-literal %ecx *(ebp+0xc)) # => eax +2565 (append-list Heap %eax *(edi+8)) # Stmt1-inouts => eax +2566 89/<- *(edi+8) 0/r32/eax # Stmt1-inouts +2567 e9/jump loop/disp32 +2568 } +2569 $parse-mu-stmt:end: +2570 # return result +2571 89/<- %eax 7/r32/edi +2572 # . reclaim locals +2573 81 0/subop/add %esp 8/imm32 +2574 # . restore registers +2575 5f/pop-to-edi +2576 59/pop-to-ecx +2577 # . epilogue +2578 89/<- %esp 5/r32/ebp +2579 5d/pop-to-ebp +2580 c3/return +2581 +2582 $parse-mu-stmt:abort: +2583 # error("invalid identifier '" name "'\n") +2584 (write-buffered Stderr "invalid identifier '") +2585 (write-slice-buffered Stderr %ecx) +2586 (write-buffered Stderr "'\n") +2587 (flush Stderr) +2588 # . syscall(exit, 1) +2589 bb/copy-to-ebx 1/imm32 +2590 b8/copy-to-eax 1/imm32/exit +2591 cd/syscall 0x80/imm8 +2592 # never gets here +2593 +2594 $parse-mu-stmt:abort2: +2595 # error("invalid statement '" line "'\n") +2596 (rewind-stream *(ebp+8)) +2597 (write-buffered Stderr "invalid identifier '") +2598 (write-stream Stderr *(ebp+8)) +2599 (write-buffered Stderr "'\n") +2600 (flush Stderr) +2601 # . syscall(exit, 1) +2602 bb/copy-to-ebx 1/imm32 +2603 b8/copy-to-eax 1/imm32/exit +2604 cd/syscall 0x80/imm8 +2605 # never gets here +2606 +2607 stmt-has-outputs?: # line : (addr stream byte) -> result/eax : boolean +2608 # . prologue +2609 55/push-ebp +2610 89/<- %ebp 4/r32/esp +2611 # . save registers +2612 51/push-ecx +2613 # var word-slice/ecx : slice +2614 68/push 0/imm32/end +2615 68/push 0/imm32/start +2616 89/<- %ecx 4/r32/esp +2617 # result = false +2618 b8/copy-to-eax 0/imm32/false +2619 (rewind-stream *(ebp+8)) +2620 { +2621 (next-word-or-string *(ebp+8) %ecx) +2622 # if slice-empty?(word-slice) break +2623 (slice-empty? %ecx) +2624 3d/compare-eax-and 0/imm32 +2625 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +2626 0f 85/jump-if-not-equal break/disp32 +2627 # if slice-starts-with?(word-slice, '#') break +2628 # . eax = *word-slice->start +2629 8b/-> *ecx 0/r32/eax +2630 8a/copy-byte *eax 0/r32/AL +2631 81 4/subop/and %eax 0xff/imm32 +2632 # . if (eax == '#') break +2633 3d/compare-eax-and 0x23/imm32/hash +2634 b8/copy-to-eax 0/imm32/false/result # restore result (if we're here it's still false) +2635 0f 84/jump-if-equal break/disp32 +2636 # if slice-equal?(word-slice, '<-') return true +2637 (slice-equal? %ecx "<-") +2638 3d/compare-eax-and 0/imm32 +2639 74/jump-if-equal loop/disp8 +2640 b8/copy-to-eax 1/imm32/true +2641 } +2642 $stmt-has-outputs:end: +2643 (rewind-stream *(ebp+8)) +2644 # . reclaim locals +2645 81 0/subop/add %esp 8/imm32 +2646 # . restore registers +2647 59/pop-to-ecx +2648 # . epilogue +2649 89/<- %esp 5/r32/ebp +2650 5d/pop-to-ebp +2651 c3/return +2652 +2653 # if 'name' starts with a digit, create a new literal var for it +2654 # otherwise return first 'name' from the top (back) of 'vars' and abort if not found +2655 lookup-var-or-literal: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) +2656 # . prologue +2657 55/push-ebp +2658 89/<- %ebp 4/r32/esp +2659 # . save registers +2660 51/push-ecx +2661 56/push-esi +2662 # esi = name +2663 8b/-> *(ebp+8) 6/r32/esi +2664 # if slice-empty?(name) abort +2665 (slice-empty? %esi) # => eax +2666 3d/compare-eax-and 0/imm32 +2667 0f 85/jump-if-not-equal $lookup-var-or-literal:abort/disp32 +2668 # var ecx : byte = *name->start +2669 8b/-> *esi 1/r32/ecx +2670 8a/copy-byte *ecx 1/r32/CL +2671 81 4/subop/and %ecx 0xff/imm32 +2672 # if is-decimal-digit?(*name->start) return new var(name) +2673 (is-decimal-digit? %ecx) # => eax +2674 81 7/subop/compare %eax 0/imm32 +2675 { +2676 74/jump-if-equal break/disp8 +2677 (new-literal-integer Heap %esi) # => eax +2678 } +2679 # otherwise return lookup-var(name, vars) +2680 { +2681 75/jump-if-not-equal break/disp8 +2682 (lookup-var %esi *(ebp+0xc)) # => eax +2683 } +2684 $lookup-var-or-literal:end: +2685 # . restore registers +2686 5e/pop-to-esi +2687 59/pop-to-ecx +2688 # . epilogue +2689 89/<- %esp 5/r32/ebp +2690 5d/pop-to-ebp +2691 c3/return +2692 +2693 $lookup-var-or-literal:abort: +2694 (write-buffered Stderr "empty variable!") 2695 (flush Stderr) 2696 # . syscall(exit, 1) 2697 bb/copy-to-ebx 1/imm32 @@ -2711,2754 +2711,2923 @@ if ('onhashchange' in window) { 2699 cd/syscall 0x80/imm8 2700 # never gets here 2701 -2702 # return first 'name' from the top (back) of 'vars', and 0/null if not found -2703 lookup-var-helper: # name: (addr array byte), vars : (addr stack (handle var)) -> result/eax: (handle var) -2704 # pseudocode: -2705 # var curr : (addr handle var) = &vars->data[vars->top - 4] -2706 # var min = vars->data -2707 # while curr >= min -2708 # var v : (handle var) = *curr -2709 # if v->name == name -2710 # return v -2711 # return 0 -2712 # -2713 # . prologue -2714 55/push-ebp -2715 89/<- %ebp 4/r32/esp -2716 # . save registers -2717 52/push-edx -2718 53/push-ebx -2719 56/push-esi -2720 # esi = vars -2721 8b/-> *(ebp+0xc) 6/r32/esi -2722 # ebx = vars->top -2723 8b/-> *esi 3/r32/ebx -2724 # if (vars->top > vars->length) abort -2725 3b/compare 0/r32/eax *(esi+4) -2726 0f 8f/jump-if-greater $lookup-var-helper:error1/disp32 -2727 # var min/edx : (addr handle var) = vars->data -2728 8d/copy-address *(esi+8) 2/r32/edx -2729 # var curr/ebx : (addr handle var) = &vars->data[vars->top - 4] -2730 81 5/subop/subtract %ebx 4/imm32 -2731 8d/copy-address *(esi+ebx+8) 3/r32/ebx -2732 { -2733 # if (curr < min) return 0 -2734 39/compare %ebx 2/r32/edx -2735 b8/copy-to-eax 0/imm32 -2736 0f 82/jump-if-lesser-unsigned break/disp32 -2737 # var v/eax : (handle var) = *curr -2738 8b/-> *ebx 0/r32/eax -2739 # if (v->name == name) return v -2740 (string-equal? *eax *(ebp+8)) # Var-name -2741 3d/compare-eax-and 0/imm32 -2742 8b/-> *ebx 0/r32/eax -2743 75/jump-if-not-equal break/disp8 -2744 # curr -= 4 -2745 81 5/subop/subtract %ebx 4/imm32 -2746 e9/jump loop/disp32 -2747 } -2748 $lookup-var-helper:end: -2749 # . restore registers -2750 5e/pop-to-esi -2751 5b/pop-to-ebx -2752 5a/pop-to-edx -2753 # . epilogue -2754 89/<- %esp 5/r32/ebp -2755 5d/pop-to-ebp -2756 c3/return -2757 -2758 $lookup-var-helper:error1: -2759 (write-buffered Stderr "malformed stack when looking up '") -2760 (write-slice-buffered Stderr *(ebp+8)) -2761 (write-buffered Stderr "'\n") -2762 (flush Stderr) -2763 # . syscall(exit, 1) -2764 bb/copy-to-ebx 1/imm32 -2765 b8/copy-to-eax 1/imm32/exit -2766 cd/syscall 0x80/imm8 -2767 # never gets here -2768 -2769 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found -2770 lookup-or-define-var: # name: (addr slice), vars : (addr stack (handle var)), fn : (handle function) -> result/eax: (handle var) -2771 # . prologue -2772 55/push-ebp -2773 89/<- %ebp 4/r32/esp -2774 # . save registers -2775 51/push-ecx -2776 # var target/ecx : (handle array byte) = slice-to-string(name) -2777 (slice-to-string Heap *(ebp+8)) # => eax -2778 89/<- %ecx 0/r32/eax -2779 # -2780 (lookup-var-helper *(ebp+8) *(ebp+0xc)) # => eax -2781 { -2782 # if (result != 0) return -2783 3d/compare-eax-and 0/imm32 -2784 75/jump-if-not-equal break/disp8 -2785 # if name is one of fn's outputs, return it -2786 { -2787 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax -2788 3d/compare-eax-and 0/imm32 -2789 # otherwise abort -2790 0f 84/jump-if-not-equal $lookup-var:abort/disp32 -2791 } -2792 } -2793 $lookup-or-define-var:end: -2794 # . restore registers -2795 59/pop-to-ecx -2796 # . epilogue -2797 89/<- %esp 5/r32/ebp -2798 5d/pop-to-ebp -2799 c3/return -2800 -2801 find-in-function-outputs: # fn : (handle function), name : (handle array byte) => result/eax : (handle var) -2802 # . prologue -2803 55/push-ebp -2804 89/<- %ebp 4/r32/esp -2805 # . save registers -2806 51/push-ecx -2807 # var curr/ecx : (handle list var) = fn->outputs -2808 8b/-> *(ebp+8) 1/r32/ecx -2809 8b/-> *(ecx+0xc) 1/r32/ecx -2810 # while curr != null -2811 { -2812 81 7/subop/compare %ecx 0/imm32 -2813 74/jump-if-equal break/disp8 -2814 # var v : (handle var) = *curr -2815 8b/-> *ecx 0/r32/eax # List-value -2816 # if (curr->name == name) return curr -2817 50/push-eax -2818 (string-equal? *eax *(ebp+0xc)) -2819 3d/compare-eax-and 0/imm32 -2820 58/pop-to-eax -2821 75/jump-if-not-equal $find-in-function-outputs:end/disp8 -2822 # curr = curr->next -2823 8b/-> *(ecx+4) 1/r32/ecx # List-next -2824 eb/jump loop/disp8 -2825 } -2826 b8/copy-to-eax 0/imm32 -2827 $find-in-function-outputs:end: -2828 # . restore registers -2829 59/pop-to-ecx -2830 # . epilogue -2831 89/<- %esp 5/r32/ebp -2832 5d/pop-to-ebp -2833 c3/return -2834 -2835 test-parse-mu-stmt: -2836 # 'increment n' -2837 # . prologue -2838 55/push-ebp -2839 89/<- %ebp 4/r32/esp -2840 # setup -2841 (clear-stream _test-input-stream) -2842 (write _test-input-stream "increment n\n") -2843 # var vars/ecx : (stack (addr var) 4) -2844 81 5/subop/subtract %esp 0x10/imm32 -2845 68/push 0x10/imm32/length -2846 68/push 0/imm32/top -2847 89/<- %ecx 4/r32/esp -2848 (clear-stack %ecx) -2849 # var v/edx : var -2850 81 5/subop/subtract %esp 0x14/imm32 # Var-size -2851 89/<- %edx 4/r32/esp -2852 (zero-out %edx 0x14) -2853 # v->name = "n" -2854 c7 0/subop/copy *edx "n"/imm32 # Var-name -2855 # -2856 (push %ecx %edx) -2857 # convert -2858 (parse-mu-stmt _test-input-stream %ecx) -2859 # check result -2860 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation -2861 # edx : (handle list var) = result->inouts -2862 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts -2863 # ebx : (handle var) = result->inouts->value -2864 8b/-> *edx 3/r32/ebx # List-value -2865 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name -2866 # . epilogue -2867 89/<- %esp 5/r32/ebp -2868 5d/pop-to-ebp -2869 c3/return -2870 -2871 new-function: # ad: (addr allocation-descriptor), name: (addr array byte), subx-name: (addr array byte), inouts: (handle list var), outputs: (handle list var), body: (handle block), next: (handle function) -> result/eax: (handle function) -2872 # . prologue -2873 55/push-ebp -2874 89/<- %ebp 4/r32/esp -2875 # . save registers -2876 51/push-ecx -2877 # -2878 (allocate *(ebp+8) *Function-size) # => eax -2879 8b/-> *(ebp+0xc) 1/r32/ecx -2880 89/<- *eax 1/r32/ecx # Function-name -2881 8b/-> *(ebp+0x10) 1/r32/ecx -2882 89/<- *(eax+4) 1/r32/ecx # Function-subx-name -2883 8b/-> *(ebp+0x14) 1/r32/ecx -2884 89/<- *(eax+8) 1/r32/ecx # Function-inouts -2885 8b/-> *(ebp+0x18) 1/r32/ecx -2886 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs -2887 8b/-> *(ebp+0x1c) 1/r32/ecx -2888 89/<- *(eax+0x10) 1/r32/ecx # Function-body -2889 8b/-> *(ebp+0x20) 1/r32/ecx -2890 89/<- *(eax+0x14) 1/r32/ecx # Function-next -2891 $new-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 new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, block: int, stack-offset: int, register: (addr array byte) -> result/eax: (handle var) -2900 # . prologue -2901 55/push-ebp -2902 89/<- %ebp 4/r32/esp -2903 # . save registers -2904 51/push-ecx -2905 # -2906 (allocate *(ebp+8) *Var-size) # => eax -2907 8b/-> *(ebp+0xc) 1/r32/ecx -2908 89/<- *eax 1/r32/ecx # Var-name -2909 8b/-> *(ebp+0x10) 1/r32/ecx -2910 89/<- *(eax+4) 1/r32/ecx # Var-type -2911 8b/-> *(ebp+0x14) 1/r32/ecx -2912 89/<- *(eax+8) 1/r32/ecx # Var-block -2913 8b/-> *(ebp+0x18) 1/r32/ecx -2914 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset -2915 8b/-> *(ebp+0x1c) 1/r32/ecx -2916 89/<- *(eax+0x10) 1/r32/ecx # Var-register -2917 $new-var:end: -2918 # . restore registers -2919 59/pop-to-ecx -2920 # . epilogue -2921 89/<- %esp 5/r32/ebp -2922 5d/pop-to-ebp -2923 c3/return -2924 -2925 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) -2926 # . prologue -2927 55/push-ebp -2928 89/<- %ebp 4/r32/esp -2929 # . save registers -2930 51/push-ecx -2931 # if (!is-hex-int?(name)) abort -2932 (is-hex-int? *(ebp+0xc)) # => eax -2933 3d/compare-eax-and 0/imm32 -2934 0f 84/jump-if-equal $new-literal-integer:abort/disp32 -2935 # var s/ecx : (addr array byte) -2936 (slice-to-string Heap *(ebp+0xc)) # => eax -2937 89/<- %ecx 0/r32/eax -2938 # -2939 (allocate *(ebp+8) *Var-size) # => eax -2940 89/<- *eax 1/r32/ecx # Var-name -2941 c7 0/subop/copy *(eax+4) 0/imm32/tag/literal # Var-type -2942 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block -2943 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset -2944 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register -2945 $new-literal-integer: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 $new-literal-integer:abort: -2954 (write-buffered Stderr "variable cannot begin with a digit '") -2955 (write-slice-buffered Stderr *(ebp+0xc)) -2956 (write-buffered Stderr "'\n") -2957 (flush Stderr) -2958 # . syscall(exit, 1) -2959 bb/copy-to-ebx 1/imm32 -2960 b8/copy-to-eax 1/imm32/exit -2961 cd/syscall 0x80/imm8 -2962 # never gets here -2963 -2964 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) -2965 # . prologue -2966 55/push-ebp -2967 89/<- %ebp 4/r32/esp -2968 # . save registers -2969 51/push-ecx -2970 # -2971 (allocate *(ebp+8) *Stmt-size) # => eax -2972 (zero-out %eax *Stmt-size) -2973 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag -2974 8b/-> *(ebp+0xc) 1/r32/ecx -2975 89/<- *(eax+4) 1/r32/ecx # Block-statements -2976 $new-block:end: -2977 # . restore registers -2978 59/pop-to-ecx -2979 # . epilogue -2980 89/<- %esp 5/r32/ebp -2981 5d/pop-to-ebp -2982 c3/return -2983 -2984 new-stmt: # ad: (addr allocation-descriptor), operation: (addr array byte), inouts: (handle list var), outputs: (handle list var) -> result/eax: (handle statement) -2985 # . prologue -2986 55/push-ebp -2987 89/<- %ebp 4/r32/esp -2988 # . save registers -2989 51/push-ecx -2990 # -2991 (allocate *(ebp+8) *Stmt-size) # => eax -2992 (zero-out %eax *Stmt-size) -2993 c7 0/subop/copy *eax 1/imm32/tag/regular-stmt # Stmt-tag -2994 8b/-> *(ebp+0xc) 1/r32/ecx -2995 89/<- *(eax+4) 1/r32/ecx # Stmt1-operation -2996 8b/-> *(ebp+0x10) 1/r32/ecx -2997 89/<- *(eax+8) 1/r32/ecx # Stmt1-inouts -2998 8b/-> *(ebp+0x14) 1/r32/ecx -2999 89/<- *(eax+0xc) 1/r32/ecx # Stmt1-outputs -3000 $new-stmt:end: -3001 # . restore registers -3002 59/pop-to-ecx -3003 # . epilogue -3004 89/<- %esp 5/r32/ebp -3005 5d/pop-to-ebp -3006 c3/return -3007 -3008 new-vardef: # ad: (addr allocation-descriptor), name: (addr array byte), type: int -> result/eax: (handle statement) -3009 # . prologue -3010 55/push-ebp -3011 89/<- %ebp 4/r32/esp -3012 # . save registers -3013 51/push-ecx -3014 # -3015 (allocate *(ebp+8) *Stmt-size) # => eax -3016 (zero-out %eax *Stmt-size) -3017 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag -3018 8b/-> *(ebp+0xc) 1/r32/ecx -3019 89/<- *(eax+4) 1/r32/ecx # Vardef-name -3020 8b/-> *(ebp+0x10) 1/r32/ecx -3021 89/<- *(eax+8) 1/r32/ecx # Vardef-type -3022 $new-vardef:end: -3023 # . restore registers -3024 59/pop-to-ecx -3025 # . epilogue -3026 89/<- %esp 5/r32/ebp -3027 5d/pop-to-ebp -3028 c3/return -3029 -3030 new-regvardef: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, register: (addr array byte) -> result/eax: (handle statement) -3031 # . prologue -3032 55/push-ebp -3033 89/<- %ebp 4/r32/esp -3034 # . save registers -3035 51/push-ecx -3036 # -3037 (allocate *(ebp+8) *Stmt-size) # => eax -3038 (zero-out %eax *Stmt-size) -3039 c7 0/subop/copy *eax 3/imm32/tag/var-in-register -3040 8b/-> *(ebp+0xc) 1/r32/ecx -3041 89/<- *(eax+4) 1/r32/ecx # Regvardef-name -3042 8b/-> *(ebp+0x10) 1/r32/ecx -3043 89/<- *(eax+8) 1/r32/ecx # Regvardef-type -3044 8b/-> *(ebp+0x14) 1/r32/ecx -3045 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-register -3046 $new-regvardef:end: -3047 # . restore registers -3048 59/pop-to-ecx -3049 # . epilogue -3050 89/<- %esp 5/r32/ebp -3051 5d/pop-to-ebp -3052 c3/return -3053 -3054 new-named-block: # ad: (addr allocation-descriptor), name: (addr array byte), data: (handle list statement) -> result/eax: (handle statement) -3055 # . prologue -3056 55/push-ebp -3057 89/<- %ebp 4/r32/esp -3058 # . save registers -3059 51/push-ecx -3060 # -3061 (allocate *(ebp+8) *Stmt-size) # => eax -3062 (zero-out %eax *Stmt-size) -3063 c7 0/subop/copy *eax 4/imm32/tag/named-block -3064 8b/-> *(ebp+0xc) 1/r32/ecx -3065 89/<- *(eax+4) 1/r32/ecx # Named-block-name -3066 8b/-> *(ebp+0x10) 1/r32/ecx -3067 89/<- *(eax+8) 1/r32/ecx # Named-block-statements -3068 $new-named-block:end: -3069 # . restore registers -3070 59/pop-to-ecx -3071 # . epilogue -3072 89/<- %esp 5/r32/ebp -3073 5d/pop-to-ebp -3074 c3/return -3075 -3076 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax : (handle list _type) -3077 # . prologue -3078 55/push-ebp -3079 89/<- %ebp 4/r32/esp -3080 # . save registers -3081 51/push-ecx -3082 # -3083 (allocate *(ebp+8) *List-size) # => eax -3084 8b/-> *(ebp+0xc) 1/r32/ecx -3085 89/<- *eax 1/r32/ecx # List-value -3086 8b/-> *(ebp+0x10) 1/r32/ecx -3087 89/<- *(eax+4) 1/r32/ecx # List-next -3088 $new-list:end: -3089 # . restore registers -3090 59/pop-to-ecx -3091 # . epilogue -3092 89/<- %esp 5/r32/ebp -3093 5d/pop-to-ebp -3094 c3/return -3095 -3096 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax : (handle list _type) -3097 # . prologue -3098 55/push-ebp -3099 89/<- %ebp 4/r32/esp -3100 # . save registers -3101 51/push-ecx -3102 # -3103 (allocate *(ebp+8) *List-size) # => eax -3104 8b/-> *(ebp+0xc) 1/r32/ecx -3105 89/<- *eax 1/r32/ecx # List-value -3106 # if (list == null) return result -3107 81 7/subop/compare *(ebp+0x10) 0/imm32 -3108 74/jump-if-equal $new-list:end/disp8 -3109 # otherwise append -3110 # var curr/ecx = list -3111 8b/-> *(ebp+0x10) 1/r32/ecx -3112 # while (curr->next != null) curr = curr->next -3113 { -3114 81 7/subop/compare *(ecx+4) 0/imm32 # List-next -3115 74/jump-if-equal break/disp8 -3116 # curr = curr->next -3117 8b/-> *(ecx+4) 1/r32/ecx -3118 eb/jump loop/disp8 -3119 } -3120 # curr->next = result -3121 89/<- *(ecx+4) 0/r32/eax -3122 # return list -3123 8b/-> *(ebp+0x10) 0/r32/eax -3124 $append-list:end: -3125 # . restore registers -3126 59/pop-to-ecx -3127 # . epilogue -3128 89/<- %esp 5/r32/ebp -3129 5d/pop-to-ebp -3130 c3/return -3131 -3132 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) -3133 # . prologue -3134 55/push-ebp -3135 89/<- %ebp 4/r32/esp -3136 # . save registers -3137 56/push-esi -3138 # esi = block -3139 8b/-> *(ebp+0xc) 6/r32/esi -3140 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements -3141 89/<- *(esi+4) 0/r32/eax # Block-statements -3142 $append-to-block:end: -3143 # . restore registers -3144 5e/pop-to-esi -3145 # . epilogue -3146 89/<- %esp 5/r32/ebp -3147 5d/pop-to-ebp -3148 c3/return -3149 -3150 ####################################################### -3151 # Type-checking -3152 ####################################################### -3153 -3154 check-mu-types: -3155 # . prologue -3156 55/push-ebp -3157 89/<- %ebp 4/r32/esp -3158 # -3159 $check-mu-types:end: -3160 # . epilogue -3161 89/<- %esp 5/r32/ebp -3162 5d/pop-to-ebp -3163 c3/return -3164 -3165 size-of: # n : (addr var) -3166 # . prologue -3167 55/push-ebp -3168 89/<- %ebp 4/r32/esp -3169 # hard-coded since we only support 'int' types for now -3170 b8/copy-to-eax 4/imm32 -3171 $size-of:end: -3172 # . epilogue -3173 89/<- %esp 5/r32/ebp -3174 5d/pop-to-ebp -3175 c3/return -3176 -3177 ####################################################### -3178 # Code-generation -3179 ####################################################### -3180 -3181 emit-subx: # out : (addr buffered-file) -3182 # . prologue -3183 55/push-ebp -3184 89/<- %ebp 4/r32/esp -3185 # . save registers -3186 50/push-eax -3187 51/push-ecx -3188 57/push-edi -3189 # edi = out -3190 8b/-> *(ebp+8) 7/r32/edi -3191 # var curr/ecx : (handle function) = *Program -3192 8b/-> *Program 1/r32/ecx -3193 { -3194 # if (curr == null) break -3195 81 7/subop/compare %ecx 0/imm32 -3196 0f 84/jump-if-equal break/disp32 -3197 (emit-subx-function %edi %ecx) -3198 # curr = curr->next -3199 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -3200 e9/jump loop/disp32 -3201 } -3202 $emit-subx:end: -3203 # . restore registers -3204 5f/pop-to-edi -3205 59/pop-to-ecx -3206 58/pop-to-eax -3207 # . epilogue -3208 89/<- %esp 5/r32/ebp -3209 5d/pop-to-ebp -3210 c3/return -3211 -3212 emit-subx-function: # out : (addr buffered-file), f : (handle function) -3213 # . prologue -3214 55/push-ebp -3215 89/<- %ebp 4/r32/esp -3216 # . save registers -3217 50/push-eax -3218 51/push-ecx -3219 57/push-edi -3220 # edi = out -3221 8b/-> *(ebp+8) 7/r32/edi -3222 # ecx = f -3223 8b/-> *(ebp+0xc) 1/r32/ecx -3224 # -3225 (write-buffered %edi *ecx) -3226 (write-buffered %edi ":\n") -3227 (emit-subx-prologue %edi) -3228 (emit-subx-block %edi *(ecx+0x10)) # Function-body -3229 (emit-subx-epilogue %edi) -3230 $emit-subx-function:end: -3231 # . restore registers -3232 5f/pop-to-edi -3233 59/pop-to-ecx -3234 58/pop-to-eax -3235 # . epilogue -3236 89/<- %esp 5/r32/ebp -3237 5d/pop-to-ebp -3238 c3/return -3239 -3240 emit-subx-block: # out : (addr buffered-file), block : (handle block) -3241 # . prologue -3242 55/push-ebp -3243 89/<- %ebp 4/r32/esp -3244 # curr/esi : (handle list statement) = block->statements -3245 8b/-> *(ebp+0xc) 6/r32/esi -3246 8b/-> *(esi+4) 6/r32/esi # Block-statements -3247 # -3248 { -3249 $emit-subx-block:check-empty: -3250 81 7/subop/compare %esi 0/imm32 -3251 0f 84/jump-if-equal break/disp32 -3252 (write-buffered *(ebp+8) "{\n") -3253 { -3254 $emit-subx-block:stmt: -3255 81 7/subop/compare %esi 0/imm32 -3256 74/jump-if-equal break/disp8 -3257 (emit-subx-statement *(ebp+8) *esi Primitives *Program) -3258 (write-buffered *(ebp+8) Newline) -3259 8b/-> *(esi+4) 6/r32/esi # List-next -3260 eb/jump loop/disp8 -3261 } -3262 (write-buffered *(ebp+8) "}\n") -3263 } -3264 $emit-subx-block:end: -3265 # . epilogue -3266 89/<- %esp 5/r32/ebp -3267 5d/pop-to-ebp -3268 c3/return -3269 -3270 emit-subx-statement: # out : (addr buffered-file), stmt : (handle statement), primitives : (handle primitive), functions : (handle function) -3271 # . prologue -3272 55/push-ebp -3273 89/<- %ebp 4/r32/esp -3274 # . save registers -3275 50/push-eax -3276 51/push-ecx -3277 # if stmt matches a primitive, emit it -3278 { -3279 $emit-subx-statement:primitive: -3280 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax -3281 3d/compare-eax-and 0/imm32 -3282 74/jump-if-equal break/disp8 -3283 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -3284 e9/jump $emit-subx-statement:end/disp32 -3285 } -3286 # else if stmt matches a function, emit a call to it -3287 { -3288 $emit-subx-statement:call: -3289 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax -3290 3d/compare-eax-and 0/imm32 -3291 74/jump-if-equal break/disp8 -3292 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr -3293 e9/jump $emit-subx-statement:end/disp32 -3294 } -3295 # else abort -3296 e9/jump $emit-subx-statement:abort/disp32 -3297 $emit-subx-statement:end: -3298 # . restore registers -3299 59/pop-to-ecx -3300 58/pop-to-eax -3301 # . epilogue -3302 89/<- %esp 5/r32/ebp -3303 5d/pop-to-ebp -3304 c3/return -3305 -3306 $emit-subx-statement:abort: -3307 # error("couldn't translate '" stmt "'\n") -3308 (write-buffered Stderr "couldn't translate '") -3309 #? (emit-string Stderr *(ebp+0xc)) # TODO -3310 (write-buffered Stderr "'\n") -3311 (flush Stderr) -3312 # . syscall(exit, 1) -3313 bb/copy-to-ebx 1/imm32 -3314 b8/copy-to-eax 1/imm32/exit -3315 cd/syscall 0x80/imm8 -3316 # never gets here -3317 -3318 # Primitives supported -3319 # For each operation, put variants with hard-coded registers before flexible ones. -3320 == data -3321 Primitives: -3322 # - increment/decrement -3323 _Primitive-inc-eax: -3324 # var/eax <- increment => 40/increment-eax -3325 "increment"/imm32/name -3326 0/imm32/no-inouts -3327 Single-int-var-in-eax/imm32/outputs -3328 "40/increment-eax"/imm32/subx-name -3329 0/imm32/no-rm32 -3330 0/imm32/no-r32 -3331 0/imm32/no-imm32 -3332 0/imm32/output-is-write-only -3333 _Primitive-inc-ecx/imm32/next -3334 _Primitive-inc-ecx: -3335 # var/ecx <- increment => 41/increment-ecx -3336 "increment"/imm32/name -3337 0/imm32/no-inouts -3338 Single-int-var-in-ecx/imm32/outputs -3339 "41/increment-ecx"/imm32/subx-name -3340 0/imm32/no-rm32 -3341 0/imm32/no-r32 -3342 0/imm32/no-imm32 -3343 0/imm32/output-is-write-only -3344 _Primitive-inc-edx/imm32/next -3345 _Primitive-inc-edx: -3346 # var/edx <- increment => 42/increment-edx -3347 "increment"/imm32/name -3348 0/imm32/no-inouts -3349 Single-int-var-in-edx/imm32/outputs -3350 "42/increment-edx"/imm32/subx-name -3351 0/imm32/no-rm32 -3352 0/imm32/no-r32 -3353 0/imm32/no-imm32 -3354 0/imm32/output-is-write-only -3355 _Primitive-inc-ebx/imm32/next -3356 _Primitive-inc-ebx: -3357 # var/ebx <- increment => 43/increment-ebx -3358 "increment"/imm32/name -3359 0/imm32/no-inouts -3360 Single-int-var-in-ebx/imm32/outputs -3361 "43/increment-ebx"/imm32/subx-name -3362 0/imm32/no-rm32 -3363 0/imm32/no-r32 -3364 0/imm32/no-imm32 -3365 0/imm32/output-is-write-only -3366 _Primitive-inc-esi/imm32/next -3367 _Primitive-inc-esi: -3368 # var/esi <- increment => 46/increment-esi -3369 "increment"/imm32/name -3370 0/imm32/no-inouts -3371 Single-int-var-in-esi/imm32/outputs -3372 "46/increment-esi"/imm32/subx-name -3373 0/imm32/no-rm32 -3374 0/imm32/no-r32 -3375 0/imm32/no-imm32 -3376 0/imm32/output-is-write-only -3377 _Primitive-inc-edi/imm32/next -3378 _Primitive-inc-edi: -3379 # var/edi <- increment => 47/increment-edi -3380 "increment"/imm32/name -3381 0/imm32/no-inouts -3382 Single-int-var-in-edi/imm32/outputs -3383 "47/increment-edi"/imm32/subx-name -3384 0/imm32/no-rm32 -3385 0/imm32/no-r32 -3386 0/imm32/no-imm32 -3387 0/imm32/output-is-write-only -3388 _Primitive-dec-eax/imm32/next -3389 _Primitive-dec-eax: -3390 # var/eax <- decrement => 48/decrement-eax -3391 "decrement"/imm32/name -3392 0/imm32/no-inouts -3393 Single-int-var-in-eax/imm32/outputs -3394 "48/decrement-eax"/imm32/subx-name -3395 0/imm32/no-rm32 -3396 0/imm32/no-r32 -3397 0/imm32/no-imm32 -3398 0/imm32/output-is-write-only -3399 _Primitive-dec-ecx/imm32/next -3400 _Primitive-dec-ecx: -3401 # var/ecx <- decrement => 49/decrement-ecx -3402 "decrement"/imm32/name -3403 0/imm32/no-inouts -3404 Single-int-var-in-ecx/imm32/outputs -3405 "49/decrement-ecx"/imm32/subx-name -3406 0/imm32/no-rm32 -3407 0/imm32/no-r32 -3408 0/imm32/no-imm32 -3409 0/imm32/output-is-write-only -3410 _Primitive-dec-edx/imm32/next -3411 _Primitive-dec-edx: -3412 # var/edx <- decrement => 4a/decrement-edx -3413 "decrement"/imm32/name -3414 0/imm32/no-inouts -3415 Single-int-var-in-edx/imm32/outputs -3416 "4a/decrement-edx"/imm32/subx-name -3417 0/imm32/no-rm32 -3418 0/imm32/no-r32 -3419 0/imm32/no-imm32 -3420 0/imm32/output-is-write-only -3421 _Primitive-dec-ebx/imm32/next -3422 _Primitive-dec-ebx: -3423 # var/ebx <- decrement => 4b/decrement-ebx -3424 "decrement"/imm32/name -3425 0/imm32/no-inouts -3426 Single-int-var-in-ebx/imm32/outputs -3427 "4b/decrement-ebx"/imm32/subx-name -3428 0/imm32/no-rm32 -3429 0/imm32/no-r32 -3430 0/imm32/no-imm32 -3431 0/imm32/output-is-write-only -3432 _Primitive-dec-esi/imm32/next -3433 _Primitive-dec-esi: -3434 # var/esi <- decrement => 4e/decrement-esi -3435 "decrement"/imm32/name -3436 0/imm32/no-inouts -3437 Single-int-var-in-esi/imm32/outputs -3438 "4e/decrement-esi"/imm32/subx-name -3439 0/imm32/no-rm32 -3440 0/imm32/no-r32 -3441 0/imm32/no-imm32 -3442 0/imm32/output-is-write-only -3443 _Primitive-dec-edi/imm32/next -3444 _Primitive-dec-edi: -3445 # var/edi <- decrement => 4f/decrement-edi -3446 "decrement"/imm32/name -3447 0/imm32/no-inouts -3448 Single-int-var-in-edi/imm32/outputs -3449 "4f/decrement-edi"/imm32/subx-name -3450 0/imm32/no-rm32 -3451 0/imm32/no-r32 -3452 0/imm32/no-imm32 -3453 0/imm32/output-is-write-only -3454 _Primitive-inc-mem/imm32/next -3455 _Primitive-inc-mem: -3456 # increment var => ff 0/subop/increment *(ebp+__) -3457 "increment"/imm32/name -3458 Single-int-var-on-stack/imm32/inouts -3459 0/imm32/no-outputs -3460 "ff 0/subop/increment"/imm32/subx-name -3461 1/imm32/rm32-is-first-inout -3462 0/imm32/no-r32 -3463 0/imm32/no-imm32 -3464 0/imm32/output-is-write-only -3465 _Primitive-inc-reg/imm32/next -3466 _Primitive-inc-reg: -3467 # var/reg <- increment => ff 0/subop/increment %__ -3468 "increment"/imm32/name -3469 0/imm32/no-inouts -3470 Single-int-var-in-some-register/imm32/outputs -3471 "ff 0/subop/increment"/imm32/subx-name -3472 3/imm32/rm32-is-first-output -3473 0/imm32/no-r32 -3474 0/imm32/no-imm32 -3475 0/imm32/output-is-write-only -3476 _Primitive-dec-mem/imm32/next -3477 _Primitive-dec-mem: -3478 # decrement var => ff 1/subop/decrement *(ebp+__) -3479 "decrement"/imm32/name -3480 Single-int-var-on-stack/imm32/inouts -3481 0/imm32/no-outputs -3482 "ff 1/subop/decrement"/imm32/subx-name -3483 1/imm32/rm32-is-first-inout -3484 0/imm32/no-r32 -3485 0/imm32/no-imm32 -3486 0/imm32/output-is-write-only -3487 _Primitive-dec-reg/imm32/next -3488 _Primitive-dec-reg: -3489 # var/reg <- decrement => ff 1/subop/decrement %__ -3490 "decrement"/imm32/name -3491 0/imm32/no-inouts -3492 Single-int-var-in-some-register/imm32/outputs -3493 "ff 1/subop/decrement"/imm32/subx-name -3494 3/imm32/rm32-is-first-output -3495 0/imm32/no-r32 -3496 0/imm32/no-imm32 -3497 0/imm32/output-is-write-only -3498 _Primitive-add-to-eax/imm32/next -3499 # - add -3500 _Primitive-add-to-eax: -3501 # var/eax <- add lit => 05/add-to-eax lit/imm32 -3502 "add"/imm32/name -3503 Single-lit-var/imm32/inouts -3504 Single-int-var-in-eax/imm32/outputs -3505 "05/add-to-eax"/imm32/subx-name -3506 0/imm32/no-rm32 -3507 0/imm32/no-r32 -3508 1/imm32/imm32-is-first-inout -3509 0/imm32/output-is-write-only -3510 _Primitive-add-reg-to-reg/imm32/next -3511 _Primitive-add-reg-to-reg: -3512 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 -3513 "add"/imm32/name -3514 Single-int-var-in-some-register/imm32/inouts -3515 Single-int-var-in-some-register/imm32/outputs -3516 "01/add-to"/imm32/subx-name -3517 3/imm32/rm32-is-first-output -3518 1/imm32/r32-is-first-inout -3519 0/imm32/no-imm32 -3520 0/imm32/output-is-write-only -3521 _Primitive-add-reg-to-mem/imm32/next -3522 _Primitive-add-reg-to-mem: -3523 # add-to var1 var2/reg => 01/add-to var1 var2/r32 -3524 "add-to"/imm32/name -3525 Int-var-and-second-int-var-in-some-register/imm32/inouts -3526 0/imm32/outputs -3527 "01/add-to"/imm32/subx-name -3528 1/imm32/rm32-is-first-inout -3529 2/imm32/r32-is-second-inout -3530 0/imm32/no-imm32 -3531 0/imm32/output-is-write-only -3532 _Primitive-add-mem-to-reg/imm32/next -3533 _Primitive-add-mem-to-reg: -3534 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 -3535 "add"/imm32/name -3536 Single-int-var-on-stack/imm32/inouts -3537 Single-int-var-in-some-register/imm32/outputs -3538 "03/add"/imm32/subx-name -3539 1/imm32/rm32-is-first-inout -3540 3/imm32/r32-is-first-output -3541 0/imm32/no-imm32 -3542 0/imm32/output-is-write-only -3543 _Primitive-add-lit-to-reg/imm32/next -3544 _Primitive-add-lit-to-reg: -3545 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 -3546 "add"/imm32/name -3547 Single-lit-var/imm32/inouts -3548 Single-int-var-in-some-register/imm32/outputs -3549 "81 0/subop/add"/imm32/subx-name -3550 3/imm32/rm32-is-first-output -3551 0/imm32/no-r32 -3552 1/imm32/imm32-is-first-inout -3553 0/imm32/output-is-write-only -3554 _Primitive-add-lit-to-mem/imm32/next -3555 _Primitive-add-lit-to-mem: -3556 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 -3557 "add-to"/imm32/name -3558 Int-var-and-literal/imm32/inouts -3559 0/imm32/outputs -3560 "81 0/subop/add"/imm32/subx-name -3561 1/imm32/rm32-is-first-inout -3562 0/imm32/no-r32 -3563 2/imm32/imm32-is-first-inout -3564 0/imm32/output-is-write-only -3565 _Primitive-subtract-from-eax/imm32/next -3566 # - subtract -3567 _Primitive-subtract-from-eax: -3568 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 -3569 "subtract"/imm32/name -3570 Single-lit-var/imm32/inouts -3571 Single-int-var-in-eax/imm32/outputs -3572 "2d/subtract-from-eax"/imm32/subx-name -3573 0/imm32/no-rm32 -3574 0/imm32/no-r32 -3575 1/imm32/imm32-is-first-inout -3576 0/imm32/output-is-write-only -3577 _Primitive-subtract-reg-from-reg/imm32/next -3578 _Primitive-subtract-reg-from-reg: -3579 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 -3580 "subtract"/imm32/name -3581 Single-int-var-in-some-register/imm32/inouts -3582 Single-int-var-in-some-register/imm32/outputs -3583 "29/subtract-from"/imm32/subx-name -3584 3/imm32/rm32-is-first-output -3585 1/imm32/r32-is-first-inout -3586 0/imm32/no-imm32 -3587 0/imm32/output-is-write-only -3588 _Primitive-subtract-reg-from-mem/imm32/next -3589 _Primitive-subtract-reg-from-mem: -3590 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 -3591 "subtract-from"/imm32/name -3592 Int-var-and-second-int-var-in-some-register/imm32/inouts -3593 0/imm32/outputs -3594 "29/subtract-from"/imm32/subx-name -3595 1/imm32/rm32-is-first-inout -3596 2/imm32/r32-is-second-inout -3597 0/imm32/no-imm32 -3598 0/imm32/output-is-write-only -3599 _Primitive-subtract-mem-from-reg/imm32/next -3600 _Primitive-subtract-mem-from-reg: -3601 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 -3602 "subtract"/imm32/name -3603 Single-int-var-on-stack/imm32/inouts -3604 Single-int-var-in-some-register/imm32/outputs -3605 "2b/subtract"/imm32/subx-name -3606 1/imm32/rm32-is-first-inout -3607 3/imm32/r32-is-first-output -3608 0/imm32/no-imm32 -3609 0/imm32/output-is-write-only -3610 _Primitive-subtract-lit-from-reg/imm32/next -3611 _Primitive-subtract-lit-from-reg: -3612 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 -3613 "subtract"/imm32/name -3614 Single-lit-var/imm32/inouts -3615 Single-int-var-in-some-register/imm32/outputs -3616 "81 5/subop/subtract"/imm32/subx-name -3617 3/imm32/rm32-is-first-output -3618 0/imm32/no-r32 -3619 1/imm32/imm32-is-first-inout -3620 0/imm32/output-is-write-only -3621 _Primitive-subtract-lit-from-mem/imm32/next -3622 _Primitive-subtract-lit-from-mem: -3623 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 -3624 "subtract-from"/imm32/name -3625 Int-var-and-literal/imm32/inouts -3626 0/imm32/outputs -3627 "81 5/subop/subtract"/imm32/subx-name -3628 1/imm32/rm32-is-first-inout -3629 0/imm32/no-r32 -3630 2/imm32/imm32-is-first-inout -3631 0/imm32/output-is-write-only -3632 _Primitive-and-with-eax/imm32/next -3633 # - and -3634 _Primitive-and-with-eax: -3635 # var/eax <- and lit => 25/and-with-eax lit/imm32 -3636 "and"/imm32/name -3637 Single-lit-var/imm32/inouts -3638 Single-int-var-in-eax/imm32/outputs -3639 "25/and-with-eax"/imm32/subx-name -3640 0/imm32/no-rm32 -3641 0/imm32/no-r32 -3642 1/imm32/imm32-is-first-inout -3643 0/imm32/output-is-write-only -3644 _Primitive-and-reg-with-reg/imm32/next -3645 _Primitive-and-reg-with-reg: -3646 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 -3647 "and"/imm32/name -3648 Single-int-var-in-some-register/imm32/inouts -3649 Single-int-var-in-some-register/imm32/outputs -3650 "21/and-with"/imm32/subx-name -3651 3/imm32/rm32-is-first-output -3652 1/imm32/r32-is-first-inout -3653 0/imm32/no-imm32 -3654 0/imm32/output-is-write-only -3655 _Primitive-and-reg-with-mem/imm32/next -3656 _Primitive-and-reg-with-mem: -3657 # and-with var1 var2/reg => 21/and-with var1 var2/r32 -3658 "and-with"/imm32/name -3659 Int-var-and-second-int-var-in-some-register/imm32/inouts -3660 0/imm32/outputs -3661 "21/and-with"/imm32/subx-name -3662 1/imm32/rm32-is-first-inout -3663 2/imm32/r32-is-second-inout -3664 0/imm32/no-imm32 -3665 0/imm32/output-is-write-only -3666 _Primitive-and-mem-with-reg/imm32/next -3667 _Primitive-and-mem-with-reg: -3668 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 -3669 "and"/imm32/name -3670 Single-int-var-on-stack/imm32/inouts -3671 Single-int-var-in-some-register/imm32/outputs -3672 "23/and"/imm32/subx-name -3673 1/imm32/rm32-is-first-inout -3674 3/imm32/r32-is-first-output -3675 0/imm32/no-imm32 -3676 0/imm32/output-is-write-only -3677 _Primitive-and-lit-with-reg/imm32/next -3678 _Primitive-and-lit-with-reg: -3679 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 -3680 "and"/imm32/name -3681 Single-lit-var/imm32/inouts -3682 Single-int-var-in-some-register/imm32/outputs -3683 "81 4/subop/and"/imm32/subx-name -3684 3/imm32/rm32-is-first-output -3685 0/imm32/no-r32 -3686 1/imm32/imm32-is-first-inout -3687 0/imm32/output-is-write-only -3688 _Primitive-and-lit-with-mem/imm32/next -3689 _Primitive-and-lit-with-mem: -3690 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 -3691 "and-with"/imm32/name -3692 Int-var-and-literal/imm32/inouts -3693 0/imm32/outputs -3694 "81 4/subop/and"/imm32/subx-name -3695 1/imm32/rm32-is-first-inout -3696 0/imm32/no-r32 -3697 2/imm32/imm32-is-first-inout -3698 0/imm32/output-is-write-only -3699 _Primitive-or-with-eax/imm32/next -3700 # - or -3701 _Primitive-or-with-eax: -3702 # var/eax <- or lit => 0d/or-with-eax lit/imm32 -3703 "or"/imm32/name -3704 Single-lit-var/imm32/inouts -3705 Single-int-var-in-eax/imm32/outputs -3706 "0d/or-with-eax"/imm32/subx-name -3707 0/imm32/no-rm32 -3708 0/imm32/no-r32 -3709 1/imm32/imm32-is-first-inout -3710 0/imm32/output-is-write-only -3711 _Primitive-or-reg-with-reg/imm32/next -3712 _Primitive-or-reg-with-reg: -3713 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 -3714 "or"/imm32/name -3715 Single-int-var-in-some-register/imm32/inouts -3716 Single-int-var-in-some-register/imm32/outputs -3717 "09/or-with"/imm32/subx-name -3718 3/imm32/rm32-is-first-output -3719 1/imm32/r32-is-first-inout -3720 0/imm32/no-imm32 -3721 0/imm32/output-is-write-only -3722 _Primitive-or-reg-with-mem/imm32/next -3723 _Primitive-or-reg-with-mem: -3724 # or-with var1 var2/reg => 09/or-with var1 var2/r32 -3725 "or-with"/imm32/name -3726 Int-var-and-second-int-var-in-some-register/imm32/inouts -3727 0/imm32/outputs -3728 "09/or-with"/imm32/subx-name -3729 1/imm32/rm32-is-first-inout -3730 2/imm32/r32-is-second-inout -3731 0/imm32/no-imm32 -3732 0/imm32/output-is-write-only -3733 _Primitive-or-mem-with-reg/imm32/next -3734 _Primitive-or-mem-with-reg: -3735 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 -3736 "or"/imm32/name -3737 Single-int-var-on-stack/imm32/inouts -3738 Single-int-var-in-some-register/imm32/outputs -3739 "0b/or"/imm32/subx-name -3740 1/imm32/rm32-is-first-inout -3741 3/imm32/r32-is-first-output -3742 0/imm32/no-imm32 -3743 0/imm32/output-is-write-only -3744 _Primitive-or-lit-with-reg/imm32/next -3745 _Primitive-or-lit-with-reg: -3746 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 -3747 "or"/imm32/name -3748 Single-lit-var/imm32/inouts -3749 Single-int-var-in-some-register/imm32/outputs -3750 "81 4/subop/or"/imm32/subx-name -3751 3/imm32/rm32-is-first-output -3752 0/imm32/no-r32 -3753 1/imm32/imm32-is-first-inout -3754 0/imm32/output-is-write-only -3755 _Primitive-or-lit-with-mem/imm32/next -3756 _Primitive-or-lit-with-mem: -3757 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 -3758 "or-with"/imm32/name -3759 Int-var-and-literal/imm32/inouts -3760 0/imm32/outputs -3761 "81 4/subop/or"/imm32/subx-name -3762 1/imm32/rm32-is-first-inout -3763 0/imm32/no-r32 -3764 2/imm32/imm32-is-first-inout -3765 0/imm32/output-is-write-only -3766 _Primitive-xor-with-eax/imm32/next -3767 # - xor -3768 _Primitive-xor-with-eax: -3769 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 -3770 "xor"/imm32/name -3771 Single-lit-var/imm32/inouts -3772 Single-int-var-in-eax/imm32/outputs -3773 "35/xor-with-eax"/imm32/subx-name -3774 0/imm32/no-rm32 -3775 0/imm32/no-r32 -3776 1/imm32/imm32-is-first-inout -3777 0/imm32/output-is-write-only -3778 _Primitive-xor-reg-with-reg/imm32/next -3779 _Primitive-xor-reg-with-reg: -3780 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 -3781 "xor"/imm32/name -3782 Single-int-var-in-some-register/imm32/inouts -3783 Single-int-var-in-some-register/imm32/outputs -3784 "31/xor-with"/imm32/subx-name -3785 3/imm32/rm32-is-first-output -3786 1/imm32/r32-is-first-inout -3787 0/imm32/no-imm32 -3788 0/imm32/output-is-write-only -3789 _Primitive-xor-reg-with-mem/imm32/next -3790 _Primitive-xor-reg-with-mem: -3791 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 -3792 "xor-with"/imm32/name -3793 Int-var-and-second-int-var-in-some-register/imm32/inouts -3794 0/imm32/outputs -3795 "31/xor-with"/imm32/subx-name -3796 1/imm32/rm32-is-first-inout -3797 2/imm32/r32-is-second-inout -3798 0/imm32/no-imm32 -3799 0/imm32/output-is-write-only -3800 _Primitive-xor-mem-with-reg/imm32/next -3801 _Primitive-xor-mem-with-reg: -3802 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 -3803 "xor"/imm32/name -3804 Single-int-var-on-stack/imm32/inouts -3805 Single-int-var-in-some-register/imm32/outputs -3806 "33/xor"/imm32/subx-name -3807 1/imm32/rm32-is-first-inout -3808 3/imm32/r32-is-first-output -3809 0/imm32/no-imm32 -3810 0/imm32/output-is-write-only -3811 _Primitive-xor-lit-with-reg/imm32/next -3812 _Primitive-xor-lit-with-reg: -3813 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 -3814 "xor"/imm32/name -3815 Single-lit-var/imm32/inouts -3816 Single-int-var-in-some-register/imm32/outputs -3817 "81 4/subop/xor"/imm32/subx-name -3818 3/imm32/rm32-is-first-output -3819 0/imm32/no-r32 -3820 1/imm32/imm32-is-first-inout -3821 0/imm32/output-is-write-only -3822 _Primitive-xor-lit-with-mem/imm32/next -3823 _Primitive-xor-lit-with-mem: -3824 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 -3825 "xor-with"/imm32/name -3826 Int-var-and-literal/imm32/inouts -3827 0/imm32/outputs -3828 "81 4/subop/xor"/imm32/subx-name -3829 1/imm32/rm32-is-first-inout -3830 0/imm32/no-r32 -3831 2/imm32/imm32-is-first-inout -3832 0/imm32/output-is-write-only -3833 _Primitive-copy-to-eax/imm32/next -3834 # - copy -3835 _Primitive-copy-to-eax: -3836 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 -3837 "copy"/imm32/name -3838 Single-lit-var/imm32/inouts -3839 Single-int-var-in-eax/imm32/outputs -3840 "b8/copy-to-eax"/imm32/subx-name -3841 0/imm32/no-rm32 -3842 0/imm32/no-r32 -3843 1/imm32/imm32-is-first-inout -3844 1/imm32/output-is-write-only -3845 _Primitive-copy-to-ecx/imm32/next -3846 _Primitive-copy-to-ecx: -3847 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 -3848 "copy"/imm32/name -3849 Single-lit-var/imm32/inouts -3850 Single-int-var-in-ecx/imm32/outputs -3851 "b9/copy-to-ecx"/imm32/subx-name -3852 0/imm32/no-rm32 -3853 0/imm32/no-r32 -3854 1/imm32/imm32-is-first-inout -3855 1/imm32/output-is-write-only -3856 _Primitive-copy-to-edx/imm32/next -3857 _Primitive-copy-to-edx: -3858 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 -3859 "copy"/imm32/name -3860 Single-lit-var/imm32/inouts -3861 Single-int-var-in-edx/imm32/outputs -3862 "ba/copy-to-edx"/imm32/subx-name -3863 0/imm32/no-rm32 -3864 0/imm32/no-r32 -3865 1/imm32/imm32-is-first-inout -3866 1/imm32/output-is-write-only -3867 _Primitive-copy-to-ebx/imm32/next -3868 _Primitive-copy-to-ebx: -3869 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 -3870 "copy"/imm32/name -3871 Single-lit-var/imm32/inouts -3872 Single-int-var-in-ebx/imm32/outputs -3873 "bb/copy-to-ebx"/imm32/subx-name -3874 0/imm32/no-rm32 -3875 0/imm32/no-r32 -3876 1/imm32/imm32-is-first-inout -3877 1/imm32/output-is-write-only -3878 _Primitive-copy-to-esi/imm32/next -3879 _Primitive-copy-to-esi: -3880 # var/esi <- copy lit => be/copy-to-esi lit/imm32 -3881 "copy"/imm32/name -3882 Single-lit-var/imm32/inouts -3883 Single-int-var-in-esi/imm32/outputs -3884 "be/copy-to-esi"/imm32/subx-name -3885 0/imm32/no-rm32 -3886 0/imm32/no-r32 -3887 1/imm32/imm32-is-first-inout -3888 1/imm32/output-is-write-only -3889 _Primitive-copy-to-edi/imm32/next -3890 _Primitive-copy-to-edi: -3891 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 -3892 "copy"/imm32/name -3893 Single-lit-var/imm32/inouts -3894 Single-int-var-in-edi/imm32/outputs -3895 "bf/copy-to-edi"/imm32/subx-name -3896 0/imm32/no-rm32 -3897 0/imm32/no-r32 -3898 1/imm32/imm32-is-first-inout -3899 1/imm32/output-is-write-only -3900 _Primitive-copy-reg-to-reg/imm32/next -3901 _Primitive-copy-reg-to-reg: -3902 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 -3903 "copy"/imm32/name -3904 Single-int-var-in-some-register/imm32/inouts -3905 Single-int-var-in-some-register/imm32/outputs -3906 "89/copy-to"/imm32/subx-name -3907 3/imm32/rm32-is-first-output -3908 1/imm32/r32-is-first-inout -3909 0/imm32/no-imm32 -3910 1/imm32/output-is-write-only -3911 _Primitive-copy-reg-to-mem/imm32/next -3912 _Primitive-copy-reg-to-mem: -3913 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 -3914 "copy-to"/imm32/name -3915 Int-var-and-second-int-var-in-some-register/imm32/inouts -3916 0/imm32/outputs -3917 "89/copy-to"/imm32/subx-name -3918 1/imm32/rm32-is-first-inout -3919 2/imm32/r32-is-second-inout -3920 0/imm32/no-imm32 -3921 1/imm32/output-is-write-only -3922 _Primitive-copy-mem-to-reg/imm32/next -3923 _Primitive-copy-mem-to-reg: -3924 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 -3925 "copy"/imm32/name -3926 Single-int-var-on-stack/imm32/inouts -3927 Single-int-var-in-some-register/imm32/outputs -3928 "8b/copy-from"/imm32/subx-name -3929 1/imm32/rm32-is-first-inout -3930 3/imm32/r32-is-first-output -3931 0/imm32/no-imm32 -3932 1/imm32/output-is-write-only -3933 _Primitive-copy-lit-to-reg/imm32/next -3934 _Primitive-copy-lit-to-reg: -3935 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 -3936 "copy"/imm32/name -3937 Single-lit-var/imm32/inouts -3938 Single-int-var-in-some-register/imm32/outputs -3939 "c7 0/subop/copy"/imm32/subx-name -3940 3/imm32/rm32-is-first-output -3941 0/imm32/no-r32 -3942 1/imm32/imm32-is-first-inout -3943 1/imm32/output-is-write-only -3944 _Primitive-copy-lit-to-mem/imm32/next -3945 _Primitive-copy-lit-to-mem: -3946 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 -3947 "copy-to"/imm32/name -3948 Int-var-and-literal/imm32/inouts -3949 0/imm32/outputs -3950 "c7 0/subop/copy"/imm32/subx-name -3951 1/imm32/rm32-is-first-inout -3952 0/imm32/no-r32 -3953 2/imm32/imm32-is-first-inout -3954 1/imm32/output-is-write-only -3955 0/imm32/next -3956 -3957 Single-int-var-on-stack: -3958 Int-var-on-stack/imm32 -3959 0/imm32/next -3960 -3961 Int-var-on-stack: -3962 "arg1"/imm32/name -3963 1/imm32/type-int -3964 1/imm32/some-block-depth -3965 1/imm32/some-stack-offset -3966 0/imm32/no-register -3967 -3968 Int-var-and-second-int-var-in-some-register: -3969 Int-var-on-stack/imm32 -3970 Single-int-var-in-some-register/imm32/next -3971 -3972 Int-var-and-literal: -3973 Int-var-on-stack/imm32 -3974 Single-lit-var/imm32/next -3975 -3976 Single-int-var-in-some-register: -3977 Int-var-in-some-register/imm32 -3978 0/imm32/next -3979 -3980 Int-var-in-some-register: -3981 "arg1"/imm32/name -3982 1/imm32/type-int -3983 1/imm32/some-block-depth -3984 0/imm32/no-stack-offset -3985 "*"/imm32/register -3986 -3987 Single-int-var-in-eax: -3988 Int-var-in-eax/imm32 -3989 0/imm32/next -3990 -3991 Int-var-in-eax: -3992 "arg1"/imm32/name -3993 1/imm32/type-int -3994 1/imm32/some-block-depth -3995 0/imm32/no-stack-offset -3996 "eax"/imm32/register -3997 -3998 Single-int-var-in-ecx: -3999 Int-var-in-ecx/imm32 -4000 0/imm32/next -4001 -4002 Int-var-in-ecx: -4003 "arg1"/imm32/name -4004 1/imm32/type-int -4005 1/imm32/some-block-depth -4006 0/imm32/no-stack-offset -4007 "ecx"/imm32/register -4008 -4009 Single-int-var-in-edx: -4010 Int-var-in-edx/imm32 -4011 0/imm32/next -4012 -4013 Int-var-in-edx: -4014 "arg1"/imm32/name -4015 1/imm32/type-int -4016 1/imm32/some-block-depth -4017 0/imm32/no-stack-offset -4018 "edx"/imm32/register -4019 -4020 Single-int-var-in-ebx: -4021 Int-var-in-ebx/imm32 -4022 0/imm32/next -4023 -4024 Int-var-in-ebx: -4025 "arg1"/imm32/name -4026 1/imm32/type-int -4027 1/imm32/some-block-depth -4028 0/imm32/no-stack-offset -4029 "ebx"/imm32/register -4030 -4031 Single-int-var-in-esi: -4032 Int-var-in-esi/imm32 -4033 0/imm32/next -4034 -4035 Int-var-in-esi: -4036 "arg1"/imm32/name -4037 1/imm32/type-int -4038 1/imm32/some-block-depth -4039 0/imm32/no-stack-offset -4040 "esi"/imm32/register -4041 -4042 Single-int-var-in-edi: -4043 Int-var-in-edi/imm32 -4044 0/imm32/next -4045 -4046 Int-var-in-edi: -4047 "arg1"/imm32/name -4048 1/imm32/type-int -4049 1/imm32/some-block-depth -4050 0/imm32/no-stack-offset -4051 "edi"/imm32/register -4052 -4053 Single-lit-var: -4054 Lit-var/imm32 -4055 0/imm32/next -4056 -4057 Lit-var: -4058 "literal"/imm32/name -4059 0/imm32/type-literal -4060 1/imm32/some-block-depth -4061 0/imm32/no-stack-offset -4062 0/imm32/no-register -4063 -4064 == code -4065 emit-subx-primitive: # out : (addr buffered-file), stmt : (handle statement), primitive : (handle function) -4066 # . prologue -4067 55/push-ebp -4068 89/<- %ebp 4/r32/esp -4069 # . save registers -4070 50/push-eax -4071 51/push-ecx -4072 # ecx = primitive -4073 8b/-> *(ebp+0x10) 1/r32/ecx -4074 # emit primitive name -4075 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name -4076 # emit rm32 if necessary -4077 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt -4078 # emit r32 if necessary -4079 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt -4080 # emit imm32 if necessary -4081 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt -4082 $emit-subx-primitive:end: -4083 # . restore registers -4084 59/pop-to-ecx -4085 58/pop-to-eax -4086 # . epilogue -4087 89/<- %esp 5/r32/ebp -4088 5d/pop-to-ebp -4089 c3/return -4090 -4091 emit-subx-rm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) -4092 # . prologue -4093 55/push-ebp -4094 89/<- %ebp 4/r32/esp -4095 # . save registers -4096 50/push-eax -4097 # if (l == 0) return -4098 81 7/subop/compare *(ebp+0xc) 0/imm32 -4099 74/jump-if-equal $emit-subx-rm32:end/disp8 -4100 # -4101 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4102 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var -4103 $emit-subx-rm32:end: -4104 # . restore registers -4105 58/pop-to-eax -4106 # . epilogue -4107 89/<- %esp 5/r32/ebp -4108 5d/pop-to-ebp -4109 c3/return -4110 -4111 get-stmt-operand-from-arg-location: # stmt : (handle statement), l : arg-location -> var/eax : (handle variable) -4112 # . prologue -4113 55/push-ebp -4114 89/<- %ebp 4/r32/esp -4115 # . save registers -4116 51/push-ecx -4117 # eax = l -4118 8b/-> *(ebp+0xc) 0/r32/eax -4119 # ecx = stmt -4120 8b/-> *(ebp+8) 1/r32/ecx -4121 # if (l == 1) return stmt->inouts->var -4122 { -4123 3d/compare-eax-and 1/imm32 -4124 75/jump-if-not-equal break/disp8 -4125 $get-stmt-operand-from-arg-location:1: -4126 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -4127 8b/-> *eax 0/r32/eax # Operand-var -4128 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4129 } -4130 # if (l == 2) return stmt->inouts->next->var -4131 { -4132 3d/compare-eax-and 2/imm32 -4133 75/jump-if-not-equal break/disp8 -4134 $get-stmt-operand-from-arg-location:2: -4135 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts -4136 8b/-> *(eax+4) 0/r32/eax # Operand-next -4137 8b/-> *eax 0/r32/eax # Operand-var -4138 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4139 } -4140 # if (l == 3) return stmt->outputs -4141 { -4142 3d/compare-eax-and 3/imm32 -4143 75/jump-if-not-equal break/disp8 -4144 $get-stmt-operand-from-arg-location:3: -4145 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs -4146 8b/-> *eax 0/r32/eax # Operand-var -4147 eb/jump $get-stmt-operand-from-arg-location:end/disp8 -4148 } -4149 # abort -4150 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 -4151 $get-stmt-operand-from-arg-location:end: -4152 # . restore registers -4153 59/pop-to-ecx -4154 # . epilogue -4155 89/<- %esp 5/r32/ebp -4156 5d/pop-to-ebp -4157 c3/return -4158 -4159 $get-stmt-operand-from-arg-location:abort: -4160 # error("invalid arg-location " eax) -4161 (write-buffered Stderr "invalid arg-location ") -4162 (print-int32-buffered Stderr %eax) -4163 (write-buffered Stderr "\n") -4164 (flush Stderr) -4165 # . syscall(exit, 1) -4166 bb/copy-to-ebx 1/imm32 -4167 b8/copy-to-eax 1/imm32/exit -4168 cd/syscall 0x80/imm8 -4169 # never gets here -4170 -4171 emit-subx-r32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) -4172 # . prologue -4173 55/push-ebp -4174 89/<- %ebp 4/r32/esp -4175 # . save registers -4176 50/push-eax -4177 51/push-ecx -4178 # if (location == 0) return -4179 81 7/subop/compare *(ebp+0xc) 0/imm32 -4180 0f 84/jump-if-equal $emit-subx-r32:end/disp32 -4181 # -4182 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4183 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (addr register-index) -4184 (write-buffered *(ebp+8) Space) -4185 (print-int32-buffered *(ebp+8) *eax) -4186 (write-buffered *(ebp+8) "/r32") -4187 $emit-subx-r32:end: -4188 # . restore registers -4189 59/pop-to-ecx -4190 58/pop-to-eax -4191 # . epilogue -4192 89/<- %esp 5/r32/ebp -4193 5d/pop-to-ebp -4194 c3/return -4195 -4196 emit-subx-imm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) -4197 # . prologue -4198 55/push-ebp -4199 89/<- %ebp 4/r32/esp -4200 # . save registers -4201 50/push-eax -4202 51/push-ecx -4203 # if (location == 0) return -4204 81 7/subop/compare *(ebp+0xc) 0/imm32 -4205 74/jump-if-equal $emit-subx-imm32:end/disp8 -4206 # -4207 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax -4208 (write-buffered *(ebp+8) Space) -4209 (write-buffered *(ebp+8) *eax) # Var-name -4210 (write-buffered *(ebp+8) "/imm32") -4211 $emit-subx-imm32:end: -4212 # . restore registers -4213 59/pop-to-ecx -4214 58/pop-to-eax -4215 # . epilogue -4216 89/<- %esp 5/r32/ebp -4217 5d/pop-to-ebp -4218 c3/return -4219 -4220 emit-subx-call: # out : (addr buffered-file), stmt : (handle statement), callee : (handle function) -4221 # . prologue -4222 55/push-ebp -4223 89/<- %ebp 4/r32/esp -4224 # . save registers -4225 50/push-eax -4226 51/push-ecx -4227 # -4228 (write-buffered *(ebp+8) "(") -4229 # - emit function name -4230 8b/-> *(ebp+0x10) 1/r32/ecx -4231 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name -4232 # - emit arguments -4233 # var curr/ecx : (handle list var) = stmt->inouts -4234 8b/-> *(ebp+0xc) 1/r32/ecx -4235 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts -4236 { -4237 # if (curr == null) break -4238 81 7/subop/compare %ecx 0/imm32 -4239 74/jump-if-equal break/disp8 -4240 # -4241 (emit-subx-call-operand *(ebp+8) *ecx) -4242 # curr = curr->next -4243 8b/-> *(ecx+4) 1/r32/ecx -4244 eb/jump loop/disp8 -4245 } +2702 # return first 'name' from the top (back) of 'vars' and abort if not found +2703 lookup-var: # name: (addr slice), vars : (addr stack (handle var)) -> result/eax: (handle var) +2704 # . prologue +2705 55/push-ebp +2706 89/<- %ebp 4/r32/esp +2707 # var target/eax : (handle array byte) = slice-to-string(name) +2708 (slice-to-string Heap *(ebp+8)) # => eax +2709 # +2710 (lookup-var-helper %eax *(ebp+0xc)) # => eax +2711 # if (result == 0) abort +2712 3d/compare-eax-and 0/imm32 +2713 74/jump-if-equal $lookup-var:abort/disp8 +2714 $lookup-var:end: +2715 # . epilogue +2716 89/<- %esp 5/r32/ebp +2717 5d/pop-to-ebp +2718 c3/return +2719 +2720 $lookup-var:abort: +2721 (write-buffered Stderr "unknown variable '") +2722 (write-slice-buffered Stderr *(ebp+8)) +2723 (write-buffered Stderr "'\n") +2724 (flush Stderr) +2725 # . syscall(exit, 1) +2726 bb/copy-to-ebx 1/imm32 +2727 b8/copy-to-eax 1/imm32/exit +2728 cd/syscall 0x80/imm8 +2729 # never gets here +2730 +2731 # return first 'name' from the top (back) of 'vars', and 0/null if not found +2732 lookup-var-helper: # name: (addr array byte), vars : (addr stack (handle var)) -> result/eax: (handle var) +2733 # pseudocode: +2734 # var curr : (addr handle var) = &vars->data[vars->top - 4] +2735 # var min = vars->data +2736 # while curr >= min +2737 # var v : (handle var) = *curr +2738 # if v->name == name +2739 # return v +2740 # return 0 +2741 # +2742 # . prologue +2743 55/push-ebp +2744 89/<- %ebp 4/r32/esp +2745 # . save registers +2746 52/push-edx +2747 53/push-ebx +2748 56/push-esi +2749 # esi = vars +2750 8b/-> *(ebp+0xc) 6/r32/esi +2751 # ebx = vars->top +2752 8b/-> *esi 3/r32/ebx +2753 # if (vars->top > vars->length) abort +2754 3b/compare 0/r32/eax *(esi+4) +2755 0f 8f/jump-if-greater $lookup-var-helper:error1/disp32 +2756 # var min/edx : (addr handle var) = vars->data +2757 8d/copy-address *(esi+8) 2/r32/edx +2758 # var curr/ebx : (addr handle var) = &vars->data[vars->top - 4] +2759 81 5/subop/subtract %ebx 4/imm32 +2760 8d/copy-address *(esi+ebx+8) 3/r32/ebx +2761 { +2762 # if (curr < min) return 0 +2763 39/compare %ebx 2/r32/edx +2764 b8/copy-to-eax 0/imm32 +2765 0f 82/jump-if-lesser-unsigned break/disp32 +2766 # var v/eax : (handle var) = *curr +2767 8b/-> *ebx 0/r32/eax +2768 # if (v->name == name) return v +2769 (string-equal? *eax *(ebp+8)) # Var-name +2770 3d/compare-eax-and 0/imm32 +2771 8b/-> *ebx 0/r32/eax +2772 75/jump-if-not-equal break/disp8 +2773 # curr -= 4 +2774 81 5/subop/subtract %ebx 4/imm32 +2775 e9/jump loop/disp32 +2776 } +2777 $lookup-var-helper:end: +2778 # . restore registers +2779 5e/pop-to-esi +2780 5b/pop-to-ebx +2781 5a/pop-to-edx +2782 # . epilogue +2783 89/<- %esp 5/r32/ebp +2784 5d/pop-to-ebp +2785 c3/return +2786 +2787 $lookup-var-helper:error1: +2788 (write-buffered Stderr "malformed stack when looking up '") +2789 (write-slice-buffered Stderr *(ebp+8)) +2790 (write-buffered Stderr "'\n") +2791 (flush Stderr) +2792 # . syscall(exit, 1) +2793 bb/copy-to-ebx 1/imm32 +2794 b8/copy-to-eax 1/imm32/exit +2795 cd/syscall 0x80/imm8 +2796 # never gets here +2797 +2798 # return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found +2799 lookup-or-define-var: # name: (addr slice), vars : (addr stack (handle var)), fn : (handle function) -> result/eax: (handle var) +2800 # . prologue +2801 55/push-ebp +2802 89/<- %ebp 4/r32/esp +2803 # . save registers +2804 51/push-ecx +2805 # var target/ecx : (handle array byte) = slice-to-string(name) +2806 (slice-to-string Heap *(ebp+8)) # => eax +2807 89/<- %ecx 0/r32/eax +2808 # +2809 (lookup-var-helper *(ebp+8) *(ebp+0xc)) # => eax +2810 { +2811 # if (result != 0) return +2812 3d/compare-eax-and 0/imm32 +2813 75/jump-if-not-equal break/disp8 +2814 # if name is one of fn's outputs, return it +2815 { +2816 (find-in-function-outputs *(ebp+0x10) %ecx) # => eax +2817 3d/compare-eax-and 0/imm32 +2818 # otherwise abort +2819 0f 84/jump-if-not-equal $lookup-var:abort/disp32 +2820 } +2821 } +2822 $lookup-or-define-var:end: +2823 # . restore registers +2824 59/pop-to-ecx +2825 # . epilogue +2826 89/<- %esp 5/r32/ebp +2827 5d/pop-to-ebp +2828 c3/return +2829 +2830 find-in-function-outputs: # fn : (handle function), name : (handle array byte) => result/eax : (handle var) +2831 # . prologue +2832 55/push-ebp +2833 89/<- %ebp 4/r32/esp +2834 # . save registers +2835 51/push-ecx +2836 # var curr/ecx : (handle list var) = fn->outputs +2837 8b/-> *(ebp+8) 1/r32/ecx +2838 8b/-> *(ecx+0xc) 1/r32/ecx +2839 # while curr != null +2840 { +2841 81 7/subop/compare %ecx 0/imm32 +2842 74/jump-if-equal break/disp8 +2843 # var v : (handle var) = *curr +2844 8b/-> *ecx 0/r32/eax # List-value +2845 # if (curr->name == name) return curr +2846 50/push-eax +2847 (string-equal? *eax *(ebp+0xc)) +2848 3d/compare-eax-and 0/imm32 +2849 58/pop-to-eax +2850 75/jump-if-not-equal $find-in-function-outputs:end/disp8 +2851 # curr = curr->next +2852 8b/-> *(ecx+4) 1/r32/ecx # List-next +2853 eb/jump loop/disp8 +2854 } +2855 b8/copy-to-eax 0/imm32 +2856 $find-in-function-outputs:end: +2857 # . restore registers +2858 59/pop-to-ecx +2859 # . epilogue +2860 89/<- %esp 5/r32/ebp +2861 5d/pop-to-ebp +2862 c3/return +2863 +2864 test-parse-mu-stmt: +2865 # 'increment n' +2866 # . prologue +2867 55/push-ebp +2868 89/<- %ebp 4/r32/esp +2869 # setup +2870 (clear-stream _test-input-stream) +2871 (write _test-input-stream "increment n\n") +2872 # var vars/ecx : (stack (addr var) 4) +2873 81 5/subop/subtract %esp 0x10/imm32 +2874 68/push 0x10/imm32/length +2875 68/push 0/imm32/top +2876 89/<- %ecx 4/r32/esp +2877 (clear-stack %ecx) +2878 # var v/edx : var +2879 81 5/subop/subtract %esp 0x14/imm32 # Var-size +2880 89/<- %edx 4/r32/esp +2881 (zero-out %edx 0x14) +2882 # v->name = "n" +2883 c7 0/subop/copy *edx "n"/imm32 # Var-name +2884 # +2885 (push %ecx %edx) +2886 # convert +2887 (parse-mu-stmt _test-input-stream %ecx) +2888 # check result +2889 (check-strings-equal *(eax+4) "increment" "F - test-parse-mu-stmt/name") # Stmt1-operation +2890 # edx : (handle list var) = result->inouts +2891 8b/-> *(eax+8) 2/r32/edx # Stmt1-inouts +2892 # ebx : (handle var) = result->inouts->value +2893 8b/-> *edx 3/r32/ebx # List-value +2894 (check-strings-equal *ebx "n" "F - test-parse-mu-stmt/inout:0") # Var-name +2895 # . epilogue +2896 89/<- %esp 5/r32/ebp +2897 5d/pop-to-ebp +2898 c3/return +2899 +2900 new-function: # ad: (addr allocation-descriptor), name: (addr array byte), subx-name: (addr array byte), inouts: (handle list var), outputs: (handle list var), body: (handle block), next: (handle function) -> result/eax: (handle function) +2901 # . prologue +2902 55/push-ebp +2903 89/<- %ebp 4/r32/esp +2904 # . save registers +2905 51/push-ecx +2906 # +2907 (allocate *(ebp+8) *Function-size) # => eax +2908 8b/-> *(ebp+0xc) 1/r32/ecx +2909 89/<- *eax 1/r32/ecx # Function-name +2910 8b/-> *(ebp+0x10) 1/r32/ecx +2911 89/<- *(eax+4) 1/r32/ecx # Function-subx-name +2912 8b/-> *(ebp+0x14) 1/r32/ecx +2913 89/<- *(eax+8) 1/r32/ecx # Function-inouts +2914 8b/-> *(ebp+0x18) 1/r32/ecx +2915 89/<- *(eax+0xc) 1/r32/ecx # Function-outputs +2916 8b/-> *(ebp+0x1c) 1/r32/ecx +2917 89/<- *(eax+0x10) 1/r32/ecx # Function-body +2918 8b/-> *(ebp+0x20) 1/r32/ecx +2919 89/<- *(eax+0x14) 1/r32/ecx # Function-next +2920 $new-function:end: +2921 # . restore registers +2922 59/pop-to-ecx +2923 # . epilogue +2924 89/<- %esp 5/r32/ebp +2925 5d/pop-to-ebp +2926 c3/return +2927 +2928 new-var: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, block: int, stack-offset: int, register: (addr array byte) -> result/eax: (handle var) +2929 # . prologue +2930 55/push-ebp +2931 89/<- %ebp 4/r32/esp +2932 # . save registers +2933 51/push-ecx +2934 # +2935 (allocate *(ebp+8) *Var-size) # => eax +2936 8b/-> *(ebp+0xc) 1/r32/ecx +2937 89/<- *eax 1/r32/ecx # Var-name +2938 8b/-> *(ebp+0x10) 1/r32/ecx +2939 89/<- *(eax+4) 1/r32/ecx # Var-type +2940 8b/-> *(ebp+0x14) 1/r32/ecx +2941 89/<- *(eax+8) 1/r32/ecx # Var-block +2942 8b/-> *(ebp+0x18) 1/r32/ecx +2943 89/<- *(eax+0xc) 1/r32/ecx # Var-stack-offset +2944 8b/-> *(ebp+0x1c) 1/r32/ecx +2945 89/<- *(eax+0x10) 1/r32/ecx # Var-register +2946 $new-var:end: +2947 # . restore registers +2948 59/pop-to-ecx +2949 # . epilogue +2950 89/<- %esp 5/r32/ebp +2951 5d/pop-to-ebp +2952 c3/return +2953 +2954 new-literal-integer: # ad: (addr allocation-descriptor), name: (addr slice) -> result/eax: (handle var) +2955 # . prologue +2956 55/push-ebp +2957 89/<- %ebp 4/r32/esp +2958 # . save registers +2959 51/push-ecx +2960 # if (!is-hex-int?(name)) abort +2961 (is-hex-int? *(ebp+0xc)) # => eax +2962 3d/compare-eax-and 0/imm32 +2963 0f 84/jump-if-equal $new-literal-integer:abort/disp32 +2964 # var s/ecx : (addr array byte) +2965 (slice-to-string Heap *(ebp+0xc)) # => eax +2966 89/<- %ecx 0/r32/eax +2967 # +2968 (allocate *(ebp+8) *Var-size) # => eax +2969 89/<- *eax 1/r32/ecx # Var-name +2970 89/<- %ecx 0/r32/eax +2971 (allocate *(ebp+8) *Tree-size) # => eax +2972 89/<- *(ecx+4) 0/r32/eax # Var-type +2973 89/<- %eax 1/r32/ecx +2974 c7 0/subop/copy *(eax+8) 0/imm32 # Var-block +2975 c7 0/subop/copy *(eax+0xc) 0/imm32 # Var-stack-offset +2976 c7 0/subop/copy *(eax+0x10) 0/imm32 # Var-register +2977 $new-literal-integer:end: +2978 # . restore registers +2979 59/pop-to-ecx +2980 # . epilogue +2981 89/<- %esp 5/r32/ebp +2982 5d/pop-to-ebp +2983 c3/return +2984 +2985 $new-literal-integer:abort: +2986 (write-buffered Stderr "variable cannot begin with a digit '") +2987 (write-slice-buffered Stderr *(ebp+0xc)) +2988 (write-buffered Stderr "'\n") +2989 (flush Stderr) +2990 # . syscall(exit, 1) +2991 bb/copy-to-ebx 1/imm32 +2992 b8/copy-to-eax 1/imm32/exit +2993 cd/syscall 0x80/imm8 +2994 # never gets here +2995 +2996 new-block: # ad: (addr allocation-descriptor), data: (handle list statement) -> result/eax: (handle statement) +2997 # . prologue +2998 55/push-ebp +2999 89/<- %ebp 4/r32/esp +3000 # . save registers +3001 51/push-ecx +3002 # +3003 (allocate *(ebp+8) *Stmt-size) # => eax +3004 (zero-out %eax *Stmt-size) +3005 c7 0/subop/copy *eax 0/imm32/tag/block # Stmt-tag +3006 8b/-> *(ebp+0xc) 1/r32/ecx +3007 89/<- *(eax+4) 1/r32/ecx # Block-statements +3008 $new-block:end: +3009 # . restore registers +3010 59/pop-to-ecx +3011 # . epilogue +3012 89/<- %esp 5/r32/ebp +3013 5d/pop-to-ebp +3014 c3/return +3015 +3016 new-stmt: # ad: (addr allocation-descriptor), operation: (addr array byte), inouts: (handle list var), outputs: (handle list var) -> result/eax: (handle statement) +3017 # . prologue +3018 55/push-ebp +3019 89/<- %ebp 4/r32/esp +3020 # . save registers +3021 51/push-ecx +3022 # +3023 (allocate *(ebp+8) *Stmt-size) # => eax +3024 (zero-out %eax *Stmt-size) +3025 c7 0/subop/copy *eax 1/imm32/tag/regular-stmt # Stmt-tag +3026 8b/-> *(ebp+0xc) 1/r32/ecx +3027 89/<- *(eax+4) 1/r32/ecx # Stmt1-operation +3028 8b/-> *(ebp+0x10) 1/r32/ecx +3029 89/<- *(eax+8) 1/r32/ecx # Stmt1-inouts +3030 8b/-> *(ebp+0x14) 1/r32/ecx +3031 89/<- *(eax+0xc) 1/r32/ecx # Stmt1-outputs +3032 $new-stmt:end: +3033 # . restore registers +3034 59/pop-to-ecx +3035 # . epilogue +3036 89/<- %esp 5/r32/ebp +3037 5d/pop-to-ebp +3038 c3/return +3039 +3040 new-vardef: # ad: (addr allocation-descriptor), name: (addr array byte), type: int -> result/eax: (handle statement) +3041 # . prologue +3042 55/push-ebp +3043 89/<- %ebp 4/r32/esp +3044 # . save registers +3045 51/push-ecx +3046 # +3047 (allocate *(ebp+8) *Stmt-size) # => eax +3048 (zero-out %eax *Stmt-size) +3049 c7 0/subop/copy *eax 2/imm32/tag/var-on-stack # Stmt-tag +3050 8b/-> *(ebp+0xc) 1/r32/ecx +3051 89/<- *(eax+4) 1/r32/ecx # Vardef-name +3052 8b/-> *(ebp+0x10) 1/r32/ecx +3053 89/<- *(eax+8) 1/r32/ecx # Vardef-type +3054 $new-vardef:end: +3055 # . restore registers +3056 59/pop-to-ecx +3057 # . epilogue +3058 89/<- %esp 5/r32/ebp +3059 5d/pop-to-ebp +3060 c3/return +3061 +3062 new-regvardef: # ad: (addr allocation-descriptor), name: (addr array byte), type: int, register: (addr array byte) -> result/eax: (handle statement) +3063 # . prologue +3064 55/push-ebp +3065 89/<- %ebp 4/r32/esp +3066 # . save registers +3067 51/push-ecx +3068 # +3069 (allocate *(ebp+8) *Stmt-size) # => eax +3070 (zero-out %eax *Stmt-size) +3071 c7 0/subop/copy *eax 3/imm32/tag/var-in-register +3072 8b/-> *(ebp+0xc) 1/r32/ecx +3073 89/<- *(eax+4) 1/r32/ecx # Regvardef-name +3074 8b/-> *(ebp+0x10) 1/r32/ecx +3075 89/<- *(eax+8) 1/r32/ecx # Regvardef-type +3076 8b/-> *(ebp+0x14) 1/r32/ecx +3077 89/<- *(eax+0xc) 1/r32/ecx # Regvardef-register +3078 $new-regvardef:end: +3079 # . restore registers +3080 59/pop-to-ecx +3081 # . epilogue +3082 89/<- %esp 5/r32/ebp +3083 5d/pop-to-ebp +3084 c3/return +3085 +3086 new-named-block: # ad: (addr allocation-descriptor), name: (addr array byte), data: (handle list statement) -> result/eax: (handle statement) +3087 # . prologue +3088 55/push-ebp +3089 89/<- %ebp 4/r32/esp +3090 # . save registers +3091 51/push-ecx +3092 # +3093 (allocate *(ebp+8) *Stmt-size) # => eax +3094 (zero-out %eax *Stmt-size) +3095 c7 0/subop/copy *eax 4/imm32/tag/named-block +3096 8b/-> *(ebp+0xc) 1/r32/ecx +3097 89/<- *(eax+4) 1/r32/ecx # Named-block-name +3098 8b/-> *(ebp+0x10) 1/r32/ecx +3099 89/<- *(eax+8) 1/r32/ecx # Named-block-statements +3100 $new-named-block:end: +3101 # . restore registers +3102 59/pop-to-ecx +3103 # . epilogue +3104 89/<- %esp 5/r32/ebp +3105 5d/pop-to-ebp +3106 c3/return +3107 +3108 new-list: # ad: (addr allocation-descriptor), value: _type, next: (handle list _type) -> result/eax : (handle list _type) +3109 # . prologue +3110 55/push-ebp +3111 89/<- %ebp 4/r32/esp +3112 # . save registers +3113 51/push-ecx +3114 # +3115 (allocate *(ebp+8) *List-size) # => eax +3116 8b/-> *(ebp+0xc) 1/r32/ecx +3117 89/<- *eax 1/r32/ecx # List-value +3118 8b/-> *(ebp+0x10) 1/r32/ecx +3119 89/<- *(eax+4) 1/r32/ecx # List-next +3120 $new-list:end: +3121 # . restore registers +3122 59/pop-to-ecx +3123 # . epilogue +3124 89/<- %esp 5/r32/ebp +3125 5d/pop-to-ebp +3126 c3/return +3127 +3128 append-list: # ad: (addr allocation-descriptor), value: _type, list: (handle list _type) -> result/eax : (handle list _type) +3129 # . prologue +3130 55/push-ebp +3131 89/<- %ebp 4/r32/esp +3132 # . save registers +3133 51/push-ecx +3134 # +3135 (allocate *(ebp+8) *List-size) # => eax +3136 8b/-> *(ebp+0xc) 1/r32/ecx +3137 89/<- *eax 1/r32/ecx # List-value +3138 # if (list == null) return result +3139 81 7/subop/compare *(ebp+0x10) 0/imm32 +3140 74/jump-if-equal $new-list:end/disp8 +3141 # otherwise append +3142 # var curr/ecx = list +3143 8b/-> *(ebp+0x10) 1/r32/ecx +3144 # while (curr->next != null) curr = curr->next +3145 { +3146 81 7/subop/compare *(ecx+4) 0/imm32 # List-next +3147 74/jump-if-equal break/disp8 +3148 # curr = curr->next +3149 8b/-> *(ecx+4) 1/r32/ecx +3150 eb/jump loop/disp8 +3151 } +3152 # curr->next = result +3153 89/<- *(ecx+4) 0/r32/eax +3154 # return list +3155 8b/-> *(ebp+0x10) 0/r32/eax +3156 $append-list:end: +3157 # . restore registers +3158 59/pop-to-ecx +3159 # . epilogue +3160 89/<- %esp 5/r32/ebp +3161 5d/pop-to-ebp +3162 c3/return +3163 +3164 append-to-block: # ad: (addr allocation-descriptor), block: (handle block), x: (handle stmt) +3165 # . prologue +3166 55/push-ebp +3167 89/<- %ebp 4/r32/esp +3168 # . save registers +3169 56/push-esi +3170 # esi = block +3171 8b/-> *(ebp+0xc) 6/r32/esi +3172 (append-list *(ebp+8) *(ebp+0x10) *(esi+4)) # ad, x, Block-statements +3173 89/<- *(esi+4) 0/r32/eax # Block-statements +3174 $append-to-block:end: +3175 # . restore registers +3176 5e/pop-to-esi +3177 # . epilogue +3178 89/<- %esp 5/r32/ebp +3179 5d/pop-to-ebp +3180 c3/return +3181 +3182 ####################################################### +3183 # Type-checking +3184 ####################################################### +3185 +3186 check-mu-types: +3187 # . prologue +3188 55/push-ebp +3189 89/<- %ebp 4/r32/esp +3190 # +3191 $check-mu-types:end: +3192 # . epilogue +3193 89/<- %esp 5/r32/ebp +3194 5d/pop-to-ebp +3195 c3/return +3196 +3197 size-of: # n : (addr var) +3198 # . prologue +3199 55/push-ebp +3200 89/<- %ebp 4/r32/esp +3201 # hard-coded since we only support 'int' types for now +3202 b8/copy-to-eax 4/imm32 +3203 $size-of:end: +3204 # . epilogue +3205 89/<- %esp 5/r32/ebp +3206 5d/pop-to-ebp +3207 c3/return +3208 +3209 ####################################################### +3210 # Code-generation +3211 ####################################################### +3212 +3213 emit-subx: # out : (addr buffered-file) +3214 # . prologue +3215 55/push-ebp +3216 89/<- %ebp 4/r32/esp +3217 # . save registers +3218 50/push-eax +3219 51/push-ecx +3220 57/push-edi +3221 # edi = out +3222 8b/-> *(ebp+8) 7/r32/edi +3223 # var curr/ecx : (handle function) = *Program +3224 8b/-> *Program 1/r32/ecx +3225 { +3226 # if (curr == null) break +3227 81 7/subop/compare %ecx 0/imm32 +3228 0f 84/jump-if-equal break/disp32 +3229 (emit-subx-function %edi %ecx) +3230 # curr = curr->next +3231 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +3232 e9/jump loop/disp32 +3233 } +3234 $emit-subx:end: +3235 # . restore registers +3236 5f/pop-to-edi +3237 59/pop-to-ecx +3238 58/pop-to-eax +3239 # . epilogue +3240 89/<- %esp 5/r32/ebp +3241 5d/pop-to-ebp +3242 c3/return +3243 +3244 emit-subx-function: # out : (addr buffered-file), f : (handle function) +3245 # . prologue +3246 55/push-ebp +3247 89/<- %ebp 4/r32/esp +3248 # . save registers +3249 50/push-eax +3250 51/push-ecx +3251 57/push-edi +3252 # edi = out +3253 8b/-> *(ebp+8) 7/r32/edi +3254 # ecx = f +3255 8b/-> *(ebp+0xc) 1/r32/ecx +3256 # +3257 (write-buffered %edi *ecx) +3258 (write-buffered %edi ":\n") +3259 (emit-subx-prologue %edi) +3260 (emit-subx-block %edi *(ecx+0x10)) # Function-body +3261 (emit-subx-epilogue %edi) +3262 $emit-subx-function:end: +3263 # . restore registers +3264 5f/pop-to-edi +3265 59/pop-to-ecx +3266 58/pop-to-eax +3267 # . epilogue +3268 89/<- %esp 5/r32/ebp +3269 5d/pop-to-ebp +3270 c3/return +3271 +3272 emit-subx-block: # out : (addr buffered-file), block : (handle block) +3273 # . prologue +3274 55/push-ebp +3275 89/<- %ebp 4/r32/esp +3276 # curr/esi : (handle list statement) = block->statements +3277 8b/-> *(ebp+0xc) 6/r32/esi +3278 8b/-> *(esi+4) 6/r32/esi # Block-statements +3279 # +3280 { +3281 $emit-subx-block:check-empty: +3282 81 7/subop/compare %esi 0/imm32 +3283 0f 84/jump-if-equal break/disp32 +3284 (write-buffered *(ebp+8) "{\n") +3285 { +3286 $emit-subx-block:stmt: +3287 81 7/subop/compare %esi 0/imm32 +3288 74/jump-if-equal break/disp8 +3289 (emit-subx-statement *(ebp+8) *esi Primitives *Program) +3290 (write-buffered *(ebp+8) Newline) +3291 8b/-> *(esi+4) 6/r32/esi # List-next +3292 eb/jump loop/disp8 +3293 } +3294 (write-buffered *(ebp+8) "}\n") +3295 } +3296 $emit-subx-block:end: +3297 # . epilogue +3298 89/<- %esp 5/r32/ebp +3299 5d/pop-to-ebp +3300 c3/return +3301 +3302 emit-subx-statement: # out : (addr buffered-file), stmt : (handle statement), primitives : (handle primitive), functions : (handle function) +3303 # . prologue +3304 55/push-ebp +3305 89/<- %ebp 4/r32/esp +3306 # . save registers +3307 50/push-eax +3308 51/push-ecx +3309 # if stmt matches a primitive, emit it +3310 { +3311 $emit-subx-statement:primitive: +3312 (find-matching-primitive *(ebp+0x10) *(ebp+0xc)) # primitives, stmt => curr/eax +3313 3d/compare-eax-and 0/imm32 +3314 74/jump-if-equal break/disp8 +3315 (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +3316 e9/jump $emit-subx-statement:end/disp32 +3317 } +3318 # else if stmt matches a function, emit a call to it +3319 { +3320 $emit-subx-statement:call: +3321 (find-matching-function *(ebp+0x14) *(ebp+0xc)) # functions, stmt => curr/eax +3322 3d/compare-eax-and 0/imm32 +3323 74/jump-if-equal break/disp8 +3324 (emit-subx-call *(ebp+8) *(ebp+0xc) %eax) # out, stmt, curr +3325 e9/jump $emit-subx-statement:end/disp32 +3326 } +3327 # else abort +3328 e9/jump $emit-subx-statement:abort/disp32 +3329 $emit-subx-statement:end: +3330 # . restore registers +3331 59/pop-to-ecx +3332 58/pop-to-eax +3333 # . epilogue +3334 89/<- %esp 5/r32/ebp +3335 5d/pop-to-ebp +3336 c3/return +3337 +3338 $emit-subx-statement:abort: +3339 # error("couldn't translate '" stmt "'\n") +3340 (write-buffered Stderr "couldn't translate '") +3341 #? (emit-string Stderr *(ebp+0xc)) # TODO +3342 (write-buffered Stderr "'\n") +3343 (flush Stderr) +3344 # . syscall(exit, 1) +3345 bb/copy-to-ebx 1/imm32 +3346 b8/copy-to-eax 1/imm32/exit +3347 cd/syscall 0x80/imm8 +3348 # never gets here +3349 +3350 # Primitives supported +3351 # For each operation, put variants with hard-coded registers before flexible ones. +3352 == data +3353 Primitives: +3354 # - increment/decrement +3355 _Primitive-inc-eax: +3356 # var/eax <- increment => 40/increment-eax +3357 "increment"/imm32/name +3358 0/imm32/no-inouts +3359 Single-int-var-in-eax/imm32/outputs +3360 "40/increment-eax"/imm32/subx-name +3361 0/imm32/no-rm32 +3362 0/imm32/no-r32 +3363 0/imm32/no-imm32 +3364 0/imm32/output-is-write-only +3365 _Primitive-inc-ecx/imm32/next +3366 _Primitive-inc-ecx: +3367 # var/ecx <- increment => 41/increment-ecx +3368 "increment"/imm32/name +3369 0/imm32/no-inouts +3370 Single-int-var-in-ecx/imm32/outputs +3371 "41/increment-ecx"/imm32/subx-name +3372 0/imm32/no-rm32 +3373 0/imm32/no-r32 +3374 0/imm32/no-imm32 +3375 0/imm32/output-is-write-only +3376 _Primitive-inc-edx/imm32/next +3377 _Primitive-inc-edx: +3378 # var/edx <- increment => 42/increment-edx +3379 "increment"/imm32/name +3380 0/imm32/no-inouts +3381 Single-int-var-in-edx/imm32/outputs +3382 "42/increment-edx"/imm32/subx-name +3383 0/imm32/no-rm32 +3384 0/imm32/no-r32 +3385 0/imm32/no-imm32 +3386 0/imm32/output-is-write-only +3387 _Primitive-inc-ebx/imm32/next +3388 _Primitive-inc-ebx: +3389 # var/ebx <- increment => 43/increment-ebx +3390 "increment"/imm32/name +3391 0/imm32/no-inouts +3392 Single-int-var-in-ebx/imm32/outputs +3393 "43/increment-ebx"/imm32/subx-name +3394 0/imm32/no-rm32 +3395 0/imm32/no-r32 +3396 0/imm32/no-imm32 +3397 0/imm32/output-is-write-only +3398 _Primitive-inc-esi/imm32/next +3399 _Primitive-inc-esi: +3400 # var/esi <- increment => 46/increment-esi +3401 "increment"/imm32/name +3402 0/imm32/no-inouts +3403 Single-int-var-in-esi/imm32/outputs +3404 "46/increment-esi"/imm32/subx-name +3405 0/imm32/no-rm32 +3406 0/imm32/no-r32 +3407 0/imm32/no-imm32 +3408 0/imm32/output-is-write-only +3409 _Primitive-inc-edi/imm32/next +3410 _Primitive-inc-edi: +3411 # var/edi <- increment => 47/increment-edi +3412 "increment"/imm32/name +3413 0/imm32/no-inouts +3414 Single-int-var-in-edi/imm32/outputs +3415 "47/increment-edi"/imm32/subx-name +3416 0/imm32/no-rm32 +3417 0/imm32/no-r32 +3418 0/imm32/no-imm32 +3419 0/imm32/output-is-write-only +3420 _Primitive-dec-eax/imm32/next +3421 _Primitive-dec-eax: +3422 # var/eax <- decrement => 48/decrement-eax +3423 "decrement"/imm32/name +3424 0/imm32/no-inouts +3425 Single-int-var-in-eax/imm32/outputs +3426 "48/decrement-eax"/imm32/subx-name +3427 0/imm32/no-rm32 +3428 0/imm32/no-r32 +3429 0/imm32/no-imm32 +3430 0/imm32/output-is-write-only +3431 _Primitive-dec-ecx/imm32/next +3432 _Primitive-dec-ecx: +3433 # var/ecx <- decrement => 49/decrement-ecx +3434 "decrement"/imm32/name +3435 0/imm32/no-inouts +3436 Single-int-var-in-ecx/imm32/outputs +3437 "49/decrement-ecx"/imm32/subx-name +3438 0/imm32/no-rm32 +3439 0/imm32/no-r32 +3440 0/imm32/no-imm32 +3441 0/imm32/output-is-write-only +3442 _Primitive-dec-edx/imm32/next +3443 _Primitive-dec-edx: +3444 # var/edx <- decrement => 4a/decrement-edx +3445 "decrement"/imm32/name +3446 0/imm32/no-inouts +3447 Single-int-var-in-edx/imm32/outputs +3448 "4a/decrement-edx"/imm32/subx-name +3449 0/imm32/no-rm32 +3450 0/imm32/no-r32 +3451 0/imm32/no-imm32 +3452 0/imm32/output-is-write-only +3453 _Primitive-dec-ebx/imm32/next +3454 _Primitive-dec-ebx: +3455 # var/ebx <- decrement => 4b/decrement-ebx +3456 "decrement"/imm32/name +3457 0/imm32/no-inouts +3458 Single-int-var-in-ebx/imm32/outputs +3459 "4b/decrement-ebx"/imm32/subx-name +3460 0/imm32/no-rm32 +3461 0/imm32/no-r32 +3462 0/imm32/no-imm32 +3463 0/imm32/output-is-write-only +3464 _Primitive-dec-esi/imm32/next +3465 _Primitive-dec-esi: +3466 # var/esi <- decrement => 4e/decrement-esi +3467 "decrement"/imm32/name +3468 0/imm32/no-inouts +3469 Single-int-var-in-esi/imm32/outputs +3470 "4e/decrement-esi"/imm32/subx-name +3471 0/imm32/no-rm32 +3472 0/imm32/no-r32 +3473 0/imm32/no-imm32 +3474 0/imm32/output-is-write-only +3475 _Primitive-dec-edi/imm32/next +3476 _Primitive-dec-edi: +3477 # var/edi <- decrement => 4f/decrement-edi +3478 "decrement"/imm32/name +3479 0/imm32/no-inouts +3480 Single-int-var-in-edi/imm32/outputs +3481 "4f/decrement-edi"/imm32/subx-name +3482 0/imm32/no-rm32 +3483 0/imm32/no-r32 +3484 0/imm32/no-imm32 +3485 0/imm32/output-is-write-only +3486 _Primitive-inc-mem/imm32/next +3487 _Primitive-inc-mem: +3488 # increment var => ff 0/subop/increment *(ebp+__) +3489 "increment"/imm32/name +3490 Single-int-var-on-stack/imm32/inouts +3491 0/imm32/no-outputs +3492 "ff 0/subop/increment"/imm32/subx-name +3493 1/imm32/rm32-is-first-inout +3494 0/imm32/no-r32 +3495 0/imm32/no-imm32 +3496 0/imm32/output-is-write-only +3497 _Primitive-inc-reg/imm32/next +3498 _Primitive-inc-reg: +3499 # var/reg <- increment => ff 0/subop/increment %__ +3500 "increment"/imm32/name +3501 0/imm32/no-inouts +3502 Single-int-var-in-some-register/imm32/outputs +3503 "ff 0/subop/increment"/imm32/subx-name +3504 3/imm32/rm32-is-first-output +3505 0/imm32/no-r32 +3506 0/imm32/no-imm32 +3507 0/imm32/output-is-write-only +3508 _Primitive-dec-mem/imm32/next +3509 _Primitive-dec-mem: +3510 # decrement var => ff 1/subop/decrement *(ebp+__) +3511 "decrement"/imm32/name +3512 Single-int-var-on-stack/imm32/inouts +3513 0/imm32/no-outputs +3514 "ff 1/subop/decrement"/imm32/subx-name +3515 1/imm32/rm32-is-first-inout +3516 0/imm32/no-r32 +3517 0/imm32/no-imm32 +3518 0/imm32/output-is-write-only +3519 _Primitive-dec-reg/imm32/next +3520 _Primitive-dec-reg: +3521 # var/reg <- decrement => ff 1/subop/decrement %__ +3522 "decrement"/imm32/name +3523 0/imm32/no-inouts +3524 Single-int-var-in-some-register/imm32/outputs +3525 "ff 1/subop/decrement"/imm32/subx-name +3526 3/imm32/rm32-is-first-output +3527 0/imm32/no-r32 +3528 0/imm32/no-imm32 +3529 0/imm32/output-is-write-only +3530 _Primitive-add-to-eax/imm32/next +3531 # - add +3532 _Primitive-add-to-eax: +3533 # var/eax <- add lit => 05/add-to-eax lit/imm32 +3534 "add"/imm32/name +3535 Single-lit-var/imm32/inouts +3536 Single-int-var-in-eax/imm32/outputs +3537 "05/add-to-eax"/imm32/subx-name +3538 0/imm32/no-rm32 +3539 0/imm32/no-r32 +3540 1/imm32/imm32-is-first-inout +3541 0/imm32/output-is-write-only +3542 _Primitive-add-reg-to-reg/imm32/next +3543 _Primitive-add-reg-to-reg: +3544 # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32 +3545 "add"/imm32/name +3546 Single-int-var-in-some-register/imm32/inouts +3547 Single-int-var-in-some-register/imm32/outputs +3548 "01/add-to"/imm32/subx-name +3549 3/imm32/rm32-is-first-output +3550 1/imm32/r32-is-first-inout +3551 0/imm32/no-imm32 +3552 0/imm32/output-is-write-only +3553 _Primitive-add-reg-to-mem/imm32/next +3554 _Primitive-add-reg-to-mem: +3555 # add-to var1 var2/reg => 01/add-to var1 var2/r32 +3556 "add-to"/imm32/name +3557 Int-var-and-second-int-var-in-some-register/imm32/inouts +3558 0/imm32/outputs +3559 "01/add-to"/imm32/subx-name +3560 1/imm32/rm32-is-first-inout +3561 2/imm32/r32-is-second-inout +3562 0/imm32/no-imm32 +3563 0/imm32/output-is-write-only +3564 _Primitive-add-mem-to-reg/imm32/next +3565 _Primitive-add-mem-to-reg: +3566 # var1/reg <- add var2 => 03/add var2/rm32 var1/r32 +3567 "add"/imm32/name +3568 Single-int-var-on-stack/imm32/inouts +3569 Single-int-var-in-some-register/imm32/outputs +3570 "03/add"/imm32/subx-name +3571 1/imm32/rm32-is-first-inout +3572 3/imm32/r32-is-first-output +3573 0/imm32/no-imm32 +3574 0/imm32/output-is-write-only +3575 _Primitive-add-lit-to-reg/imm32/next +3576 _Primitive-add-lit-to-reg: +3577 # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32 +3578 "add"/imm32/name +3579 Single-lit-var/imm32/inouts +3580 Single-int-var-in-some-register/imm32/outputs +3581 "81 0/subop/add"/imm32/subx-name +3582 3/imm32/rm32-is-first-output +3583 0/imm32/no-r32 +3584 1/imm32/imm32-is-first-inout +3585 0/imm32/output-is-write-only +3586 _Primitive-add-lit-to-mem/imm32/next +3587 _Primitive-add-lit-to-mem: +3588 # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32 +3589 "add-to"/imm32/name +3590 Int-var-and-literal/imm32/inouts +3591 0/imm32/outputs +3592 "81 0/subop/add"/imm32/subx-name +3593 1/imm32/rm32-is-first-inout +3594 0/imm32/no-r32 +3595 2/imm32/imm32-is-first-inout +3596 0/imm32/output-is-write-only +3597 _Primitive-subtract-from-eax/imm32/next +3598 # - subtract +3599 _Primitive-subtract-from-eax: +3600 # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32 +3601 "subtract"/imm32/name +3602 Single-lit-var/imm32/inouts +3603 Single-int-var-in-eax/imm32/outputs +3604 "2d/subtract-from-eax"/imm32/subx-name +3605 0/imm32/no-rm32 +3606 0/imm32/no-r32 +3607 1/imm32/imm32-is-first-inout +3608 0/imm32/output-is-write-only +3609 _Primitive-subtract-reg-from-reg/imm32/next +3610 _Primitive-subtract-reg-from-reg: +3611 # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32 +3612 "subtract"/imm32/name +3613 Single-int-var-in-some-register/imm32/inouts +3614 Single-int-var-in-some-register/imm32/outputs +3615 "29/subtract-from"/imm32/subx-name +3616 3/imm32/rm32-is-first-output +3617 1/imm32/r32-is-first-inout +3618 0/imm32/no-imm32 +3619 0/imm32/output-is-write-only +3620 _Primitive-subtract-reg-from-mem/imm32/next +3621 _Primitive-subtract-reg-from-mem: +3622 # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32 +3623 "subtract-from"/imm32/name +3624 Int-var-and-second-int-var-in-some-register/imm32/inouts +3625 0/imm32/outputs +3626 "29/subtract-from"/imm32/subx-name +3627 1/imm32/rm32-is-first-inout +3628 2/imm32/r32-is-second-inout +3629 0/imm32/no-imm32 +3630 0/imm32/output-is-write-only +3631 _Primitive-subtract-mem-from-reg/imm32/next +3632 _Primitive-subtract-mem-from-reg: +3633 # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32 +3634 "subtract"/imm32/name +3635 Single-int-var-on-stack/imm32/inouts +3636 Single-int-var-in-some-register/imm32/outputs +3637 "2b/subtract"/imm32/subx-name +3638 1/imm32/rm32-is-first-inout +3639 3/imm32/r32-is-first-output +3640 0/imm32/no-imm32 +3641 0/imm32/output-is-write-only +3642 _Primitive-subtract-lit-from-reg/imm32/next +3643 _Primitive-subtract-lit-from-reg: +3644 # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32 +3645 "subtract"/imm32/name +3646 Single-lit-var/imm32/inouts +3647 Single-int-var-in-some-register/imm32/outputs +3648 "81 5/subop/subtract"/imm32/subx-name +3649 3/imm32/rm32-is-first-output +3650 0/imm32/no-r32 +3651 1/imm32/imm32-is-first-inout +3652 0/imm32/output-is-write-only +3653 _Primitive-subtract-lit-from-mem/imm32/next +3654 _Primitive-subtract-lit-from-mem: +3655 # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32 +3656 "subtract-from"/imm32/name +3657 Int-var-and-literal/imm32/inouts +3658 0/imm32/outputs +3659 "81 5/subop/subtract"/imm32/subx-name +3660 1/imm32/rm32-is-first-inout +3661 0/imm32/no-r32 +3662 2/imm32/imm32-is-first-inout +3663 0/imm32/output-is-write-only +3664 _Primitive-and-with-eax/imm32/next +3665 # - and +3666 _Primitive-and-with-eax: +3667 # var/eax <- and lit => 25/and-with-eax lit/imm32 +3668 "and"/imm32/name +3669 Single-lit-var/imm32/inouts +3670 Single-int-var-in-eax/imm32/outputs +3671 "25/and-with-eax"/imm32/subx-name +3672 0/imm32/no-rm32 +3673 0/imm32/no-r32 +3674 1/imm32/imm32-is-first-inout +3675 0/imm32/output-is-write-only +3676 _Primitive-and-reg-with-reg/imm32/next +3677 _Primitive-and-reg-with-reg: +3678 # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32 +3679 "and"/imm32/name +3680 Single-int-var-in-some-register/imm32/inouts +3681 Single-int-var-in-some-register/imm32/outputs +3682 "21/and-with"/imm32/subx-name +3683 3/imm32/rm32-is-first-output +3684 1/imm32/r32-is-first-inout +3685 0/imm32/no-imm32 +3686 0/imm32/output-is-write-only +3687 _Primitive-and-reg-with-mem/imm32/next +3688 _Primitive-and-reg-with-mem: +3689 # and-with var1 var2/reg => 21/and-with var1 var2/r32 +3690 "and-with"/imm32/name +3691 Int-var-and-second-int-var-in-some-register/imm32/inouts +3692 0/imm32/outputs +3693 "21/and-with"/imm32/subx-name +3694 1/imm32/rm32-is-first-inout +3695 2/imm32/r32-is-second-inout +3696 0/imm32/no-imm32 +3697 0/imm32/output-is-write-only +3698 _Primitive-and-mem-with-reg/imm32/next +3699 _Primitive-and-mem-with-reg: +3700 # var1/reg <- and var2 => 23/and var2/rm32 var1/r32 +3701 "and"/imm32/name +3702 Single-int-var-on-stack/imm32/inouts +3703 Single-int-var-in-some-register/imm32/outputs +3704 "23/and"/imm32/subx-name +3705 1/imm32/rm32-is-first-inout +3706 3/imm32/r32-is-first-output +3707 0/imm32/no-imm32 +3708 0/imm32/output-is-write-only +3709 _Primitive-and-lit-with-reg/imm32/next +3710 _Primitive-and-lit-with-reg: +3711 # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32 +3712 "and"/imm32/name +3713 Single-lit-var/imm32/inouts +3714 Single-int-var-in-some-register/imm32/outputs +3715 "81 4/subop/and"/imm32/subx-name +3716 3/imm32/rm32-is-first-output +3717 0/imm32/no-r32 +3718 1/imm32/imm32-is-first-inout +3719 0/imm32/output-is-write-only +3720 _Primitive-and-lit-with-mem/imm32/next +3721 _Primitive-and-lit-with-mem: +3722 # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32 +3723 "and-with"/imm32/name +3724 Int-var-and-literal/imm32/inouts +3725 0/imm32/outputs +3726 "81 4/subop/and"/imm32/subx-name +3727 1/imm32/rm32-is-first-inout +3728 0/imm32/no-r32 +3729 2/imm32/imm32-is-first-inout +3730 0/imm32/output-is-write-only +3731 _Primitive-or-with-eax/imm32/next +3732 # - or +3733 _Primitive-or-with-eax: +3734 # var/eax <- or lit => 0d/or-with-eax lit/imm32 +3735 "or"/imm32/name +3736 Single-lit-var/imm32/inouts +3737 Single-int-var-in-eax/imm32/outputs +3738 "0d/or-with-eax"/imm32/subx-name +3739 0/imm32/no-rm32 +3740 0/imm32/no-r32 +3741 1/imm32/imm32-is-first-inout +3742 0/imm32/output-is-write-only +3743 _Primitive-or-reg-with-reg/imm32/next +3744 _Primitive-or-reg-with-reg: +3745 # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32 +3746 "or"/imm32/name +3747 Single-int-var-in-some-register/imm32/inouts +3748 Single-int-var-in-some-register/imm32/outputs +3749 "09/or-with"/imm32/subx-name +3750 3/imm32/rm32-is-first-output +3751 1/imm32/r32-is-first-inout +3752 0/imm32/no-imm32 +3753 0/imm32/output-is-write-only +3754 _Primitive-or-reg-with-mem/imm32/next +3755 _Primitive-or-reg-with-mem: +3756 # or-with var1 var2/reg => 09/or-with var1 var2/r32 +3757 "or-with"/imm32/name +3758 Int-var-and-second-int-var-in-some-register/imm32/inouts +3759 0/imm32/outputs +3760 "09/or-with"/imm32/subx-name +3761 1/imm32/rm32-is-first-inout +3762 2/imm32/r32-is-second-inout +3763 0/imm32/no-imm32 +3764 0/imm32/output-is-write-only +3765 _Primitive-or-mem-with-reg/imm32/next +3766 _Primitive-or-mem-with-reg: +3767 # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32 +3768 "or"/imm32/name +3769 Single-int-var-on-stack/imm32/inouts +3770 Single-int-var-in-some-register/imm32/outputs +3771 "0b/or"/imm32/subx-name +3772 1/imm32/rm32-is-first-inout +3773 3/imm32/r32-is-first-output +3774 0/imm32/no-imm32 +3775 0/imm32/output-is-write-only +3776 _Primitive-or-lit-with-reg/imm32/next +3777 _Primitive-or-lit-with-reg: +3778 # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32 +3779 "or"/imm32/name +3780 Single-lit-var/imm32/inouts +3781 Single-int-var-in-some-register/imm32/outputs +3782 "81 4/subop/or"/imm32/subx-name +3783 3/imm32/rm32-is-first-output +3784 0/imm32/no-r32 +3785 1/imm32/imm32-is-first-inout +3786 0/imm32/output-is-write-only +3787 _Primitive-or-lit-with-mem/imm32/next +3788 _Primitive-or-lit-with-mem: +3789 # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32 +3790 "or-with"/imm32/name +3791 Int-var-and-literal/imm32/inouts +3792 0/imm32/outputs +3793 "81 4/subop/or"/imm32/subx-name +3794 1/imm32/rm32-is-first-inout +3795 0/imm32/no-r32 +3796 2/imm32/imm32-is-first-inout +3797 0/imm32/output-is-write-only +3798 _Primitive-xor-with-eax/imm32/next +3799 # - xor +3800 _Primitive-xor-with-eax: +3801 # var/eax <- xor lit => 35/xor-with-eax lit/imm32 +3802 "xor"/imm32/name +3803 Single-lit-var/imm32/inouts +3804 Single-int-var-in-eax/imm32/outputs +3805 "35/xor-with-eax"/imm32/subx-name +3806 0/imm32/no-rm32 +3807 0/imm32/no-r32 +3808 1/imm32/imm32-is-first-inout +3809 0/imm32/output-is-write-only +3810 _Primitive-xor-reg-with-reg/imm32/next +3811 _Primitive-xor-reg-with-reg: +3812 # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32 +3813 "xor"/imm32/name +3814 Single-int-var-in-some-register/imm32/inouts +3815 Single-int-var-in-some-register/imm32/outputs +3816 "31/xor-with"/imm32/subx-name +3817 3/imm32/rm32-is-first-output +3818 1/imm32/r32-is-first-inout +3819 0/imm32/no-imm32 +3820 0/imm32/output-is-write-only +3821 _Primitive-xor-reg-with-mem/imm32/next +3822 _Primitive-xor-reg-with-mem: +3823 # xor-with var1 var2/reg => 31/xor-with var1 var2/r32 +3824 "xor-with"/imm32/name +3825 Int-var-and-second-int-var-in-some-register/imm32/inouts +3826 0/imm32/outputs +3827 "31/xor-with"/imm32/subx-name +3828 1/imm32/rm32-is-first-inout +3829 2/imm32/r32-is-second-inout +3830 0/imm32/no-imm32 +3831 0/imm32/output-is-write-only +3832 _Primitive-xor-mem-with-reg/imm32/next +3833 _Primitive-xor-mem-with-reg: +3834 # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32 +3835 "xor"/imm32/name +3836 Single-int-var-on-stack/imm32/inouts +3837 Single-int-var-in-some-register/imm32/outputs +3838 "33/xor"/imm32/subx-name +3839 1/imm32/rm32-is-first-inout +3840 3/imm32/r32-is-first-output +3841 0/imm32/no-imm32 +3842 0/imm32/output-is-write-only +3843 _Primitive-xor-lit-with-reg/imm32/next +3844 _Primitive-xor-lit-with-reg: +3845 # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32 +3846 "xor"/imm32/name +3847 Single-lit-var/imm32/inouts +3848 Single-int-var-in-some-register/imm32/outputs +3849 "81 4/subop/xor"/imm32/subx-name +3850 3/imm32/rm32-is-first-output +3851 0/imm32/no-r32 +3852 1/imm32/imm32-is-first-inout +3853 0/imm32/output-is-write-only +3854 _Primitive-xor-lit-with-mem/imm32/next +3855 _Primitive-xor-lit-with-mem: +3856 # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32 +3857 "xor-with"/imm32/name +3858 Int-var-and-literal/imm32/inouts +3859 0/imm32/outputs +3860 "81 4/subop/xor"/imm32/subx-name +3861 1/imm32/rm32-is-first-inout +3862 0/imm32/no-r32 +3863 2/imm32/imm32-is-first-inout +3864 0/imm32/output-is-write-only +3865 _Primitive-copy-to-eax/imm32/next +3866 # - copy +3867 _Primitive-copy-to-eax: +3868 # var/eax <- copy lit => b8/copy-to-eax lit/imm32 +3869 "copy"/imm32/name +3870 Single-lit-var/imm32/inouts +3871 Single-int-var-in-eax/imm32/outputs +3872 "b8/copy-to-eax"/imm32/subx-name +3873 0/imm32/no-rm32 +3874 0/imm32/no-r32 +3875 1/imm32/imm32-is-first-inout +3876 1/imm32/output-is-write-only +3877 _Primitive-copy-to-ecx/imm32/next +3878 _Primitive-copy-to-ecx: +3879 # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32 +3880 "copy"/imm32/name +3881 Single-lit-var/imm32/inouts +3882 Single-int-var-in-ecx/imm32/outputs +3883 "b9/copy-to-ecx"/imm32/subx-name +3884 0/imm32/no-rm32 +3885 0/imm32/no-r32 +3886 1/imm32/imm32-is-first-inout +3887 1/imm32/output-is-write-only +3888 _Primitive-copy-to-edx/imm32/next +3889 _Primitive-copy-to-edx: +3890 # var/edx <- copy lit => ba/copy-to-edx lit/imm32 +3891 "copy"/imm32/name +3892 Single-lit-var/imm32/inouts +3893 Single-int-var-in-edx/imm32/outputs +3894 "ba/copy-to-edx"/imm32/subx-name +3895 0/imm32/no-rm32 +3896 0/imm32/no-r32 +3897 1/imm32/imm32-is-first-inout +3898 1/imm32/output-is-write-only +3899 _Primitive-copy-to-ebx/imm32/next +3900 _Primitive-copy-to-ebx: +3901 # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32 +3902 "copy"/imm32/name +3903 Single-lit-var/imm32/inouts +3904 Single-int-var-in-ebx/imm32/outputs +3905 "bb/copy-to-ebx"/imm32/subx-name +3906 0/imm32/no-rm32 +3907 0/imm32/no-r32 +3908 1/imm32/imm32-is-first-inout +3909 1/imm32/output-is-write-only +3910 _Primitive-copy-to-esi/imm32/next +3911 _Primitive-copy-to-esi: +3912 # var/esi <- copy lit => be/copy-to-esi lit/imm32 +3913 "copy"/imm32/name +3914 Single-lit-var/imm32/inouts +3915 Single-int-var-in-esi/imm32/outputs +3916 "be/copy-to-esi"/imm32/subx-name +3917 0/imm32/no-rm32 +3918 0/imm32/no-r32 +3919 1/imm32/imm32-is-first-inout +3920 1/imm32/output-is-write-only +3921 _Primitive-copy-to-edi/imm32/next +3922 _Primitive-copy-to-edi: +3923 # var/edi <- copy lit => bf/copy-to-edi lit/imm32 +3924 "copy"/imm32/name +3925 Single-lit-var/imm32/inouts +3926 Single-int-var-in-edi/imm32/outputs +3927 "bf/copy-to-edi"/imm32/subx-name +3928 0/imm32/no-rm32 +3929 0/imm32/no-r32 +3930 1/imm32/imm32-is-first-inout +3931 1/imm32/output-is-write-only +3932 _Primitive-copy-reg-to-reg/imm32/next +3933 _Primitive-copy-reg-to-reg: +3934 # var1/reg <- copy var2/reg => 89/copy-to var1/rm32 var2/r32 +3935 "copy"/imm32/name +3936 Single-int-var-in-some-register/imm32/inouts +3937 Single-int-var-in-some-register/imm32/outputs +3938 "89/copy-to"/imm32/subx-name +3939 3/imm32/rm32-is-first-output +3940 1/imm32/r32-is-first-inout +3941 0/imm32/no-imm32 +3942 1/imm32/output-is-write-only +3943 _Primitive-copy-reg-to-mem/imm32/next +3944 _Primitive-copy-reg-to-mem: +3945 # copy-to var1 var2/reg => 89/copy-to var1 var2/r32 +3946 "copy-to"/imm32/name +3947 Int-var-and-second-int-var-in-some-register/imm32/inouts +3948 0/imm32/outputs +3949 "89/copy-to"/imm32/subx-name +3950 1/imm32/rm32-is-first-inout +3951 2/imm32/r32-is-second-inout +3952 0/imm32/no-imm32 +3953 1/imm32/output-is-write-only +3954 _Primitive-copy-mem-to-reg/imm32/next +3955 _Primitive-copy-mem-to-reg: +3956 # var1/reg <- copy var2 => 8b/copy-from var2/rm32 var1/r32 +3957 "copy"/imm32/name +3958 Single-int-var-on-stack/imm32/inouts +3959 Single-int-var-in-some-register/imm32/outputs +3960 "8b/copy-from"/imm32/subx-name +3961 1/imm32/rm32-is-first-inout +3962 3/imm32/r32-is-first-output +3963 0/imm32/no-imm32 +3964 1/imm32/output-is-write-only +3965 _Primitive-copy-lit-to-reg/imm32/next +3966 _Primitive-copy-lit-to-reg: +3967 # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32 +3968 "copy"/imm32/name +3969 Single-lit-var/imm32/inouts +3970 Single-int-var-in-some-register/imm32/outputs +3971 "c7 0/subop/copy"/imm32/subx-name +3972 3/imm32/rm32-is-first-output +3973 0/imm32/no-r32 +3974 1/imm32/imm32-is-first-inout +3975 1/imm32/output-is-write-only +3976 _Primitive-copy-lit-to-mem/imm32/next +3977 _Primitive-copy-lit-to-mem: +3978 # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32 +3979 "copy-to"/imm32/name +3980 Int-var-and-literal/imm32/inouts +3981 0/imm32/outputs +3982 "c7 0/subop/copy"/imm32/subx-name +3983 1/imm32/rm32-is-first-inout +3984 0/imm32/no-r32 +3985 2/imm32/imm32-is-first-inout +3986 1/imm32/output-is-write-only +3987 0/imm32/next +3988 +3989 Single-int-var-on-stack: +3990 Int-var-on-stack/imm32 +3991 0/imm32/next +3992 +3993 Int-var-on-stack: +3994 "arg1"/imm32/name +3995 Type-int/imm32 +3996 1/imm32/some-block-depth +3997 1/imm32/some-stack-offset +3998 0/imm32/no-register +3999 +4000 Int-var-and-second-int-var-in-some-register: +4001 Int-var-on-stack/imm32 +4002 Single-int-var-in-some-register/imm32/next +4003 +4004 Int-var-and-literal: +4005 Int-var-on-stack/imm32 +4006 Single-lit-var/imm32/next +4007 +4008 Single-int-var-in-some-register: +4009 Int-var-in-some-register/imm32 +4010 0/imm32/next +4011 +4012 Int-var-in-some-register: +4013 "arg1"/imm32/name +4014 Type-int/imm32 +4015 1/imm32/some-block-depth +4016 0/imm32/no-stack-offset +4017 "*"/imm32/register +4018 +4019 Single-int-var-in-eax: +4020 Int-var-in-eax/imm32 +4021 0/imm32/next +4022 +4023 Int-var-in-eax: +4024 "arg1"/imm32/name +4025 Type-int/imm32 +4026 1/imm32/some-block-depth +4027 0/imm32/no-stack-offset +4028 "eax"/imm32/register +4029 +4030 Single-int-var-in-ecx: +4031 Int-var-in-ecx/imm32 +4032 0/imm32/next +4033 +4034 Int-var-in-ecx: +4035 "arg1"/imm32/name +4036 Type-int/imm32 +4037 1/imm32/some-block-depth +4038 0/imm32/no-stack-offset +4039 "ecx"/imm32/register +4040 +4041 Single-int-var-in-edx: +4042 Int-var-in-edx/imm32 +4043 0/imm32/next +4044 +4045 Int-var-in-edx: +4046 "arg1"/imm32/name +4047 Type-int/imm32 +4048 1/imm32/some-block-depth +4049 0/imm32/no-stack-offset +4050 "edx"/imm32/register +4051 +4052 Single-int-var-in-ebx: +4053 Int-var-in-ebx/imm32 +4054 0/imm32/next +4055 +4056 Int-var-in-ebx: +4057 "arg1"/imm32/name +4058 Type-int/imm32 +4059 1/imm32/some-block-depth +4060 0/imm32/no-stack-offset +4061 "ebx"/imm32/register +4062 +4063 Single-int-var-in-esi: +4064 Int-var-in-esi/imm32 +4065 0/imm32/next +4066 +4067 Int-var-in-esi: +4068 "arg1"/imm32/name +4069 Type-int/imm32 +4070 1/imm32/some-block-depth +4071 0/imm32/no-stack-offset +4072 "esi"/imm32/register +4073 +4074 Single-int-var-in-edi: +4075 Int-var-in-edi/imm32 +4076 0/imm32/next +4077 +4078 Int-var-in-edi: +4079 "arg1"/imm32/name +4080 Type-int/imm32 +4081 1/imm32/some-block-depth +4082 0/imm32/no-stack-offset +4083 "edi"/imm32/register +4084 +4085 Single-lit-var: +4086 Lit-var/imm32 +4087 0/imm32/next +4088 +4089 Lit-var: +4090 "literal"/imm32/name +4091 Type-literal/imm32 +4092 1/imm32/some-block-depth +4093 0/imm32/no-stack-offset +4094 0/imm32/no-register +4095 +4096 Type-int: +4097 1/imm32/left/int +4098 0/imm32/right/null +4099 +4100 Type-literal: +4101 0/imm32/left/literal +4102 0/imm32/right/null +4103 +4104 == code +4105 emit-subx-primitive: # out : (addr buffered-file), stmt : (handle statement), primitive : (handle function) +4106 # . prologue +4107 55/push-ebp +4108 89/<- %ebp 4/r32/esp +4109 # . save registers +4110 50/push-eax +4111 51/push-ecx +4112 # ecx = primitive +4113 8b/-> *(ebp+0x10) 1/r32/ecx +4114 # emit primitive name +4115 (write-buffered *(ebp+8) *(ecx+0xc)) # Primitive-subx-name +4116 # emit rm32 if necessary +4117 (emit-subx-rm32 *(ebp+8) *(ecx+0x10) *(ebp+0xc)) # out, Primitive-subx-rm32, stmt +4118 # emit r32 if necessary +4119 (emit-subx-r32 *(ebp+8) *(ecx+0x14) *(ebp+0xc)) # out, Primitive-subx-r32, stmt +4120 # emit imm32 if necessary +4121 (emit-subx-imm32 *(ebp+8) *(ecx+0x18) *(ebp+0xc)) # out, Primitive-subx-imm32, stmt +4122 $emit-subx-primitive:end: +4123 # . restore registers +4124 59/pop-to-ecx +4125 58/pop-to-eax +4126 # . epilogue +4127 89/<- %esp 5/r32/ebp +4128 5d/pop-to-ebp +4129 c3/return +4130 +4131 emit-subx-rm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) +4132 # . prologue +4133 55/push-ebp +4134 89/<- %ebp 4/r32/esp +4135 # . save registers +4136 50/push-eax +4137 # if (l == 0) return +4138 81 7/subop/compare *(ebp+0xc) 0/imm32 +4139 74/jump-if-equal $emit-subx-rm32:end/disp8 +4140 # +4141 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4142 (emit-subx-var-as-rm32 *(ebp+8) %eax) # out, var +4143 $emit-subx-rm32:end: +4144 # . restore registers +4145 58/pop-to-eax +4146 # . epilogue +4147 89/<- %esp 5/r32/ebp +4148 5d/pop-to-ebp +4149 c3/return +4150 +4151 get-stmt-operand-from-arg-location: # stmt : (handle statement), l : arg-location -> var/eax : (handle variable) +4152 # . prologue +4153 55/push-ebp +4154 89/<- %ebp 4/r32/esp +4155 # . save registers +4156 51/push-ecx +4157 # eax = l +4158 8b/-> *(ebp+0xc) 0/r32/eax +4159 # ecx = stmt +4160 8b/-> *(ebp+8) 1/r32/ecx +4161 # if (l == 1) return stmt->inouts->var +4162 { +4163 3d/compare-eax-and 1/imm32 +4164 75/jump-if-not-equal break/disp8 +4165 $get-stmt-operand-from-arg-location:1: +4166 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +4167 8b/-> *eax 0/r32/eax # Operand-var +4168 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4169 } +4170 # if (l == 2) return stmt->inouts->next->var +4171 { +4172 3d/compare-eax-and 2/imm32 +4173 75/jump-if-not-equal break/disp8 +4174 $get-stmt-operand-from-arg-location:2: +4175 8b/-> *(ecx+8) 0/r32/eax # Stmt1-inouts +4176 8b/-> *(eax+4) 0/r32/eax # Operand-next +4177 8b/-> *eax 0/r32/eax # Operand-var +4178 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4179 } +4180 # if (l == 3) return stmt->outputs +4181 { +4182 3d/compare-eax-and 3/imm32 +4183 75/jump-if-not-equal break/disp8 +4184 $get-stmt-operand-from-arg-location:3: +4185 8b/-> *(ecx+0xc) 0/r32/eax # Stmt1-outputs +4186 8b/-> *eax 0/r32/eax # Operand-var +4187 eb/jump $get-stmt-operand-from-arg-location:end/disp8 +4188 } +4189 # abort +4190 e9/jump $get-stmt-operand-from-arg-location:abort/disp32 +4191 $get-stmt-operand-from-arg-location:end: +4192 # . restore registers +4193 59/pop-to-ecx +4194 # . epilogue +4195 89/<- %esp 5/r32/ebp +4196 5d/pop-to-ebp +4197 c3/return +4198 +4199 $get-stmt-operand-from-arg-location:abort: +4200 # error("invalid arg-location " eax) +4201 (write-buffered Stderr "invalid arg-location ") +4202 (print-int32-buffered Stderr %eax) +4203 (write-buffered Stderr "\n") +4204 (flush Stderr) +4205 # . syscall(exit, 1) +4206 bb/copy-to-ebx 1/imm32 +4207 b8/copy-to-eax 1/imm32/exit +4208 cd/syscall 0x80/imm8 +4209 # never gets here +4210 +4211 emit-subx-r32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) +4212 # . prologue +4213 55/push-ebp +4214 89/<- %ebp 4/r32/esp +4215 # . save registers +4216 50/push-eax +4217 51/push-ecx +4218 # if (location == 0) return +4219 81 7/subop/compare *(ebp+0xc) 0/imm32 +4220 0f 84/jump-if-equal $emit-subx-r32:end/disp32 +4221 # +4222 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4223 (maybe-get Registers *(eax+0x10) 8) # Var-register => eax : (addr register-index) +4224 (write-buffered *(ebp+8) Space) +4225 (print-int32-buffered *(ebp+8) *eax) +4226 (write-buffered *(ebp+8) "/r32") +4227 $emit-subx-r32:end: +4228 # . restore registers +4229 59/pop-to-ecx +4230 58/pop-to-eax +4231 # . epilogue +4232 89/<- %esp 5/r32/ebp +4233 5d/pop-to-ebp +4234 c3/return +4235 +4236 emit-subx-imm32: # out : (addr buffered-file), l : arg-location, stmt : (handle statement) +4237 # . prologue +4238 55/push-ebp +4239 89/<- %ebp 4/r32/esp +4240 # . save registers +4241 50/push-eax +4242 51/push-ecx +4243 # if (location == 0) return +4244 81 7/subop/compare *(ebp+0xc) 0/imm32 +4245 74/jump-if-equal $emit-subx-imm32:end/disp8 4246 # -4247 (write-buffered *(ebp+8) ")") -4248 $emit-subx-call:end: -4249 # . restore registers -4250 59/pop-to-ecx -4251 58/pop-to-eax -4252 # . epilogue -4253 89/<- %esp 5/r32/ebp -4254 5d/pop-to-ebp -4255 c3/return -4256 -4257 emit-subx-call-operand: # out : (addr buffered-file), operand : (handle variable) -4258 # . prologue -4259 55/push-ebp -4260 89/<- %ebp 4/r32/esp -4261 # . save registers -4262 50/push-eax -4263 # eax = operand -4264 8b/-> *(ebp+0xc) 0/r32/eax -4265 # if non-literal, emit appropriately -4266 (emit-subx-var-as-rm32 *(ebp+8) %eax) -4267 # else if (operand->type == literal) emit "__" -4268 { -4269 81 7/subop/compare *(eax+4) 0/imm32 # Var-type -4270 75/jump-if-not-equal break/disp8 -4271 $emit-subx-call-operand:literal: -4272 (write-buffered *(ebp+8) Space) -4273 (write-buffered *(ebp+8) *eax) -4274 } -4275 $emit-subx-call-operand:end: -4276 # . restore registers -4277 58/pop-to-eax -4278 # . epilogue -4279 89/<- %esp 5/r32/ebp -4280 5d/pop-to-ebp -4281 c3/return -4282 -4283 emit-subx-var-as-rm32: # out : (addr buffered-file), operand : (handle variable) -4284 # . prologue -4285 55/push-ebp -4286 89/<- %ebp 4/r32/esp -4287 # . save registers -4288 50/push-eax -4289 # eax = operand -4290 8b/-> *(ebp+0xc) 0/r32/eax -4291 # if (operand->register) emit "%__" -4292 { -4293 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register -4294 74/jump-if-equal break/disp8 -4295 $emit-subx-var-as-rm32:register: -4296 (write-buffered *(ebp+8) " %") -4297 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register -4298 } -4299 # else if (operand->stack-offset) emit "*(ebp+__)" -4300 { -4301 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset -4302 74/jump-if-equal break/disp8 -4303 $emit-subx-var-as-rm32:stack: -4304 (write-buffered *(ebp+8) Space) -4305 (write-buffered *(ebp+8) "*(ebp+") -4306 8b/-> *(ebp+0xc) 0/r32/eax -4307 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset -4308 (write-buffered *(ebp+8) ")") -4309 } -4310 $emit-subx-var-as-rm32:end: -4311 # . restore registers -4312 58/pop-to-eax -4313 # . epilogue -4314 89/<- %esp 5/r32/ebp -4315 5d/pop-to-ebp -4316 c3/return -4317 -4318 find-matching-function: # functions : (addr function), stmt : (handle statement) -> result/eax : (handle function) -4319 # . prologue -4320 55/push-ebp -4321 89/<- %ebp 4/r32/esp -4322 # . save registers -4323 51/push-ecx -4324 # var curr/ecx : (handle function) = functions -4325 8b/-> *(ebp+8) 1/r32/ecx -4326 { -4327 # if (curr == null) break -4328 81 7/subop/compare %ecx 0/imm32 -4329 74/jump-if-equal break/disp8 -4330 # if match(stmt, curr) return curr -4331 { -4332 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax -4333 3d/compare-eax-and 0/imm32 -4334 74/jump-if-equal break/disp8 -4335 89/<- %eax 1/r32/ecx -4336 eb/jump $find-matching-function:end/disp8 -4337 } -4338 # curr = curr->next -4339 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next -4340 eb/jump loop/disp8 -4341 } -4342 # return null -4343 b8/copy-to-eax 0/imm32 -4344 $find-matching-function:end: -4345 # . restore registers -4346 59/pop-to-ecx -4347 # . epilogue -4348 89/<- %esp 5/r32/ebp -4349 5d/pop-to-ebp -4350 c3/return -4351 -4352 find-matching-primitive: # primitives : (handle primitive), stmt : (handle statement) -> result/eax : (handle primitive) -4353 # . prologue -4354 55/push-ebp -4355 89/<- %ebp 4/r32/esp -4356 # . save registers -4357 51/push-ecx -4358 # var curr/ecx : (handle primitive) = primitives -4359 8b/-> *(ebp+8) 1/r32/ecx -4360 { -4361 $find-matching-primitive:loop: -4362 # if (curr == null) break -4363 81 7/subop/compare %ecx 0/imm32 -4364 0f 84/jump-if-equal break/disp32 -4365 #? (write-buffered Stderr "prim: ") -4366 #? (write-buffered Stderr *ecx) # Primitive-name -4367 #? (write-buffered Stderr " => ") -4368 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name -4369 #? (write-buffered Stderr "\n") -4370 #? (flush Stderr) -4371 # if match(curr, stmt) return curr -4372 { -4373 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax -4374 3d/compare-eax-and 0/imm32 -4375 74/jump-if-equal break/disp8 -4376 89/<- %eax 1/r32/ecx -4377 eb/jump $find-matching-primitive:end/disp8 -4378 } -4379 $find-matching-primitive:next-primitive: -4380 # curr = curr->next -4381 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next -4382 e9/jump loop/disp32 -4383 } -4384 # return null -4385 b8/copy-to-eax 0/imm32 -4386 $find-matching-primitive:end: -4387 # . restore registers -4388 59/pop-to-ecx -4389 # . epilogue -4390 89/<- %esp 5/r32/ebp -4391 5d/pop-to-ebp -4392 c3/return -4393 -4394 mu-stmt-matches-function?: # stmt : (handle statement), function : (handle function) => result/eax : boolean -4395 # . prologue -4396 55/push-ebp -4397 89/<- %ebp 4/r32/esp -4398 # . save registers -4399 51/push-ecx -4400 # return function->name == stmt->operation -4401 8b/-> *(ebp+8) 1/r32/ecx -4402 8b/-> *(ebp+0xc) 0/r32/eax -4403 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax -4404 $mu-stmt-matches-function?:end: -4405 # . restore registers -4406 59/pop-to-ecx -4407 # . epilogue -4408 89/<- %esp 5/r32/ebp -4409 5d/pop-to-ebp -4410 c3/return -4411 -4412 mu-stmt-matches-primitive?: # stmt : (handle statement), primitive : (handle primitive) => result/eax : boolean -4413 # A mu stmt matches a primitive if the name matches, all the inout vars -4414 # match, and all the output vars match. -4415 # Vars match if types match and registers match. -4416 # In addition, a stmt output matches a primitive's output if types match -4417 # and the primitive has a wildcard register. -4418 # . prologue -4419 55/push-ebp -4420 89/<- %ebp 4/r32/esp -4421 # . save registers -4422 51/push-ecx -4423 52/push-edx -4424 53/push-ebx -4425 56/push-esi -4426 57/push-edi -4427 # ecx = stmt -4428 8b/-> *(ebp+8) 1/r32/ecx -4429 # edx = primitive -4430 8b/-> *(ebp+0xc) 2/r32/edx -4431 { -4432 $mu-stmt-matches-primitive?:check-name: -4433 # if (primitive->name != stmt->operation) return false -4434 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax -4435 3d/compare-eax-and 0/imm32 -4436 75/jump-if-not-equal break/disp8 -4437 b8/copy-to-eax 0/imm32 -4438 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4439 } -4440 $mu-stmt-matches-primitive?:check-inouts: -4441 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) -4442 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts -4443 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts -4444 { -4445 # if (curr == 0 && curr2 == 0) move on to check outputs -4446 { -4447 81 7/subop/compare %esi 0/imm32 -4448 75/jump-if-not-equal break/disp8 -4449 $mu-stmt-matches-primitive?:stmt-inout-is-null: -4450 { -4451 81 7/subop/compare %edi 0/imm32 -4452 75/jump-if-not-equal break/disp8 -4453 # -4454 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 -4455 } -4456 # return false -4457 b8/copy-to-eax 0/imm32/false -4458 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4459 } -4460 # if (curr2 == 0) return false -4461 { -4462 81 7/subop/compare %edi 0/imm32 -4463 75/jump-if-not-equal break/disp8 -4464 $mu-stmt-matches-primitive?:prim-inout-is-null: -4465 b8/copy-to-eax 0/imm32/false -4466 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4467 } -4468 # if (curr != curr2) return false -4469 { -4470 (operand-matches-primitive? *esi *edi) # => eax -4471 3d/compare-eax-and 0/imm32 -4472 75/jump-if-not-equal break/disp8 -4473 b8/copy-to-eax 0/imm32/false -4474 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4475 } -4476 # curr=curr->next -4477 8b/-> *(esi+4) 6/r32/esi # Operand-next -4478 # curr2=curr2->next -4479 8b/-> *(edi+4) 7/r32/edi # Operand-next -4480 eb/jump loop/disp8 -4481 } -4482 $mu-stmt-matches-primitive?:check-outputs: -4483 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) -4484 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs -4485 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs -4486 { -4487 # if (curr == 0) return (curr2 == 0) -4488 { -4489 $mu-stmt-matches-primitive?:check-output: -4490 81 7/subop/compare %esi 0/imm32 -4491 75/jump-if-not-equal break/disp8 -4492 { -4493 81 7/subop/compare %edi 0/imm32 -4494 75/jump-if-not-equal break/disp8 -4495 # return true -4496 b8/copy-to-eax 1/imm32 -4497 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4498 } -4499 # return false -4500 b8/copy-to-eax 0/imm32 -4501 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4502 } -4503 # if (curr2 == 0) return false -4504 { -4505 81 7/subop/compare %edi 0/imm32 -4506 75/jump-if-not-equal break/disp8 -4507 b8/copy-to-eax 0/imm32 -4508 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4509 } -4510 # if (curr != curr2) return false -4511 { -4512 (operand-matches-primitive? *esi *edi) # => eax -4513 3d/compare-eax-and 0/imm32 -4514 75/jump-if-not-equal break/disp8 -4515 b8/copy-to-eax 0/imm32 -4516 e9/jump $mu-stmt-matches-primitive?:end/disp32 -4517 } -4518 # curr=curr->next -4519 8b/-> *(esi+4) 6/r32/esi # Operand-next -4520 # curr2=curr2->next -4521 8b/-> *(edi+4) 7/r32/edi # Operand-next -4522 eb/jump loop/disp8 -4523 } -4524 $mu-stmt-matches-primitive?:return-true: -4525 b8/copy-to-eax 1/imm32 -4526 $mu-stmt-matches-primitive?:end: -4527 # . restore registers -4528 5f/pop-to-edi -4529 5e/pop-to-esi -4530 5b/pop-to-ebx -4531 5a/pop-to-edx -4532 59/pop-to-ecx -4533 # . epilogue -4534 89/<- %esp 5/r32/ebp -4535 5d/pop-to-ebp -4536 c3/return -4537 -4538 operand-matches-primitive?: # var : (handle var), prim-var : (handle var) => result/eax : boolean -4539 # . prologue -4540 55/push-ebp -4541 89/<- %ebp 4/r32/esp -4542 # . save registers -4543 56/push-esi -4544 57/push-edi -4545 # esi = var -4546 8b/-> *(ebp+8) 6/r32/esi -4547 # edi = prim-var -4548 8b/-> *(ebp+0xc) 7/r32/edi -4549 # if (var->type != prim-var->type) return false -4550 8b/-> *(esi+4) 0/r32/eax # Var-type -4551 39/compare *(edi+4) 0/r32/eax # Var-type -4552 b8/copy-to-eax 0/imm32/false -4553 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 -4554 # return false if var->register doesn't match prim-var->register -4555 { -4556 # if addresses are equal, don't return here -4557 8b/-> *(esi+0x10) 0/r32/eax -4558 39/compare *(edi+0x10) 0/r32/eax -4559 74/jump-if-equal break/disp8 -4560 # if either address is 0, return false -4561 3d/compare-eax-and 0/imm32 -4562 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -4563 81 7/subop/compare *(edi+0x10) 0/imm32 -4564 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result -4565 # if prim-var->register is "*", return true -4566 (string-equal? *(edi+0x10) "*") # Var-register -4567 3d/compare-eax-and 0/imm32 -4568 b8/copy-to-eax 1/imm32/true -4569 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 -4570 # if string contents don't match, return false -4571 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register -4572 3d/compare-eax-and 0/imm32 -4573 b8/copy-to-eax 0/imm32/false -4574 74/jump-if-equal $operand-matches-primitive?:end/disp8 -4575 } -4576 # return true -4577 b8/copy-to-eax 1/imm32/true -4578 $operand-matches-primitive?:end: -4579 # . restore registers -4580 5f/pop-to-edi -4581 5e/pop-to-esi -4582 # . epilogue -4583 89/<- %esp 5/r32/ebp -4584 5d/pop-to-ebp -4585 c3/return -4586 -4587 test-emit-subx-statement-primitive: -4588 # Primitive operation on a variable on the stack. -4589 # increment foo -4590 # => -4591 # ff 0/subop/increment *(ebp-8) -4592 # -4593 # There's a variable on the var stack as follows: -4594 # name: 'foo' -4595 # type: int -4596 # stack-offset: -8 -4597 # -4598 # There's a primitive with this info: -4599 # name: 'increment' -4600 # inouts: int/mem -4601 # value: 'ff 0/subop/increment' -4602 # -4603 # There's nothing in functions. -4604 # -4605 # . prologue -4606 55/push-ebp -4607 89/<- %ebp 4/r32/esp -4608 # setup -4609 (clear-stream _test-output-stream) -4610 (clear-stream $_test-output-buffered-file->buffer) -4611 # var var-foo/ecx : var -4612 68/push 0/imm32/no-register -4613 68/push -8/imm32/stack-offset -4614 68/push 1/imm32/block-depth -4615 68/push 1/imm32/type-int -4616 68/push "foo"/imm32 -4617 89/<- %ecx 4/r32/esp -4618 # var operand/ebx : (list var) -4619 68/push 0/imm32/next -4620 51/push-ecx/var-foo -4621 89/<- %ebx 4/r32/esp -4622 # var stmt/esi : statement -4623 68/push 0/imm32/next -4624 68/push 0/imm32/outputs -4625 53/push-ebx/operands -4626 68/push "increment"/imm32/operation -4627 68/push 1/imm32 -4628 89/<- %esi 4/r32/esp -4629 # var primitives/ebx : primitive -4630 68/push 0/imm32/next -4631 68/push 0/imm32/output-is-write-only -4632 68/push 0/imm32/no-imm32 -4633 68/push 0/imm32/no-r32 -4634 68/push 1/imm32/rm32-is-first-inout -4635 68/push "ff 0/subop/increment"/imm32/subx-name -4636 68/push 0/imm32/outputs -4637 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call -4638 68/push "increment"/imm32/name -4639 89/<- %ebx 4/r32/esp -4640 # convert -4641 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -4642 (flush _test-output-buffered-file) -4643 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4649 # check output -4650 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") -4651 # . epilogue -4652 89/<- %esp 5/r32/ebp -4653 5d/pop-to-ebp -4654 c3/return -4655 -4656 test-emit-subx-statement-primitive-register: -4657 # Primitive operation on a variable in a register. -4658 # foo <- increment -4659 # => -4660 # ff 0/subop/increment %eax # sub-optimal, but should suffice -4661 # -4662 # There's a variable on the var stack as follows: -4663 # name: 'foo' -4664 # type: int -4665 # register: 'eax' -4666 # -4667 # There's a primitive with this info: -4668 # name: 'increment' -4669 # out: int/reg -4670 # value: 'ff 0/subop/increment' -4671 # -4672 # There's nothing in functions. -4673 # -4674 # . prologue -4675 55/push-ebp -4676 89/<- %ebp 4/r32/esp -4677 # setup -4678 (clear-stream _test-output-stream) -4679 (clear-stream $_test-output-buffered-file->buffer) -4680 # var var-foo/ecx : var in eax -4681 68/push "eax"/imm32/register -4682 68/push 0/imm32/no-stack-offset -4683 68/push 1/imm32/block-depth -4684 68/push 1/imm32/type-int -4685 68/push "foo"/imm32 -4686 89/<- %ecx 4/r32/esp -4687 # var operand/ebx : (list var) -4688 68/push 0/imm32/next -4689 51/push-ecx/var-foo -4690 89/<- %ebx 4/r32/esp -4691 # var stmt/esi : statement -4692 68/push 0/imm32/next -4693 53/push-ebx/outputs -4694 68/push 0/imm32/inouts -4695 68/push "increment"/imm32/operation -4696 68/push 1/imm32 -4697 89/<- %esi 4/r32/esp -4698 # var formal-var/ebx : var in any register -4699 68/push Any-register/imm32 -4700 68/push 0/imm32/no-stack-offset -4701 68/push 1/imm32/block-depth -4702 68/push 1/imm32/type-int -4703 68/push "dummy"/imm32 -4704 89/<- %ebx 4/r32/esp -4705 # var operand/ebx : (list var) -4706 68/push 0/imm32/next -4707 53/push-ebx/formal-var -4708 89/<- %ebx 4/r32/esp -4709 # var primitives/ebx : primitive -4710 68/push 0/imm32/next -4711 68/push 0/imm32/output-is-write-only -4712 68/push 0/imm32/no-imm32 -4713 68/push 0/imm32/no-r32 -4714 68/push 3/imm32/rm32-in-first-output -4715 68/push "ff 0/subop/increment"/imm32/subx-name -4716 53/push-ebx/outputs -4717 68/push 0/imm32/inouts -4718 68/push "increment"/imm32/name -4719 89/<- %ebx 4/r32/esp -4720 # convert -4721 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -4722 (flush _test-output-buffered-file) -4723 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4729 # check output -4730 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") -4731 # . epilogue -4732 89/<- %esp 5/r32/ebp -4733 5d/pop-to-ebp -4734 c3/return -4735 -4736 test-emit-subx-statement-select-primitive: -4737 # Select the right primitive between overloads. -4738 # foo <- increment -4739 # => -4740 # ff 0/subop/increment %eax # sub-optimal, but should suffice -4741 # -4742 # There's a variable on the var stack as follows: -4743 # name: 'foo' -4744 # type: int -4745 # register: 'eax' -4746 # -4747 # There's two primitives, as follows: -4748 # - name: 'increment' -4749 # out: int/reg -4750 # value: 'ff 0/subop/increment' -4751 # - name: 'increment' -4752 # inout: int/mem -4753 # value: 'ff 0/subop/increment' -4754 # -4755 # There's nothing in functions. -4756 # -4757 # . prologue -4758 55/push-ebp -4759 89/<- %ebp 4/r32/esp -4760 # setup -4761 (clear-stream _test-output-stream) -4762 (clear-stream $_test-output-buffered-file->buffer) -4763 # var var-foo/ecx : var in eax -4764 68/push "eax"/imm32/register -4765 68/push 0/imm32/no-stack-offset -4766 68/push 1/imm32/block-depth -4767 68/push 1/imm32/type-int -4768 68/push "foo"/imm32 -4769 89/<- %ecx 4/r32/esp -4770 # var real-outputs/edi : (list var) -4771 68/push 0/imm32/next -4772 51/push-ecx/var-foo -4773 89/<- %edi 4/r32/esp -4774 # var stmt/esi : statement -4775 68/push 0/imm32/next -4776 57/push-edi/outputs -4777 68/push 0/imm32/inouts -4778 68/push "increment"/imm32/operation -4779 68/push 1/imm32 -4780 89/<- %esi 4/r32/esp -4781 # var formal-var/ebx : var in any register -4782 68/push Any-register/imm32 -4783 68/push 0/imm32/no-stack-offset -4784 68/push 1/imm32/block-depth -4785 68/push 1/imm32/type-int -4786 68/push "dummy"/imm32 -4787 89/<- %ebx 4/r32/esp -4788 # var formal-outputs/ebx : (list var) = {formal-var, 0} -4789 68/push 0/imm32/next -4790 53/push-ebx/formal-var -4791 89/<- %ebx 4/r32/esp -4792 # var primitive1/ebx : primitive -4793 68/push 0/imm32/next -4794 68/push 0/imm32/output-is-write-only -4795 68/push 0/imm32/no-imm32 -4796 68/push 0/imm32/no-r32 -4797 68/push 3/imm32/rm32-in-first-output -4798 68/push "ff 0/subop/increment"/imm32/subx-name -4799 53/push-ebx/outputs/formal-outputs -4800 68/push 0/imm32/inouts -4801 68/push "increment"/imm32/name -4802 89/<- %ebx 4/r32/esp -4803 # var primitives/ebx : primitive -4804 53/push-ebx/next -4805 68/push 0/imm32/output-is-write-only -4806 68/push 0/imm32/no-imm32 -4807 68/push 0/imm32/no-r32 -4808 68/push 1/imm32/rm32-is-first-inout -4809 68/push "ff 0/subop/increment"/imm32/subx-name -4810 68/push 0/imm32/outputs -4811 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -4812 68/push "increment"/imm32/name +4247 (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc)) # stmt, l => var/eax +4248 (write-buffered *(ebp+8) Space) +4249 (write-buffered *(ebp+8) *eax) # Var-name +4250 (write-buffered *(ebp+8) "/imm32") +4251 $emit-subx-imm32:end: +4252 # . restore registers +4253 59/pop-to-ecx +4254 58/pop-to-eax +4255 # . epilogue +4256 89/<- %esp 5/r32/ebp +4257 5d/pop-to-ebp +4258 c3/return +4259 +4260 emit-subx-call: # out : (addr buffered-file), stmt : (handle statement), callee : (handle function) +4261 # . prologue +4262 55/push-ebp +4263 89/<- %ebp 4/r32/esp +4264 # . save registers +4265 50/push-eax +4266 51/push-ecx +4267 # +4268 (write-buffered *(ebp+8) "(") +4269 # - emit function name +4270 8b/-> *(ebp+0x10) 1/r32/ecx +4271 (write-buffered *(ebp+8) *(ecx+4)) # Function-subx-name +4272 # - emit arguments +4273 # var curr/ecx : (handle list var) = stmt->inouts +4274 8b/-> *(ebp+0xc) 1/r32/ecx +4275 8b/-> *(ecx+8) 1/r32/ecx # Stmt1-inouts +4276 { +4277 # if (curr == null) break +4278 81 7/subop/compare %ecx 0/imm32 +4279 74/jump-if-equal break/disp8 +4280 # +4281 (emit-subx-call-operand *(ebp+8) *ecx) +4282 # curr = curr->next +4283 8b/-> *(ecx+4) 1/r32/ecx +4284 eb/jump loop/disp8 +4285 } +4286 # +4287 (write-buffered *(ebp+8) ")") +4288 $emit-subx-call:end: +4289 # . restore registers +4290 59/pop-to-ecx +4291 58/pop-to-eax +4292 # . epilogue +4293 89/<- %esp 5/r32/ebp +4294 5d/pop-to-ebp +4295 c3/return +4296 +4297 emit-subx-call-operand: # out : (addr buffered-file), operand : (handle variable) +4298 # . prologue +4299 55/push-ebp +4300 89/<- %ebp 4/r32/esp +4301 # . save registers +4302 50/push-eax +4303 # eax = operand +4304 8b/-> *(ebp+0xc) 0/r32/eax +4305 # if (operand->register) emit "%__" +4306 { +4307 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +4308 74/jump-if-equal break/disp8 +4309 $emit-subx-call-operand:register: +4310 (write-buffered *(ebp+8) " %") +4311 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +4312 e9/jump $emit-subx-call-operand:end/disp32 +4313 } +4314 # else if (operand->stack-offset) emit "*(ebp+__)" +4315 { +4316 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +4317 74/jump-if-equal break/disp8 +4318 $emit-subx-call-operand:stack: +4319 (write-buffered *(ebp+8) Space) +4320 (write-buffered *(ebp+8) "*(ebp+") +4321 8b/-> *(ebp+0xc) 0/r32/eax +4322 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +4323 (write-buffered *(ebp+8) ")") +4324 e9/jump $emit-subx-call-operand:end/disp32 +4325 } +4326 # else if (operand->type == literal) emit "__" +4327 { +4328 50/push-eax +4329 8b/-> *(eax+4) 0/r32/eax # Var-type +4330 81 7/subop/compare *eax 0/imm32 # Tree-left +4331 58/pop-to-eax +4332 75/jump-if-not-equal break/disp8 +4333 $emit-subx-call-operand:literal: +4334 (write-buffered *(ebp+8) Space) +4335 (write-buffered *(ebp+8) *eax) +4336 } +4337 $emit-subx-call-operand:end: +4338 # . restore registers +4339 58/pop-to-eax +4340 # . epilogue +4341 89/<- %esp 5/r32/ebp +4342 5d/pop-to-ebp +4343 c3/return +4344 +4345 emit-subx-var-as-rm32: # out : (addr buffered-file), operand : (handle variable) +4346 # . prologue +4347 55/push-ebp +4348 89/<- %ebp 4/r32/esp +4349 # . save registers +4350 50/push-eax +4351 # eax = operand +4352 8b/-> *(ebp+0xc) 0/r32/eax +4353 # if (operand->register) emit "%__" +4354 { +4355 81 7/subop/compare *(eax+0x10) 0/imm32 # Var-register +4356 74/jump-if-equal break/disp8 +4357 $emit-subx-var-as-rm32:register: +4358 (write-buffered *(ebp+8) " %") +4359 (write-buffered *(ebp+8) *(eax+0x10)) # Var-register +4360 } +4361 # else if (operand->stack-offset) emit "*(ebp+__)" +4362 { +4363 81 7/subop/compare *(eax+0xc) 0/imm32 # Var-stack-offset +4364 74/jump-if-equal break/disp8 +4365 $emit-subx-var-as-rm32:stack: +4366 (write-buffered *(ebp+8) Space) +4367 (write-buffered *(ebp+8) "*(ebp+") +4368 8b/-> *(ebp+0xc) 0/r32/eax +4369 (print-int32-buffered *(ebp+8) *(eax+0xc)) # Var-stack-offset +4370 (write-buffered *(ebp+8) ")") +4371 } +4372 $emit-subx-var-as-rm32:end: +4373 # . restore registers +4374 58/pop-to-eax +4375 # . epilogue +4376 89/<- %esp 5/r32/ebp +4377 5d/pop-to-ebp +4378 c3/return +4379 +4380 find-matching-function: # functions : (addr function), stmt : (handle statement) -> result/eax : (handle function) +4381 # . prologue +4382 55/push-ebp +4383 89/<- %ebp 4/r32/esp +4384 # . save registers +4385 51/push-ecx +4386 # var curr/ecx : (handle function) = functions +4387 8b/-> *(ebp+8) 1/r32/ecx +4388 { +4389 # if (curr == null) break +4390 81 7/subop/compare %ecx 0/imm32 +4391 74/jump-if-equal break/disp8 +4392 # if match(stmt, curr) return curr +4393 { +4394 (mu-stmt-matches-function? *(ebp+0xc) %ecx) # => eax +4395 3d/compare-eax-and 0/imm32 +4396 74/jump-if-equal break/disp8 +4397 89/<- %eax 1/r32/ecx +4398 eb/jump $find-matching-function:end/disp8 +4399 } +4400 # curr = curr->next +4401 8b/-> *(ecx+0x14) 1/r32/ecx # Function-next +4402 eb/jump loop/disp8 +4403 } +4404 # return null +4405 b8/copy-to-eax 0/imm32 +4406 $find-matching-function:end: +4407 # . restore registers +4408 59/pop-to-ecx +4409 # . epilogue +4410 89/<- %esp 5/r32/ebp +4411 5d/pop-to-ebp +4412 c3/return +4413 +4414 find-matching-primitive: # primitives : (handle primitive), stmt : (handle statement) -> result/eax : (handle primitive) +4415 # . prologue +4416 55/push-ebp +4417 89/<- %ebp 4/r32/esp +4418 # . save registers +4419 51/push-ecx +4420 # var curr/ecx : (handle primitive) = primitives +4421 8b/-> *(ebp+8) 1/r32/ecx +4422 { +4423 $find-matching-primitive:loop: +4424 # if (curr == null) break +4425 81 7/subop/compare %ecx 0/imm32 +4426 0f 84/jump-if-equal break/disp32 +4427 #? (write-buffered Stderr "prim: ") +4428 #? (write-buffered Stderr *ecx) # Primitive-name +4429 #? (write-buffered Stderr " => ") +4430 #? (write-buffered Stderr *(ecx+0xc)) # Primitive-subx-name +4431 #? (write-buffered Stderr "\n") +4432 #? (flush Stderr) +4433 # if match(curr, stmt) return curr +4434 { +4435 (mu-stmt-matches-primitive? *(ebp+0xc) %ecx) # => eax +4436 3d/compare-eax-and 0/imm32 +4437 74/jump-if-equal break/disp8 +4438 89/<- %eax 1/r32/ecx +4439 eb/jump $find-matching-primitive:end/disp8 +4440 } +4441 $find-matching-primitive:next-primitive: +4442 # curr = curr->next +4443 8b/-> *(ecx+0x20) 1/r32/ecx # Primitive-next +4444 e9/jump loop/disp32 +4445 } +4446 # return null +4447 b8/copy-to-eax 0/imm32 +4448 $find-matching-primitive:end: +4449 # . restore registers +4450 59/pop-to-ecx +4451 # . epilogue +4452 89/<- %esp 5/r32/ebp +4453 5d/pop-to-ebp +4454 c3/return +4455 +4456 mu-stmt-matches-function?: # stmt : (handle statement), function : (handle function) => result/eax : boolean +4457 # . prologue +4458 55/push-ebp +4459 89/<- %ebp 4/r32/esp +4460 # . save registers +4461 51/push-ecx +4462 # return function->name == stmt->operation +4463 8b/-> *(ebp+8) 1/r32/ecx +4464 8b/-> *(ebp+0xc) 0/r32/eax +4465 (string-equal? *(ecx+4) *eax) # Stmt1-operation, Function-name => eax +4466 $mu-stmt-matches-function?:end: +4467 # . restore registers +4468 59/pop-to-ecx +4469 # . epilogue +4470 89/<- %esp 5/r32/ebp +4471 5d/pop-to-ebp +4472 c3/return +4473 +4474 mu-stmt-matches-primitive?: # stmt : (handle statement), primitive : (handle primitive) => result/eax : boolean +4475 # A mu stmt matches a primitive if the name matches, all the inout vars +4476 # match, and all the output vars match. +4477 # Vars match if types match and registers match. +4478 # In addition, a stmt output matches a primitive's output if types match +4479 # and the primitive has a wildcard register. +4480 # . prologue +4481 55/push-ebp +4482 89/<- %ebp 4/r32/esp +4483 # . save registers +4484 51/push-ecx +4485 52/push-edx +4486 53/push-ebx +4487 56/push-esi +4488 57/push-edi +4489 # ecx = stmt +4490 8b/-> *(ebp+8) 1/r32/ecx +4491 # edx = primitive +4492 8b/-> *(ebp+0xc) 2/r32/edx +4493 { +4494 $mu-stmt-matches-primitive?:check-name: +4495 # if (primitive->name != stmt->operation) return false +4496 (string-equal? *(ecx+4) *edx) # Stmt1-operation, Primitive-name => eax +4497 3d/compare-eax-and 0/imm32 +4498 75/jump-if-not-equal break/disp8 +4499 b8/copy-to-eax 0/imm32 +4500 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4501 } +4502 $mu-stmt-matches-primitive?:check-inouts: +4503 # for (curr/esi in stmt->inouts, curr2/edi in primitive->inouts) +4504 8b/-> *(ecx+8) 6/r32/esi # Stmt1-inouts +4505 8b/-> *(edx+4) 7/r32/edi # Primitive-inouts +4506 { +4507 # if (curr == 0 && curr2 == 0) move on to check outputs +4508 { +4509 81 7/subop/compare %esi 0/imm32 +4510 75/jump-if-not-equal break/disp8 +4511 $mu-stmt-matches-primitive?:stmt-inout-is-null: +4512 { +4513 81 7/subop/compare %edi 0/imm32 +4514 75/jump-if-not-equal break/disp8 +4515 # +4516 e9/jump $mu-stmt-matches-primitive?:check-outputs/disp32 +4517 } +4518 # return false +4519 b8/copy-to-eax 0/imm32/false +4520 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4521 } +4522 # if (curr2 == 0) return false +4523 { +4524 81 7/subop/compare %edi 0/imm32 +4525 75/jump-if-not-equal break/disp8 +4526 $mu-stmt-matches-primitive?:prim-inout-is-null: +4527 b8/copy-to-eax 0/imm32/false +4528 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4529 } +4530 # if (curr != curr2) return false +4531 { +4532 (operand-matches-primitive? *esi *edi) # => eax +4533 3d/compare-eax-and 0/imm32 +4534 75/jump-if-not-equal break/disp8 +4535 b8/copy-to-eax 0/imm32/false +4536 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4537 } +4538 # curr=curr->next +4539 8b/-> *(esi+4) 6/r32/esi # Operand-next +4540 # curr2=curr2->next +4541 8b/-> *(edi+4) 7/r32/edi # Operand-next +4542 eb/jump loop/disp8 +4543 } +4544 $mu-stmt-matches-primitive?:check-outputs: +4545 # for (curr/esi in stmt->outputs, curr2/edi in primitive->outputs) +4546 8b/-> *(ecx+0xc) 6/r32/esi # Stmt1-outputs +4547 8b/-> *(edx+8) 7/r32/edi # Primitive-outputs +4548 { +4549 # if (curr == 0) return (curr2 == 0) +4550 { +4551 $mu-stmt-matches-primitive?:check-output: +4552 81 7/subop/compare %esi 0/imm32 +4553 75/jump-if-not-equal break/disp8 +4554 { +4555 81 7/subop/compare %edi 0/imm32 +4556 75/jump-if-not-equal break/disp8 +4557 # return true +4558 b8/copy-to-eax 1/imm32 +4559 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4560 } +4561 # return false +4562 b8/copy-to-eax 0/imm32 +4563 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4564 } +4565 # if (curr2 == 0) return false +4566 { +4567 81 7/subop/compare %edi 0/imm32 +4568 75/jump-if-not-equal break/disp8 +4569 b8/copy-to-eax 0/imm32 +4570 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4571 } +4572 # if (curr != curr2) return false +4573 { +4574 (operand-matches-primitive? *esi *edi) # List-value List-value => eax +4575 3d/compare-eax-and 0/imm32 +4576 75/jump-if-not-equal break/disp8 +4577 b8/copy-to-eax 0/imm32 +4578 e9/jump $mu-stmt-matches-primitive?:end/disp32 +4579 } +4580 # curr=curr->next +4581 8b/-> *(esi+4) 6/r32/esi # Operand-next +4582 # curr2=curr2->next +4583 8b/-> *(edi+4) 7/r32/edi # Operand-next +4584 eb/jump loop/disp8 +4585 } +4586 $mu-stmt-matches-primitive?:return-true: +4587 b8/copy-to-eax 1/imm32 +4588 $mu-stmt-matches-primitive?:end: +4589 # . restore registers +4590 5f/pop-to-edi +4591 5e/pop-to-esi +4592 5b/pop-to-ebx +4593 5a/pop-to-edx +4594 59/pop-to-ecx +4595 # . epilogue +4596 89/<- %esp 5/r32/ebp +4597 5d/pop-to-ebp +4598 c3/return +4599 +4600 operand-matches-primitive?: # var : (handle var), prim-var : (handle var) => result/eax : boolean +4601 # . prologue +4602 55/push-ebp +4603 89/<- %ebp 4/r32/esp +4604 # . save registers +4605 56/push-esi +4606 57/push-edi +4607 # esi = var +4608 8b/-> *(ebp+8) 6/r32/esi +4609 # edi = prim-var +4610 8b/-> *(ebp+0xc) 7/r32/edi +4611 # if (var->type != prim-var->type) return false +4612 (type-equal? *(esi+4) *(edi+4)) # Var-type, Var-type => eax +4613 3d/compare-eax-and 0/imm32 +4614 b8/copy-to-eax 0/imm32/false +4615 74/jump-if-equal $operand-matches-primitive?:end/disp8 +4616 # return false if var->register doesn't match prim-var->register +4617 { +4618 # if addresses are equal, don't return here +4619 8b/-> *(esi+0x10) 0/r32/eax +4620 39/compare *(edi+0x10) 0/r32/eax +4621 74/jump-if-equal break/disp8 +4622 # if either address is 0, return false +4623 3d/compare-eax-and 0/imm32 +4624 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +4625 81 7/subop/compare *(edi+0x10) 0/imm32 +4626 74/jump-if-equal $operand-matches-primitive?:end/disp8 # eax goes from meaning var->register to result +4627 # if prim-var->register is "*", return true +4628 (string-equal? *(edi+0x10) "*") # Var-register +4629 3d/compare-eax-and 0/imm32 +4630 b8/copy-to-eax 1/imm32/true +4631 75/jump-if-not-equal $operand-matches-primitive?:end/disp8 +4632 # if string contents don't match, return false +4633 (string-equal? *(esi+0x10) *(edi+0x10)) # Var-register Var-register +4634 3d/compare-eax-and 0/imm32 +4635 b8/copy-to-eax 0/imm32/false +4636 74/jump-if-equal $operand-matches-primitive?:end/disp8 +4637 } +4638 # return true +4639 b8/copy-to-eax 1/imm32/true +4640 $operand-matches-primitive?:end: +4641 # . restore registers +4642 5f/pop-to-edi +4643 5e/pop-to-esi +4644 # . epilogue +4645 89/<- %esp 5/r32/ebp +4646 5d/pop-to-ebp +4647 c3/return +4648 +4649 type-equal?: # a : (handle tree type-id), b : (handle tree type-id) => result/eax : boolean +4650 # . prologue +4651 55/push-ebp +4652 89/<- %ebp 4/r32/esp +4653 # . save registers +4654 51/push-ecx +4655 52/push-edx +4656 # ecx = a +4657 8b/-> *(ebp+8) 1/r32/ecx +4658 # edx = b +4659 8b/-> *(ebp+0xc) 2/r32/edx +4660 # if (a == b) return true +4661 8b/-> %ecx 0/r32/eax # Var-type +4662 39/compare %edx 0/r32/eax # Var-type +4663 b8/copy-to-eax 1/imm32/true +4664 0f 84/jump-if-equal $type-equal?:end/disp32 +4665 # if (a == 0) return false +4666 81 7/subop/compare %ecx 0/imm32 +4667 b8/copy-to-eax 0/imm32/false +4668 0f 84/jump-if-equal $type-equal?:end/disp32 +4669 # if (b == 0) return false +4670 81 7/subop/compare %edx 0/imm32 +4671 b8/copy-to-eax 0/imm32/false +4672 0f 84/jump-if-equal $type-equal?:end/disp32 +4673 # if (!type-equal?(a->left, b->left)) return false +4674 (type-equal? *ecx *edx) # Tree-left, Tree-left => eax +4675 3d/compare-eax-and 0/imm32 +4676 0f 84/jump-if-equal $type-equal?:end/disp32 +4677 # return type-equal?(a->right, b->right +4678 (type-equal? *(ecx+4) *(edx+4)) # Tree-right, Tree-right => eax +4679 $type-equal?:end: +4680 # . restore registers +4681 5a/pop-to-edx +4682 59/pop-to-ecx +4683 # . epilogue +4684 89/<- %esp 5/r32/ebp +4685 5d/pop-to-ebp +4686 c3/return +4687 +4688 test-emit-subx-statement-primitive: +4689 # Primitive operation on a variable on the stack. +4690 # increment foo +4691 # => +4692 # ff 0/subop/increment *(ebp-8) +4693 # +4694 # There's a variable on the var stack as follows: +4695 # name: 'foo' +4696 # type: int +4697 # stack-offset: -8 +4698 # +4699 # There's a primitive with this info: +4700 # name: 'increment' +4701 # inouts: int/mem +4702 # value: 'ff 0/subop/increment' +4703 # +4704 # There's nothing in functions. +4705 # +4706 # . prologue +4707 55/push-ebp +4708 89/<- %ebp 4/r32/esp +4709 # setup +4710 (clear-stream _test-output-stream) +4711 (clear-stream $_test-output-buffered-file->buffer) +4712 # var type/ecx : (handle tree type-id) = int +4713 68/push 0/imm32/right/null +4714 68/push 1/imm32/left/int +4715 89/<- %ecx 4/r32/esp +4716 # var var-foo/ecx : var +4717 68/push 0/imm32/no-register +4718 68/push -8/imm32/stack-offset +4719 68/push 1/imm32/block-depth +4720 51/push-ecx +4721 68/push "foo"/imm32 +4722 89/<- %ecx 4/r32/esp +4723 # var operand/ebx : (list var) +4724 68/push 0/imm32/next +4725 51/push-ecx/var-foo +4726 89/<- %ebx 4/r32/esp +4727 # var stmt/esi : statement +4728 68/push 0/imm32/next +4729 68/push 0/imm32/outputs +4730 53/push-ebx/operands +4731 68/push "increment"/imm32/operation +4732 68/push 1/imm32 +4733 89/<- %esi 4/r32/esp +4734 # var primitives/ebx : primitive +4735 68/push 0/imm32/next +4736 68/push 0/imm32/output-is-write-only +4737 68/push 0/imm32/no-imm32 +4738 68/push 0/imm32/no-r32 +4739 68/push 1/imm32/rm32-is-first-inout +4740 68/push "ff 0/subop/increment"/imm32/subx-name +4741 68/push 0/imm32/outputs +4742 53/push-ebx/inouts # hack; in practice we won't have the same var in function definition and call +4743 68/push "increment"/imm32/name +4744 89/<- %ebx 4/r32/esp +4745 # convert +4746 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +4747 (flush _test-output-buffered-file) +4748 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +4754 # check output +4755 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-statement-primitive") +4756 # . epilogue +4757 89/<- %esp 5/r32/ebp +4758 5d/pop-to-ebp +4759 c3/return +4760 +4761 test-emit-subx-statement-primitive-register: +4762 # Primitive operation on a variable in a register. +4763 # foo <- increment +4764 # => +4765 # ff 0/subop/increment %eax # sub-optimal, but should suffice +4766 # +4767 # There's a variable on the var stack as follows: +4768 # name: 'foo' +4769 # type: int +4770 # register: 'eax' +4771 # +4772 # There's a primitive with this info: +4773 # name: 'increment' +4774 # out: int/reg +4775 # value: 'ff 0/subop/increment' +4776 # +4777 # There's nothing in functions. +4778 # +4779 # . prologue +4780 55/push-ebp +4781 89/<- %ebp 4/r32/esp +4782 # setup +4783 (clear-stream _test-output-stream) +4784 (clear-stream $_test-output-buffered-file->buffer) +4785 # var type/ecx : (handle tree type-id) = int +4786 68/push 0/imm32/right/null +4787 68/push 1/imm32/left/int +4788 89/<- %ecx 4/r32/esp +4789 # var var-foo/ecx : var in eax +4790 68/push "eax"/imm32/register +4791 68/push 0/imm32/no-stack-offset +4792 68/push 1/imm32/block-depth +4793 51/push-ecx +4794 68/push "foo"/imm32 +4795 89/<- %ecx 4/r32/esp +4796 # var operand/ebx : (list var) +4797 68/push 0/imm32/next +4798 51/push-ecx/var-foo +4799 89/<- %ebx 4/r32/esp +4800 # var stmt/esi : statement +4801 68/push 0/imm32/next +4802 53/push-ebx/outputs +4803 68/push 0/imm32/inouts +4804 68/push "increment"/imm32/operation +4805 68/push 1/imm32 +4806 89/<- %esi 4/r32/esp +4807 # var formal-var/ebx : var in any register +4808 68/push Any-register/imm32 +4809 68/push 0/imm32/no-stack-offset +4810 68/push 1/imm32/block-depth +4811 ff 6/subop/push *(ecx+4) # Var-type +4812 68/push "dummy"/imm32 4813 89/<- %ebx 4/r32/esp -4814 # convert -4815 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -4816 (flush _test-output-buffered-file) -4817 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4823 # check output -4824 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") -4825 # . epilogue -4826 89/<- %esp 5/r32/ebp -4827 5d/pop-to-ebp -4828 c3/return -4829 -4830 test-emit-subx-statement-select-primitive-2: -4831 # Select the right primitive between overloads. -4832 # foo <- increment -4833 # => -4834 # ff 0/subop/increment %eax # sub-optimal, but should suffice -4835 # -4836 # There's a variable on the var stack as follows: -4837 # name: 'foo' -4838 # type: int -4839 # register: 'eax' -4840 # -4841 # There's two primitives, as follows: -4842 # - name: 'increment' -4843 # out: int/reg -4844 # value: 'ff 0/subop/increment' -4845 # - name: 'increment' -4846 # inout: int/mem -4847 # value: 'ff 0/subop/increment' -4848 # -4849 # There's nothing in functions. +4814 # var operand/ebx : (list var) +4815 68/push 0/imm32/next +4816 53/push-ebx/formal-var +4817 89/<- %ebx 4/r32/esp +4818 # var primitives/ebx : primitive +4819 68/push 0/imm32/next +4820 68/push 0/imm32/output-is-write-only +4821 68/push 0/imm32/no-imm32 +4822 68/push 0/imm32/no-r32 +4823 68/push 3/imm32/rm32-in-first-output +4824 68/push "ff 0/subop/increment"/imm32/subx-name +4825 53/push-ebx/outputs +4826 68/push 0/imm32/inouts +4827 68/push "increment"/imm32/name +4828 89/<- %ebx 4/r32/esp +4829 # convert +4830 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +4831 (flush _test-output-buffered-file) +4832 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +4838 # check output +4839 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-primitive-register") +4840 # . epilogue +4841 89/<- %esp 5/r32/ebp +4842 5d/pop-to-ebp +4843 c3/return +4844 +4845 test-emit-subx-statement-select-primitive: +4846 # Select the right primitive between overloads. +4847 # foo <- increment +4848 # => +4849 # ff 0/subop/increment %eax # sub-optimal, but should suffice 4850 # -4851 # . prologue -4852 55/push-ebp -4853 89/<- %ebp 4/r32/esp -4854 # setup -4855 (clear-stream _test-output-stream) -4856 (clear-stream $_test-output-buffered-file->buffer) -4857 # var var-foo/ecx : var in eax -4858 68/push "eax"/imm32/register -4859 68/push 0/imm32/no-stack-offset -4860 68/push 1/imm32/block-depth -4861 68/push 1/imm32/type-int -4862 68/push "foo"/imm32 -4863 89/<- %ecx 4/r32/esp -4864 # var inouts/edi : (list var) -4865 68/push 0/imm32/next -4866 51/push-ecx/var-foo -4867 89/<- %edi 4/r32/esp -4868 # var stmt/esi : statement -4869 68/push 0/imm32/next -4870 68/push 0/imm32/outputs -4871 57/push-edi/inouts -4872 68/push "increment"/imm32/operation -4873 68/push 1/imm32 -4874 89/<- %esi 4/r32/esp -4875 # var formal-var/ebx : var in any register -4876 68/push Any-register/imm32 -4877 68/push 0/imm32/no-stack-offset -4878 68/push 1/imm32/block-depth -4879 68/push 1/imm32/type-int -4880 68/push "dummy"/imm32 -4881 89/<- %ebx 4/r32/esp -4882 # var operand/ebx : (list var) -4883 68/push 0/imm32/next -4884 53/push-ebx/formal-var -4885 89/<- %ebx 4/r32/esp -4886 # var primitive1/ebx : primitive -4887 68/push 0/imm32/next -4888 68/push 0/imm32/output-is-write-only -4889 68/push 0/imm32/no-imm32 -4890 68/push 0/imm32/no-r32 -4891 68/push 3/imm32/rm32-in-first-output -4892 68/push "ff 0/subop/increment"/imm32/subx-name -4893 53/push-ebx/outputs/formal-outputs -4894 68/push 0/imm32/inouts -4895 68/push "increment"/imm32/name -4896 89/<- %ebx 4/r32/esp -4897 # var primitives/ebx : primitive -4898 53/push-ebx/next -4899 68/push 0/imm32/output-is-write-only -4900 68/push 0/imm32/no-imm32 -4901 68/push 0/imm32/no-r32 -4902 68/push 1/imm32/rm32-is-first-inout -4903 68/push "ff 0/subop/increment"/imm32/subx-name -4904 68/push 0/imm32/outputs -4905 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call -4906 68/push "increment"/imm32/name -4907 89/<- %ebx 4/r32/esp -4908 # convert -4909 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) -4910 (flush _test-output-buffered-file) -4911 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4917 # check output -4918 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") -4919 # . epilogue -4920 89/<- %esp 5/r32/ebp -4921 5d/pop-to-ebp -4922 c3/return -4923 -4924 test-increment-register: -4925 # Select the right primitive between overloads. -4926 # foo <- increment -4927 # => -4928 # 50/increment-eax -4929 # -4930 # There's a variable on the var stack as follows: -4931 # name: 'foo' -4932 # type: int -4933 # register: 'eax' -4934 # -4935 # Primitives are the global definitions. -4936 # -4937 # There are no functions defined. -4938 # -4939 # . prologue -4940 55/push-ebp -4941 89/<- %ebp 4/r32/esp -4942 # setup -4943 (clear-stream _test-output-stream) -4944 (clear-stream $_test-output-buffered-file->buffer) -4945 # var var-foo/ecx : var in eax -4946 68/push "eax"/imm32/register -4947 68/push 0/imm32/no-stack-offset -4948 68/push 1/imm32/block-depth -4949 68/push 1/imm32/type-int -4950 68/push "foo"/imm32 -4951 89/<- %ecx 4/r32/esp -4952 # var real-outputs/edi : (list var) -4953 68/push 0/imm32/next -4954 51/push-ecx/var-foo -4955 89/<- %edi 4/r32/esp -4956 # var stmt/esi : statement -4957 68/push 0/imm32/next -4958 57/push-edi/outputs -4959 68/push 0/imm32/inouts -4960 68/push "increment"/imm32/operation -4961 68/push 1/imm32 -4962 89/<- %esi 4/r32/esp -4963 # convert -4964 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -4965 (flush _test-output-buffered-file) -4966 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -4972 # check output -4973 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") -4974 # . epilogue -4975 89/<- %esp 5/r32/ebp -4976 5d/pop-to-ebp -4977 c3/return -4978 -4979 test-increment-var: -4980 # Select the right primitive between overloads. -4981 # foo <- increment -4982 # => -4983 # ff 0/subop/increment %eax # sub-optimal, but should suffice -4984 # -4985 # There's a variable on the var stack as follows: -4986 # name: 'foo' -4987 # type: int -4988 # register: 'eax' -4989 # -4990 # Primitives are the global definitions. -4991 # -4992 # There are no functions defined. -4993 # -4994 # . prologue -4995 55/push-ebp -4996 89/<- %ebp 4/r32/esp -4997 # setup -4998 (clear-stream _test-output-stream) -4999 (clear-stream $_test-output-buffered-file->buffer) -5000 # var var-foo/ecx : var in eax -5001 68/push "eax"/imm32/register -5002 68/push 0/imm32/no-stack-offset -5003 68/push 1/imm32/block-depth -5004 68/push 1/imm32/type-int -5005 68/push "foo"/imm32 -5006 89/<- %ecx 4/r32/esp -5007 # var inouts/edi : (list var) -5008 68/push 0/imm32/next -5009 51/push-ecx/var-foo -5010 89/<- %edi 4/r32/esp -5011 # var stmt/esi : statement -5012 68/push 0/imm32/next -5013 68/push 0/imm32/outputs -5014 57/push-edi/inouts -5015 68/push "increment"/imm32/operation -5016 68/push 1/imm32 -5017 89/<- %esi 4/r32/esp -5018 # convert -5019 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5020 (flush _test-output-buffered-file) -5021 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5027 # check output -5028 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") -5029 # . epilogue -5030 89/<- %esp 5/r32/ebp -5031 5d/pop-to-ebp -5032 c3/return -5033 -5034 test-add-reg-to-reg: -5035 # var1/reg <- add var2/reg -5036 # => -5037 # 01/add %var1 var2 -5038 # -5039 # . prologue -5040 55/push-ebp -5041 89/<- %ebp 4/r32/esp -5042 # setup -5043 (clear-stream _test-output-stream) -5044 (clear-stream $_test-output-buffered-file->buffer) -5045 # var var-var1/ecx : var in eax -5046 68/push "eax"/imm32/register -5047 68/push 0/imm32/no-stack-offset -5048 68/push 1/imm32/block-depth -5049 68/push 1/imm32/type-int -5050 68/push "var1"/imm32 -5051 89/<- %ecx 4/r32/esp -5052 # var var-var2/edx : var in ecx -5053 68/push "ecx"/imm32/register -5054 68/push 0/imm32/no-stack-offset -5055 68/push 1/imm32/block-depth -5056 68/push 1/imm32/type-int -5057 68/push "var2"/imm32 -5058 89/<- %edx 4/r32/esp -5059 # var inouts/esi : (list var2) -5060 68/push 0/imm32/next -5061 52/push-edx/var-var2 -5062 89/<- %esi 4/r32/esp -5063 # var outputs/edi : (list var1) -5064 68/push 0/imm32/next -5065 51/push-ecx/var-var1 -5066 89/<- %edi 4/r32/esp -5067 # var stmt/esi : statement -5068 68/push 0/imm32/next -5069 57/push-edi/outputs -5070 56/push-esi/inouts -5071 68/push "add"/imm32/operation -5072 68/push 1/imm32 -5073 89/<- %esi 4/r32/esp -5074 # convert -5075 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5076 (flush _test-output-buffered-file) -5077 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5083 # check output -5084 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") -5085 # . epilogue -5086 89/<- %esp 5/r32/ebp -5087 5d/pop-to-ebp -5088 c3/return -5089 -5090 test-add-reg-to-mem: -5091 # add-to var1 var2/reg -5092 # => -5093 # 01/add *(ebp+__) var2 -5094 # -5095 # . prologue -5096 55/push-ebp -5097 89/<- %ebp 4/r32/esp -5098 # setup -5099 (clear-stream _test-output-stream) -5100 (clear-stream $_test-output-buffered-file->buffer) -5101 # var var-var1/ecx : var -5102 68/push 0/imm32/no-register -5103 68/push 8/imm32/stack-offset -5104 68/push 1/imm32/block-depth -5105 68/push 1/imm32/type-int -5106 68/push "var1"/imm32 -5107 89/<- %ecx 4/r32/esp -5108 # var var-var2/edx : var in ecx -5109 68/push "ecx"/imm32/register -5110 68/push 0/imm32/no-stack-offset -5111 68/push 1/imm32/block-depth -5112 68/push 1/imm32/type-int -5113 68/push "var2"/imm32 -5114 89/<- %edx 4/r32/esp -5115 # var inouts/esi : (list var2) -5116 68/push 0/imm32/next -5117 52/push-edx/var-var2 -5118 89/<- %esi 4/r32/esp -5119 # var inouts = (list var1 var2) -5120 56/push-esi/next -5121 51/push-ecx/var-var1 -5122 89/<- %esi 4/r32/esp -5123 # var stmt/esi : statement -5124 68/push 0/imm32/next -5125 68/push 0/imm32/outputs -5126 56/push-esi/inouts -5127 68/push "add-to"/imm32/operation -5128 68/push 1/imm32 -5129 89/<- %esi 4/r32/esp -5130 # convert -5131 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5132 (flush _test-output-buffered-file) -5133 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5139 # check output -5140 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") -5141 # . epilogue -5142 89/<- %esp 5/r32/ebp -5143 5d/pop-to-ebp -5144 c3/return -5145 -5146 test-add-mem-to-reg: -5147 # var1/reg <- add var2 -5148 # => -5149 # 03/add *(ebp+__) var1 -5150 # -5151 # . prologue -5152 55/push-ebp -5153 89/<- %ebp 4/r32/esp -5154 # setup -5155 (clear-stream _test-output-stream) -5156 (clear-stream $_test-output-buffered-file->buffer) -5157 # var var-var1/ecx : var in eax -5158 68/push "eax"/imm32/register -5159 68/push 0/imm32/no-stack-offset -5160 68/push 1/imm32/block-depth -5161 68/push 1/imm32/type-int -5162 68/push "var1"/imm32 -5163 89/<- %ecx 4/r32/esp -5164 # var var-var2/edx : var -5165 68/push 0/imm32/no-register -5166 68/push 8/imm32/stack-offset -5167 68/push 1/imm32/block-depth -5168 68/push 1/imm32/type-int -5169 68/push "var2"/imm32 -5170 89/<- %edx 4/r32/esp -5171 # var inouts/esi : (list var2) -5172 68/push 0/imm32/next -5173 52/push-edx/var-var2 -5174 89/<- %esi 4/r32/esp -5175 # var outputs/edi : (list var1) -5176 68/push 0/imm32/next -5177 51/push-ecx/var-var1 -5178 89/<- %edi 4/r32/esp -5179 # var stmt/esi : statement -5180 68/push 0/imm32/next -5181 57/push-edi/outputs -5182 56/push-esi/inouts -5183 68/push "add"/imm32/operation -5184 68/push 1/imm32 -5185 89/<- %esi 4/r32/esp -5186 # convert -5187 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5188 (flush _test-output-buffered-file) -5189 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5195 # check output -5196 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") -5197 # . epilogue -5198 89/<- %esp 5/r32/ebp -5199 5d/pop-to-ebp -5200 c3/return -5201 -5202 test-add-literal-to-eax: -5203 # var1/eax <- add 0x34 -5204 # => -5205 # 05/add-to-eax 0x34/imm32 -5206 # -5207 # . prologue -5208 55/push-ebp -5209 89/<- %ebp 4/r32/esp -5210 # setup -5211 (clear-stream _test-output-stream) -5212 (clear-stream $_test-output-buffered-file->buffer) -5213 # var var-var1/ecx : var in eax -5214 68/push "eax"/imm32/register -5215 68/push 0/imm32/no-stack-offset -5216 68/push 1/imm32/block-depth -5217 68/push 1/imm32/type-int -5218 68/push "var1"/imm32 -5219 89/<- %ecx 4/r32/esp -5220 # var var-var2/edx : var literal -5221 68/push 0/imm32/no-register -5222 68/push 0/imm32/no-stack-offset -5223 68/push 1/imm32/block-depth -5224 68/push 0/imm32/type-literal -5225 68/push "0x34"/imm32 -5226 89/<- %edx 4/r32/esp -5227 # var inouts/esi : (list var2) -5228 68/push 0/imm32/next -5229 52/push-edx/var-var2 -5230 89/<- %esi 4/r32/esp -5231 # var outputs/edi : (list var1) -5232 68/push 0/imm32/next -5233 51/push-ecx/var-var1 -5234 89/<- %edi 4/r32/esp -5235 # var stmt/esi : statement -5236 68/push 0/imm32/next -5237 57/push-edi/outputs -5238 56/push-esi/inouts -5239 68/push "add"/imm32/operation -5240 68/push 1/imm32 -5241 89/<- %esi 4/r32/esp -5242 # convert -5243 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5244 (flush _test-output-buffered-file) -5245 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5251 # check output -5252 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") -5253 # . epilogue -5254 89/<- %esp 5/r32/ebp -5255 5d/pop-to-ebp -5256 c3/return -5257 -5258 test-add-literal-to-reg: -5259 # var1/ecx <- add 0x34 -5260 # => -5261 # 81 0/subop/add %ecx 0x34/imm32 -5262 # -5263 # . prologue -5264 55/push-ebp -5265 89/<- %ebp 4/r32/esp -5266 # setup -5267 (clear-stream _test-output-stream) -5268 (clear-stream $_test-output-buffered-file->buffer) -5269 # var var-var1/ecx : var in ecx -5270 68/push "ecx"/imm32/register -5271 68/push 0/imm32/no-stack-offset -5272 68/push 1/imm32/block-depth -5273 68/push 1/imm32/type-int -5274 68/push "var1"/imm32 -5275 89/<- %ecx 4/r32/esp -5276 # var var-var2/edx : var literal -5277 68/push 0/imm32/no-register -5278 68/push 0/imm32/no-stack-offset -5279 68/push 1/imm32/block-depth -5280 68/push 0/imm32/type-literal -5281 68/push "0x34"/imm32 -5282 89/<- %edx 4/r32/esp -5283 # var inouts/esi : (list var2) -5284 68/push 0/imm32/next -5285 52/push-edx/var-var2 -5286 89/<- %esi 4/r32/esp -5287 # var outputs/edi : (list var1) -5288 68/push 0/imm32/next -5289 51/push-ecx/var-var1 -5290 89/<- %edi 4/r32/esp -5291 # var stmt/esi : statement -5292 68/push 0/imm32/next -5293 57/push-edi/outputs -5294 56/push-esi/inouts -5295 68/push "add"/imm32/operation -5296 68/push 1/imm32 -5297 89/<- %esi 4/r32/esp -5298 # convert -5299 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5300 (flush _test-output-buffered-file) -5301 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5307 # check output -5308 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") -5309 # . epilogue -5310 89/<- %esp 5/r32/ebp -5311 5d/pop-to-ebp -5312 c3/return -5313 -5314 test-add-literal-to-mem: -5315 # add-to var1, 0x34 -5316 # => -5317 # 81 0/subop/add %eax 0x34/imm32 -5318 # -5319 # . prologue -5320 55/push-ebp -5321 89/<- %ebp 4/r32/esp -5322 # setup -5323 (clear-stream _test-output-stream) -5324 (clear-stream $_test-output-buffered-file->buffer) -5325 # var var-var1/ecx : var -5326 68/push 0/imm32/no-register -5327 68/push 8/imm32/stack-offset -5328 68/push 1/imm32/block-depth -5329 68/push 1/imm32/type-int -5330 68/push "var1"/imm32 -5331 89/<- %ecx 4/r32/esp -5332 # var var-var2/edx : var literal -5333 68/push 0/imm32/no-register -5334 68/push 0/imm32/no-stack-offset -5335 68/push 1/imm32/block-depth -5336 68/push 0/imm32/type-literal -5337 68/push "0x34"/imm32 -5338 89/<- %edx 4/r32/esp -5339 # var inouts/esi : (list var2) -5340 68/push 0/imm32/next -5341 52/push-edx/var-var2 -5342 89/<- %esi 4/r32/esp -5343 # var inouts = (list var1 inouts) -5344 56/push-esi/next -5345 51/push-ecx/var-var1 -5346 89/<- %esi 4/r32/esp -5347 # var stmt/esi : statement -5348 68/push 0/imm32/next -5349 68/push 0/imm32/outputs -5350 56/push-esi/inouts -5351 68/push "add-to"/imm32/operation -5352 68/push 1/imm32 -5353 89/<- %esi 4/r32/esp -5354 # convert -5355 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) -5356 (flush _test-output-buffered-file) -5357 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5363 # check output -5364 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") -5365 # . epilogue -5366 89/<- %esp 5/r32/ebp -5367 5d/pop-to-ebp -5368 c3/return -5369 -5370 test-emit-subx-statement-function-call: -5371 # Call a function on a variable on the stack. -5372 # f foo -5373 # => -5374 # (f2 *(ebp-8)) -5375 # (Changing the function name supports overloading in general, but here it -5376 # just serves to help disambiguate things.) -5377 # -5378 # There's a variable on the var stack as follows: -5379 # name: 'foo' -5380 # type: int -5381 # stack-offset: -8 -5382 # -5383 # There's nothing in primitives. -5384 # -5385 # There's a function with this info: -5386 # name: 'f' -5387 # inout: int/mem -5388 # value: 'f2' -5389 # -5390 # . prologue -5391 55/push-ebp -5392 89/<- %ebp 4/r32/esp -5393 # setup -5394 (clear-stream _test-output-stream) -5395 (clear-stream $_test-output-buffered-file->buffer) -5396 # var var-foo/ecx : var -5397 68/push 0/imm32/no-register -5398 68/push -8/imm32/stack-offset -5399 68/push 0/imm32/block-depth -5400 68/push 1/imm32/type-int -5401 68/push "foo"/imm32 -5402 89/<- %ecx 4/r32/esp -5403 # var operands/esi : (list var) -5404 68/push 0/imm32/next -5405 51/push-ecx/var-foo -5406 89/<- %esi 4/r32/esp -5407 # var stmt/esi : statement -5408 68/push 0/imm32/next -5409 68/push 0/imm32/outputs -5410 56/push-esi/inouts -5411 68/push "f"/imm32/operation -5412 68/push 1/imm32 -5413 89/<- %esi 4/r32/esp -5414 # var functions/ebx : function -5415 68/push 0/imm32/next -5416 68/push 0/imm32/body -5417 68/push 0/imm32/outputs -5418 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -5419 68/push "f2"/imm32/subx-name -5420 68/push "f"/imm32/name -5421 89/<- %ebx 4/r32/esp -5422 # convert -5423 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -5424 (flush _test-output-buffered-file) -5425 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5431 # check output -5432 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") -5433 # . epilogue -5434 89/<- %esp 5/r32/ebp -5435 5d/pop-to-ebp -5436 c3/return -5437 -5438 test-emit-subx-statement-function-call-with-literal-arg: -5439 # Call a function on a literal. -5440 # f 34 -5441 # => -5442 # (f2 34) -5443 # -5444 # . prologue -5445 55/push-ebp -5446 89/<- %ebp 4/r32/esp -5447 # setup -5448 (clear-stream _test-output-stream) -5449 (clear-stream $_test-output-buffered-file->buffer) -5450 # var var-foo/ecx : var literal -5451 68/push 0/imm32/no-register -5452 68/push 0/imm32/no-stack-offset -5453 68/push 0/imm32/block-depth -5454 68/push 0/imm32/type-literal -5455 68/push "34"/imm32 -5456 89/<- %ecx 4/r32/esp -5457 # var operands/esi : (list var) -5458 68/push 0/imm32/next -5459 51/push-ecx/var-foo -5460 89/<- %esi 4/r32/esp -5461 # var stmt/esi : statement -5462 68/push 0/imm32/next -5463 68/push 0/imm32/outputs -5464 56/push-esi/inouts -5465 68/push "f"/imm32/operation -5466 68/push 1/imm32 -5467 89/<- %esi 4/r32/esp -5468 # var functions/ebx : function -5469 68/push 0/imm32/next -5470 68/push 0/imm32/body -5471 68/push 0/imm32/outputs -5472 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call -5473 68/push "f2"/imm32/subx-name -5474 68/push "f"/imm32/name -5475 89/<- %ebx 4/r32/esp -5476 # convert -5477 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) -5478 (flush _test-output-buffered-file) -5479 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- -5485 # check output -5486 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") -5487 # . epilogue -5488 89/<- %esp 5/r32/ebp -5489 5d/pop-to-ebp -5490 c3/return -5491 -5492 emit-subx-prologue: # out : (addr buffered-file) -5493 # . prologue -5494 55/push-ebp -5495 89/<- %ebp 4/r32/esp -5496 # -5497 (write-buffered *(ebp+8) "# . prologue\n") -5498 (write-buffered *(ebp+8) "55/push-ebp\n") -5499 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") -5500 $emit-subx-prologue:end: -5501 # . epilogue -5502 89/<- %esp 5/r32/ebp -5503 5d/pop-to-ebp -5504 c3/return -5505 -5506 emit-subx-epilogue: # out : (addr buffered-file) -5507 # . prologue -5508 55/push-ebp -5509 89/<- %ebp 4/r32/esp -5510 # -5511 (write-buffered *(ebp+8) "# . epilogue\n") -5512 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") -5513 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") -5514 (write-buffered *(ebp+8) "c3/return\n") -5515 $emit-subx-epilogue:end: -5516 # . epilogue -5517 89/<- %esp 5/r32/ebp -5518 5d/pop-to-ebp -5519 c3/return +4851 # There's a variable on the var stack as follows: +4852 # name: 'foo' +4853 # type: int +4854 # register: 'eax' +4855 # +4856 # There's two primitives, as follows: +4857 # - name: 'increment' +4858 # out: int/reg +4859 # value: 'ff 0/subop/increment' +4860 # - name: 'increment' +4861 # inout: int/mem +4862 # value: 'ff 0/subop/increment' +4863 # +4864 # There's nothing in functions. +4865 # +4866 # . prologue +4867 55/push-ebp +4868 89/<- %ebp 4/r32/esp +4869 # setup +4870 (clear-stream _test-output-stream) +4871 (clear-stream $_test-output-buffered-file->buffer) +4872 # var type/ecx : (handle tree type-id) = int +4873 68/push 0/imm32/right/null +4874 68/push 1/imm32/left/int +4875 89/<- %ecx 4/r32/esp +4876 # var var-foo/ecx : var in eax +4877 68/push "eax"/imm32/register +4878 68/push 0/imm32/no-stack-offset +4879 68/push 1/imm32/block-depth +4880 51/push-ecx +4881 68/push "foo"/imm32 +4882 89/<- %ecx 4/r32/esp +4883 # var real-outputs/edi : (list var) +4884 68/push 0/imm32/next +4885 51/push-ecx/var-foo +4886 89/<- %edi 4/r32/esp +4887 # var stmt/esi : statement +4888 68/push 0/imm32/next +4889 57/push-edi/outputs +4890 68/push 0/imm32/inouts +4891 68/push "increment"/imm32/operation +4892 68/push 1/imm32 +4893 89/<- %esi 4/r32/esp +4894 # var formal-var/ebx : var in any register +4895 68/push Any-register/imm32 +4896 68/push 0/imm32/no-stack-offset +4897 68/push 1/imm32/block-depth +4898 ff 6/subop/push *(ecx+4) # Var-type +4899 68/push "dummy"/imm32 +4900 89/<- %ebx 4/r32/esp +4901 # var formal-outputs/ebx : (list var) = {formal-var, 0} +4902 68/push 0/imm32/next +4903 53/push-ebx/formal-var +4904 89/<- %ebx 4/r32/esp +4905 # var primitive1/ebx : primitive +4906 68/push 0/imm32/next +4907 68/push 0/imm32/output-is-write-only +4908 68/push 0/imm32/no-imm32 +4909 68/push 0/imm32/no-r32 +4910 68/push 3/imm32/rm32-in-first-output +4911 68/push "ff 0/subop/increment"/imm32/subx-name +4912 53/push-ebx/outputs/formal-outputs +4913 68/push 0/imm32/inouts +4914 68/push "increment"/imm32/name +4915 89/<- %ebx 4/r32/esp +4916 # var primitives/ebx : primitive +4917 53/push-ebx/next +4918 68/push 0/imm32/output-is-write-only +4919 68/push 0/imm32/no-imm32 +4920 68/push 0/imm32/no-r32 +4921 68/push 1/imm32/rm32-is-first-inout +4922 68/push "ff 0/subop/increment"/imm32/subx-name +4923 68/push 0/imm32/outputs +4924 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +4925 68/push "increment"/imm32/name +4926 89/<- %ebx 4/r32/esp +4927 # convert +4928 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +4929 (flush _test-output-buffered-file) +4930 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +4936 # check output +4937 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive") +4938 # . epilogue +4939 89/<- %esp 5/r32/ebp +4940 5d/pop-to-ebp +4941 c3/return +4942 +4943 test-emit-subx-statement-select-primitive-2: +4944 # Select the right primitive between overloads. +4945 # foo <- increment +4946 # => +4947 # ff 0/subop/increment %eax # sub-optimal, but should suffice +4948 # +4949 # There's a variable on the var stack as follows: +4950 # name: 'foo' +4951 # type: int +4952 # register: 'eax' +4953 # +4954 # There's two primitives, as follows: +4955 # - name: 'increment' +4956 # out: int/reg +4957 # value: 'ff 0/subop/increment' +4958 # - name: 'increment' +4959 # inout: int/mem +4960 # value: 'ff 0/subop/increment' +4961 # +4962 # There's nothing in functions. +4963 # +4964 # . prologue +4965 55/push-ebp +4966 89/<- %ebp 4/r32/esp +4967 # setup +4968 (clear-stream _test-output-stream) +4969 (clear-stream $_test-output-buffered-file->buffer) +4970 # var type/ecx : (handle tree type-id) = int +4971 68/push 0/imm32/right/null +4972 68/push 1/imm32/left/int +4973 89/<- %ecx 4/r32/esp +4974 # var var-foo/ecx : var in eax +4975 68/push "eax"/imm32/register +4976 68/push 0/imm32/no-stack-offset +4977 68/push 1/imm32/block-depth +4978 51/push-ecx +4979 68/push "foo"/imm32 +4980 89/<- %ecx 4/r32/esp +4981 # var inouts/edi : (list var) +4982 68/push 0/imm32/next +4983 51/push-ecx/var-foo +4984 89/<- %edi 4/r32/esp +4985 # var stmt/esi : statement +4986 68/push 0/imm32/next +4987 68/push 0/imm32/outputs +4988 57/push-edi/inouts +4989 68/push "increment"/imm32/operation +4990 68/push 1/imm32 +4991 89/<- %esi 4/r32/esp +4992 # var formal-var/ebx : var in any register +4993 68/push Any-register/imm32 +4994 68/push 0/imm32/no-stack-offset +4995 68/push 1/imm32/block-depth +4996 ff 6/subop/push *(ecx+4) # Var-type +4997 68/push "dummy"/imm32 +4998 89/<- %ebx 4/r32/esp +4999 # var operand/ebx : (list var) +5000 68/push 0/imm32/next +5001 53/push-ebx/formal-var +5002 89/<- %ebx 4/r32/esp +5003 # var primitive1/ebx : primitive +5004 68/push 0/imm32/next +5005 68/push 0/imm32/output-is-write-only +5006 68/push 0/imm32/no-imm32 +5007 68/push 0/imm32/no-r32 +5008 68/push 3/imm32/rm32-in-first-output +5009 68/push "ff 0/subop/increment"/imm32/subx-name +5010 53/push-ebx/outputs/formal-outputs +5011 68/push 0/imm32/inouts +5012 68/push "increment"/imm32/name +5013 89/<- %ebx 4/r32/esp +5014 # var primitives/ebx : primitive +5015 53/push-ebx/next +5016 68/push 0/imm32/output-is-write-only +5017 68/push 0/imm32/no-imm32 +5018 68/push 0/imm32/no-r32 +5019 68/push 1/imm32/rm32-is-first-inout +5020 68/push "ff 0/subop/increment"/imm32/subx-name +5021 68/push 0/imm32/outputs +5022 57/push-edi/inouts/real-outputs # hack; in practice we won't have the same var in function definition and call +5023 68/push "increment"/imm32/name +5024 89/<- %ebx 4/r32/esp +5025 # convert +5026 (emit-subx-statement _test-output-buffered-file %esi %ebx 0) +5027 (flush _test-output-buffered-file) +5028 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5034 # check output +5035 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-statement-select-primitive-2") +5036 # . epilogue +5037 89/<- %esp 5/r32/ebp +5038 5d/pop-to-ebp +5039 c3/return +5040 +5041 test-increment-register: +5042 # Select the right primitive between overloads. +5043 # foo <- increment +5044 # => +5045 # 50/increment-eax +5046 # +5047 # There's a variable on the var stack as follows: +5048 # name: 'foo' +5049 # type: int +5050 # register: 'eax' +5051 # +5052 # Primitives are the global definitions. +5053 # +5054 # There are no functions defined. +5055 # +5056 # . prologue +5057 55/push-ebp +5058 89/<- %ebp 4/r32/esp +5059 # setup +5060 (clear-stream _test-output-stream) +5061 (clear-stream $_test-output-buffered-file->buffer) +5062 # var type/ecx : (handle tree type-id) = int +5063 68/push 0/imm32/right/null +5064 68/push 1/imm32/left/int +5065 89/<- %ecx 4/r32/esp +5066 # var var-foo/ecx : var in eax +5067 68/push "eax"/imm32/register +5068 68/push 0/imm32/no-stack-offset +5069 68/push 1/imm32/block-depth +5070 51/push-ecx +5071 68/push "foo"/imm32 +5072 89/<- %ecx 4/r32/esp +5073 # var real-outputs/edi : (list var) +5074 68/push 0/imm32/next +5075 51/push-ecx/var-foo +5076 89/<- %edi 4/r32/esp +5077 # var stmt/esi : statement +5078 68/push 0/imm32/next +5079 57/push-edi/outputs +5080 68/push 0/imm32/inouts +5081 68/push "increment"/imm32/operation +5082 68/push 1/imm32/regular-statement +5083 89/<- %esi 4/r32/esp +5084 # convert +5085 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5086 (flush _test-output-buffered-file) +5087 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5093 # check output +5094 (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register") +5095 # . epilogue +5096 89/<- %esp 5/r32/ebp +5097 5d/pop-to-ebp +5098 c3/return +5099 +5100 test-increment-var: +5101 # Select the right primitive between overloads. +5102 # foo <- increment +5103 # => +5104 # ff 0/subop/increment %eax # sub-optimal, but should suffice +5105 # +5106 # There's a variable on the var stack as follows: +5107 # name: 'foo' +5108 # type: int +5109 # register: 'eax' +5110 # +5111 # Primitives are the global definitions. +5112 # +5113 # There are no functions defined. +5114 # +5115 # . prologue +5116 55/push-ebp +5117 89/<- %ebp 4/r32/esp +5118 # setup +5119 (clear-stream _test-output-stream) +5120 (clear-stream $_test-output-buffered-file->buffer) +5121 # var type/ecx : (handle tree type-id) = int +5122 68/push 0/imm32/right/null +5123 68/push 1/imm32/left/int +5124 89/<- %ecx 4/r32/esp +5125 # var var-foo/ecx : var in eax +5126 68/push "eax"/imm32/register +5127 68/push 0/imm32/no-stack-offset +5128 68/push 1/imm32/block-depth +5129 51/push-ecx +5130 68/push "foo"/imm32 +5131 89/<- %ecx 4/r32/esp +5132 # var inouts/edi : (list var) +5133 68/push 0/imm32/next +5134 51/push-ecx/var-foo +5135 89/<- %edi 4/r32/esp +5136 # var stmt/esi : statement +5137 68/push 0/imm32/next +5138 68/push 0/imm32/outputs +5139 57/push-edi/inouts +5140 68/push "increment"/imm32/operation +5141 68/push 1/imm32 +5142 89/<- %esi 4/r32/esp +5143 # convert +5144 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5145 (flush _test-output-buffered-file) +5146 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5152 # check output +5153 (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-increment-var") +5154 # . epilogue +5155 89/<- %esp 5/r32/ebp +5156 5d/pop-to-ebp +5157 c3/return +5158 +5159 test-add-reg-to-reg: +5160 # var1/reg <- add var2/reg +5161 # => +5162 # 01/add %var1 var2 +5163 # +5164 # . prologue +5165 55/push-ebp +5166 89/<- %ebp 4/r32/esp +5167 # setup +5168 (clear-stream _test-output-stream) +5169 (clear-stream $_test-output-buffered-file->buffer) +5170 # var type/ecx : (handle tree type-id) = int +5171 68/push 0/imm32/right/null +5172 68/push 1/imm32/left/int +5173 89/<- %ecx 4/r32/esp +5174 # var var-var1/ecx : var in eax +5175 68/push "eax"/imm32/register +5176 68/push 0/imm32/no-stack-offset +5177 68/push 1/imm32/block-depth +5178 51/push-ecx +5179 68/push "var1"/imm32 +5180 89/<- %ecx 4/r32/esp +5181 # var var-var2/edx : var in ecx +5182 68/push "ecx"/imm32/register +5183 68/push 0/imm32/no-stack-offset +5184 68/push 1/imm32/block-depth +5185 ff 6/subop/push *(ecx+4) # Var-type +5186 68/push "var2"/imm32 +5187 89/<- %edx 4/r32/esp +5188 # var inouts/esi : (list var2) +5189 68/push 0/imm32/next +5190 52/push-edx/var-var2 +5191 89/<- %esi 4/r32/esp +5192 # var outputs/edi : (list var1) +5193 68/push 0/imm32/next +5194 51/push-ecx/var-var1 +5195 89/<- %edi 4/r32/esp +5196 # var stmt/esi : statement +5197 68/push 0/imm32/next +5198 57/push-edi/outputs +5199 56/push-esi/inouts +5200 68/push "add"/imm32/operation +5201 68/push 1/imm32 +5202 89/<- %esi 4/r32/esp +5203 # convert +5204 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5205 (flush _test-output-buffered-file) +5206 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5212 # check output +5213 (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg") +5214 # . epilogue +5215 89/<- %esp 5/r32/ebp +5216 5d/pop-to-ebp +5217 c3/return +5218 +5219 test-add-reg-to-mem: +5220 # add-to var1 var2/reg +5221 # => +5222 # 01/add *(ebp+__) var2 +5223 # +5224 # . prologue +5225 55/push-ebp +5226 89/<- %ebp 4/r32/esp +5227 # setup +5228 (clear-stream _test-output-stream) +5229 (clear-stream $_test-output-buffered-file->buffer) +5230 # var type/ecx : (handle tree type-id) = int +5231 68/push 0/imm32/right/null +5232 68/push 1/imm32/left/int +5233 89/<- %ecx 4/r32/esp +5234 # var var-var1/ecx : var +5235 68/push 0/imm32/no-register +5236 68/push 8/imm32/stack-offset +5237 68/push 1/imm32/block-depth +5238 51/push-ecx +5239 68/push "var1"/imm32 +5240 89/<- %ecx 4/r32/esp +5241 # var var-var2/edx : var in ecx +5242 68/push "ecx"/imm32/register +5243 68/push 0/imm32/no-stack-offset +5244 68/push 1/imm32/block-depth +5245 ff 6/subop/push *(ecx+4) # Var-type +5246 68/push "var2"/imm32 +5247 89/<- %edx 4/r32/esp +5248 # var inouts/esi : (list var2) +5249 68/push 0/imm32/next +5250 52/push-edx/var-var2 +5251 89/<- %esi 4/r32/esp +5252 # var inouts = (list var1 var2) +5253 56/push-esi/next +5254 51/push-ecx/var-var1 +5255 89/<- %esi 4/r32/esp +5256 # var stmt/esi : statement +5257 68/push 0/imm32/next +5258 68/push 0/imm32/outputs +5259 56/push-esi/inouts +5260 68/push "add-to"/imm32/operation +5261 68/push 1/imm32 +5262 89/<- %esi 4/r32/esp +5263 # convert +5264 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5265 (flush _test-output-buffered-file) +5266 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5272 # check output +5273 (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem") +5274 # . epilogue +5275 89/<- %esp 5/r32/ebp +5276 5d/pop-to-ebp +5277 c3/return +5278 +5279 test-add-mem-to-reg: +5280 # var1/reg <- add var2 +5281 # => +5282 # 03/add *(ebp+__) var1 +5283 # +5284 # . prologue +5285 55/push-ebp +5286 89/<- %ebp 4/r32/esp +5287 # setup +5288 (clear-stream _test-output-stream) +5289 (clear-stream $_test-output-buffered-file->buffer) +5290 # var type/ecx : (handle tree type-id) = int +5291 68/push 0/imm32/right/null +5292 68/push 1/imm32/left/int +5293 89/<- %ecx 4/r32/esp +5294 # var var-var1/ecx : var in eax +5295 68/push "eax"/imm32/register +5296 68/push 0/imm32/no-stack-offset +5297 68/push 1/imm32/block-depth +5298 51/push-ecx +5299 68/push "var1"/imm32 +5300 89/<- %ecx 4/r32/esp +5301 # var var-var2/edx : var +5302 68/push 0/imm32/no-register +5303 68/push 8/imm32/stack-offset +5304 68/push 1/imm32/block-depth +5305 ff 6/subop/push *(ecx+4) # Var-type +5306 68/push "var2"/imm32 +5307 89/<- %edx 4/r32/esp +5308 # var inouts/esi : (list var2) +5309 68/push 0/imm32/next +5310 52/push-edx/var-var2 +5311 89/<- %esi 4/r32/esp +5312 # var outputs/edi : (list var1) +5313 68/push 0/imm32/next +5314 51/push-ecx/var-var1 +5315 89/<- %edi 4/r32/esp +5316 # var stmt/esi : statement +5317 68/push 0/imm32/next +5318 57/push-edi/outputs +5319 56/push-esi/inouts +5320 68/push "add"/imm32/operation +5321 68/push 1/imm32 +5322 89/<- %esi 4/r32/esp +5323 # convert +5324 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5325 (flush _test-output-buffered-file) +5326 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5332 # check output +5333 (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg") +5334 # . epilogue +5335 89/<- %esp 5/r32/ebp +5336 5d/pop-to-ebp +5337 c3/return +5338 +5339 test-add-literal-to-eax: +5340 # var1/eax <- add 0x34 +5341 # => +5342 # 05/add-to-eax 0x34/imm32 +5343 # +5344 # . prologue +5345 55/push-ebp +5346 89/<- %ebp 4/r32/esp +5347 # setup +5348 (clear-stream _test-output-stream) +5349 (clear-stream $_test-output-buffered-file->buffer) +5350 # var type/ecx : (handle tree type-id) = int +5351 68/push 0/imm32/right/null +5352 68/push 1/imm32/left/int +5353 89/<- %ecx 4/r32/esp +5354 # var var-var1/ecx : var in eax +5355 68/push "eax"/imm32/register +5356 68/push 0/imm32/no-stack-offset +5357 68/push 1/imm32/block-depth +5358 51/push-ecx +5359 68/push "var1"/imm32 +5360 89/<- %ecx 4/r32/esp +5361 # var type/edx : (handle tree type-id) = literal +5362 68/push 0/imm32/right/null +5363 68/push 0/imm32/left/literal +5364 89/<- %edx 4/r32/esp +5365 # var var-var2/edx : var literal +5366 68/push 0/imm32/no-register +5367 68/push 0/imm32/no-stack-offset +5368 68/push 1/imm32/block-depth +5369 52/push-edx +5370 68/push "0x34"/imm32 +5371 89/<- %edx 4/r32/esp +5372 # var inouts/esi : (list var2) +5373 68/push 0/imm32/next +5374 52/push-edx/var-var2 +5375 89/<- %esi 4/r32/esp +5376 # var outputs/edi : (list var1) +5377 68/push 0/imm32/next +5378 51/push-ecx/var-var1 +5379 89/<- %edi 4/r32/esp +5380 # var stmt/esi : statement +5381 68/push 0/imm32/next +5382 57/push-edi/outputs +5383 56/push-esi/inouts +5384 68/push "add"/imm32/operation +5385 68/push 1/imm32 +5386 89/<- %esi 4/r32/esp +5387 # convert +5388 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5389 (flush _test-output-buffered-file) +5390 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5396 # check output +5397 (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax") +5398 # . epilogue +5399 89/<- %esp 5/r32/ebp +5400 5d/pop-to-ebp +5401 c3/return +5402 +5403 test-add-literal-to-reg: +5404 # var1/ecx <- add 0x34 +5405 # => +5406 # 81 0/subop/add %ecx 0x34/imm32 +5407 # +5408 # . prologue +5409 55/push-ebp +5410 89/<- %ebp 4/r32/esp +5411 # setup +5412 (clear-stream _test-output-stream) +5413 (clear-stream $_test-output-buffered-file->buffer) +5414 # var type/ecx : (handle tree type-id) = int +5415 68/push 0/imm32/right/null +5416 68/push 1/imm32/left/int +5417 89/<- %ecx 4/r32/esp +5418 # var var-var1/ecx : var in ecx +5419 68/push "ecx"/imm32/register +5420 68/push 0/imm32/no-stack-offset +5421 68/push 1/imm32/block-depth +5422 51/push-ecx +5423 68/push "var1"/imm32 +5424 89/<- %ecx 4/r32/esp +5425 # var type/edx : (handle tree type-id) = literal +5426 68/push 0/imm32/right/null +5427 68/push 0/imm32/left/literal +5428 89/<- %edx 4/r32/esp +5429 # var var-var2/edx : var literal +5430 68/push 0/imm32/no-register +5431 68/push 0/imm32/no-stack-offset +5432 68/push 1/imm32/block-depth +5433 52/push-edx +5434 68/push "0x34"/imm32 +5435 89/<- %edx 4/r32/esp +5436 # var inouts/esi : (list var2) +5437 68/push 0/imm32/next +5438 52/push-edx/var-var2 +5439 89/<- %esi 4/r32/esp +5440 # var outputs/edi : (list var1) +5441 68/push 0/imm32/next +5442 51/push-ecx/var-var1 +5443 89/<- %edi 4/r32/esp +5444 # var stmt/esi : statement +5445 68/push 0/imm32/next +5446 57/push-edi/outputs +5447 56/push-esi/inouts +5448 68/push "add"/imm32/operation +5449 68/push 1/imm32 +5450 89/<- %esi 4/r32/esp +5451 # convert +5452 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5453 (flush _test-output-buffered-file) +5454 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5460 # check output +5461 (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg") +5462 # . epilogue +5463 89/<- %esp 5/r32/ebp +5464 5d/pop-to-ebp +5465 c3/return +5466 +5467 test-add-literal-to-mem: +5468 # add-to var1, 0x34 +5469 # => +5470 # 81 0/subop/add %eax 0x34/imm32 +5471 # +5472 # . prologue +5473 55/push-ebp +5474 89/<- %ebp 4/r32/esp +5475 # setup +5476 (clear-stream _test-output-stream) +5477 (clear-stream $_test-output-buffered-file->buffer) +5478 # var type/ecx : (handle tree type-id) = int +5479 68/push 0/imm32/right/null +5480 68/push 1/imm32/left/int +5481 89/<- %ecx 4/r32/esp +5482 # var var-var1/ecx : var +5483 68/push 0/imm32/no-register +5484 68/push 8/imm32/stack-offset +5485 68/push 1/imm32/block-depth +5486 51/push-ecx +5487 68/push "var1"/imm32 +5488 89/<- %ecx 4/r32/esp +5489 # var type/edx : (handle tree type-id) = literal +5490 68/push 0/imm32/right/null +5491 68/push 0/imm32/left/literal +5492 89/<- %edx 4/r32/esp +5493 # var var-var2/edx : var literal +5494 68/push 0/imm32/no-register +5495 68/push 0/imm32/no-stack-offset +5496 68/push 1/imm32/block-depth +5497 52/push-edx +5498 68/push "0x34"/imm32 +5499 89/<- %edx 4/r32/esp +5500 # var inouts/esi : (list var2) +5501 68/push 0/imm32/next +5502 52/push-edx/var-var2 +5503 89/<- %esi 4/r32/esp +5504 # var inouts = (list var1 inouts) +5505 56/push-esi/next +5506 51/push-ecx/var-var1 +5507 89/<- %esi 4/r32/esp +5508 # var stmt/esi : statement +5509 68/push 0/imm32/next +5510 68/push 0/imm32/outputs +5511 56/push-esi/inouts +5512 68/push "add-to"/imm32/operation +5513 68/push 1/imm32 +5514 89/<- %esi 4/r32/esp +5515 # convert +5516 (emit-subx-statement _test-output-buffered-file %esi Primitives 0) +5517 (flush _test-output-buffered-file) +5518 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5524 # check output +5525 (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem") +5526 # . epilogue +5527 89/<- %esp 5/r32/ebp +5528 5d/pop-to-ebp +5529 c3/return +5530 +5531 test-emit-subx-statement-function-call: +5532 # Call a function on a variable on the stack. +5533 # f foo +5534 # => +5535 # (f2 *(ebp-8)) +5536 # (Changing the function name supports overloading in general, but here it +5537 # just serves to help disambiguate things.) +5538 # +5539 # There's a variable on the var stack as follows: +5540 # name: 'foo' +5541 # type: int +5542 # stack-offset: -8 +5543 # +5544 # There's nothing in primitives. +5545 # +5546 # There's a function with this info: +5547 # name: 'f' +5548 # inout: int/mem +5549 # value: 'f2' +5550 # +5551 # . prologue +5552 55/push-ebp +5553 89/<- %ebp 4/r32/esp +5554 # setup +5555 (clear-stream _test-output-stream) +5556 (clear-stream $_test-output-buffered-file->buffer) +5557 # var type/ecx : (handle tree type-id) = int +5558 68/push 0/imm32/right/null +5559 68/push 1/imm32/left/int +5560 89/<- %ecx 4/r32/esp +5561 # var var-foo/ecx : var +5562 68/push 0/imm32/no-register +5563 68/push -8/imm32/stack-offset +5564 68/push 0/imm32/block-depth +5565 51/push-ecx +5566 68/push "foo"/imm32 +5567 89/<- %ecx 4/r32/esp +5568 # var operands/esi : (list var) +5569 68/push 0/imm32/next +5570 51/push-ecx/var-foo +5571 89/<- %esi 4/r32/esp +5572 # var stmt/esi : statement +5573 68/push 0/imm32/next +5574 68/push 0/imm32/outputs +5575 56/push-esi/inouts +5576 68/push "f"/imm32/operation +5577 68/push 1/imm32 +5578 89/<- %esi 4/r32/esp +5579 # var functions/ebx : function +5580 68/push 0/imm32/next +5581 68/push 0/imm32/body +5582 68/push 0/imm32/outputs +5583 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +5584 68/push "f2"/imm32/subx-name +5585 68/push "f"/imm32/name +5586 89/<- %ebx 4/r32/esp +5587 # convert +5588 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +5589 (flush _test-output-buffered-file) +5590 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5596 # check output +5597 (check-next-stream-line-equal _test-output-stream "(f2 *(ebp+0xfffffff8))" "F - test-emit-subx-statement-function-call") +5598 # . epilogue +5599 89/<- %esp 5/r32/ebp +5600 5d/pop-to-ebp +5601 c3/return +5602 +5603 test-emit-subx-statement-function-call-with-literal-arg: +5604 # Call a function on a literal. +5605 # f 34 +5606 # => +5607 # (f2 34) +5608 # +5609 # . prologue +5610 55/push-ebp +5611 89/<- %ebp 4/r32/esp +5612 # setup +5613 (clear-stream _test-output-stream) +5614 (clear-stream $_test-output-buffered-file->buffer) +5615 # var type/ecx : (handle tree type-id) = literal +5616 68/push 0/imm32/right/null +5617 68/push 0/imm32/left/literal +5618 89/<- %ecx 4/r32/esp +5619 # var var-foo/ecx : var literal +5620 68/push 0/imm32/no-register +5621 68/push 0/imm32/no-stack-offset +5622 68/push 0/imm32/block-depth +5623 51/push-ecx +5624 68/push "34"/imm32 +5625 89/<- %ecx 4/r32/esp +5626 # var operands/esi : (list var) +5627 68/push 0/imm32/next +5628 51/push-ecx/var-foo +5629 89/<- %esi 4/r32/esp +5630 # var stmt/esi : statement +5631 68/push 0/imm32/next +5632 68/push 0/imm32/outputs +5633 56/push-esi/inouts +5634 68/push "f"/imm32/operation +5635 68/push 1/imm32 +5636 89/<- %esi 4/r32/esp +5637 # var functions/ebx : function +5638 68/push 0/imm32/next +5639 68/push 0/imm32/body +5640 68/push 0/imm32/outputs +5641 51/push-ecx/inouts # hack; in practice we won't have the same var in function definition and call +5642 68/push "f2"/imm32/subx-name +5643 68/push "f"/imm32/name +5644 89/<- %ebx 4/r32/esp +5645 # convert +5646 (emit-subx-statement _test-output-buffered-file %esi 0 %ebx) +5647 (flush _test-output-buffered-file) +5648 +-- 6 lines: #? # dump _test-output-stream -------------------------------------------------------------------------------------------------------------- +5654 # check output +5655 (check-next-stream-line-equal _test-output-stream "(f2 34)" "F - test-emit-subx-statement-function-call-with-literal-arg") +5656 # . epilogue +5657 89/<- %esp 5/r32/ebp +5658 5d/pop-to-ebp +5659 c3/return +5660 +5661 emit-subx-prologue: # out : (addr buffered-file) +5662 # . prologue +5663 55/push-ebp +5664 89/<- %ebp 4/r32/esp +5665 # +5666 (write-buffered *(ebp+8) "# . prologue\n") +5667 (write-buffered *(ebp+8) "55/push-ebp\n") +5668 (write-buffered *(ebp+8) "89/<- %ebp 4/r32/esp\n") +5669 $emit-subx-prologue:end: +5670 # . epilogue +5671 89/<- %esp 5/r32/ebp +5672 5d/pop-to-ebp +5673 c3/return +5674 +5675 emit-subx-epilogue: # out : (addr buffered-file) +5676 # . prologue +5677 55/push-ebp +5678 89/<- %ebp 4/r32/esp +5679 # +5680 (write-buffered *(ebp+8) "# . epilogue\n") +5681 (write-buffered *(ebp+8) "89/<- %esp 5/r32/ebp\n") +5682 (write-buffered *(ebp+8) "5d/pop-to-ebp\n") +5683 (write-buffered *(ebp+8) "c3/return\n") +5684 $emit-subx-epilogue:end: +5685 # . epilogue +5686 89/<- %esp 5/r32/ebp +5687 5d/pop-to-ebp +5688 c3/return
diff --git a/html/apps/sigils.subx.html b/html/apps/sigils.subx.html index 8e590953..0dd7a70e 100644 --- a/html/apps/sigils.subx.html +++ b/html/apps/sigils.subx.html @@ -1211,7 +1211,7 @@ if ('onhashchange' in window) { 1388 68/push "Registers"/imm32 1389 68/push 8/imm32/row-size 1390 50/push-eax -1391 68/push Registers/imm32 +1391 68/push Registers/imm32 1392 # . . call 1393 e8/call get-slice/disp32 1394 # . . discard args @@ -2060,7 +2060,7 @@ if ('onhashchange' in window) { 2287 68/push "Registers"/imm32 2288 68/push 8/imm32/row-size 2289 56/push-esi -2290 68/push Registers/imm32 +2290 68/push Registers/imm32 2291 # . . call 2292 e8/call get-slice/disp32 2293 # . . discard args @@ -2147,7 +2147,7 @@ if ('onhashchange' in window) { 2374 # . . push args 2375 68/push 8/imm32/row-size 2376 51/push-ecx -2377 68/push Registers/imm32 +2377 68/push Registers/imm32 2378 # . . call 2379 e8/call maybe-get-slice/disp32 2380 # . . discard args @@ -2465,7 +2465,7 @@ if ('onhashchange' in window) { 2692 68/push "next-register"/imm32 2693 68/push 8/imm32/row-size 2694 51/push-ecx -2695 68/push Registers/imm32 +2695 68/push Registers/imm32 2696 # . . call 2697 e8/call get-slice/disp32 2698 # . . discard args @@ -3491,7 +3491,7 @@ if ('onhashchange' in window) { 3893 # . . push args 3894 68/push 8/imm32/row-size 3895 56/push-esi -3896 68/push Registers/imm32 +3896 68/push Registers/imm32 3897 # . . cal 3898 e8/call maybe-get-slice/disp32 3899 # . . discard args