about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xapps/mubin238793 -> 239403 bytes
-rw-r--r--apps/mu.subx110
-rw-r--r--mu_instructions26
3 files changed, 113 insertions, 23 deletions
diff --git a/apps/mu b/apps/mu
index 611e1302..466ec552 100755
--- a/apps/mu
+++ b/apps/mu
Binary files differdiff --git a/apps/mu.subx b/apps/mu.subx
index 3d6c9dc2..1d1d60ab 100644
--- a/apps/mu.subx
+++ b/apps/mu.subx
@@ -2436,14 +2436,15 @@ test-convert-length-of-array:
     (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
-    (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/9")
-    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/11")
-    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/12")
-    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/13")
-    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/14")
-    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/15")
-    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/16")
-    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/17")
+    (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
+    (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm32"  "F - test-convert-length-of-array/9")
+    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
+    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
+    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
+    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
+    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
+    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
+    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
     # . epilogue
     89/<- %esp 5/r32/ebp
     5d/pop-to-ebp
@@ -2484,14 +2485,15 @@ test-convert-length-of-array-on-stack:
     (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
     (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
     (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
-    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/10")
-    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/11")
-    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/12")
-    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/13")
-    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/14")
-    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/15")
-    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/16")
-    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/17")
+    (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm32"  "F - test-convert-length-of-array-on-stack/10")
+    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
+    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
+    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
+    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
+    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
+    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
+    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
+    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
     # . epilogue
     89/<- %esp 5/r32/ebp
     5d/pop-to-ebp
@@ -8842,28 +8844,31 @@ translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
     # . save registers
     50/push-eax
     51/push-ecx
+    52/push-edx
+    53/push-ebx
     # ecx = stmt
     8b/-> *(ebp+0xc) 1/r32/ecx
     #
     (emit-indent *(ebp+8) *Curr-block-depth)
     (write-buffered *(ebp+8) "8b/-> *")
-    # var base/eax: (handle var) = inouts[0]
+    # var base/ebx: (addr var) = inouts[0]
     (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
+    89/<- %ebx 0/r32/eax
     # if base is an (addr array ...) in a register
     {
-      81 7/subop/compare *(eax+0x18)) 0/imm32  # Var-register
+      81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
       74/jump-if-= break/disp8
-      (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
+      (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
       (write-buffered *(ebp+8) %eax)
       eb/jump $translate-mu-length-stmt:emit-output/disp8
     }
     # otherwise if base is an (array ...) on the stack
     {
-      81 7/subop/compare *(eax+0x14)) 0/imm32  # Var-offset
+      81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
       74/jump-if-= break/disp8
       (write-buffered *(ebp+8) "(ebp+")
-      (print-int32-buffered *(ebp+8) *(eax+0x14))  # Var-offset
+      (print-int32-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
       (write-buffered *(ebp+8) ")")
     }
 $translate-mu-length-stmt:emit-output:
@@ -8871,12 +8876,40 @@ $translate-mu-length-stmt:emit-output:
     # outputs[0] "/r32"
     (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
     (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
+    # edx = outputs[0]->register
     (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
-    (get Registers %eax 0xc "Registers")  # => eax
+    89/<- %edx 0/r32/eax
+    #
+    (get Registers %edx 0xc "Registers")  # => eax
     (print-int32-buffered *(ebp+8) *eax)
     (write-buffered *(ebp+8) "/r32\n")
+$translate-mu-length-stmt:check-power-of-2:
+    # ecx = size-of(element-type(base))
+    (array-element-type-id %ebx)  # => eax
+    (size-of-type-id %eax)  # => eax
+    89/<- %ecx 0/r32/eax
+    #
+    (power-of-2? %ecx)  # => eax
+    3d/compare-eax-and 0/imm32/false
+    {
+      0f 84/jump-if-= break/disp32
+$translate-mu-length-stmt:is-power-of-2:
+      (emit-indent *(ebp+8) *Curr-block-depth)
+      (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
+      (write-buffered *(ebp+8) %edx)
+      (write-buffered *(ebp+8) Space)
+      (num-shift-rights %ecx)  # => eax
+      (print-int32-buffered *(ebp+8) %eax)
+      (write-buffered *(ebp+8) "/imm32\n")
+      eb/jump $translate-mu-length-stmt:end/disp8
+    }
+    {
+      75/jump-if-!= break/disp8
+$translate-mu-length-stmt:not-power-of-2:
+    }
 $translate-mu-length-stmt:end:
     # . restore registers
+    5b/pop-to-ebx
     59/pop-to-ecx
     58/pop-to-eax
     # . epilogue
@@ -9310,6 +9343,39 @@ $array-element-type-id:end:
     5d/pop-to-ebp
     c3/return
 
+power-of-2?:  # n: int -> result/eax: boolean
+    # precondition: n is positive
+    # . prologue
+    55/push-ebp
+    89/<- %ebp 4/r32/esp
+    # eax = n
+    8b/-> *(ebp+8) 0/r32/eax
+    # if (n < 0) abort
+    3d/compare-eax-with 0/imm32
+    0f 8c/jump-if-< $power-of-2?:abort/disp32
+    # var tmp/eax: int = n-1
+    48/decrement-eax
+    # var tmp2/eax: int = n & tmp
+    23/and-> *(ebp+8) 0/r32/eax
+    # return (tmp2 == 0)
+    3d/compare-eax-and 0/imm32
+    0f 94/set-byte-if-= %al
+    81 4/subop/and %eax 0xff/imm32
+$power-of-2?:end:
+    # . epilogue
+    89/<- %esp 5/r32/ebp
+    5d/pop-to-ebp
+    c3/return
+
+$power-of-2?:abort:
+    (write-buffered Stderr "power-of-2?: negative number\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
+
 num-shift-rights:  # n: int -> result/eax: int
     # precondition: n is a positive power of 2
     # . prologue
diff --git a/mu_instructions b/mu_instructions
index 1037e8e3..754f51bb 100644
--- a/mu_instructions
+++ b/mu_instructions
@@ -183,11 +183,35 @@ var/reg: (offset T) <- compute-offset arr: (addr array T), idx: int       # arr
 var/reg <- index arr/rega: (addr array T), o/rego: offset
   => "8d/copy-address *(" rega "+" rego "+4) " reg "/r32"
 
-Computing the length of an array can get complex.
+Computing the length of an array is complex.
 
 var/reg <- length arr/reg2: (addr array T)
   | if T is byte (TODO)
       => "8b/-> *" reg2 " " reg "/r32"
+  | if size-of(T) is 4 or 8 or 16 or 32 or 64 or 128
+      => "8b/-> *" reg2 " " reg "/r32"
+         "c1/shift 5/subop/logic-right %" reg " " log2(size-of(T)) "/imm8"
+  | otherwise (TODO)
+      x86 has no instruction to divide by a literal, so
+      we need up to 3 extra registers! eax/edx for division and say ecx
+      => if reg is not eax
+          "50/push-eax"
+         if reg is not ecx
+          "51/push-ecx"
+         if reg is not edx
+          "52/push-edx"
+         "8b/-> *" reg2 " eax/r32"
+         "31/xor %edx 2/r32/edx"  # sign-extend, but array size can't be negative
+         "b9/copy-to-ecx " size-of(T) "/imm32"
+         "f7 7/subop/idiv-eax-edx-by %ecx"
+         if reg is not eax
+           "89/<- %" reg " 0/r32/eax"
+         if reg is not edx
+          "5a/pop-to-edx"
+         if reg is not ecx
+          "59/pop-to-ecx"
+         if reg is not eax
+          "58/pop-to-eax"
 
 # User-defined types