From 3fc841c85d1b8dbbdb72b6dd7a5f2d132205bc5a Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Fri, 23 Oct 2009 15:05:20 +0000 Subject: [PATCH] Fix 41787 From-SVN: r153498 --- gcc/ChangeLog | 20 +++++ gcc/config/rs6000/rs6000.c | 77 +++++++++++++++++-- gcc/config/rs6000/rs6000.h | 10 ++- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.target/powerpc/vsx-vrsave.c | 20 +++++ 5 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/vsx-vrsave.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7e51d688bf3..e7068a9a543 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2009-10-23 Michael Meissner + + PR target/41787 + * config/rs6000/rs6000.c (struct machine_function): Add + vsx_or_altivec_used_p to record if vector types are used. + (rs6000_expand_to_rtl_hook): Rename from + rs6000_alloc_sdmode_stack_slot. If VSX, check to see if there are + any vector operations, so if there are, we can set VRSAVE to + non-zero when only floating point vector registers are used. + (TARGET_EXPAND_TO_RTL_HOOK): Use rs6000_expand_to_rtl_hook. + (rs6000_check_vector_mode): Inner function to check if vector + types are used in the code. + (compute_vrsave_mask): If VSX, make sure VRSAVE is non-zero if + vector instructions are used. + + * config/rs6000/rs6000.h (HARD_REGNO_CALL_PART_CLOBBERED): + Indicate that VSX registers which overlap floating point + registers, can't be used across a call, since the ABI only states + the scalar part of the register will be saved and restored. + 2009-10-23 Joseph Myers PR c/41673 diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 9b03a9bfe68..88649ea0735 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -130,6 +130,8 @@ typedef struct GTY(()) machine_function 64-bits wide and is allocated early enough so that the offset does not overflow the 16-bit load/store offset field. */ rtx sdmode_stack_slot; + /* True if any VSX or ALTIVEC vector type was used. */ + bool vsx_or_altivec_used_p; } machine_function; /* Target cpu type */ @@ -913,7 +915,7 @@ static void rs6000_elf_encode_section_info (tree, rtx, int) ATTRIBUTE_UNUSED; #endif static bool rs6000_use_blocks_for_constant_p (enum machine_mode, const_rtx); -static void rs6000_alloc_sdmode_stack_slot (void); +static void rs6000_expand_to_rtl_hook (void); static void rs6000_instantiate_decls (void); #if TARGET_XCOFF static void rs6000_xcoff_asm_output_anchor (rtx); @@ -1505,7 +1507,7 @@ static const struct attribute_spec rs6000_attribute_table[] = #define TARGET_BUILTIN_RECIPROCAL rs6000_builtin_reciprocal #undef TARGET_EXPAND_TO_RTL_HOOK -#define TARGET_EXPAND_TO_RTL_HOOK rs6000_alloc_sdmode_stack_slot +#define TARGET_EXPAND_TO_RTL_HOOK rs6000_expand_to_rtl_hook #undef TARGET_INSTANTIATE_DECLS #define TARGET_INSTANTIATE_DECLS rs6000_instantiate_decls @@ -13190,6 +13192,38 @@ rs6000_check_sdmode (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) return NULL_TREE; } +static tree +rs6000_check_vector_mode (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) +{ + /* Don't walk into types. */ + if (*tp == NULL_TREE || *tp == error_mark_node || TYPE_P (*tp)) + { + *walk_subtrees = 0; + return NULL_TREE; + } + + switch (TREE_CODE (*tp)) + { + case VAR_DECL: + case PARM_DECL: + case FIELD_DECL: + case RESULT_DECL: + case SSA_NAME: + case REAL_CST: + case INDIRECT_REF: + case ALIGN_INDIRECT_REF: + case MISALIGNED_INDIRECT_REF: + case VIEW_CONVERT_EXPR: + if (VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (*tp)))) + return *tp; + break; + default: + break; + } + + return NULL_TREE; +} + enum reload_reg_type { GPR_REGISTER_TYPE, VECTOR_REGISTER_TYPE, @@ -13630,11 +13664,17 @@ rs6000_ira_cover_classes (void) return (TARGET_VSX) ? cover_vsx : cover_pre_vsx; } -/* Allocate a 64-bit stack slot to be used for copying SDmode - values through if this function has any SDmode references. */ +/* Scan the trees looking for certain types. + + Allocate a 64-bit stack slot to be used for copying SDmode values through if + this function has any SDmode references. + + If VSX, note whether any vector operation was done so we can set VRSAVE to + non-zero, even if we just use the floating point registers to tell the + kernel to save the vector registers. */ static void -rs6000_alloc_sdmode_stack_slot (void) +rs6000_expand_to_rtl_hook (void) { tree t; basic_block bb; @@ -13642,6 +13682,24 @@ rs6000_alloc_sdmode_stack_slot (void) gcc_assert (cfun->machine->sdmode_stack_slot == NULL_RTX); + /* Check for vectors. */ + if (TARGET_VSX) + { + FOR_EACH_BB (bb) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + if (walk_gimple_op (gsi_stmt (gsi), rs6000_check_vector_mode, + NULL)) + { + cfun->machine->vsx_or_altivec_used_p = true; + goto found_vector; + } + } + found_vector: + ; + } + + /* Check for SDmode being used. */ FOR_EACH_BB (bb) for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { @@ -16783,6 +16841,15 @@ compute_vrsave_mask (void) if (df_regs_ever_live_p (i)) mask |= ALTIVEC_REG_BIT (i); + /* If VSX is used, we might have used a traditional floating point register + in a vector mode without using any altivec registers. However the VRSAVE + register does not have room to indicate the floating point registers. + Modern kernels only look to see if the value is non-zero to determine if + they need to save the vector registers, so we just set an arbitrary + value if any vector type was used. */ + if (mask == 0 && TARGET_VSX && cfun->machine->vsx_or_altivec_used_p) + mask = 0xFFF; + if (mask == 0) return mask; diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 25d760a5be6..4b1ca3d635a 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -1033,10 +1033,12 @@ extern unsigned rs6000_pointer_size; #define HARD_REGNO_NREGS(REGNO, MODE) rs6000_hard_regno_nregs[(MODE)][(REGNO)] -#define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE) \ - ((TARGET_32BIT && TARGET_POWERPC64 \ - && (GET_MODE_SIZE (MODE) > 4) \ - && INT_REGNO_P (REGNO)) ? 1 : 0) +#define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE) \ + (((TARGET_32BIT && TARGET_POWERPC64 \ + && (GET_MODE_SIZE (MODE) > 4) \ + && INT_REGNO_P (REGNO)) ? 1 : 0) \ + || (TARGET_VSX && FP_REGNO_P (REGNO) \ + && GET_MODE_SIZE (MODE) > 8)) #define VSX_VECTOR_MODE(MODE) \ ((MODE) == V4SFmode \ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 81d39b58144..03d21650a0d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2009-10-22 Michael Meissner + + PR target/41787 + * gcc.target/powerpc/vsx-vrsave.c: New file. + 2009-10-23 Joseph Myers PR c/41673 diff --git a/gcc/testsuite/gcc.target/powerpc/vsx-vrsave.c b/gcc/testsuite/gcc.target/powerpc/vsx-vrsave.c new file mode 100644 index 00000000000..83125f67fcc --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/vsx-vrsave.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target { powerpc*-*-* } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-require-effective-target powerpc_vsx_ok } */ +/* { dg-options "-O2 -mcpu=power7" } */ +/* { dg-final { scan-assembler-times "mtvrsave" 2 } } */ + +/* Check whether VRSAVE is set to non-zero if VSX vector operations were + used, but it should not be set if there are no vector operations. */ + +void +generates_vrsave (vector double *a, vector double *b, vector double *c) +{ + *a = *b + *c; +} + +void +no_vrsave (double *a, double *b, double *c) +{ + *a = *b + *c; +}