From cd1d88799a9ee2c26c87a1a48819353887e816c4 Mon Sep 17 00:00:00 2001 From: Alexey Borzenkov Date: Wed, 25 Jan 2012 22:16:54 +0400 Subject: [PATCH] Fix support for Linux/S390 zSeries --- platform/switch_s390_unix.h | 43 +++++++++++++++++++++++++++++++------ slp_platformselect.h | 2 +- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/platform/switch_s390_unix.h b/platform/switch_s390_unix.h index a96c741e..88a42a6a 100644 --- a/platform/switch_s390_unix.h +++ b/platform/switch_s390_unix.h @@ -2,6 +2,11 @@ * this is the internal transfer function. * * HISTORY + * 25-Jan-12 Alexey Borzenkov + * Fixed Linux/S390 port to work correctly with + * different optimization options both on 31-bit + * and 64-bit. Thanks to Stefan Raabe for lots + * of testing. * 24-Nov-02 Christian Tismer * needed to add another magic constant to insure * that f in slp_eval_frame(PyFrameObject *f) @@ -15,24 +20,50 @@ #ifdef SLP_EVAL -#define STACK_MAGIC 0 +#ifdef __s390x__ +#define STACK_MAGIC 20 /* 20 * 8 = 160 bytes of function call area */ +#else +#define STACK_MAGIC 24 /* 24 * 4 = 96 bytes of function call area */ +#endif -#define REGS_TO_SAVE "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r14", \ +/* Technically, r11-r13 also need saving, but function prolog starts + with stm(g) and since there are so many saved registers already + it won't be optimized, resulting in all r6-r15 being saved */ +#define REGS_TO_SAVE "r6", "r7", "r8", "r9", "r10", "r14", \ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15" static int slp_switch(void) { - register int *stackref, stsizediff; + register long *stackref, stsizediff; __asm__ volatile ("" : : : REGS_TO_SAVE); - __asm__ ("lr %0, 15" : "=g" (stackref) : ); +#ifdef __s390x__ + __asm__ volatile ("lgr %0, 15" : "=r" (stackref) : ); +#else + __asm__ volatile ("lr %0, 15" : "=r" (stackref) : ); +#endif { SLP_SAVE_STATE(stackref, stsizediff); +/* N.B. + r11 may be used as the frame pointer, and in that case it cannot be + clobbered and needs offsetting just like the stack pointer (but in cases + where frame pointer isn't used we might clobber it accidentally). What's + scary is that r11 is 2nd (and even 1st when GOT is used) callee saved + register that gcc would chose for surviving function calls. However, + since r6-r10 are clobbered above, their cost for reuse is reduced, so + gcc IRA will chose them over r11 (not seeing r11 is implicitly saved), + making it relatively safe to offset in all cases. :) */ __asm__ volatile ( - "ar 15, %0" +#ifdef __s390x__ + "agr 15, %0\n\t" + "agr 11, %0" +#else + "ar 15, %0\n\t" + "ar 11, %0" +#endif : /* no outputs */ - : "g" (stsizediff) + : "r" (stsizediff) ); SLP_RESTORE_STATE(); } diff --git a/slp_platformselect.h b/slp_platformselect.h index 04fddf22..efbc00dc 100644 --- a/slp_platformselect.h +++ b/slp_platformselect.h @@ -25,7 +25,7 @@ #elif defined(__GNUC__) && defined(__s390__) && defined(__linux__) #include "platform/switch_s390_unix.h" /* Linux/S390 */ #elif defined(__GNUC__) && defined(__s390x__) && defined(__linux__) -#include "platform/switch_s390_unix.h" /* Linux/S390 zSeries (identical) */ +#include "platform/switch_s390_unix.h" /* Linux/S390 zSeries (64-bit) */ #elif defined(__GNUC__) && defined(__arm__) #include "platform/switch_arm32_gcc.h" /* gcc using arm32 */ #elif defined(__GNUC__) && defined(__mips__) && defined(__linux__)