about summary refs log tree commit diff stats
path: root/101stack_allocate.subx
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-03-11 16:52:37 -0700
committerKartik Agaram <vc@akkartik.com>2020-03-11 17:21:59 -0700
commit28746b36660093dcbf53667f4f67320d278359ea (patch)
treea3feabc3190234fcb9c2dd8802250c191c53bea2 /101stack_allocate.subx
parentbfb7c601354563498433d22f4dcf3ad4280a7314 (diff)
downloadmu-28746b36660093dcbf53667f4f67320d278359ea.tar.gz
6123 - runtime helper for initializing arrays
I built this in 3 phases:
a) create a helper in the bootstrap VM to render the state of the stack.
b) interactively arrive at the right function (tools/stack_array.subx)
c) pull the final solution into the standard library (093stack_allocate.subx)

As the final layer says, this may not be the fastest approach for most
(or indeed any) Mu programs. Perhaps it's better on balance for the compiler
to just emit n/4 `push` instructions.

(I'm sure this solution can be optimized further.)
Diffstat (limited to '101stack_allocate.subx')
-rw-r--r--101stack_allocate.subx62
1 files changed, 62 insertions, 0 deletions
diff --git a/101stack_allocate.subx b/101stack_allocate.subx
new file mode 100644
index 00000000..02ad84f2
--- /dev/null
+++ b/101stack_allocate.subx
@@ -0,0 +1,62 @@
+# A function which pushes n zeros on the stack.
+# Not really useful to call manually.
+# The Mu compiler uses it when defining arrays on the stack.
+
+== code
+
+#? Entry:
+#?     # . prologue
+#?     89/<- %ebp 4/r32/esp
+#?     #
+#?     68/push 0xfcfdfeff/imm32
+#?     b8/copy-to-eax 0x34353637/imm32
+#? $dump-stack0:
+#?     (push-n-zero-bytes 4)
+#?     68/push 0x20/imm32
+#? $dump-stack9:
+#?     b8/copy-to-eax 1/imm32/exit
+#?     cd/syscall 0x80/imm8
+
+# This is not a regular function, so it won't be idiomatic.
+# Registers must be properly restored.
+# Registers can be spilled, but that modifies the stack and needs to be
+# cleaned up.
+
+# Overhead:
+#   62 + n*6 instructions to push n bytes.
+# If we just emitted code to push n zeroes, it would be:
+#   5 bytes for 4 zero bytes, so 1.25 bytes per zero. And that's not even
+#   instructions.
+# But on the other hand it would destroy the instruction cache, where this
+# approach requires 15 instructions, fixed.
+
+# n must be positive
+push-n-zero-bytes:  # n: int
+$push-n-zero-bytes:prologue:
+    89/<- *Push-n-zero-bytes-ebp 5/r32/ebp  # spill ebp without affecting stack
+    89/<- %ebp 4/r32/esp
+$push-n-zero-bytes:copy-ra:
+    # -- esp = ebp
+    50/push-eax
+    # -- esp+8 = ebp+4
+    # -- esp+4 = ebp
+    8b/-> *(esp+4) 0/r32/eax
+    2b/subtract *(ebp+4) 4/r32/esp
+    # -- esp+4+n = ebp
+    89/<- *(esp+4) 0/r32/eax
+    58/pop-to-eax
+    # -- esp+n = ebp
+$push-n-zero-bytes:bulk-cleaning:
+    89/<- *Push-n-zero-bytes-esp 4/r32/esp
+    81 0/subop/add *Push-n-zero-bytes-esp 4/imm32
+    81 0/subop/add *(ebp+4) 4/imm32
+    (zero-out *Push-n-zero-bytes-esp *(ebp+4))  # n+4
+$push-n-zero-bytes:epilogue:
+    8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp  # restore spill
+    c3/return
+
+== data
+Push-n-zero-bytes-ebp:  # (addr int)
+  0/imm32
+Push-n-zero-bytes-esp:  # (addr int)
+  0/imm32