summaryrefslogtreecommitdiff
path: root/coroutine/ppc64le
diff options
context:
space:
mode:
authorodaira <odaira@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-12-10 23:22:56 +0000
committerodaira <odaira@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-12-10 23:22:56 +0000
commit3a5cc345f8bab6d179f79265ba20234e41494a68 (patch)
tree4a1344ced170115c98519b3b3df165c24fc3ae1c /coroutine/ppc64le
parentdff1e89bfb77e5d57bc56312364ac2036f3f7a99 (diff)
Native coroutine implementation for ppc64le Linux
* configure.ac: enable fiber coroutine for powerpc64le-linux * coroutine/ppc64le/Context.S: coroutine_transfer implementation * coroutine/ppc64le/Context.h: coroutine implementation git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66315 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'coroutine/ppc64le')
-rw-r--r--coroutine/ppc64le/Context.S72
-rw-r--r--coroutine/ppc64le/Context.h54
2 files changed, 126 insertions, 0 deletions
diff --git a/coroutine/ppc64le/Context.S b/coroutine/ppc64le/Context.S
new file mode 100644
index 0000000000..1b39086f8f
--- /dev/null
+++ b/coroutine/ppc64le/Context.S
@@ -0,0 +1,72 @@
+.text
+.align 2
+
+.globl coroutine_transfer
+.type coroutine_transfer, @function
+coroutine_transfer:
+ # Make space on the stack for caller registers
+ addi 1,1,-152
+
+ # Save caller registers
+ std 14,0(1)
+ std 15,8(1)
+ std 16,16(1)
+ std 17,24(1)
+ std 18,32(1)
+ std 19,40(1)
+ std 20,48(1)
+ std 21,56(1)
+ std 22,64(1)
+ std 23,72(1)
+ std 24,80(1)
+ std 25,88(1)
+ std 26,96(1)
+ std 27,104(1)
+ std 28,112(1)
+ std 29,120(1)
+ std 30,128(1)
+ std 31,136(1)
+
+ # Save return address
+ mflr 0
+ std 0,144(1)
+
+ # Save stack pointer to first argument
+ std 1,0(3)
+
+ # Load stack pointer from second argument
+ ld 1,0(4)
+
+ # Restore caller registers
+ ld 14,0(1)
+ ld 15,8(1)
+ ld 16,16(1)
+ ld 17,24(1)
+ ld 18,32(1)
+ ld 19,40(1)
+ ld 20,48(1)
+ ld 21,56(1)
+ ld 22,64(1)
+ ld 23,72(1)
+ ld 24,80(1)
+ ld 25,88(1)
+ ld 26,96(1)
+ ld 27,104(1)
+ ld 28,112(1)
+ ld 29,120(1)
+ ld 30,128(1)
+ ld 31,136(1)
+
+ # Load return address
+ ld 0,144(1)
+ mtlr 0
+
+ # Pop stack frame
+ addi 1,1,152
+
+ # Jump to return address
+ blr
+
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/coroutine/ppc64le/Context.h b/coroutine/ppc64le/Context.h
new file mode 100644
index 0000000000..de592f5a46
--- /dev/null
+++ b/coroutine/ppc64le/Context.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <assert.h>
+#include <string.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+#define COROUTINE __attribute__((noreturn)) void
+
+const size_t COROUTINE_REGISTERS =
+ 19 /* 18 general purpose registers (r14-r31) and 1 return address */
+ + 4; /* space for fiber_entry() to store the link register */
+
+typedef struct
+{
+ void **stack_pointer;
+} coroutine_context;
+
+typedef COROUTINE(* coroutine_start)(coroutine_context *from, coroutine_context *self);
+
+static inline void coroutine_initialize(
+ coroutine_context *context,
+ coroutine_start start,
+ void *stack_pointer,
+ size_t stack_size
+) {
+ /* Force 16-byte alignment */
+ context->stack_pointer = (void**)((uintptr_t)stack_pointer & ~0xF);
+
+ if (!start) {
+ assert(!context->stack_pointer);
+ /* We are main coroutine for this thread */
+ return;
+ }
+
+ context->stack_pointer -= COROUTINE_REGISTERS;
+ memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
+
+ /* Skip a global prologue that sets the TOC register */
+ context->stack_pointer[18] = ((char*)start) + 8;
+}
+
+coroutine_context * coroutine_transfer(coroutine_context * current, coroutine_context * target);
+
+static inline void coroutine_destroy(coroutine_context * context)
+{
+ context->stack_pointer = NULL;
+}
+
+#if __cplusplus
+}
+#endif