diff --git a/addr2line.c b/addr2line.c index fe4ad84423..0d45ec9414 100644 --- a/addr2line.c +++ b/addr2line.c @@ -869,8 +869,11 @@ typedef struct { int type; } DebugInfoValue; -/* TODO: Big Endian */ +#if defined(WORDS_BIGENDIAN) +#define MERGE_2INTS(a,b,sz) (((uint64_t)(a)< #define COROUTINE __attribute__((noreturn)) void +#define COROUTINE_LIMITED_ADDRESS_SPACE enum { COROUTINE_REGISTERS = diff --git a/coroutine/ppc64/Context.S b/coroutine/ppc64/Context.S index 1bd9268f93..f8561e0e7d 100644 --- a/coroutine/ppc64/Context.S +++ b/coroutine/ppc64/Context.S @@ -1,70 +1,89 @@ +; Based on the code by Samuel Williams. Created by Sergey Fedorov on 04/06/2022. +; Credits to Samuel Williams, Rei Odaira and Iain Sandoe. Errors, if any, are mine. +; Some relevant examples: https://github.com/gcc-mirror/gcc/blob/master/libphobos/libdruntime/config/powerpc/switchcontext.S +; https://github.com/gcc-mirror/gcc/blob/master/libgcc/config/rs6000/darwin-gpsave.S +; https://www.ibm.com/docs/en/aix/7.2?topic=epilogs-saving-gprs-only + +; Notice that this code is only for Darwin (macOS). Darwin ABI differs from AIX and ELF. +; To add support for AIX, *BSD or *Linux, please make separate implementations. + #define TOKEN_PASTE(x,y) x##y #define PREFIXED_SYMBOL(prefix,name) TOKEN_PASTE(prefix,name) +.machine ppc64 ; = G5 .text -.align 3 .globl PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer) +.align 2 + PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer): - # Make space on the stack for caller registers - addi r1,r1,-152 + ; Make space on the stack for caller registers + ; (Should we rather use red zone? See libphobos example.) + subi r1,r1,160 - # Save caller registers - std r14,0(r1) - std r15,8(r1) - std r16,16(r1) - std r17,24(r1) - std r18,32(r1) - std r19,40(r1) - std r20,48(r1) - std r21,56(r1) - std r22,64(r1) - std r23,72(r1) - std r24,80(r1) - std r25,88(r1) - std r26,96(r1) - std r27,104(r1) - std r28,112(r1) - std r29,120(r1) - std r30,128(r1) - std r31,136(r1) - - # Save return address + ; Get LR mflr r0 - std r0,144(r1) - # Save stack pointer to first argument + ; Save caller registers + std r31,0(r1) + std r30,8(r1) + std r29,16(r1) + std r28,24(r1) + std r27,32(r1) + std r26,40(r1) + std r25,48(r1) + std r24,56(r1) + std r23,64(r1) + std r22,72(r1) + std r21,80(r1) + std r20,88(r1) + std r19,96(r1) + std r18,104(r1) + std r17,112(r1) + std r16,120(r1) + std r15,128(r1) + std r14,136(r1) + std r13,144(r1) + + ; Save return address + ; Possibly should rather be saved into linkage area, see libphobos and IBM docs + std r0,152(r1) + + ; Save stack pointer to first argument std r1,0(r3) - # Load stack pointer from second argument + ; Load stack pointer from second argument ld r1,0(r4) - # Restore caller registers - ld r14,0(r1) - ld r15,8(r1) - ld r16,16(r1) - ld r17,24(r1) - ld r18,32(r1) - ld r19,40(r1) - ld r20,48(r1) - ld r21,56(r1) - ld r22,64(r1) - ld r23,72(r1) - ld r24,80(r1) - ld r25,88(r1) - ld r26,96(r1) - ld r27,104(r1) - ld r28,112(r1) - ld r29,120(r1) - ld r30,128(r1) - ld r31,136(r1) + ; Load return address + ld r0,152(r1) - # Load return address - ld r0,144(r1) + ; Restore caller registers + ld r13,144(r1) + ld r14,136(r1) + ld r15,128(r1) + ld r16,120(r1) + ld r17,112(r1) + ld r18,104(r1) + ld r19,96(r1) + ld r20,88(r1) + ld r21,80(r1) + ld r22,72(r1) + ld r23,64(r1) + ld r24,56(r1) + ld r25,48(r1) + ld r26,40(r1) + ld r27,32(r1) + ld r28,24(r1) + ld r29,16(r1) + ld r30,8(r1) + ld r31,0(r1) + + ; Set LR mtlr r0 - # Pop stack frame - addi r1,r1,152 + ; Pop stack frame + addi r1,r1,160 - # Jump to return address + ; Jump to return address blr diff --git a/coroutine/ppc64/Context.h b/coroutine/ppc64/Context.h index 5b47511b9c..3e6f77f55a 100644 --- a/coroutine/ppc64/Context.h +++ b/coroutine/ppc64/Context.h @@ -12,7 +12,7 @@ enum { COROUTINE_REGISTERS = - 19 /* 18 general purpose registers (r14–r31) and 1 return address */ + 20 /* 19 general purpose registers (r13–r31) and 1 return address */ + 4 /* space for fiber_entry() to store the link register */ }; @@ -44,7 +44,7 @@ static inline void coroutine_initialize( 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; + context->stack_pointer[19] = ((char*)start) + 8; } struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target); diff --git a/dln.c b/dln.c index bf87251bb6..0edd709bbe 100644 --- a/dln.c +++ b/dln.c @@ -41,6 +41,10 @@ static void dln_loaderror(const char *format, ...); # include #endif +#if defined __APPLE__ +# include +#endif + #ifndef xmalloc void *xmalloc(); void *xcalloc(); @@ -58,7 +62,7 @@ void *xrealloc(); #include #ifndef S_ISDIR -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif #ifdef HAVE_SYS_PARAM_H diff --git a/error.c b/error.c index ceea1c55d1..67e81d08a0 100644 --- a/error.c +++ b/error.c @@ -668,7 +668,7 @@ bug_important_message(FILE *out, const char *const msg, size_t len) #undef CRASH_REPORTER_MAY_BE_CREATED #if defined(__APPLE__) && \ - (!defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6) + (!defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 || defined(__POWERPC__)) /* 10.6 PPC case */ # define CRASH_REPORTER_MAY_BE_CREATED #endif static void diff --git a/gc.c b/gc.c index 7373bcfd67..ffc610dcc7 100644 --- a/gc.c +++ b/gc.c @@ -1359,6 +1359,27 @@ tick(void) return val; } +/* Implementation for macOS PPC by @nobu + * See: https://github.com/ruby/ruby/pull/5975#discussion_r890045558 + */ +#elif defined(__POWERPC__) && defined(__APPLE__) +typedef unsigned long long tick_t; +#define PRItick "llu" + +static __inline__ tick_t +tick(void) +{ + unsigned long int upper, lower, tmp; + # define mftbu(r) __asm__ volatile("mftbu %0" : "=r"(r)) + # define mftb(r) __asm__ volatile("mftb %0" : "=r"(r)) + do { + mftbu(upper); + mftb(lower); + mftbu(tmp); + } while (tmp != upper); + return ((tick_t)upper << 32) | lower; +} + #elif defined(__aarch64__) && defined(__GNUC__) typedef unsigned long tick_t; #define PRItick "lu" diff --git a/gc.h b/gc.h index 3d863fce8a..e1ce802095 100644 --- a/gc.h +++ b/gc.h @@ -6,10 +6,12 @@ #define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movq\t%%rsp, %0" : "=r" (*(p))) #elif defined(__i386) && defined(__GNUC__) #define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movl\t%%esp, %0" : "=r" (*(p))) -#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && !defined(_AIX) +#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && !defined(_AIX) && !defined(__APPLE__) // Not Apple is NEEDED to unbreak ppc64 build on Darwin. Don't ask. #define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr\t%0, %%r1" : "=r" (*(p))) #elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && defined(_AIX) #define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr %0,1" : "=r" (*(p))) +#elif defined(__POWERPC__) && defined(__APPLE__) // Darwin ppc and ppc64 +#define SET_MACHINE_STACK_END(p) __asm__ volatile("mr %0, r1" : "=r" (*(p))) #elif defined(__aarch64__) && defined(__GNUC__) #define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mov\t%0, sp" : "=r" (*(p))) #else diff --git a/include/ruby/internal/config.h b/include/ruby/internal/config.h index 0c434e5b05..aa63376d7c 100644 --- a/include/ruby/internal/config.h +++ b/include/ruby/internal/config.h @@ -113,6 +113,8 @@ # define UNALIGNED_WORD_ACCESS 1 #elif defined(__powerpc64__) # define UNALIGNED_WORD_ACCESS 1 +#elif defined(__POWERPC__) // __POWERPC__ is defined for ppc and ppc64 on Darwin +# define UNALIGNED_WORD_ACCESS 1 #elif defined(__aarch64__) # define UNALIGNED_WORD_ACCESS 1 #elif defined(__mc68020__) diff --git a/regint.h b/regint.h index 6c88f278c1..00b4b6ed9b 100644 --- a/regint.h +++ b/regint.h @@ -49,10 +49,11 @@ # endif #endif +/* __POWERPC__ added to accommodate Darwin case. */ #ifndef UNALIGNED_WORD_ACCESS # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \ - defined(__powerpc64__) || defined(__aarch64__) || \ + defined(__powerpc64__) || defined(__POWERPC__) || defined(__aarch64__) || \ defined(__mc68020__) # define UNALIGNED_WORD_ACCESS 1 # else diff --git a/siphash.c b/siphash.c index 294e75eaec..61b8604fc9 100644 --- a/siphash.c +++ b/siphash.c @@ -34,10 +34,11 @@ #error "Only strictly little or big endian supported" #endif +/* __POWERPC__ added to accommodate Darwin case. */ #ifndef UNALIGNED_WORD_ACCESS # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \ - defined(__powerpc64__) || defined(__aarch64__) || \ + defined(__powerpc64__) || defined(__POWERPC__) || defined(__aarch64__) || \ defined(__mc68020__) # define UNALIGNED_WORD_ACCESS 1 # endif diff --git a/st.c b/st.c index cffcde273c..0fb8f82bc3 100644 --- a/st.c +++ b/st.c @@ -1671,10 +1671,11 @@ st_values_check(st_table *tab, st_data_t *values, st_index_t size, */ #define FNV_32_PRIME 0x01000193 +/* __POWERPC__ added to accommodate Darwin case. */ #ifndef UNALIGNED_WORD_ACCESS # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \ - defined(__powerpc64__) || defined(__aarch64__) || \ + defined(__powerpc64__) || defined(__POWERPC__) || defined(__aarch64__) || \ defined(__mc68020__) # define UNALIGNED_WORD_ACCESS 1 # endif diff --git a/tool/m4/ruby_default_arch.m4 b/tool/m4/ruby_default_arch.m4 index 03e52f7776..35eb8112f6 100644 --- a/tool/m4/ruby_default_arch.m4 +++ b/tool/m4/ruby_default_arch.m4 @@ -5,6 +5,7 @@ AS_CASE([$1], [arm64], [], [*64], [ARCH_FLAG=-m64], [[i[3-6]86]], [ARCH_FLAG=-m32], + [ppc], [ARCH_FLAG=-m32], [AC_MSG_ERROR(unknown target architecture: $target_archs)] ) AC_MSG_RESULT([$ARCH_FLAG]) diff --git a/vm_core.h b/vm_core.h index 9aee345210..3bd907b227 100644 --- a/vm_core.h +++ b/vm_core.h @@ -780,8 +780,8 @@ typedef struct rb_vm_struct { #define RUBY_VM_FIBER_VM_STACK_SIZE ( 16 * 1024 * sizeof(VALUE)) /* 64 KB or 128 KB */ #define RUBY_VM_FIBER_VM_STACK_SIZE_MIN ( 2 * 1024 * sizeof(VALUE)) /* 8 KB or 16 KB */ #define RUBY_VM_FIBER_MACHINE_STACK_SIZE ( 64 * 1024 * sizeof(VALUE)) /* 256 KB or 512 KB */ -#if defined(__powerpc64__) -#define RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN ( 32 * 1024 * sizeof(VALUE)) /* 128 KB or 256 KB */ +#if defined(__powerpc64__) || defined(__ppc64__) // macOS has __ppc64__ +#define RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN ( 32 * 1024 * sizeof(VALUE)) /* 128 KB or 256 KB */ #else #define RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN ( 16 * 1024 * sizeof(VALUE)) /* 64 KB or 128 KB */ #endif diff --git a/vm_exec.c b/vm_exec.c index 591a0de57b..0f59d08b96 100644 --- a/vm_exec.c +++ b/vm_exec.c @@ -55,7 +55,7 @@ static void vm_insns_counter_count_insn(int insn) {} #elif defined(__GNUC__) && defined(__i386__) #define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("e" reg) -#elif defined(__GNUC__) && defined(__powerpc64__) +#elif defined(__GNUC__) && (defined(__powerpc64__) || defined(__POWERPC__)) #define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("r" reg) #elif defined(__GNUC__) && defined(__aarch64__) @@ -92,7 +92,7 @@ vm_exec_core(rb_execution_context_t *ec, VALUE initial) DECL_SC_REG(rb_control_frame_t *, cfp, "15"); #define USE_MACHINE_REGS 1 -#elif defined(__GNUC__) && defined(__powerpc64__) +#elif defined(__GNUC__) && (defined(__powerpc64__) || defined(__POWERPC__)) DECL_SC_REG(const VALUE *, pc, "14"); DECL_SC_REG(rb_control_frame_t *, cfp, "15"); #define USE_MACHINE_REGS 1