summaryrefslogtreecommitdiff
path: root/zap/src/mem/foreach.S
diff options
context:
space:
mode:
Diffstat (limited to 'zap/src/mem/foreach.S')
-rw-r--r--zap/src/mem/foreach.S71
1 files changed, 71 insertions, 0 deletions
diff --git a/zap/src/mem/foreach.S b/zap/src/mem/foreach.S
new file mode 100644
index 0000000..fe96538
--- /dev/null
+++ b/zap/src/mem/foreach.S
@@ -0,0 +1,71 @@
+/*
+ Copyright 2022 Gabriel Jensen.
+ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+ If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+
+#include <zap/priv.h>
+
+.globl zap_foreach
+
+zap_foreach:
+
+ /*
+ void * ptr
+ zap_sz sz
+ zap_sz num
+ void (* fn)(void *)
+ */
+
+#if defined(__amd64__)
+
+ # rbx: Address of the current element.
+ # r12: Address of the element after the last input element.
+ # r13: Size of each input element.
+ # r14: Address of the function.
+
+ # We're gonna use callee-saved registers for storing values so they don't get overwritten with each function call.
+
+ # Push the callee-saved registers:
+ pushq %rbx
+ pushq %r12
+ pushq %r13
+ pushq %r14
+
+ # Move registers into place:
+ movq %rdi,%rbx
+ movq %rsi,%r13
+ movq %rcx,%r14
+
+ # Get the one-past-the-end address:
+ movq %rdx,%r12
+ imulq %r13,%r12 # Calculate the array size in bytes (sz * num). We're using signed multiply because the equivalent using the unsigned instruction would use more instructions.
+ addq %rbx,%r12
+
+ # Iterate through the array:
+.loop:
+
+ # Check if we have reached the one-past-the-end address:
+ cmpq %rbx,%r12
+ je .done
+
+ # Call the provided function:
+ movq %rbx,%rdi # Provide the current address to the function.
+ call *%r14 # We don't need to save any registers for this as we only use callee-saved registers.
+
+ # Continue to the next element:
+ addq %r13,%rbx
+ jmp .loop
+
+ # Finish:
+.done:
+
+ # Restore the callee-saved registers:
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %rbx
+
+ ret
+
+#endif