From 3a5cc345f8bab6d179f79265ba20234e41494a68 Mon Sep 17 00:00:00 2001 From: odaira Date: Mon, 10 Dec 2018 23:22:56 +0000 Subject: [PATCH] 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 --- configure.ac | 3 ++ coroutine/ppc64le/Context.S | 72 +++++++++++++++++++++++++++++++++++++ coroutine/ppc64le/Context.h | 54 ++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 coroutine/ppc64le/Context.S create mode 100644 coroutine/ppc64le/Context.h diff --git a/configure.ac b/configure.ac index 845e7e154d..4e3f1ef0e5 100644 --- a/configure.ac +++ b/configure.ac @@ -2331,6 +2331,9 @@ AS_CASE(["$rb_cv_fiber_coroutine"], [yes|''], [ [x64-mingw32], [ rb_cv_fiber_coroutine=win64 ], + [powerpc64le-linux], [ + rb_cv_fiber_coroutine=ppc64le + ], [*], [ rb_cv_fiber_coroutine= ] 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 +#include + +#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