Index: gcc-4.4.1/gcc/testsuite/gcc.target/powerpc/pr41175.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.4.1/gcc/testsuite/gcc.target/powerpc/pr41175.c 2009-10-06 14:09:19.757404626 -0700 @@ -0,0 +1,461 @@ +/* PR target/41175 */ +/* { dg-do run } */ +/* { dg-options "-Os" } */ + +#define X2(n) X1(n##0) X1(n##1) +#define X4(n) X2(n##0) X2(n##1) +#define X8(n) X4(n##0) X4(n##1) + +#ifndef __SPE__ +#define FLOAT_REG_CONSTRAINT "f" +#else +#define FLOAT_REG_CONSTRAINT "r" +#endif + +volatile int ll; + +__attribute__((noinline)) void +foo (void) +{ + asm volatile ("" : : : "memory"); +} + +__attribute__((noinline)) void +bar (char *p) +{ + asm volatile ("" : : "r" (p) : "memory"); +} + +__attribute__((noinline)) void +f1 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X8(c) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X8(c) "=m" (mem) : : "memory"); + foo (); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X8(c) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f2 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X8(c) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X8(c) "=m" (mem) : : "memory"); + char *pp = __builtin_alloca (ll); + bar (pp); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X8(c) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f3 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X8(c) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X8(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X8(c) "m" (mem) : "memory"); +} + +#ifndef __NO_FPRS__ +__attribute__((noinline)) void +f4 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X8(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X4(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X8(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X4(d) "=m" (mem) : : "memory"); + foo (); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X8(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X4(d) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f5 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X8(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X4(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X8(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X4(d) "=m" (mem) : : "memory"); + char *pp = __builtin_alloca (ll); + bar (pp); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X8(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X4(d) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f6 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X8(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X4(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X8(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X4(d) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X8(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X4(d) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f7 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X8(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X2(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X8(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X2(d) "=m" (mem) : : "memory"); + foo (); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X8(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X2(d) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f8 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X8(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X2(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X8(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X2(d) "=m" (mem) : : "memory"); + char *pp = __builtin_alloca (ll); + bar (pp); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X8(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X2(d) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f9 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X8(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X2(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X8(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X2(d) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X8(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X2(d) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f10 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X4(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X1(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X4(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X1(d) "=m" (mem) : : "memory"); + foo (); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X4(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X1(d) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f11 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X4(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X1(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X4(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X1(d) "=m" (mem) : : "memory"); + char *pp = __builtin_alloca (ll); + bar (pp); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X4(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X1(d) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f12 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X4(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X1(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X4(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X1(d) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X4(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X1(d) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f13 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X2(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X8(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X2(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X8(d) "=m" (mem) : : "memory"); + foo (); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X2(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X8(d) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f14 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X2(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X8(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X2(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X8(d) "=m" (mem) : : "memory"); + char *pp = __builtin_alloca (ll); + bar (pp); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X2(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X8(d) "m" (mem) : "memory"); +} + +__attribute__((noinline)) void +f15 (void) +{ + int mem; +#undef X1 +#define X1(n) int gpr##n = 0; + X8(a) X8(b) X2(c) +#undef X1 +#define X1(n) double fpr##n = 0.0; + X8(d) +#undef X1 +#define X1(n) "+r" (gpr##n), + asm volatile ("" : X8(a) "=m" (mem) : : "memory"); + asm volatile ("" : X8(b) "=m" (mem) : : "memory"); + asm volatile ("" : X2(c) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "+" FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : X8(d) "=m" (mem) : : "memory"); +#undef X1 +#define X1(n) "r" (gpr##n), + asm volatile ("" : : X8(a) "m" (mem) : "memory"); + asm volatile ("" : : X8(b) "m" (mem) : "memory"); + asm volatile ("" : : X2(c) "m" (mem) : "memory"); +#undef X1 +#define X1(n) FLOAT_REG_CONSTRAINT (fpr##n), + asm volatile ("" : : X8(d) "m" (mem) : "memory"); +} +#endif + +int +main () +{ + ll = 60; + f1 (); + f2 (); + f3 (); +#ifndef __NO_FPRS__ + f4 (); + f5 (); + f6 (); + f7 (); + f8 (); + f9 (); + f10 (); + f11 (); + f12 (); + f13 (); + f14 (); + f15 (); +#endif + return 0; +} Index: gcc-4.4.1/gcc/config/rs6000/spe.md =================================================================== --- gcc-4.4.1.orig/gcc/config/rs6000/spe.md 2009-10-06 13:51:50.387320717 -0700 +++ gcc-4.4.1/gcc/config/rs6000/spe.md 2009-10-06 14:09:19.767365878 -0700 @@ -3156,9 +3156,9 @@ [(match_parallel 0 "any_parallel_operand" [(clobber (reg:P 65)) (use (match_operand:P 1 "symbol_ref_operand" "s")) - (use (match_operand:P 2 "gpc_reg_operand" "r")) - (set (match_operand:V2SI 3 "memory_operand" "=m") - (match_operand:V2SI 4 "gpc_reg_operand" "r"))])] + (use (reg:P 11)) + (set (match_operand:V2SI 2 "memory_operand" "=m") + (match_operand:V2SI 3 "gpc_reg_operand" "r"))])] "TARGET_SPE_ABI" "bl %z1" [(set_attr "type" "branch") @@ -3168,9 +3168,9 @@ [(match_parallel 0 "any_parallel_operand" [(clobber (reg:P 65)) (use (match_operand:P 1 "symbol_ref_operand" "s")) - (use (match_operand:P 2 "gpc_reg_operand" "r")) - (set (match_operand:V2SI 3 "gpc_reg_operand" "=r") - (match_operand:V2SI 4 "memory_operand" "m"))])] + (use (reg:P 11)) + (set (match_operand:V2SI 2 "gpc_reg_operand" "=r") + (match_operand:V2SI 3 "memory_operand" "m"))])] "TARGET_SPE_ABI" "bl %z1" [(set_attr "type" "branch") @@ -3181,9 +3181,9 @@ [(return) (clobber (reg:P 65)) (use (match_operand:P 1 "symbol_ref_operand" "s")) - (use (match_operand:P 2 "gpc_reg_operand" "r")) - (set (match_operand:V2SI 3 "gpc_reg_operand" "=r") - (match_operand:V2SI 4 "memory_operand" "m"))])] + (use (reg:P 11)) + (set (match_operand:V2SI 2 "gpc_reg_operand" "=r") + (match_operand:V2SI 3 "memory_operand" "m"))])] "TARGET_SPE_ABI" "b %z1" [(set_attr "type" "branch") Index: gcc-4.4.1/gcc/config/rs6000/linux64.h =================================================================== --- gcc-4.4.1.orig/gcc/config/rs6000/linux64.h 2009-10-06 13:51:50.347316402 -0700 +++ gcc-4.4.1/gcc/config/rs6000/linux64.h 2009-10-06 14:09:19.777366800 -0700 @@ -433,11 +433,11 @@ extern int dot_symbols; #undef SAVE_FP_PREFIX #define SAVE_FP_PREFIX (TARGET_64BIT ? "._savef" : "_savefpr_") #undef SAVE_FP_SUFFIX -#define SAVE_FP_SUFFIX (TARGET_64BIT ? "" : "_l") +#define SAVE_FP_SUFFIX "" #undef RESTORE_FP_PREFIX #define RESTORE_FP_PREFIX (TARGET_64BIT ? "._restf" : "_restfpr_") #undef RESTORE_FP_SUFFIX -#define RESTORE_FP_SUFFIX (TARGET_64BIT ? "" : "_l") +#define RESTORE_FP_SUFFIX "" /* Dwarf2 debugging. */ #undef PREFERRED_DEBUGGING_TYPE Index: gcc-4.4.1/gcc/config/rs6000/rs6000.c =================================================================== --- gcc-4.4.1.orig/gcc/config/rs6000/rs6000.c 2009-10-06 14:09:04.737313663 -0700 +++ gcc-4.4.1/gcc/config/rs6000/rs6000.c 2009-10-06 14:09:19.797315286 -0700 @@ -15843,7 +15843,8 @@ static bool no_global_regs_above (int first, bool gpr) { int i; - for (i = first; i < gpr ? 32 : 64 ; i++) + int last = gpr ? 32 : 64; + for (i = first; i < last; i++) if (global_regs[i]) return false; return true; @@ -15860,54 +15861,136 @@ no_global_regs_above (int first, bool gp static GTY(()) rtx savres_routine_syms[N_SAVRES_REGISTERS][8]; -/* Return the symbol for an out-of-line register save/restore routine. +/* Temporary holding space for an out-of-line register save/restore + routine name. */ +static char savres_routine_name[30]; + +/* Return the name for an out-of-line register save/restore routine. + We are saving/restoring GPRs if GPR is true. */ + +static char * +rs6000_savres_routine_name (rs6000_stack_t *info, int regno, + bool savep, bool gpr, bool lr) +{ + const char *prefix = ""; + const char *suffix = ""; + + /* Different targets are supposed to define + {SAVE,RESTORE}_FP_{PREFIX,SUFFIX} with the idea that the needed + routine name could be defined with: + + sprintf (name, "%s%d%s", SAVE_FP_PREFIX, regno, SAVE_FP_SUFFIX) + + This is a nice idea in practice, but in reality, things are + complicated in several ways: + + - ELF targets have save/restore routines for GPRs. + + - SPE targets use different prefixes for 32/64-bit registers, and + neither of them fit neatly in the FOO_{PREFIX,SUFFIX} regimen. + + - PPC64 ELF targets have routines for save/restore of GPRs that + differ in what they do with the link register, so having a set + prefix doesn't work. (We only use one of the save routines at + the moment, though.) + + - PPC32 elf targets have "exit" versions of the restore routines + that restore the link register and can save some extra space. + These require an extra suffix. (There are also "tail" versions + of the restore routines and "GOT" versions of the save routines, + but we don't generate those at present. Same problems apply, + though.) + + We deal with all this by synthesizing our own prefix/suffix and + using that for the simple sprintf call shown above. */ + if (TARGET_SPE) + { + /* No floating point saves on the SPE. */ + gcc_assert (gpr); + + if (savep) + prefix = info->spe_64bit_regs_used ? "_save64gpr_" : "_save32gpr_"; + else + prefix = info->spe_64bit_regs_used ? "_rest64gpr_" : "_rest32gpr_"; + + if (lr) + suffix = "_x"; + } + else if (DEFAULT_ABI == ABI_V4) + { + if (TARGET_64BIT) + goto aix_names; + + if (gpr) + prefix = savep ? "_savegpr_" : "_restgpr_"; + else + prefix = savep ? "_savefpr_" : "_restfpr_"; + + if (lr) + suffix = "_x"; + } + else if (DEFAULT_ABI == ABI_AIX) + { +#ifndef POWERPC_LINUX + /* No out-of-line save/restore routines for GPRs on AIX. */ + gcc_assert (!TARGET_AIX || !gpr); +#endif + + aix_names: + if (gpr) + prefix = (savep + ? (lr ? "_savegpr0_" : "_savegpr1_") + : (lr ? "_restgpr0_" : "_restgpr1_")); +#ifdef POWERPC_LINUX + else if (lr) + prefix = (savep ? "_savefpr_" : "_restfpr_"); +#endif + else + { + prefix = savep ? SAVE_FP_PREFIX : RESTORE_FP_PREFIX; + suffix = savep ? SAVE_FP_SUFFIX : RESTORE_FP_SUFFIX; + } + } + else if (DEFAULT_ABI == ABI_DARWIN) + sorry ("Out-of-line save/restore routines not supported on Darwin"); + + sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix); + + return savres_routine_name; +} + +/* Return an RTL SYMBOL_REF for an out-of-line register save/restore routine. We are saving/restoring GPRs if GPR is true. */ static rtx -rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep, bool gpr, bool exitp) +rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep, + bool gpr, bool lr) { int regno = gpr ? info->first_gp_reg_save : (info->first_fp_reg_save - 32); rtx sym; int select = ((savep ? 1 : 0) << 2 - | (gpr - /* On the SPE, we never have any FPRs, but we do have - 32/64-bit versions of the routines. */ - ? (TARGET_SPE_ABI && info->spe_64bit_regs_used ? 1 : 0) - : 0) << 1 - | (exitp ? 1: 0)); + | ((TARGET_SPE_ABI + /* On the SPE, we never have any FPRs, but we do have + 32/64-bit versions of the routines. */ + ? (info->spe_64bit_regs_used ? 1 : 0) + : (gpr ? 1 : 0)) << 1) + | (lr ? 1: 0)); /* Don't generate bogus routine names. */ - gcc_assert (FIRST_SAVRES_REGISTER <= regno && regno <= LAST_SAVRES_REGISTER); + gcc_assert (FIRST_SAVRES_REGISTER <= regno + && regno <= LAST_SAVRES_REGISTER); sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select]; if (sym == NULL) { - char name[30]; - const char *action; - const char *regkind; - const char *exit_suffix; - - action = savep ? "save" : "rest"; - - /* SPE has slightly different names for its routines depending on - whether we are saving 32-bit or 64-bit registers. */ - if (TARGET_SPE_ABI) - { - /* No floating point saves on the SPE. */ - gcc_assert (gpr); - - regkind = info->spe_64bit_regs_used ? "64gpr" : "32gpr"; - } - else - regkind = gpr ? "gpr" : "fpr"; - - exit_suffix = exitp ? "_x" : ""; + char *name; - sprintf (name, "_%s%s_%d%s", action, regkind, regno, exit_suffix); + name = rs6000_savres_routine_name (info, regno, savep, gpr, lr); sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); + SYMBOL_REF_FLAGS (sym) |= SYMBOL_FLAG_FUNCTION; } return sym; @@ -15935,8 +16018,13 @@ rs6000_emit_stack_reset (rs6000_stack_t { rs6000_emit_stack_tie (); if (sp_offset != 0) - emit_insn (gen_addsi3 (sp_reg_rtx, frame_reg_rtx, - GEN_INT (sp_offset))); + { + rtx dest_reg = savres ? gen_rtx_REG (Pmode, 11) : sp_reg_rtx; + + return emit_insn (gen_addsi3 (dest_reg, frame_reg_rtx, + GEN_INT (sp_offset))); + } + else if (!savres) emit_move_insn (sp_reg_rtx, frame_reg_rtx); } @@ -15965,7 +16053,7 @@ static rtx rs6000_make_savres_rtx (rs6000_stack_t *info, rtx frame_reg_rtx, int save_area_offset, enum machine_mode reg_mode, - bool savep, bool gpr, bool exitp) + bool savep, bool gpr, bool lr) { int i; int offset, start_reg, end_reg, n_regs; @@ -15979,20 +16067,21 @@ rs6000_make_savres_rtx (rs6000_stack_t * : info->first_fp_reg_save); end_reg = gpr ? 32 : 64; n_regs = end_reg - start_reg; - p = rtvec_alloc ((exitp ? 4 : 3) + n_regs); - - /* If we're saving registers, then we should never say we're exiting. */ - gcc_assert ((savep && !exitp) || !savep); + p = rtvec_alloc ((lr ? 4 : 3) + n_regs); - if (exitp) + if (!savep && lr) RTVEC_ELT (p, offset++) = gen_rtx_RETURN (VOIDmode); RTVEC_ELT (p, offset++) = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 65)); - sym = rs6000_savres_routine_sym (info, savep, gpr, exitp); + sym = rs6000_savres_routine_sym (info, savep, gpr, lr); RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, sym); - RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 11)); + RTVEC_ELT (p, offset++) + = gen_rtx_USE (VOIDmode, + gen_rtx_REG (Pmode, DEFAULT_ABI != ABI_AIX ? 11 + : gpr && !lr ? 12 + : 1)); for (i = 0; i < end_reg - start_reg; i++) { @@ -16007,6 +16096,16 @@ rs6000_make_savres_rtx (rs6000_stack_t * savep ? reg : mem); } + if (savep && lr) + { + rtx addr, reg, mem; + reg = gen_rtx_REG (Pmode, 0); + addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->lr_save_offset)); + mem = gen_frame_mem (Pmode, addr); + RTVEC_ELT (p, i + offset) = gen_rtx_SET (VOIDmode, mem, reg); + } + return gen_rtx_PARALLEL (VOIDmode, p); } @@ -16027,7 +16126,10 @@ rs6000_reg_live_or_pic_offset_p (int reg enum { SAVRES_MULTIPLE = 0x1, SAVRES_INLINE_FPRS = 0x2, - SAVRES_INLINE_GPRS = 0x4 + SAVRES_INLINE_GPRS = 0x4, + SAVRES_NOINLINE_GPRS_SAVES_LR = 0x8, + SAVRES_NOINLINE_FPRS_SAVES_LR = 0x10, + SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR = 0x20 }; /* Determine the strategy for savings/restoring registers. */ @@ -16042,6 +16144,7 @@ rs6000_savres_strategy (rs6000_stack_t * bool savres_gprs_inline; bool noclobber_global_gprs = no_global_regs_above (info->first_gp_reg_save, /*gpr=*/true); + int strategy; using_multiple_p = (TARGET_MULTIPLE && ! TARGET_POWERPC64 && (!TARGET_SPE_ABI @@ -16061,6 +16164,10 @@ rs6000_savres_strategy (rs6000_stack_t * || info->first_fp_reg_save == 64 || !no_global_regs_above (info->first_fp_reg_save, /*gpr=*/false) + /* The out-of-line FP routines use + double-precision stores; we can't use those + routines if we don't have such stores. */ + || (TARGET_HARD_FLOAT && !TARGET_DOUBLE_FLOAT) || FP_SAVE_INLINE (info->first_fp_reg_save)); savres_gprs_inline = (common /* Saving CR interferes with the exit routines @@ -16098,9 +16205,22 @@ rs6000_savres_strategy (rs6000_stack_t * savres_gprs_inline = savres_gprs_inline || using_multiple_p; } - return (using_multiple_p - | (savres_fprs_inline << 1) - | (savres_gprs_inline << 2)); + strategy = (using_multiple_p + | (savres_fprs_inline << 1) + | (savres_gprs_inline << 2)); +#ifdef POWERPC_LINUX + if (TARGET_64BIT) + { + if (!savres_fprs_inline) + strategy |= SAVRES_NOINLINE_FPRS_SAVES_LR; + else if (!savres_gprs_inline && info->first_fp_reg_save == 64) + strategy |= SAVRES_NOINLINE_GPRS_SAVES_LR; + } +#else + if (TARGET_AIX && !savres_fprs_inline) + strategy |= SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR; +#endif + return strategy; } /* Emit function prologue as insns. */ @@ -16122,7 +16242,7 @@ rs6000_emit_prologue (void) int using_store_multiple; int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE && df_regs_ever_live_p (STATIC_CHAIN_REGNUM) - && !call_used_regs[STATIC_CHAIN_REGNUM]); + && call_used_regs[STATIC_CHAIN_REGNUM]); HOST_WIDE_INT sp_offset = 0; if (TARGET_FIX_AND_CONTINUE) @@ -16307,24 +16427,30 @@ rs6000_emit_prologue (void) gen_rtx_REG (Pmode, LR_REGNO)); RTX_FRAME_RELATED_P (insn) = 1; - addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + if (!(strategy & (SAVRES_NOINLINE_GPRS_SAVES_LR + | SAVRES_NOINLINE_FPRS_SAVES_LR))) + { + addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->lr_save_offset + sp_offset)); - reg = gen_rtx_REG (Pmode, 0); - mem = gen_rtx_MEM (Pmode, addr); - /* This should not be of rs6000_sr_alias_set, because of - __builtin_return_address. */ + reg = gen_rtx_REG (Pmode, 0); + mem = gen_rtx_MEM (Pmode, addr); + /* This should not be of rs6000_sr_alias_set, because of + __builtin_return_address. */ - insn = emit_move_insn (mem, reg); - rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, - NULL_RTX, NULL_RTX); + insn = emit_move_insn (mem, reg); + rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, + NULL_RTX, NULL_RTX); + } } - /* If we need to save CR, put it into r12. */ + /* If we need to save CR, put it into r12 or r11. */ if (!WORLD_SAVE_P (info) && info->cr_save_p && frame_reg_rtx != frame_ptr_rtx) { rtx set; - cr_save_rtx = gen_rtx_REG (SImode, 12); + cr_save_rtx + = gen_rtx_REG (SImode, DEFAULT_ABI == ABI_AIX && !saving_GPRs_inline + ? 11 : 12); insn = emit_insn (gen_movesi_from_cr (cr_save_rtx)); RTX_FRAME_RELATED_P (insn) = 1; /* Now, there's no way that dwarf2out_frame_debug_expr is going @@ -16363,7 +16489,9 @@ rs6000_emit_prologue (void) info->fp_save_offset + sp_offset, DFmode, /*savep=*/true, /*gpr=*/false, - /*exitp=*/false); + /*lr=*/(strategy + & SAVRES_NOINLINE_FPRS_SAVES_LR) + != 0); insn = emit_insn (par); rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, NULL_RTX, NULL_RTX); @@ -16459,7 +16587,7 @@ rs6000_emit_prologue (void) par = rs6000_make_savres_rtx (info, gen_rtx_REG (Pmode, 11), 0, reg_mode, /*savep=*/true, /*gpr=*/true, - /*exitp=*/false); + /*lr=*/false); insn = emit_insn (par); rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, NULL_RTX, NULL_RTX); @@ -16474,25 +16602,24 @@ rs6000_emit_prologue (void) { rtx par; - /* Need to adjust r11 if we saved any FPRs. */ + /* Need to adjust r11 (r12) if we saved any FPRs. */ if (info->first_fp_reg_save != 64) { - rtx r11 = gen_rtx_REG (reg_mode, 11); - rtx offset = GEN_INT (info->total_size - + (-8 * (64-info->first_fp_reg_save))); - rtx ptr_reg = (sp_reg_rtx == frame_reg_rtx - ? sp_reg_rtx : r11); - - emit_insn (TARGET_32BIT - ? gen_addsi3 (r11, ptr_reg, offset) - : gen_adddi3 (r11, ptr_reg, offset)); + rtx dest_reg = gen_rtx_REG (reg_mode, DEFAULT_ABI == ABI_AIX + ? 12 : 11); + rtx offset = GEN_INT (sp_offset + + (-8 * (64-info->first_fp_reg_save))); + emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, offset)); } par = rs6000_make_savres_rtx (info, frame_reg_rtx, info->gp_save_offset + sp_offset, reg_mode, /*savep=*/true, /*gpr=*/true, - /*exitp=*/false); + /*lr=*/(strategy + & SAVRES_NOINLINE_GPRS_SAVES_LR) + != 0); + insn = emit_insn (par); rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, NULL_RTX, NULL_RTX); @@ -16772,9 +16899,18 @@ rs6000_output_function_prologue (FILE *f fp values. */ if (info->first_fp_reg_save < 64 && !FP_SAVE_INLINE (info->first_fp_reg_save)) - fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n", - SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX, - RESTORE_FP_PREFIX, info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX); + { + char *name; + int regno = info->first_fp_reg_save - 32; + + name = rs6000_savres_routine_name (info, regno, /*savep=*/true, + /*gpr=*/false, /*lr=*/false); + fprintf (file, "\t.extern %s\n", name); + + name = rs6000_savres_routine_name (info, regno, /*savep=*/false, + /*gpr=*/false, /*lr=*/true); + fprintf (file, "\t.extern %s\n", name); + } /* Write .extern for AIX common mode routines, if needed. */ if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined) @@ -16891,6 +17027,7 @@ rs6000_emit_epilogue (int sibcall) int sp_offset = 0; rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1); rtx frame_reg_rtx = sp_reg_rtx; + rtx cr_save_reg = NULL_RTX; enum machine_mode reg_mode = Pmode; int reg_size = TARGET_32BIT ? 4 : 8; int i; @@ -16924,8 +17061,10 @@ rs6000_emit_epilogue (int sibcall) || (cfun->calls_alloca && !frame_pointer_needed)); restore_lr = (info->lr_save_p - && restoring_GPRs_inline - && restoring_FPRs_inline); + && (restoring_FPRs_inline + || (strategy & SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR)) + && (restoring_GPRs_inline + || info->first_fp_reg_save < 64)); if (WORLD_SAVE_P (info)) { @@ -17197,7 +17336,7 @@ rs6000_emit_epilogue (int sibcall) /* Get the old lr if we saved it. If we are restoring registers out-of-line, then the out-of-line routines can do this for us. */ - if (restore_lr) + if (restore_lr && restoring_GPRs_inline) { rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx, info->lr_save_offset + sp_offset); @@ -17211,12 +17350,17 @@ rs6000_emit_epilogue (int sibcall) rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->cr_save_offset + sp_offset)); rtx mem = gen_frame_mem (SImode, addr); + cr_save_reg = gen_rtx_REG (SImode, + DEFAULT_ABI == ABI_AIX + && !restoring_GPRs_inline + && info->first_fp_reg_save < 64 + ? 11 : 12); + emit_move_insn (cr_save_reg, mem); - emit_move_insn (gen_rtx_REG (SImode, 12), mem); } /* Set LR here to try to overlap restores below. */ - if (restore_lr) + if (restore_lr && restoring_GPRs_inline) emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO), gen_rtx_REG (Pmode, 0)); @@ -17318,7 +17462,7 @@ rs6000_emit_epilogue (int sibcall) par = rs6000_make_savres_rtx (info, gen_rtx_REG (Pmode, 11), 0, reg_mode, /*savep=*/false, /*gpr=*/true, - /*exitp=*/true); + /*lr=*/true); emit_jump_insn (par); /* We don't want anybody else emitting things after we jumped @@ -17337,20 +17481,24 @@ rs6000_emit_epilogue (int sibcall) rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx, sp_offset, can_use_exit); else - emit_insn (gen_addsi3 (gen_rtx_REG (Pmode, 11), - sp_reg_rtx, - GEN_INT (sp_offset - info->fp_size))); + { + emit_insn (gen_add3_insn (gen_rtx_REG (Pmode, DEFAULT_ABI == ABI_AIX + ? 12 : 11), + frame_reg_rtx, + GEN_INT (sp_offset - info->fp_size))); + if (REGNO (frame_reg_rtx) == 11) + sp_offset += info->fp_size; + } par = rs6000_make_savres_rtx (info, frame_reg_rtx, info->gp_save_offset, reg_mode, /*savep=*/false, /*gpr=*/true, - /*exitp=*/can_use_exit); + /*lr=*/can_use_exit); if (can_use_exit) { if (info->cr_save_p) - rs6000_restore_saved_cr (gen_rtx_REG (SImode, 12), - using_mtcr_multiple); + rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple); emit_jump_insn (par); @@ -17396,6 +17544,16 @@ rs6000_emit_epilogue (int sibcall) } } + if (restore_lr && !restoring_GPRs_inline) + { + rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx, + info->lr_save_offset + sp_offset); + + emit_move_insn (gen_rtx_REG (Pmode, 0), mem); + emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO), + gen_rtx_REG (Pmode, 0)); + } + /* Restore fpr's if we need to do it without calling a function. */ if (restoring_FPRs_inline) for (i = 0; i < 64 - info->first_fp_reg_save; i++) @@ -17419,7 +17577,7 @@ rs6000_emit_epilogue (int sibcall) /* If we saved cr, restore it here. Just those that were used. */ if (info->cr_save_p) - rs6000_restore_saved_cr (gen_rtx_REG (SImode, 12), using_mtcr_multiple); + rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple); /* If this is V.4, unwind the stack pointer after all of the loads have been done. */ @@ -17437,13 +17595,14 @@ rs6000_emit_epilogue (int sibcall) if (!sibcall) { rtvec p; + bool lr = (strategy & SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0; if (! restoring_FPRs_inline) p = rtvec_alloc (4 + 64 - info->first_fp_reg_save); else p = rtvec_alloc (2); RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode); - RTVEC_ELT (p, 1) = (restoring_FPRs_inline + RTVEC_ELT (p, 1) = ((restoring_FPRs_inline || !lr) ? gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 65)) : gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 65))); @@ -17458,10 +17617,12 @@ rs6000_emit_epilogue (int sibcall) sym = rs6000_savres_routine_sym (info, /*savep=*/false, /*gpr=*/false, - /*exitp=*/true); + /*lr=*/lr); RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode, sym); RTVEC_ELT (p, 3) = gen_rtx_USE (VOIDmode, - gen_rtx_REG (Pmode, 11)); + gen_rtx_REG (Pmode, + DEFAULT_ABI == ABI_AIX + ? 1 : 11)); for (i = 0; i < 64 - info->first_fp_reg_save; i++) { rtx addr, mem; Index: gcc-4.4.1/gcc/config/rs6000/rs6000.md =================================================================== --- gcc-4.4.1.orig/gcc/config/rs6000/rs6000.md 2009-10-06 14:09:12.087313658 -0700 +++ gcc-4.4.1/gcc/config/rs6000/rs6000.md 2009-10-06 14:09:19.797315286 -0700 @@ -14868,6 +14868,19 @@ [(set_attr "type" "branch") (set_attr "length" "4")]) +(define_insn "*return_and_restore_fpregs_aix_" + [(match_parallel 0 "any_parallel_operand" + [(return) + (use (match_operand:P 1 "register_operand" "l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (match_operand:P 3 "gpc_reg_operand" "r")) + (set (match_operand:DF 4 "gpc_reg_operand" "=d") + (match_operand:DF 5 "memory_operand" "m"))])] + "" + "b %z2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + ; This is used in compiling the unwind routines. (define_expand "eh_return" [(use (match_operand 0 "general_operand" ""))] Index: gcc-4.4.1/gcc/config/rs6000/sysv4.h =================================================================== --- gcc-4.4.1.orig/gcc/config/rs6000/sysv4.h 2009-10-06 13:51:50.447316469 -0700 +++ gcc-4.4.1/gcc/config/rs6000/sysv4.h 2009-10-06 14:09:19.807390239 -0700 @@ -271,27 +271,25 @@ do { \ #endif /* Define cutoff for using external functions to save floating point. - Currently on 64-bit V.4, always use inline stores. When optimizing - for size on 32-bit targets, use external functions when - profitable. */ -#define FP_SAVE_INLINE(FIRST_REG) (optimize_size && !TARGET_64BIT \ + When optimizing for size, use external functions when profitable. */ +#define FP_SAVE_INLINE(FIRST_REG) (optimize_size \ ? ((FIRST_REG) == 62 \ || (FIRST_REG) == 63) \ : (FIRST_REG) < 64) /* And similarly for general purpose registers. */ #define GP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 32 \ - && (TARGET_64BIT || !optimize_size)) + && !optimize_size) /* Put jump tables in read-only memory, rather than in .text. */ #define JUMP_TABLES_IN_TEXT_SECTION 0 /* Prefix and suffix to use to saving floating point. */ #define SAVE_FP_PREFIX "_savefpr_" -#define SAVE_FP_SUFFIX (TARGET_64BIT ? "_l" : "") +#define SAVE_FP_SUFFIX "" /* Prefix and suffix to use to restoring floating point. */ #define RESTORE_FP_PREFIX "_restfpr_" -#define RESTORE_FP_SUFFIX (TARGET_64BIT ? "_l" : "") +#define RESTORE_FP_SUFFIX "" /* Type used for ptrdiff_t, as a string used in a declaration. */ #define PTRDIFF_TYPE "int"