about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-03-12 00:17:35 -0700
committerKartik Agaram <vc@akkartik.com>2020-03-12 00:17:35 -0700
commit92ca78429cf37f4d9a7c43c052d4f06706a5dac8 (patch)
treec2935ec0d2185d8095a0231ada01e2c449455bbf
parentd5171ad7feaa153eaea25f959919258393bd99dc (diff)
downloadmu-92ca78429cf37f4d9a7c43c052d4f06706a5dac8.tar.gz
6131 - operating on arrays on the stack
-rwxr-xr-xapps/mubin189700 -> 195063 bytes
-rw-r--r--apps/mu.subx344
-rw-r--r--mu_instructions6
-rw-r--r--mu_summary2
4 files changed, 306 insertions, 46 deletions
diff --git a/apps/mu b/apps/mu
index cfba9ca5..d18385ac 100755
--- a/apps/mu
+++ b/apps/mu
Binary files differdiff --git a/apps/mu.subx b/apps/mu.subx
index 8f632bf7..5f7114bd 100644
--- a/apps/mu.subx
+++ b/apps/mu.subx
@@ -2398,6 +2398,114 @@ test-convert-index-into-array-with-literal:
     5d/pop-to-ebp
     c3/return
 
+test-convert-index-into-array-on-stack:
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # setup
+    (clear-stream _test-input-stream)
+    (clear-stream $_test-input-buffered-file->buffer)
+    (clear-stream _test-output-stream)
+    (clear-stream $_test-output-buffered-file->buffer)
+    #
+    (write _test-input-stream "fn foo {\n")
+    (write _test-input-stream "  var arr: (array int 3)\n")
+    (write _test-input-stream "  var idx/eax: int <- copy 2\n")
+    (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
+    (write _test-input-stream "}\n")
+    # convert
+    (convert-mu _test-input-buffered-file _test-output-buffered-file)
+    (flush _test-output-buffered-file)
+#?     # dump _test-output-stream {{{
+#?     (write 2 "^")
+#?     (write-stream 2 _test-output-stream)
+#?     (write 2 "$\n")
+#?     (rewind-stream _test-output-stream)
+#?     # }}}
+    # check output
+    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
+    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
+    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
+    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
+    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
+    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
+    # var arr
+    (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
+    (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
+    # var idx
+    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
+    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
+    # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
+    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp + eax<<0x00000002 + 0xfffffff4) 0x00000000/r32"  "F - test-convert-index-into-array-on-stack/10")
+    # reclaim idx
+    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
+    # reclaim arr
+    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
+    #
+    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
+    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
+    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
+    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
+    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
+    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+test-convert-index-into-array-on-stack-with-literal:
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # setup
+    (clear-stream _test-input-stream)
+    (clear-stream $_test-input-buffered-file->buffer)
+    (clear-stream _test-output-stream)
+    (clear-stream $_test-output-buffered-file->buffer)
+    #
+    (write _test-input-stream "fn foo {\n")
+    (write _test-input-stream "  var arr: (array int 3)\n")
+    (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
+    (write _test-input-stream "}\n")
+    # convert
+    (convert-mu _test-input-buffered-file _test-output-buffered-file)
+    (flush _test-output-buffered-file)
+#?     # dump _test-output-stream {{{
+#?     (write 2 "^")
+#?     (write-stream 2 _test-output-stream)
+#?     (write 2 "$\n")
+#?     (rewind-stream _test-output-stream)
+#?     # }}}
+    # check output
+    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
+    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
+    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
+    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
+    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
+    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
+    # var arr
+    (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
+    (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
+    # var x
+    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
+    # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
+    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp + 0xfffffffc) 0x00000000/r32"  "F - test-convert-index-into-array-on-stack-with-literal/9")
+    # reclaim x
+    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
+    # reclaim arr
+    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack-with-literal/11")
+    #
+    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
+    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
+    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
+    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
+    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
+    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
 test-convert-index-into-array-using-offset:
     # . prologue
     55/push-ebp
@@ -6663,7 +6771,7 @@ compute-reg-and-maybe-emit-spill:  # out: (addr buffered-file), stmt: (handle re
     (already-spilled-this-block? %ecx *(ebp+0x10))  # => eax
     3d/compare-eax-and 0/imm32/false
     75/jump-if-!= $compute-reg-and-maybe-emit-spill:end/disp8
-    # TODO: assert(sizeof(output) == 4)
+    # TODO: assert(size-of(output) == 4)
     # *Curr-local-stack-offset -= 4
     81 5/subop/subtract *Curr-local-stack-offset 4/imm32
     # emit spill
@@ -7397,6 +7505,58 @@ translate-mu-index-stmt:  # out: (address buffered-file), stmt: (handle stmt)
     55/push-ebp
     89/<- %ebp 4/r32/esp
     # . save registers
+    51/push-ecx
+    # var base/ecx: (handle var) = stmt->inouts[0]
+    8b/-> *(ebp+0xc) 1/r32/ecx
+    8b/-> *(ecx+8) 1/r32/ecx  # Stmt1-inouts
+    8b/-> *ecx 1/r32/ecx  # Stmt-var-value
+    # if (var->register) do one thing
+    {
+      81 7/subop/compare *(ecx+0x10) 0/imm32  # Var-register
+      74/jump-if-= break/disp8
+      # TODO: ensure there's no dereference
+      (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc))
+      eb/jump $translate-mu-index-stmt:end/disp8
+    }
+    # if (var->offset) do a different thing
+    {
+      81 7/subop/compare *(ecx+0xc) 0/imm32  # Var-offset
+      74/jump-if-= break/disp8
+      # TODO: ensure there's no dereference
+      (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc))
+      eb/jump $translate-mu-index-stmt:end/disp8
+    }
+$translate-mu-index-stmt:end:
+    # . restore registers
+    59/pop-to-ecx
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+$translate-mu-index-stmt-with-array:error1:
+    (write-buffered Stderr "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
+    (flush Stderr)
+    # . syscall(exit, 1)
+    bb/copy-to-ebx  1/imm32
+    b8/copy-to-eax  1/imm32/exit
+    cd/syscall  0x80/imm8
+    # never gets here
+
+$translate-mu-index-stmt-with-array:error2:
+    (write-buffered Stderr "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
+    (flush Stderr)
+    # . syscall(exit, 1)
+    bb/copy-to-ebx  1/imm32
+    b8/copy-to-eax  1/imm32/exit
+    cd/syscall  0x80/imm8
+    # never gets here
+
+translate-mu-index-stmt-with-array-in-register:  # out: (address buffered-file), stmt: (handle stmt)
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
     50/push-eax
     51/push-ecx
     52/push-edx
@@ -7405,7 +7565,7 @@ translate-mu-index-stmt:  # out: (address buffered-file), stmt: (handle stmt)
     (emit-indent *(ebp+8) *Curr-block-depth)
     (write-buffered *(ebp+8) "8d/copy-address *(")
     # TODO: ensure inouts[0] is in a register and not dereferenced
-$translate-mu-index-stmt:emit-base:
+$translate-mu-index-stmt-with-array-in-register:emit-base:
     # ecx = stmt
     8b/-> *(ebp+0xc) 1/r32/ecx
     # var base/ebx: (handle var) = inouts[0]
@@ -7415,62 +7575,61 @@ $translate-mu-index-stmt:emit-base:
     (write-buffered *(ebp+8) *(ebx+0x10))  # Var-register
     #
     (write-buffered *(ebp+8) " + ")
-    # var idx/edx: (handle var) = inouts[1]
+    # var index/edx: (handle var) = inouts[1]
     8b/-> *(ecx+8) 2/r32/edx  # Stmt1-inouts
     8b/-> *(edx+4) 2/r32/edx  # Stmt-var-next
     8b/-> *edx 2/r32/edx  # Stmt-var-value
-    # if inouts[1]->register
+    # if index->register
     81 7/subop/compare *(edx+0x10) 0/imm32  # Var-register
     {
       0f 84/jump-if-= break/disp32
-$translate-mu-index-stmt:emit-register-index:
-      # if inouts[1] is an int
+$translate-mu-index-stmt-with-array-in-register:emit-register-index:
+      # if index is an int
       (is-simple-mu-type? *(edx+4) 1)  # Var-type, int => eax
       3d/compare-eax-and 0/imm32/false
       {
         0f 84/jump-if-= break/disp32
-$translate-mu-index-stmt:emit-int-register-index:
-        # print inouts[1]->register "<<" log2(sizeof(element(inouts[0]->type))) " + 4) "
-        # . inouts[1]->register "<<"
+$translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
+        # print index->register "<<" log2(size-of(element(base->type))) " + 4) "
+        # . index->register "<<"
         (write-buffered *(ebp+8) *(edx+0x10))  # Var-register
         (write-buffered *(ebp+8) "<<")
-        # . log2(sizeof(element(inouts[0]->type)))
+        # . log2(size-of(element(base->type)))
         # TODO: ensure size is a power of 2
         (array-element-type-id %ebx)  # => eax
         (size-of-type-id %eax)  # => eax
         (num-shift-rights %eax)  # => eax
         (print-int32-buffered *(ebp+8) %eax)
-        e9/jump $translate-mu-index-stmt:emit-register-index-done/disp32
+        e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
       }
-      # if inouts[1]->type is any other atom, abort
+      # if index->type is any other atom, abort
       8b/-> *(edx+4) 0/r32/eax  # Var-type
       8b/-> *eax 0/r32/eax  # Tree-left or Atom-value
       3b/compare 0/r32/eax *Max-type-id
-      0f 82/jump-if-addr< $translate-mu-index-stmt:error2/disp32
-      # if inouts[1] is (offset ...)
+      0f 82/jump-if-addr< $translate-mu-index-stmt-with-array:error2/disp32
+      # if index has type (offset ...)
       (is-simple-mu-type? %eax 7)  # offset => eax
       3d/compare-eax-and 0/imm32/false
       {
         0f 84/jump-if-= break/disp32
-        # print inouts[1]->register "<<" log2(sizeof(element(inouts[0]->type))) " + 4) "
-$translate-mu-index-stmt:emit-offset-register-index:
-        # . inouts[1]->register
+        # print index->register " + 4) "
+$translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
         (write-buffered *(ebp+8) *(edx+0x10))  # Var-register
       }
-$translate-mu-index-stmt:emit-register-index-done:
+$translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
       (write-buffered *(ebp+8) " + 4) ")
-      e9/jump $translate-mu-index-stmt:emit-output/disp32
+      e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
     }
-    # otherwise if inouts[1] is a literal
+    # otherwise if index is a literal
     (is-simple-mu-type? *(edx+4) 0)  # Var-type => eax
     3d/compare-eax-and 0/imm32/false
     {
       0f 84/jump-if-= break/disp32
-$translate-mu-index-stmt:emit-literal-index:
-      # var idx-value/edx: int = parse-hex-int(inouts[1]->name)
+$translate-mu-index-stmt-with-array-in-register:emit-literal-index:
+      # var index-value/edx: int = parse-hex-int(index->name)
       (parse-hex-int *edx)  # Var-name => eax
       89/<- %edx 0/r32/eax
-      # offset = n * sizeof(element(inouts[0]->type))
+      # offset = idx-value * size-of(element(base->type))
       (array-element-type-id %ebx)  # => eax
       (size-of-type-id %eax)  # => eax
       f7 4/subop/multiply-into-eax %edx  # clobbers edx
@@ -7480,18 +7639,19 @@ $translate-mu-index-stmt:emit-literal-index:
       # print offset
       (print-int32-buffered *(ebp+8) %eax)
       (write-buffered *(ebp+8) ") ")
-      e9/jump $translate-mu-index-stmt:emit-output/disp32
+      e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
     }
     # otherwise abort
-    e9/jump $translate-mu-index-stmt:error1/disp32
-$translate-mu-index-stmt:emit-output:
+    e9/jump $translate-mu-index-stmt-with-array:error1/disp32
+$translate-mu-index-stmt-with-array-in-register:emit-output:
     # outputs[0] "/r32"
+    8b/-> *(ebp+0xc) 1/r32/ecx
     8b/-> *(ecx+0xc) 0/r32/eax  # Stmt1-outputs
     8b/-> *eax 0/r32/eax  # Stmt-var-value
     (get Registers *(eax+0x10) 8 "Registers")  # Var-register => eax
     (print-int32-buffered *(ebp+8) *eax)
     (write-buffered *(ebp+8) "/r32\n")
-$translate-mu-index-stmt:end:
+$translate-mu-index-stmt-with-array-in-register:end:
     # . restore registers
     5b/pop-to-ebx
     5a/pop-to-edx
@@ -7502,23 +7662,117 @@ $translate-mu-index-stmt:end:
     5d/pop-to-ebp
     c3/return
 
-$translate-mu-index-stmt:error1:
-    (write-buffered Stderr "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
-    (flush Stderr)
-    # . syscall(exit, 1)
-    bb/copy-to-ebx  1/imm32
-    b8/copy-to-eax  1/imm32/exit
-    cd/syscall  0x80/imm8
-    # never gets here
-
-$translate-mu-index-stmt:error2:
-    (write-buffered Stderr "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
-    (flush Stderr)
-    # . syscall(exit, 1)
-    bb/copy-to-ebx  1/imm32
-    b8/copy-to-eax  1/imm32/exit
-    cd/syscall  0x80/imm8
-    # never gets here
+translate-mu-index-stmt-with-array-on-stack:  # out: (address buffered-file), stmt: (handle stmt)
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # . save registers
+    50/push-eax
+    51/push-ecx
+    52/push-edx
+    53/push-ebx
+    #
+    (emit-indent *(ebp+8) *Curr-block-depth)
+    (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
+    # var curr/eax = stmt->inouts
+    8b/-> *(ebp+0xc) 0/r32/eax
+    # var base/ecx: (handle var) = stmt->inouts[0]
+    8b/-> *(eax+8) 0/r32/eax  # Stmt1-inouts
+    8b/-> *eax 1/r32/ecx  # Stmt-var-value
+    # curr = curr->next
+    8b/-> *(eax+4) 0/r32/eax  # Stmt-var-next
+    # var index/edx: (handle var) = stmt->inouts[1]
+    8b/-> *eax 2/r32/edx  # Stmt-var-value
+    # if index->register
+    81 7/subop/compare *(edx+0x10) 0/imm32  # Var-register
+    {
+      0f 84/jump-if-= break/disp32
+$translate-mu-index-stmt-with-array-on-stack:emit-register-index:
+      # if index is an int
+      (is-simple-mu-type? *(edx+4) 1)  # Var-type, int => eax
+      3d/compare-eax-and 0/imm32/false
+      {
+        0f 84/jump-if-= break/disp32
+$translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
+        # print index->register "<<" log2(size-of(element-type(base))) " + " base->offset+4
+        # . inouts[1]->register "<<"
+        (write-buffered *(ebp+8) *(edx+0x10))  # Var-register
+        (write-buffered *(ebp+8) "<<")
+        # . log2(size-of(element(base)))
+        # TODO: ensure size is a power of 2
+        (array-element-type-id %ecx)  # => eax
+        (size-of-type-id %eax)  # => eax
+        (num-shift-rights %eax)  # => eax
+        (print-int32-buffered *(ebp+8) %eax)
+        #
+        (write-buffered *(ebp+8) " + ")
+        #
+        8b/-> *(ecx+0xc) 0/r32/eax  # Var-offset
+        05/add-to-eax 4/imm32
+        (print-int32-buffered *(ebp+8) %eax)
+        e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
+      }
+      # if index->type is any other atom, abort
+      8b/-> *(edx+4) 0/r32/eax  # Var-type
+      8b/-> *eax 0/r32/eax  # Tree-left or Atom-value
+      3b/compare 0/r32/eax *Max-type-id
+      0f 82/jump-if-addr< $translate-mu-index-stmt-with-array:error2/disp32
+      # if index has type (offset ...)
+      (is-simple-mu-type? %eax 7)  # offset => eax
+      3d/compare-eax-and 0/imm32/false
+      {
+        0f 84/jump-if-= break/disp32
+        # print index->register
+$translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
+        (write-buffered *(ebp+8) *(edx+0x10))  # Var-register
+      }
+$translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
+      (write-buffered *(ebp+8) ") ")
+      e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
+    }
+    # otherwise if index is a literal
+    (is-simple-mu-type? *(edx+4) 0)  # Var-type => eax
+    3d/compare-eax-and 0/imm32/false
+    {
+      0f 84/jump-if-= break/disp32
+$translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
+      # var idx-value/edx: int = parse-hex-int(index->name)
+      (parse-hex-int *edx)  # Var-name => eax
+      89/<- %ebx 0/r32/eax
+      # offset = idx-value * size-of(element-type(base->type))
+      (array-element-type-id %ecx)  # => eax
+      (size-of-type-id %eax)  # => eax
+      f7 4/subop/multiply-into-eax %ebx  # clobbers edx
+      # offset += base->offset
+      03/add-to 0/r32/eax *(ecx+0xc)  # Var-offset
+      # offset += 4 for array size
+      05/add-to-eax 4/imm32
+      # TODO: check edx for overflow
+      # print offset
+      (print-int32-buffered *(ebp+8) %eax)
+      (write-buffered *(ebp+8) ") ")
+      e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
+    }
+    # otherwise abort
+    e9/jump $translate-mu-index-stmt-with-array:error1/disp32
+$translate-mu-index-stmt-with-array-on-stack:emit-output:
+    # outputs[0] "/r32"
+    8b/-> *(ebp+0xc) 0/r32/eax
+    8b/-> *(eax+0xc) 0/r32/eax  # Stmt1-outputs
+    8b/-> *eax 0/r32/eax  # Stmt-var-value
+    (get Registers *(eax+0x10) 8 "Registers")  # Var-register => eax
+    (print-int32-buffered *(ebp+8) *eax)
+    (write-buffered *(ebp+8) "/r32\n")
+$translate-mu-index-stmt-with-array-on-stack:end:
+    # . restore registers
+    5b/pop-to-ebx
+    5a/pop-to-edx
+    59/pop-to-ecx
+    58/pop-to-eax
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
 
 translate-mu-compute-index-stmt:  # out: (address buffered-file), stmt: (handle stmt)
     # . prologue
@@ -7539,7 +7793,7 @@ $translate-mu-compute-index-stmt:emit-elem-size:
     8b/-> *(ecx+8) 2/r32/edx  # Stmt1-inouts
     # var base/ebx: (handle var)
     8b/-> *edx 3/r32/ebx  # Stmt-var-value
-    # print sizeof(element(base->type))
+    # print size-of(element(base->type))
     (array-element-type-id %ebx)  # => eax
     (size-of-type-id %eax)  # => eax
     (print-int32-buffered *(ebp+8) %eax)
diff --git a/mu_instructions b/mu_instructions
index fa696f82..a66ea67e 100644
--- a/mu_instructions
+++ b/mu_instructions
@@ -210,9 +210,13 @@ Array operations
 var/reg <- length arr/reg2: (addr array T)
                             {.name="length",          .inouts=[reg2], .outputs=[reg1],  .subx-name="8b/copy-from",          .rm32="*" inouts[0],                        .r32=outputs[0]}
 var/reg <- index arr/rega: (addr array T), idx/regi: int
-                            {.name="index",           .inouts=[rega, regi], .outputs=[reg], .subx-name="8d/copy-address",   .rm32="*(" inouts[0] "+" inouts[1] "<<2)",  .r32=outputs[0]}
+                            {.name="index",           .inouts=[rega, regi], .outputs=[reg], .subx-name="8d/copy-address",   .rm32="*(" inouts[0] "+" inouts[1] "<<" log2(sizeof(T)) "+4)", .r32=outputs[0]}
+var/reg <- index arr: (array T sz), idx/regi: int
+                            {.name="index",           .inouts=[arr, regi], .outputs=[reg], .subx-name="8d/copy-address",    .rm32="*(ebp+" inouts[1] "<<" log2(sizeof(T)) " + " inouts[0].stack-offset+4 ")",  .r32=outputs[0]}
 var/reg <- index arr/rega: (addr array T), n
                             {.name="index",           .inouts=[rega, n], .outputs=[reg], .subx-name="8d/copy-address",      .rm32="*(" inouts[0] "+" inouts[1]*size(T) ")",  .r32=outputs[0]}
+var/reg <- index arr: (array T sz), n
+                            {.name="index",           .inouts=[arr, n], .outputs=[reg], .subx-name="8d/copy-address",       .rm32="*(ebp+" inouts[0].stack-offset+4 + inouts[1]*size(T) ")",  .r32=outputs[0]}
 
 var/reg: (offset T) <- compute-offset arr: (addr array T), idx/regi: int  # arr can be in reg or mem
                             {.name="compute-offset",  .inouts=[arr, regi],  .outputs=[reg], .subx-name="69/multiply",       .rm32=inouts[1],                            .r32=outputs[0],    .imm32=sizeof(T)}
diff --git a/mu_summary b/mu_summary
index addfa340..7ecea2b1 100644
--- a/mu_summary
+++ b/mu_summary
@@ -199,7 +199,9 @@ Similarly, conditional loops:
 
   var/reg: int <- length arr/reg: (addr array T)
   var/reg: (addr T) <- index arr/reg: (addr array T), idx/reg: int
+  var/reg: (addr T) <- index arr: (array T sz), idx/reg: int
   var/reg: (addr T) <- index arr/reg: (addr array T), n
+  var/reg: (addr T) <- index arr: (array T sz), n
 
   var/reg: (offset T) <- compute-offset arr: (addr array T), idx/reg: int  # arr can be in reg or mem
   var/reg: (offset T) <- compute-offset arr: (addr array T), idx: int  # arr can be in reg or mem