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
This commit is contained in:
odaira 2018-12-10 23:22:56 +00:00
Родитель dff1e89bfb
Коммит 3a5cc345f8
3 изменённых файлов: 129 добавлений и 0 удалений

Просмотреть файл

@ -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=
]

Просмотреть файл

@ -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

Просмотреть файл

@ -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