public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: PowerPC prologue and epilogue 6
@ 2012-05-29 19:26 Dominique Dhumieres
  2012-05-30 11:42 ` Alan Modra
  0 siblings, 1 reply; 14+ messages in thread
From: Dominique Dhumieres @ 2012-05-29 19:26 UTC (permalink / raw)
  To: amodra; +Cc: IainS, gcc-patches

Alan,

I think the following patch

--- ../_gcc_clean/gcc/testsuite/gcc.target/powerpc/powerpc.exp	2012-05-02 14:25:40.000000000 +0200
+++ ../work/gcc/testsuite/gcc.target/powerpc/powerpc.exp	2012-05-29 21:14:48.000000000 +0200
@@ -47,4 +47,5 @@ set-torture-options $SAVRES_TEST_OPTS
 gcc-dg-runtest [list $srcdir/$subdir/savres.c] $alti
 
 # All done.
+torture-finish
 dg-finish

is required to avoid the errors of the kind 

ERROR: tcl error sourcing /home/gccbuild/gcc_trunk_anonsvn/gcc/gcc/testsuite/gcc.target/powerpc/powerpc.exp.
ERROR: torture-init: torture_without_loops is not empty as expected

(see http://gcc.gnu.org/ml/gcc-testresults/2012-05/msg02608.html ).

In addition the tests of savres.c fails on powerpc-apple-darwin9 with

FAIL: gcc.target/powerpc/savres.c (test for excess errors)
Excess errors:
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:109:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:123:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:135:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:170:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:180:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:212:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:222:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:251:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:259:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:289:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:303:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:315:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:350:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:360:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:392:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:402:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:431:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:439:3: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:472:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:491:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:508:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:558:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:573:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:620:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:635:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:679:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:692:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:737:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:756:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:773:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:823:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:838:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:885:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:900:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:944:5: error: PIC register clobbered by 'r31' in 'asm'
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:957:5: error: PIC register clobbered by 'r31' in 'asm'

WARNING: gcc.target/powerpc/savres.c compilation failed to produce executable

However I am not able to say if this generic or due to some Iain's patches
I have in my tree.

TIA

Dominique

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-05-29 19:26 PowerPC prologue and epilogue 6 Dominique Dhumieres
@ 2012-05-30 11:42 ` Alan Modra
  2012-05-30 13:22   ` Dominique Dhumieres
  0 siblings, 1 reply; 14+ messages in thread
From: Alan Modra @ 2012-05-30 11:42 UTC (permalink / raw)
  To: Dominique Dhumieres; +Cc: IainS, gcc-patches

On Tue, May 29, 2012 at 09:26:37PM +0200, Dominique Dhumieres wrote:
>  gcc-dg-runtest [list $srcdir/$subdir/savres.c] $alti
>  
>  # All done.
> +torture-finish
>  dg-finish
> 
> is required to avoid the errors of the kind 
> 
> ERROR: tcl error sourcing /home/gccbuild/gcc_trunk_anonsvn/gcc/gcc/testsuite/gcc.target/powerpc/powerpc.exp.
> ERROR: torture-init: torture_without_loops is not empty as expected

Yes indeed, and it would be wise to ensure torture-options.exp is
loaded too.  I'm committing the following as obvious.

	* gcc.target/powerpc/powerpc.exp: Load torture-options.exp, call
	torture-finish.

Index: gcc/testsuite/gcc.target/powerpc/powerpc.exp
===================================================================
--- gcc/testsuite/gcc.target/powerpc/powerpc.exp	(revision 187999)
+++ gcc/testsuite/gcc.target/powerpc/powerpc.exp	(working copy)
@@ -23,6 +23,7 @@
 
 # Load support procs.
 load_lib gcc-dg.exp
+load_lib torture-options.exp
 
 # If a testcase doesn't have special options, use these.
 global DEFAULT_CFLAGS
@@ -47,4 +48,5 @@
 gcc-dg-runtest [list $srcdir/$subdir/savres.c] $alti
 
 # All done.
+torture-finish
 dg-finish

> FAIL: gcc.target/powerpc/savres.c (test for excess errors)
> Excess errors:
> /opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:109:3: error: PIC register clobbered by 'r31' in 'asm'

Hmm, this will be because darwin is PIC by default.  Does adding
-static to the dg-options line in savres.c fix the darwin fail?

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-05-30 11:42 ` Alan Modra
@ 2012-05-30 13:22   ` Dominique Dhumieres
  2012-05-31  0:13     ` Alan Modra
  0 siblings, 1 reply; 14+ messages in thread
From: Dominique Dhumieres @ 2012-05-30 13:22 UTC (permalink / raw)
  To: dominiq, amodra; +Cc: IainS, gcc-patches

> Yes indeed, and it would be wise to ensure torture-options.exp is
> loaded too.  I'm committing the following as obvious.

Thanks

> Hmm, this will be because darwin is PIC by default.  Does adding
> -static to the dg-options line in savres.c fix the darwin fail?

With the following change

--- /opt/gcc/_gcc_clean/gcc/testsuite/gcc.target/powerpc/savres.c	2012-05-02 14:25:40.000000000 +0200
+++ /opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c	2012-05-30 13:45:15.000000000 +0200
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-fno-inline -fomit-frame-pointer" } */
+/* { dg-options "-fno-inline -fomit-frame-pointer -static" } */
 
 /* -fno-inline -maltivec -m32/-m64 -mmultiple/no-multiple -Os/-O2.  */
 #ifndef NO_BODY

I get an ICE of the form

/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c: In function 'nb_all':
/opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:473:3: internal compiler error: in rs6000_emit_prologue, at config/rs6000/rs6000.c:19850

Is the test intended to work on PIC targets?

Cheers,

Dominique

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-05-30 13:22   ` Dominique Dhumieres
@ 2012-05-31  0:13     ` Alan Modra
  2012-05-31  1:11       ` Alan Modra
  0 siblings, 1 reply; 14+ messages in thread
From: Alan Modra @ 2012-05-31  0:13 UTC (permalink / raw)
  To: Dominique Dhumieres; +Cc: IainS, gcc-patches

On Wed, May 30, 2012 at 03:21:28PM +0200, Dominique Dhumieres wrote:
> I get an ICE of the form
> 
> /opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c: In function 'nb_all':
> /opt/gcc/work/gcc/testsuite/gcc.target/powerpc/savres.c:473:3: internal compiler error: in rs6000_emit_prologue, at config/rs6000/rs6000.c:19850
> 
> Is the test intended to work on PIC targets?

No, but see rs6000/darwin.h CC1_SPEC.  "-static" makes you non-PIC.

I've just built a darwin cc1 to reproduce the problem.  The ICE is on
	    START_USE (ptr_regno);
when setting up a reg to use for altivec saves.  The reg clashes with
the static chain pointer (nb_all is a nested function), so this is a
real bug that the register checks have uncovered.  I haven't
determined whether this is a new bug introduced with my prologue
changes, or whether it's a long-standing bug.  I suspect the latter.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-05-31  0:13     ` Alan Modra
@ 2012-05-31  1:11       ` Alan Modra
  2012-05-31  8:39         ` Alan Modra
  0 siblings, 1 reply; 14+ messages in thread
From: Alan Modra @ 2012-05-31  1:11 UTC (permalink / raw)
  To: Dominique Dhumieres, IainS, gcc-patches

On Thu, May 31, 2012 at 09:43:09AM +0930, Alan Modra wrote:
> real bug that the register checks have uncovered.  I haven't
> determined whether this is a new bug introduced with my prologue
> changes, or whether it's a long-standing bug.  I suspect the latter.

Looks like it is one I introduced.  gcc-4.6 uses r12 to save altivec
regs, my new code tries to use r11.  Will fix.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-05-31  1:11       ` Alan Modra
@ 2012-05-31  8:39         ` Alan Modra
  2012-05-31 12:16           ` Dominique Dhumieres
  0 siblings, 1 reply; 14+ messages in thread
From: Alan Modra @ 2012-05-31  8:39 UTC (permalink / raw)
  To: Dominique Dhumieres, IainS, David Edelsohn, gcc-patches

On Thu, May 31, 2012 at 10:41:26AM +0930, Alan Modra wrote:
> Looks like it is one I introduced.  gcc-4.6 uses r12 to save altivec
> regs, my new code tries to use r11.  Will fix.

Please try out this patch on Darwin.  Bootstrapped and regression
tested powerpc-linux.

gcc/
	* config/rs6000/rs6000.c (ptr_regno_for_savres): Comment.
	(rs6000_emit_prologue): Ensure register used for inline saves
	of vector regs is not the static chain register.  Revise comment.
gcc/testsuite/
	* gcc.target/powerpc/savres.c: Add -static to dg-options.
	Check static chain in nested funcs.

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 187999)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -19108,6 +19161,9 @@ rs6000_emit_stack_reset (rs6000_stack_t *info,
   return NULL_RTX;
 }
 
+/* Return the register number used as a pointer by out-of-line
+   save/restore functions.  */
+
 static inline unsigned
 ptr_regno_for_savres (int sel)
 {
@@ -19845,6 +19901,9 @@ rs6000_emit_prologue (void)
 	  int sel = SAVRES_SAVE | SAVRES_VR;
 	  unsigned ptr_regno = ptr_regno_for_savres (sel);
 
+	  if (using_static_chain_p
+	      && ptr_regno == STATIC_CHAIN_REGNUM)
+	    ptr_regno = 12;
 	  if (REGNO (frame_reg_rtx) != ptr_regno)
 	    START_USE (ptr_regno);
 	  ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
@@ -19953,9 +20012,9 @@ rs6000_emit_prologue (void)
       int offset;
       int save_regno;
 
-      /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
-	 as frame_reg_rtx and r11 as the static chain pointer for
-	 nested functions.  */
+      /* Get VRSAVE onto a GPR.  Note that ABI_V4 and ABI_DARWIN might
+	 be using r12 as frame_reg_rtx and r11 as the static chain
+	 pointer for nested functions.  */
       save_regno = 12;
       if (DEFAULT_ABI == ABI_AIX && !using_static_chain_p)
 	save_regno = 11;
Index: gcc/testsuite/gcc.target/powerpc/savres.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/savres.c	(revision 187999)
+++ gcc/testsuite/gcc.target/powerpc/savres.c	(working copy)
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-fno-inline -fomit-frame-pointer" } */
+/* { dg-options "-fno-inline -fomit-frame-pointer -static" } */
 
 /* -fno-inline -maltivec -m32/-m64 -mmultiple/no-multiple -Os/-O2.  */
 #ifndef NO_BODY
@@ -73,6 +73,7 @@ __attribute__ ((vector_size (16))) int val31 = {-3
 
 #else /* NO_BODY */
 /* For looking at prologue and epilogue code without distractions.  */
+#define abort()
 #define TRASH_ALL_CR
 #define TRASH_ALL_VR
 #define TRASH_ALL_FPR
@@ -458,7 +459,7 @@ void s_0 (void)
 void wb_all (void)
 {
   char b[10];
-  void nb_all (void)
+  char *nb_all (void)
   {
     char a[33000];
     TRASH_ALL_CR;
@@ -470,14 +471,16 @@ void wb_all (void)
     USE_ALL_FPR;
     USE_ALL_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "cr3", "cr4", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31");
+    return b;
   }
-  nb_all();
+  if (nb_all() != b)
+    abort ();
 }
 
 void wb_cvfr (void)
 {
   char b[10];
-  void nb_cvfr (void)
+  char *nb_cvfr (void)
   {
     char a[33000];
     TRASH_SOME_CR;
@@ -489,14 +492,16 @@ void wb_cvfr (void)
     USE_SOME_FPR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+    return b;
   }
-  nb_cvfr ();
+  if (nb_cvfr () != b)
+    abort ();
 }
 
 void wb_vfr (void)
 {
   char b[10];
-  void nb_vfr (void)
+  char *nb_vfr (void)
   {
     char a[33000];
     TRASH_SOME_VR;
@@ -506,14 +511,16 @@ void wb_vfr (void)
     USE_SOME_FPR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+    return b;
   }
-  nb_vfr ();
+  if (nb_vfr () != b)
+    abort ();
 }
 
 void wb_cvf (void)
 {
   char b[10];
-  void nb_cvf (void)
+  char *nb_cvf (void)
   {
     char a[33000];
     TRASH_SOME_CR;
@@ -523,14 +530,16 @@ void wb_cvf (void)
     USE_SOME_VR;
     USE_SOME_FPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "fr28", "fr31");
+    return b;
   }
-  nb_cvf ();
+  if (nb_cvf () != b)
+    abort ();
 }
 
 void wb_vf (void)
 {
   char b[10];
-  void nb_vf (void)
+  char *nb_vf (void)
   {
     char a[33000];
     TRASH_SOME_VR;
@@ -538,15 +547,17 @@ void wb_vf (void)
     USE_SOME_VR;
     USE_SOME_FPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "fr28", "fr31");
+    return b;
   }
-  nb_vf ();
+  if (nb_vf () != b)
+    abort ();
 }
 #endif
 
 void wb_cvr (void)
 {
   char b[10];
-  void nb_cvr (void)
+  char *nb_cvr (void)
   {
     char a[33000];
     TRASH_SOME_CR;
@@ -556,14 +567,16 @@ void wb_cvr (void)
     USE_SOME_VR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "r30", "r31");
+    return b;
   }
-  nb_cvr ();
+  if (nb_cvr () != b)
+    abort ();
 }
 
 void wb_vr (void)
 {
   char b[10];
-  void nb_vr (void)
+  char *nb_vr (void)
   {
     char a[33000];
     TRASH_SOME_VR;
@@ -571,14 +584,16 @@ void wb_vr (void)
     USE_SOME_VR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "r30", "r31");
+    return b;
   }
-  nb_vr ();
+  if (nb_vr () != b)
+    abort ();
 }
 
 void wb_cv (void)
 {
   char b[10];
-  void nb_cv (void)
+  char *nb_cv (void)
   {
     char a[33000];
     TRASH_SOME_CR;
@@ -586,21 +601,25 @@ void wb_cv (void)
     USE_SOME_CR;
     USE_SOME_VR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31");
+    return b;
   }
-  nb_cv ();
+  if (nb_cv () != b)
+    abort ();
 }
 
 void wb_v (void)
 {
   char b[10];
-  void nb_v (void)
+  char *nb_v (void)
   {
     char a[33000];
     TRASH_SOME_VR;
     USE_SOME_VR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31");
+    return b;
   }
-  nb_v ();
+  if (nb_v () != b)
+    abort ();
 }
 #endif
 
@@ -608,7 +627,7 @@ void wb_v (void)
 void wb_cfr (void)
 {
   char b[10];
-  void nb_cfr (void)
+  char *nb_cfr (void)
   {
     char a[33000];
     TRASH_SOME_CR;
@@ -618,14 +637,16 @@ void wb_cfr (void)
     USE_SOME_FPR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "fr28", "fr31", "r30", "r31");
+    return b;
   }
-  nb_cfr ();
+  if (nb_cfr () != b)
+    abort ();
 }
 
 void wb_fr (void)
 {
   char b[10];
-  void nb_fr (void)
+  char *nb_fr (void)
   {
     char a[33000];
     TRASH_SOME_FPR;
@@ -633,14 +654,16 @@ void wb_fr (void)
     USE_SOME_FPR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "fr28", "fr31", "r30", "r31");
+    return b;
   }
-  nb_fr ();
+  if (nb_fr () != b)
+    abort ();
 }
 
 void wb_cf (void)
 {
   char b[10];
-  void nb_cf (void)
+  char *nb_cf (void)
   {
     char a[33000];
     TRASH_SOME_CR;
@@ -648,28 +671,32 @@ void wb_cf (void)
     USE_SOME_CR;
     USE_SOME_FPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "fr28", "fr31");
+    return b;
   }
-  nb_cf ();
+  if (nb_cf () != b)
+    abort ();
 }
 
 void wb_f (void)
 {
   char b[10];
-  void nb_f (void)
+  char *nb_f (void)
   {
     char a[33000];
     TRASH_SOME_FPR;
     USE_SOME_FPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "fr28", "fr31");
+    return b;
   }
-  nb_f ();
+  if (nb_f () != b)
+    abort ();
 }
 #endif
 
 void wb_cr (void)
 {
   char b[10];
-  void nb_cr (void)
+  char *nb_cr (void)
   {
     char a[33000];
     TRASH_SOME_CR;
@@ -677,45 +704,53 @@ void wb_cr (void)
     USE_SOME_CR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "r30", "r31");
+    return b;
   }
-  nb_cr ();
+  if (nb_cr () != b)
+    abort ();
 }
 
 void wb_r (void)
 {
   char b[10];
-  void nb_r (void)
+  char *nb_r (void)
   {
     char a[33000];
     TRASH_SOME_GPR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "r30", "r31");
+    return b;
   }
-  nb_r ();
+  if (nb_r () != b)
+    abort ();
 }
 
 void wb_c (void)
 {
   char b[10];
-  void nb_c (void)
+  char *nb_c (void)
   {
     char a[33000];
     TRASH_SOME_CR;
     USE_SOME_CR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2");
+    return b;
   }
-  nb_c ();
+  if (nb_c () != b)
+    abort ();
 }
 
 void wb_0 (void)
 {
   char b[10];
-  void nb_0 (void)
+  char *nb_0 (void)
   {
     char a[33000];
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) );
+    return b;
   }
-  nb_0 ();
+  if (nb_0 () != b)
+    abort ();
 }
 
 #ifdef __ALTIVEC__
@@ -723,7 +758,7 @@ void wb_0 (void)
 void ws_all (void)
 {
   char b[10];
-  void ns_all (void)
+  char *ns_all (void)
   {
     char a[33];
     TRASH_ALL_CR;
@@ -735,14 +770,16 @@ void ws_all (void)
     USE_ALL_FPR;
     USE_ALL_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "cr3", "cr4", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31");
+    return b;
   }
-  ns_all();
+  if (ns_all() != b)
+    abort ();
 }
 
 void ws_cvfr (void)
 {
   char b[10];
-  void ns_cvfr (void)
+  char *ns_cvfr (void)
   {
     char a[33];
     TRASH_SOME_CR;
@@ -754,14 +791,16 @@ void ws_cvfr (void)
     USE_SOME_FPR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+    return b;
   }
-  ns_cvfr ();
+  if (ns_cvfr () != b)
+    abort ();
 }
 
 void ws_vfr (void)
 {
   char b[10];
-  void ns_vfr (void)
+  char *ns_vfr (void)
   {
     char a[33];
     TRASH_SOME_VR;
@@ -771,14 +810,16 @@ void ws_vfr (void)
     USE_SOME_FPR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+    return b;
   }
-  ns_vfr ();
+  if (ns_vfr () != b)
+    abort ();
 }
 
 void ws_cvf (void)
 {
   char b[10];
-  void ns_cvf (void)
+  char *ns_cvf (void)
   {
     char a[33];
     TRASH_SOME_CR;
@@ -788,14 +829,16 @@ void ws_cvf (void)
     USE_SOME_VR;
     USE_SOME_FPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "fr28", "fr31");
+    return b;
   }
-  ns_cvf ();
+  if (ns_cvf () != b)
+    abort ();
 }
 
 void ws_vf (void)
 {
   char b[10];
-  void ns_vf (void)
+  char *ns_vf (void)
   {
     char a[33];
     TRASH_SOME_VR;
@@ -803,15 +846,17 @@ void ws_vf (void)
     USE_SOME_VR;
     USE_SOME_FPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "fr28", "fr31");
+    return b;
   }
-  ns_vf ();
+  if (ns_vf () != b)
+    abort ();
 }
 #endif
 
 void ws_cvr (void)
 {
   char b[10];
-  void ns_cvr (void)
+  char *ns_cvr (void)
   {
     char a[33];
     TRASH_SOME_CR;
@@ -821,14 +866,16 @@ void ws_cvr (void)
     USE_SOME_VR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "r30", "r31");
+    return b;
   }
-  ns_cvr ();
+  if (ns_cvr () != b)
+    abort ();
 }
 
 void ws_vr (void)
 {
   char b[10];
-  void ns_vr (void)
+  char *ns_vr (void)
   {
     char a[33];
     TRASH_SOME_VR;
@@ -836,14 +883,16 @@ void ws_vr (void)
     USE_SOME_VR;
     USE_SOME_FPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "r30", "r31");
+    return b;
   }
-  ns_vr ();
+  if (ns_vr () != b)
+    abort ();
 }
 
 void ws_cv (void)
 {
   char b[10];
-  void ns_cv (void)
+  char *ns_cv (void)
   {
     char a[33];
     TRASH_SOME_CR;
@@ -851,21 +900,25 @@ void ws_cv (void)
     USE_SOME_CR;
     USE_SOME_VR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31");
+    return b;
   }
-  ns_cv ();
+  if (ns_cv () != b)
+    abort ();
 }
 
 void ws_v (void)
 {
   char b[10];
-  void ns_v (void)
+  char *ns_v (void)
   {
     char a[33];
     TRASH_SOME_VR;
     USE_SOME_VR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31");
+    return b;
   }
-  ns_v ();
+  if (ns_v () != b)
+    abort ();
 }
 #endif
 
@@ -873,7 +926,7 @@ void ws_v (void)
 void ws_cfr (void)
 {
   char b[10];
-  void ns_cfr (void)
+  char *ns_cfr (void)
   {
     char a[33];
     TRASH_SOME_CR;
@@ -883,14 +936,16 @@ void ws_cfr (void)
     USE_SOME_FPR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "fr28", "fr31", "r30", "r31");
+    return b;
   }
-  ns_cfr ();
+  if (ns_cfr () != b)
+    abort ();
 }
 
 void ws_fr (void)
 {
   char b[10];
-  void ns_fr (void)
+  char *ns_fr (void)
   {
     char a[33];
     TRASH_SOME_FPR;
@@ -898,14 +953,16 @@ void ws_fr (void)
     USE_SOME_FPR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "fr28", "fr31", "r30", "r31");
+    return b;
   }
-  ns_fr ();
+  if (ns_fr () != b)
+    abort ();
 }
 
 void ws_cf (void)
 {
   char b[10];
-  void ns_cf (void)
+  char *ns_cf (void)
   {
     char a[33];
     TRASH_SOME_CR;
@@ -913,28 +970,32 @@ void ws_cf (void)
     USE_SOME_CR;
     USE_SOME_FPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "fr28", "fr31");
+    return b;
   }
-  ns_cf ();
+  if (ns_cf () != b)
+    abort ();
 }
 
 void ws_f (void)
 {
   char b[10];
-  void ns_f (void)
+  char *ns_f (void)
   {
     char a[33];
     TRASH_SOME_FPR;
     USE_SOME_FPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "fr28", "fr31");
+    return b;
   }
-  ns_f ();
+  if (ns_f () != b)
+    abort ();
 }
 #endif
 
 void ws_cr (void)
 {
   char b[10];
-  void ns_cr (void)
+  char *ns_cr (void)
   {
     char a[33];
     TRASH_SOME_CR;
@@ -942,45 +1003,53 @@ void ws_cr (void)
     USE_SOME_CR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "r30", "r31");
+    return b;
   }
-  ns_cr ();
+  if (ns_cr () != b)
+    abort ();
 }
 
 void ws_r (void)
 {
   char b[10];
-  void ns_r (void)
+  char *ns_r (void)
   {
     char a[33];
     TRASH_SOME_GPR;
     USE_SOME_GPR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "r30", "r31");
+    return b;
   }
-  ns_r ();
+  if (ns_r () != b)
+    abort ();
 }
 
 void ws_c (void)
 {
   char b[10];
-  void ns_c (void)
+  char *ns_c (void)
   {
     char a[33];
     TRASH_SOME_CR;
     USE_SOME_CR;
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2");
+    return b;
   }
-  ns_c ();
+  if (ns_c () != b)
+    abort ();
 }
 
 void ws_0 (void)
 {
   char b[10];
-  void ns_0 (void)
+  char *ns_0 (void)
   {
     char a[33];
     __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) );
+    return b;
   }
-  ns_0 ();
+  if (ns_0 () != b)
+    abort ();
 }
 
 int main (void)


-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-05-31  8:39         ` Alan Modra
@ 2012-05-31 12:16           ` Dominique Dhumieres
  2012-05-31 13:26             ` Alan Modra
  0 siblings, 1 reply; 14+ messages in thread
From: Dominique Dhumieres @ 2012-05-31 12:16 UTC (permalink / raw)
  To: IainS, gcc-patches, dominiq, dje.gcc, amodra

> Please try out this patch on Darwin.  Bootstrapped and regression
> tested powerpc-linux.

I have applied the patch to r188026 and updated the build.
As patched the test gcc.target/powerpc/savres.c now fails with

FAIL: gcc.target/powerpc/savres.c (test for excess errors)
Excess errors:
ld_classic: can't locate file for: -lcrt0.o

According Iain Sandoe

> -static is not applicable to Darwin (except for kernel code).
> to make the test non-pic - use "-mdynamic-no-pic" (Darwin-only).

Replacing -static with -mdynamic-no-pic makes the test to pass
(the final patch will require the suitable dg directives;-).

Thanks

Dominique

PS Clean bootstrap and full regtesting scheduled for the next week-end).

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-05-31 12:16           ` Dominique Dhumieres
@ 2012-05-31 13:26             ` Alan Modra
  2012-05-31 13:42               ` Dominique Dhumieres
  0 siblings, 1 reply; 14+ messages in thread
From: Alan Modra @ 2012-05-31 13:26 UTC (permalink / raw)
  To: Dominique Dhumieres; +Cc: IainS, gcc-patches, dje.gcc

On Thu, May 31, 2012 at 02:16:32PM +0200, Dominique Dhumieres wrote:
> (the final patch will require the suitable dg directives;-).

This is really stretching my testsuite knowledge.  Maybe add

/* { dg-additional-options "-mdynamic-no-pic" { target *-*-darwin* } } */


-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-05-31 13:26             ` Alan Modra
@ 2012-05-31 13:42               ` Dominique Dhumieres
  2012-05-31 17:18                 ` Mike Stump
  0 siblings, 1 reply; 14+ messages in thread
From: Dominique Dhumieres @ 2012-05-31 13:42 UTC (permalink / raw)
  To: dominiq, amodra; +Cc: IainS, gcc-patches, dje.gcc

> This is really stretching my testsuite knowledge.  Maybe add
>
>/* { dg-additional-options "-mdynamic-no-pic" { target *-*-darwin* } } */

Using

/* { dg-options "-fno-inline -fomit-frame-pointer" } */
/* { dg-additional-options "-mdynamic-no-pic" { target *-*-darwin* } } */

works for me on powerpc-apple-darwin9, but I can't test it on nondarwin powerpc.

Dominique

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-05-31 13:42               ` Dominique Dhumieres
@ 2012-05-31 17:18                 ` Mike Stump
  0 siblings, 0 replies; 14+ messages in thread
From: Mike Stump @ 2012-05-31 17:18 UTC (permalink / raw)
  To: Dominique Dhumieres; +Cc: amodra, IainS, gcc-patches, dje.gcc

On May 31, 2012, at 6:42 AM, Dominique Dhumieres wrote:
>> This is really stretching my testsuite knowledge.  Maybe add
>> 
>> /* { dg-additional-options "-mdynamic-no-pic" { target *-*-darwin* } } */
> 
> Using
> 
> /* { dg-options "-fno-inline -fomit-frame-pointer" } */
> /* { dg-additional-options "-mdynamic-no-pic" { target *-*-darwin* } } */
> 
> works for me on powerpc-apple-darwin9, but I can't test it on nondarwin powerpc.

Looks good...

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-04-25  5:21     ` Alan Modra
@ 2012-04-25 12:53       ` David Edelsohn
  0 siblings, 0 replies; 14+ messages in thread
From: David Edelsohn @ 2012-04-25 12:53 UTC (permalink / raw)
  To: Alan Modra, gcc-patches

On Wed, Apr 25, 2012 at 1:20 AM, Alan Modra <amodra@gmail.com> wrote:

> This patch adds a testcase to verify register saves and restores.
> I tried to write it so that it will run on all powerpc targets.  From
> past experience it probably won't.  OK to apply anyway, and fix
> fallout later?
>
>        * gcc.target/powerpc/savres.c: New test.
>        * gcc.target/powerpc/powerpc.exp: Run it.

Okay.

Thanks, David

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-04-24 23:19   ` David Edelsohn
@ 2012-04-25  5:21     ` Alan Modra
  2012-04-25 12:53       ` David Edelsohn
  0 siblings, 1 reply; 14+ messages in thread
From: Alan Modra @ 2012-04-25  5:21 UTC (permalink / raw)
  To: David Edelsohn; +Cc: gcc-patches

On Tue, Apr 24, 2012 at 07:19:42PM -0400, David Edelsohn wrote:
> This patch is okay with the macro usage fix.

Thanks, series 2 to 6 committed as 186796, 186797, 186798, 186799,
186800.  I noticed after I committed the lot that 186797 has some
duplicated lines (harmless), corrected in 186798, and 186799 kept the
old cr_save_regno assignment (again harmless), corrected in 186800.
A result of merge conflicts.  I normally start from a clean source
tree, apply patch as posted, commit, repeat.  This time I had a series
of directories with the cumulative patches applied.  Bad idea unless
you use "mf" to resolve conflicts..

This patch adds a testcase to verify register saves and restores.
I tried to write it so that it will run on all powerpc targets.  From
past experience it probably won't.  OK to apply anyway, and fix
fallout later?

	* gcc.target/powerpc/savres.c: New test.
	* gcc.target/powerpc/powerpc.exp: Run it.

Index: gcc/testsuite/gcc.target/powerpc/powerpc.exp
===================================================================
--- gcc/testsuite/gcc.target/powerpc/powerpc.exp	(revision 186800)
+++ gcc/testsuite/gcc.target/powerpc/powerpc.exp	(working copy)
@@ -37,5 +37,14 @@
 dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \
 	"" $DEFAULT_CFLAGS
 
+set SAVRES_TEST_OPTS [list -Os -O2 {-Os -mno-multiple} {-O2 -mno-multiple}]
+set alti ""
+if [check_vmx_hw_available] {
+    set alti "-maltivec"
+}
+torture-init
+set-torture-options $SAVRES_TEST_OPTS
+gcc-dg-runtest [list $srcdir/$subdir/savres.c] $alti
+
 # All done.
 dg-finish
Index: gcc/testsuite/gcc.target/powerpc/savres.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/savres.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/savres.c	(revision 0)
@@ -0,0 +1,1158 @@
+/* { dg-do run } */
+/* { dg-options "-fno-inline -fomit-frame-pointer" } */
+
+/* -fno-inline -maltivec -m32/-m64 -mmultiple/no-multiple -Os/-O2.  */
+#ifndef NO_BODY
+#define abort() __builtin_abort ()
+#define vec_all_eq(v1,v2) __builtin_vec_vcmpeq_p (2, v1, v2)
+#define SET(T,R,V) register T R __asm__ (#R) = V
+#define SET_GPR(R,V) SET (long, R, V)
+#define SET_FPR(R,V) SET (double, R, V)
+#define SET_VR(R,V) SET (__attribute__ ((vector_size (16))) int, R, V)
+#define SET_CR(R,V) __asm__ __volatile__ ("mtcrf %0,%1" : : "n" (1<<(7-R)), "r" (V<<(4*(7-R))) : "cr" #R)
+#define TRASH_GPR(R) SET_GPR (R, 0)
+#define TRASH_FPR(R) SET_FPR (R, 0)
+#define TRASH_VR(R) SET_VR (R, val0)
+#define TRASH_CR(R) SET_CR (R, 0)
+#define TRASH_SOME_GPR TRASH_GPR (r30); TRASH_GPR (r31)
+#define TRASH_SOME_FPR TRASH_FPR (fr28); TRASH_FPR (fr31)
+#define TRASH_SOME_VR TRASH_VR (v26); TRASH_VR (v27); TRASH_VR (v31)
+#define TRASH_SOME_CR TRASH_CR (2)
+#define TRASH_ALL_GPR TRASH_GPR (r14); TRASH_GPR (r15); TRASH_GPR (r16); TRASH_GPR (r17); TRASH_GPR (r18); TRASH_GPR (r19); TRASH_GPR (r20); TRASH_GPR (r21); TRASH_GPR (r22); TRASH_GPR (r23); TRASH_GPR (r24); TRASH_GPR (r25); TRASH_GPR (r26); TRASH_GPR (r27); TRASH_GPR (r28); TRASH_GPR (r29); TRASH_GPR (r30); TRASH_GPR (r31)
+#define TRASH_ALL_FPR TRASH_FPR (fr14); TRASH_FPR (fr15); TRASH_FPR (fr16); TRASH_FPR (fr17); TRASH_FPR (fr18); TRASH_FPR (fr19); TRASH_FPR (fr20); TRASH_FPR (fr21); TRASH_FPR (fr22); TRASH_FPR (fr23); TRASH_FPR (fr24); TRASH_FPR (fr25); TRASH_FPR (fr26); TRASH_FPR (fr27); TRASH_FPR (fr28); TRASH_FPR (fr29); TRASH_FPR (fr30); TRASH_FPR (fr31)
+#define TRASH_ALL_VR TRASH_VR (v20); TRASH_VR (v21); TRASH_VR (v22); TRASH_VR (v23); TRASH_VR (v24); TRASH_VR (v25); TRASH_VR (v26); TRASH_VR (v27); TRASH_VR (v28); TRASH_VR (v29); TRASH_VR (v30); TRASH_VR (v31)
+#define TRASH_ALL_CR TRASH_CR (2); TRASH_CR (3); TRASH_CR (4)
+#define USE_SOME_GPR __asm__ __volatile__ ("#%0 %1" : : "r" (r30), "r" (r31))
+#define USE_SOME_FPR __asm__ __volatile__ ("#%0 %1" : : "f" (fr28), "f" (fr31))
+#define USE_SOME_VR __asm__ __volatile__ ("#%0 %1 %2" : : "v" (v26), "v" (v27), "v" (v31))
+#define USE_SOME_CR
+#define USE_ALL_GPR __asm__ __volatile__ ("#%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14 %15 %16 %17" : : "r" (r14), "r" (r15), "r" (r16), "r" (r17), "r" (r18), "r" (r19), "r" (r20), "r" (r21), "r" (r22), "r" (r23), "r" (r24), "r" (r25), "r" (r26), "r" (r27), "r" (r28), "r" (r29), "r" (r30), "r" (r31))
+#define USE_ALL_FPR __asm__ __volatile__ ("#%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14 %15 %16 %17" : : "f" (fr14), "f" (fr15), "f" (fr16), "f" (fr17), "f" (fr18), "f" (fr19), "f" (fr20), "f" (fr21), "f" (fr22), "f" (fr23), "f" (fr24), "f" (fr25), "f" (fr26), "f" (fr27), "f" (fr28), "f" (fr29), "f" (fr30), "f" (fr31))
+#define USE_ALL_VR __asm__ __volatile__ ("#%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11" : : "v" (v20), "v" (v21), "v" (v22), "v" (v23), "v" (v24), "v" (v25), "v" (v26), "v" (v27), "v" (v28), "v" (v29), "v" (v30), "v" (v31))
+#define USE_ALL_CR
+
+#define INIT_GPR SET_GPR (r14, 14); SET_GPR (r15, 15); SET_GPR (r16, 16); SET_GPR (r17, 17); SET_GPR (r18, 18); SET_GPR (r19, 19); SET_GPR (r20, 20); SET_GPR (r21, 21); SET_GPR (r22, 22); SET_GPR (r23, 23); SET_GPR (r24, 24); SET_GPR (r25, 25); SET_GPR (r26, 26); SET_GPR (r27, 27); SET_GPR (r28, 28); SET_GPR (r29, 29); SET_GPR (r30, 30); SET_GPR (r31, 31)
+#define INIT_FPR SET_FPR (fr14, 140.0); SET_FPR (fr15, 150.0); SET_FPR (fr16, 160.0); SET_FPR (fr17, 170.0); SET_FPR (fr18, 180.0); SET_FPR (fr19, 190.0); SET_FPR (fr20, 200.0); SET_FPR (fr21, 210.0); SET_FPR (fr22, 220.0); SET_FPR (fr23, 230.0); SET_FPR (fr24, 240.0); SET_FPR (fr25, 250.0); SET_FPR (fr26, 260.0); SET_FPR (fr27, 270.0); SET_FPR (fr28, 280.0); SET_FPR (fr29, 290.0); SET_FPR (fr30, 300.0); SET_FPR (fr31, 310.0)
+#define INIT_VR SET_VR (v20, val20); SET_VR (v21, val21); SET_VR (v22, val22); SET_VR (v23, val23); SET_VR (v24, val24); SET_VR (v25, val25); SET_VR (v26, val26); SET_VR (v27, val27); SET_VR (v28, val28); SET_VR (v29, val29); SET_VR (v30, val30); SET_VR (v31, val31)
+#define INIT_CR SET_CR (2, 6); SET_CR (3, 7); SET_CR (4, 8)
+#ifdef __ALTIVEC__
+__attribute__ ((vector_size (16))) int val0 = {0,0,0,0};
+__attribute__ ((vector_size (16))) int val20 = {-201,-202,-203,-204};
+__attribute__ ((vector_size (16))) int val21 = {-211,-212,-213,-214};
+__attribute__ ((vector_size (16))) int val22 = {-221,-222,-223,-224};
+__attribute__ ((vector_size (16))) int val23 = {-231,-232,-233,-234};
+__attribute__ ((vector_size (16))) int val24 = {-241,-242,-243,-244};
+__attribute__ ((vector_size (16))) int val25 = {-251,-252,-253,-254};
+__attribute__ ((vector_size (16))) int val26 = {-261,-262,-263,-264};
+__attribute__ ((vector_size (16))) int val27 = {-271,-272,-273,-274};
+__attribute__ ((vector_size (16))) int val28 = {-281,-282,-283,-284};
+__attribute__ ((vector_size (16))) int val29 = {-291,-292,-293,-294};
+__attribute__ ((vector_size (16))) int val30 = {-301,-302,-303,-304};
+__attribute__ ((vector_size (16))) int val31 = {-311,-312,-313,-314};
+#define INIT_REGS INIT_VR; INIT_FPR; INIT_GPR; INIT_CR
+#else
+#ifndef __NO_FPRS__
+#define INIT_REGS INIT_FPR; INIT_GPR; INIT_CR
+#else
+#define INIT_REGS INIT_GPR; INIT_CR
+#endif
+#endif
+#define VERIFY_GPR if (r14 != 14 || r15 != 15 || r16 != 16 || r17 != 17 || r18 != 18 || r19 != 19 || r20 != 20 || r21 != 21 || r22 != 22 || r23 != 23 || r24 != 24 || r25 != 25 || r26 != 26 || r27 != 27 || r28 != 28 || r29 != 29 || r30 != 30 || r31 != 31) abort ()
+#define VERIFY_FPR if (fr14 != 140.0 || fr15 != 150.0 || fr16 != 160.0 || fr17 != 170.0 || fr18 != 180.0 || fr19 != 190.0 || fr20 != 200.0 || fr21 != 210.0 || fr22 != 220.0 || fr23 != 230.0 || fr24 != 240.0 || fr25 != 250.0 || fr26 != 260.0 || fr27 != 270.0 || fr28 != 280.0 || fr29 != 290.0 || fr30 != 300.0 || fr31 != 310.0) abort ()
+#define VERIFY_VR if (!vec_all_eq (v20, val20) || !vec_all_eq (v21, val21) || !vec_all_eq (v22, val22) || !vec_all_eq (v23, val23) || !vec_all_eq (v24, val24) || !vec_all_eq (v25, val25) || !vec_all_eq (v26, val26) || !vec_all_eq (v27, val27) || !vec_all_eq (v28, val28) || !vec_all_eq (v29, val29) || !vec_all_eq (v30, val30) || !vec_all_eq (v31, val31)) abort ()
+#define VERIFY_CR ({ int tmp; __asm__ __volatile__ ("mfcr %0" : "=r" (tmp)); if ((tmp & ((15 << 20) | (15 << 16) | (15 << 12))) != ((6 << 20) | (7 << 16) | (8 << 12))) abort (); })
+#ifdef __ALTIVEC__
+#define VERIFY_REGS VERIFY_VR; VERIFY_FPR; VERIFY_GPR; VERIFY_CR
+#else
+#ifndef __NO_FPRS__
+#define VERIFY_REGS VERIFY_FPR; VERIFY_GPR; VERIFY_CR
+#else
+#define VERIFY_REGS VERIFY_GPR; VERIFY_CR
+#endif
+#endif
+
+#else /* NO_BODY */
+/* For looking at prologue and epilogue code without distractions.  */
+#define TRASH_ALL_CR
+#define TRASH_ALL_VR
+#define TRASH_ALL_FPR
+#define TRASH_ALL_GPR
+#define USE_ALL_CR
+#define USE_ALL_VR
+#define USE_ALL_FPR
+#define USE_ALL_GPR
+#define TRASH_SOME_CR
+#define TRASH_SOME_VR
+#define TRASH_SOME_FPR
+#define TRASH_SOME_GPR
+#define USE_SOME_CR
+#define USE_SOME_VR
+#define USE_SOME_FPR
+#define USE_SOME_GPR
+#define INIT_REGS
+#define VERIFY_REGS
+#endif
+
+#ifdef __ALTIVEC__
+#ifndef __NO_FPRS__
+void b_all (void)
+{
+  char a[33000];
+  TRASH_ALL_CR;
+  TRASH_ALL_VR;
+  TRASH_ALL_FPR;
+  TRASH_ALL_GPR;
+  USE_ALL_CR;
+  USE_ALL_VR;
+  USE_ALL_FPR;
+  USE_ALL_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "cr3", "cr4", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31");
+}
+
+void b_cvfr (void)
+{
+  char a[33000];
+  TRASH_SOME_CR;
+  TRASH_SOME_VR;
+  TRASH_SOME_FPR;
+  TRASH_SOME_GPR;
+  USE_SOME_CR;
+  USE_SOME_VR;
+  USE_SOME_FPR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+}
+
+void b_vfr (void)
+{
+  char a[33000];
+  TRASH_SOME_VR;
+  TRASH_SOME_FPR;
+  TRASH_SOME_GPR;
+  USE_SOME_VR;
+  USE_SOME_FPR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+}
+
+void b_cvf (void)
+{
+  char a[33000];
+  TRASH_SOME_CR;
+  TRASH_SOME_VR;
+  TRASH_SOME_FPR;
+  USE_SOME_CR;
+  USE_SOME_VR;
+  USE_SOME_FPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "v26", "v27", "v31", "fr28", "fr31");
+}
+
+void b_vf (void)
+{
+  char a[33000];
+  TRASH_SOME_VR;
+  TRASH_SOME_FPR;
+  USE_SOME_VR;
+  USE_SOME_FPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "v26", "v27", "v31", "fr28", "fr31");
+}
+#endif
+
+void b_cvr (void)
+{
+  char a[33000];
+  TRASH_SOME_CR;
+  TRASH_SOME_VR;
+  TRASH_SOME_GPR;
+  USE_SOME_CR;
+  USE_SOME_VR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "v26", "v27", "v31", "r30", "r31");
+}
+
+void b_vr (void)
+{
+  char a[33000];
+  TRASH_SOME_VR;
+  TRASH_SOME_GPR;
+  USE_SOME_VR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "v26", "v27", "v31", "r30", "r31");
+}
+
+void b_cv (void)
+{
+  char a[33000];
+  TRASH_SOME_CR;
+  TRASH_SOME_VR;
+  USE_SOME_CR;
+  USE_SOME_VR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "v26", "v27", "v31");
+}
+
+void b_v (void)
+{
+  char a[33000];
+  TRASH_SOME_VR;
+  USE_SOME_VR;
+  __asm __volatile ("#%0" : "=m" (a) : : "v26", "v27", "v31");
+}
+#endif
+
+#ifndef __NO_FPRS__
+void b_cfr (void)
+{
+  char a[33000];
+  TRASH_SOME_CR;
+  TRASH_SOME_FPR;
+  TRASH_SOME_GPR;
+  USE_SOME_CR;
+  USE_SOME_FPR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "fr28", "fr31", "r30", "r31");
+}
+
+void b_fr (void)
+{
+  char a[33000];
+  TRASH_SOME_FPR;
+  TRASH_SOME_GPR;
+  USE_SOME_FPR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "fr28", "fr31", "r30", "r31");
+}
+
+void b_cf (void)
+{
+  char a[33000];
+  TRASH_SOME_CR;
+  TRASH_SOME_FPR;
+  USE_SOME_CR;
+  USE_SOME_FPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "fr28", "fr31");
+}
+
+void b_f (void)
+{
+  char a[33000];
+  TRASH_SOME_FPR;
+  USE_SOME_FPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "fr28", "fr31");
+}
+#endif
+
+void b_cr (void)
+{
+  char a[33000];
+  TRASH_SOME_CR;
+  TRASH_SOME_GPR;
+  USE_SOME_CR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "r30", "r31");
+}
+
+void b_r (void)
+{
+  char a[33000];
+  TRASH_SOME_GPR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "r30", "r31");
+}
+
+void b_c (void)
+{
+  char a[33000];
+  TRASH_SOME_CR;
+  USE_SOME_CR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2");
+}
+
+void b_0 (void)
+{
+  char a[33000];
+  __asm __volatile ("#%0" : "=m" (a) );
+}
+
+#ifdef __ALTIVEC__
+#ifndef __NO_FPRS__
+void s_all (void)
+{
+  char a[33];
+  TRASH_ALL_CR;
+  TRASH_ALL_VR;
+  TRASH_ALL_FPR;
+  TRASH_ALL_GPR;
+  USE_ALL_CR;
+  USE_ALL_VR;
+  USE_ALL_FPR;
+  USE_ALL_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "cr3", "cr4", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31");
+}
+
+void s_cvfr (void)
+{
+  char a[33];
+  TRASH_SOME_CR;
+  TRASH_SOME_VR;
+  TRASH_SOME_FPR;
+  TRASH_SOME_GPR;
+  USE_SOME_CR;
+  USE_SOME_VR;
+  USE_SOME_FPR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+}
+
+void s_vfr (void)
+{
+  char a[33];
+  TRASH_SOME_VR;
+  TRASH_SOME_FPR;
+  TRASH_SOME_GPR;
+  USE_SOME_VR;
+  USE_SOME_FPR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+}
+
+void s_cvf (void)
+{
+  char a[33];
+  TRASH_SOME_CR;
+  TRASH_SOME_VR;
+  TRASH_SOME_FPR;
+  USE_SOME_CR;
+  USE_SOME_VR;
+  USE_SOME_FPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "v26", "v27", "v31", "fr28", "fr31");
+}
+
+void s_vf (void)
+{
+  char a[33];
+  TRASH_SOME_VR;
+  TRASH_SOME_FPR;
+  USE_SOME_VR;
+  USE_SOME_FPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "v26", "v27", "v31", "fr28", "fr31");
+}
+#endif
+
+void s_cvr (void)
+{
+  char a[33];
+  TRASH_SOME_CR;
+  TRASH_SOME_VR;
+  TRASH_SOME_GPR;
+  USE_SOME_CR;
+  USE_SOME_VR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "v26", "v27", "v31", "r30", "r31");
+}
+
+void s_vr (void)
+{
+  char a[33];
+  TRASH_SOME_VR;
+  TRASH_SOME_GPR;
+  USE_SOME_VR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "v26", "v27", "v31", "r30", "r31");
+}
+
+void s_cv (void)
+{
+  char a[33];
+  TRASH_SOME_CR;
+  TRASH_SOME_VR;
+  USE_SOME_CR;
+  USE_SOME_VR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "v26", "v27", "v31");
+}
+
+void s_v (void)
+{
+  char a[33];
+  TRASH_SOME_VR;
+  USE_SOME_VR;
+  __asm __volatile ("#%0" : "=m" (a) : : "v26", "v27", "v31");
+}
+#endif
+
+#ifndef __NO_FPRS__
+void s_cfr (void)
+{
+  char a[33];
+  TRASH_SOME_CR;
+  TRASH_SOME_FPR;
+  TRASH_SOME_GPR;
+  USE_SOME_CR;
+  USE_SOME_FPR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "fr28", "fr31", "r30", "r31");
+}
+
+void s_fr (void)
+{
+  char a[33];
+  TRASH_SOME_FPR;
+  TRASH_SOME_GPR;
+  USE_SOME_FPR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "fr28", "fr31", "r30", "r31");
+}
+
+void s_cf (void)
+{
+  char a[33];
+  TRASH_SOME_CR;
+  TRASH_SOME_FPR;
+  USE_SOME_CR;
+  USE_SOME_FPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "fr28", "fr31");
+}
+
+void s_f (void)
+{
+  char a[33];
+  TRASH_SOME_FPR;
+  USE_SOME_FPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "fr28", "fr31");
+}
+#endif
+
+void s_cr (void)
+{
+  char a[33];
+  TRASH_SOME_CR;
+  TRASH_SOME_GPR;
+  USE_SOME_CR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2", "r30", "r31");
+}
+
+void s_r (void)
+{
+  char a[33];
+  TRASH_SOME_GPR;
+  USE_SOME_GPR;
+  __asm __volatile ("#%0" : "=m" (a) : : "r30", "r31");
+}
+
+void s_c (void)
+{
+  char a[33];
+  TRASH_SOME_CR;
+  USE_SOME_CR;
+  __asm __volatile ("#%0" : "=m" (a) : : "cr2");
+}
+
+void s_0 (void)
+{
+  char a[33];
+  __asm __volatile ("#%0" : "=m" (a) );
+}
+
+#ifdef __ALTIVEC__
+#ifndef __NO_FPRS__
+void wb_all (void)
+{
+  char b[10];
+  void nb_all (void)
+  {
+    char a[33000];
+    TRASH_ALL_CR;
+    TRASH_ALL_VR;
+    TRASH_ALL_FPR;
+    TRASH_ALL_GPR;
+    USE_ALL_CR;
+    USE_ALL_VR;
+    USE_ALL_FPR;
+    USE_ALL_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "cr3", "cr4", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31");
+  }
+  nb_all();
+}
+
+void wb_cvfr (void)
+{
+  char b[10];
+  void nb_cvfr (void)
+  {
+    char a[33000];
+    TRASH_SOME_CR;
+    TRASH_SOME_VR;
+    TRASH_SOME_FPR;
+    TRASH_SOME_GPR;
+    USE_SOME_CR;
+    USE_SOME_VR;
+    USE_SOME_FPR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+  }
+  nb_cvfr ();
+}
+
+void wb_vfr (void)
+{
+  char b[10];
+  void nb_vfr (void)
+  {
+    char a[33000];
+    TRASH_SOME_VR;
+    TRASH_SOME_FPR;
+    TRASH_SOME_GPR;
+    USE_SOME_VR;
+    USE_SOME_FPR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+  }
+  nb_vfr ();
+}
+
+void wb_cvf (void)
+{
+  char b[10];
+  void nb_cvf (void)
+  {
+    char a[33000];
+    TRASH_SOME_CR;
+    TRASH_SOME_VR;
+    TRASH_SOME_FPR;
+    USE_SOME_CR;
+    USE_SOME_VR;
+    USE_SOME_FPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "fr28", "fr31");
+  }
+  nb_cvf ();
+}
+
+void wb_vf (void)
+{
+  char b[10];
+  void nb_vf (void)
+  {
+    char a[33000];
+    TRASH_SOME_VR;
+    TRASH_SOME_FPR;
+    USE_SOME_VR;
+    USE_SOME_FPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "fr28", "fr31");
+  }
+  nb_vf ();
+}
+#endif
+
+void wb_cvr (void)
+{
+  char b[10];
+  void nb_cvr (void)
+  {
+    char a[33000];
+    TRASH_SOME_CR;
+    TRASH_SOME_VR;
+    TRASH_SOME_GPR;
+    USE_SOME_CR;
+    USE_SOME_VR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "r30", "r31");
+  }
+  nb_cvr ();
+}
+
+void wb_vr (void)
+{
+  char b[10];
+  void nb_vr (void)
+  {
+    char a[33000];
+    TRASH_SOME_VR;
+    TRASH_SOME_GPR;
+    USE_SOME_VR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "r30", "r31");
+  }
+  nb_vr ();
+}
+
+void wb_cv (void)
+{
+  char b[10];
+  void nb_cv (void)
+  {
+    char a[33000];
+    TRASH_SOME_CR;
+    TRASH_SOME_VR;
+    USE_SOME_CR;
+    USE_SOME_VR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31");
+  }
+  nb_cv ();
+}
+
+void wb_v (void)
+{
+  char b[10];
+  void nb_v (void)
+  {
+    char a[33000];
+    TRASH_SOME_VR;
+    USE_SOME_VR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31");
+  }
+  nb_v ();
+}
+#endif
+
+#ifndef __NO_FPRS__
+void wb_cfr (void)
+{
+  char b[10];
+  void nb_cfr (void)
+  {
+    char a[33000];
+    TRASH_SOME_CR;
+    TRASH_SOME_FPR;
+    TRASH_SOME_GPR;
+    USE_SOME_CR;
+    USE_SOME_FPR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "fr28", "fr31", "r30", "r31");
+  }
+  nb_cfr ();
+}
+
+void wb_fr (void)
+{
+  char b[10];
+  void nb_fr (void)
+  {
+    char a[33000];
+    TRASH_SOME_FPR;
+    TRASH_SOME_GPR;
+    USE_SOME_FPR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "fr28", "fr31", "r30", "r31");
+  }
+  nb_fr ();
+}
+
+void wb_cf (void)
+{
+  char b[10];
+  void nb_cf (void)
+  {
+    char a[33000];
+    TRASH_SOME_CR;
+    TRASH_SOME_FPR;
+    USE_SOME_CR;
+    USE_SOME_FPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "fr28", "fr31");
+  }
+  nb_cf ();
+}
+
+void wb_f (void)
+{
+  char b[10];
+  void nb_f (void)
+  {
+    char a[33000];
+    TRASH_SOME_FPR;
+    USE_SOME_FPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "fr28", "fr31");
+  }
+  nb_f ();
+}
+#endif
+
+void wb_cr (void)
+{
+  char b[10];
+  void nb_cr (void)
+  {
+    char a[33000];
+    TRASH_SOME_CR;
+    TRASH_SOME_GPR;
+    USE_SOME_CR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "r30", "r31");
+  }
+  nb_cr ();
+}
+
+void wb_r (void)
+{
+  char b[10];
+  void nb_r (void)
+  {
+    char a[33000];
+    TRASH_SOME_GPR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "r30", "r31");
+  }
+  nb_r ();
+}
+
+void wb_c (void)
+{
+  char b[10];
+  void nb_c (void)
+  {
+    char a[33000];
+    TRASH_SOME_CR;
+    USE_SOME_CR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2");
+  }
+  nb_c ();
+}
+
+void wb_0 (void)
+{
+  char b[10];
+  void nb_0 (void)
+  {
+    char a[33000];
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) );
+  }
+  nb_0 ();
+}
+
+#ifdef __ALTIVEC__
+#ifndef __NO_FPRS__
+void ws_all (void)
+{
+  char b[10];
+  void ns_all (void)
+  {
+    char a[33];
+    TRASH_ALL_CR;
+    TRASH_ALL_VR;
+    TRASH_ALL_FPR;
+    TRASH_ALL_GPR;
+    USE_ALL_CR;
+    USE_ALL_VR;
+    USE_ALL_FPR;
+    USE_ALL_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "cr3", "cr4", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31");
+  }
+  ns_all();
+}
+
+void ws_cvfr (void)
+{
+  char b[10];
+  void ns_cvfr (void)
+  {
+    char a[33];
+    TRASH_SOME_CR;
+    TRASH_SOME_VR;
+    TRASH_SOME_FPR;
+    TRASH_SOME_GPR;
+    USE_SOME_CR;
+    USE_SOME_VR;
+    USE_SOME_FPR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+  }
+  ns_cvfr ();
+}
+
+void ws_vfr (void)
+{
+  char b[10];
+  void ns_vfr (void)
+  {
+    char a[33];
+    TRASH_SOME_VR;
+    TRASH_SOME_FPR;
+    TRASH_SOME_GPR;
+    USE_SOME_VR;
+    USE_SOME_FPR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "fr28", "fr31", "r30", "r31");
+  }
+  ns_vfr ();
+}
+
+void ws_cvf (void)
+{
+  char b[10];
+  void ns_cvf (void)
+  {
+    char a[33];
+    TRASH_SOME_CR;
+    TRASH_SOME_VR;
+    TRASH_SOME_FPR;
+    USE_SOME_CR;
+    USE_SOME_VR;
+    USE_SOME_FPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "fr28", "fr31");
+  }
+  ns_cvf ();
+}
+
+void ws_vf (void)
+{
+  char b[10];
+  void ns_vf (void)
+  {
+    char a[33];
+    TRASH_SOME_VR;
+    TRASH_SOME_FPR;
+    USE_SOME_VR;
+    USE_SOME_FPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "fr28", "fr31");
+  }
+  ns_vf ();
+}
+#endif
+
+void ws_cvr (void)
+{
+  char b[10];
+  void ns_cvr (void)
+  {
+    char a[33];
+    TRASH_SOME_CR;
+    TRASH_SOME_VR;
+    TRASH_SOME_GPR;
+    USE_SOME_CR;
+    USE_SOME_VR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31", "r30", "r31");
+  }
+  ns_cvr ();
+}
+
+void ws_vr (void)
+{
+  char b[10];
+  void ns_vr (void)
+  {
+    char a[33];
+    TRASH_SOME_VR;
+    TRASH_SOME_FPR;
+    USE_SOME_VR;
+    USE_SOME_FPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31", "r30", "r31");
+  }
+  ns_vr ();
+}
+
+void ws_cv (void)
+{
+  char b[10];
+  void ns_cv (void)
+  {
+    char a[33];
+    TRASH_SOME_CR;
+    TRASH_SOME_VR;
+    USE_SOME_CR;
+    USE_SOME_VR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "v26", "v27", "v31");
+  }
+  ns_cv ();
+}
+
+void ws_v (void)
+{
+  char b[10];
+  void ns_v (void)
+  {
+    char a[33];
+    TRASH_SOME_VR;
+    USE_SOME_VR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "v26", "v27", "v31");
+  }
+  ns_v ();
+}
+#endif
+
+#ifndef __NO_FPRS__
+void ws_cfr (void)
+{
+  char b[10];
+  void ns_cfr (void)
+  {
+    char a[33];
+    TRASH_SOME_CR;
+    TRASH_SOME_FPR;
+    TRASH_SOME_GPR;
+    USE_SOME_CR;
+    USE_SOME_FPR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "fr28", "fr31", "r30", "r31");
+  }
+  ns_cfr ();
+}
+
+void ws_fr (void)
+{
+  char b[10];
+  void ns_fr (void)
+  {
+    char a[33];
+    TRASH_SOME_FPR;
+    TRASH_SOME_GPR;
+    USE_SOME_FPR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "fr28", "fr31", "r30", "r31");
+  }
+  ns_fr ();
+}
+
+void ws_cf (void)
+{
+  char b[10];
+  void ns_cf (void)
+  {
+    char a[33];
+    TRASH_SOME_CR;
+    TRASH_SOME_FPR;
+    USE_SOME_CR;
+    USE_SOME_FPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "fr28", "fr31");
+  }
+  ns_cf ();
+}
+
+void ws_f (void)
+{
+  char b[10];
+  void ns_f (void)
+  {
+    char a[33];
+    TRASH_SOME_FPR;
+    USE_SOME_FPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "fr28", "fr31");
+  }
+  ns_f ();
+}
+#endif
+
+void ws_cr (void)
+{
+  char b[10];
+  void ns_cr (void)
+  {
+    char a[33];
+    TRASH_SOME_CR;
+    TRASH_SOME_GPR;
+    USE_SOME_CR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2", "r30", "r31");
+  }
+  ns_cr ();
+}
+
+void ws_r (void)
+{
+  char b[10];
+  void ns_r (void)
+  {
+    char a[33];
+    TRASH_SOME_GPR;
+    USE_SOME_GPR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "r30", "r31");
+  }
+  ns_r ();
+}
+
+void ws_c (void)
+{
+  char b[10];
+  void ns_c (void)
+  {
+    char a[33];
+    TRASH_SOME_CR;
+    USE_SOME_CR;
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) : : "cr2");
+  }
+  ns_c ();
+}
+
+void ws_0 (void)
+{
+  char b[10];
+  void ns_0 (void)
+  {
+    char a[33];
+    __asm __volatile ("#%0 %1" : "=m" (a), "=m" (b) );
+  }
+  ns_0 ();
+}
+
+int main (void)
+{
+  INIT_REGS;
+  USE_ALL_CR;
+#ifdef __ALTIVEC__
+  USE_ALL_VR;
+#ifndef __NO_FPRS__
+  USE_ALL_FPR;
+#endif
+#endif
+  USE_ALL_GPR;
+#ifdef __ALTIVEC__
+#ifndef __NO_FPRS__
+  b_all ();
+  VERIFY_REGS;
+  b_cvfr ();
+  VERIFY_REGS;
+  b_vfr ();
+  VERIFY_REGS;
+  b_cvf ();
+  VERIFY_REGS;
+  b_vf ();
+  VERIFY_REGS;
+#endif
+  b_cvr ();
+  VERIFY_REGS;
+  b_vr ();
+  VERIFY_REGS;
+  b_cv ();
+  VERIFY_REGS;
+  b_v ();
+  VERIFY_REGS;
+#endif
+#ifndef __NO_FPRS__
+  b_cfr ();
+  VERIFY_REGS;
+  b_fr ();
+  VERIFY_REGS;
+  b_cf ();
+  VERIFY_REGS;
+  b_f ();
+  VERIFY_REGS;
+#endif
+  b_cr ();
+  VERIFY_REGS;
+  b_r ();
+  VERIFY_REGS;
+  b_c ();
+  VERIFY_REGS;
+  b_0 ();
+  VERIFY_REGS;
+#ifdef __ALTIVEC__
+#ifndef __NO_FPRS__
+  s_all ();
+  VERIFY_REGS;
+  s_cvfr ();
+  VERIFY_REGS;
+  s_vfr ();
+  VERIFY_REGS;
+  s_cvf ();
+  VERIFY_REGS;
+  s_vf ();
+  VERIFY_REGS;
+#endif
+  s_cvr ();
+  VERIFY_REGS;
+  s_vr ();
+  VERIFY_REGS;
+  s_cv ();
+  VERIFY_REGS;
+  s_v ();
+  VERIFY_REGS;
+#endif
+#ifndef __NO_FPRS__
+  s_cfr ();
+  VERIFY_REGS;
+  s_fr ();
+  VERIFY_REGS;
+  s_cf ();
+  VERIFY_REGS;
+  s_f ();
+  VERIFY_REGS;
+#endif
+  s_cr ();
+  VERIFY_REGS;
+  s_r ();
+  VERIFY_REGS;
+  s_c ();
+  VERIFY_REGS;
+  s_0 ();
+  VERIFY_REGS;
+#ifdef __ALTIVEC__
+#ifndef __NO_FPRS__
+  wb_all ();
+  VERIFY_REGS;
+  wb_cvfr ();
+  VERIFY_REGS;
+  wb_vfr ();
+  VERIFY_REGS;
+  wb_cvf ();
+  VERIFY_REGS;
+  wb_vf ();
+  VERIFY_REGS;
+#endif
+  wb_cvr ();
+  VERIFY_REGS;
+  wb_vr ();
+  VERIFY_REGS;
+  wb_cv ();
+  VERIFY_REGS;
+  wb_v ();
+  VERIFY_REGS;
+#endif
+#ifndef __NO_FPRS__
+  wb_cfr ();
+  VERIFY_REGS;
+  wb_fr ();
+  VERIFY_REGS;
+  wb_cf ();
+  VERIFY_REGS;
+  wb_f ();
+  VERIFY_REGS;
+#endif
+  wb_cr ();
+  VERIFY_REGS;
+  wb_r ();
+  VERIFY_REGS;
+  wb_c ();
+  VERIFY_REGS;
+  wb_0 ();
+  VERIFY_REGS;
+#ifdef __ALTIVEC__
+#ifndef __NO_FPRS__
+  ws_all ();
+  VERIFY_REGS;
+  ws_cvfr ();
+  VERIFY_REGS;
+  ws_vfr ();
+  VERIFY_REGS;
+  ws_cvf ();
+  VERIFY_REGS;
+  ws_vf ();
+  VERIFY_REGS;
+#endif
+  ws_cvr ();
+  VERIFY_REGS;
+  ws_vr ();
+  VERIFY_REGS;
+  ws_cv ();
+  VERIFY_REGS;
+  ws_v ();
+  VERIFY_REGS;
+#endif
+#ifndef __NO_FPRS__
+  ws_cfr ();
+  VERIFY_REGS;
+  ws_fr ();
+  VERIFY_REGS;
+  ws_cf ();
+  VERIFY_REGS;
+  ws_f ();
+  VERIFY_REGS;
+#endif
+  ws_cr ();
+  VERIFY_REGS;
+  ws_r ();
+  VERIFY_REGS;
+  ws_c ();
+  VERIFY_REGS;
+  ws_0 ();
+  VERIFY_REGS;
+  return 0;
+}


-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: PowerPC prologue and epilogue 6
  2012-04-21  6:49 ` PowerPC prologue and epilogue 6 Alan Modra
@ 2012-04-24 23:19   ` David Edelsohn
  2012-04-25  5:21     ` Alan Modra
  0 siblings, 1 reply; 14+ messages in thread
From: David Edelsohn @ 2012-04-24 23:19 UTC (permalink / raw)
  To: gcc-patches, Alan Modra

On Sat, Apr 21, 2012 at 2:48 AM, Alan Modra <amodra@gmail.com> wrote:
> This patch adds out-of-line vector saves and restores.  To do this I
> made some infrastructure changes to various functions like
> rs6000_emit_savres_rtx that currently take boolean parameters (savep,
> gpr, and lr).  Rather than add yet another boolean to specify vector
> regs, I chose to lump them all together in a bitmask.  This made the
> patch a little larger but overall is a better interface, I think.
>
> I also revert a change I made in
> http://gcc.gnu.org/ml/gcc-patches/2012-04/msg01014.html to always use
> r11 as a frame reg whenever abiv4 emits out-of-line saves.  Code
> quality in functions with small frames is better without that
> particular change.  This however meant some changes are required later
> when setting up pointer regs for gpr and fpr out-of-line saves.
>
> What else is here?  Improved register selection when saving vrsave in
> the prologue and when restoring cr in the epilogue, allowing better
> scheduling.  A fix to rs6000_output_function_prologue to output the
> correct .extern for ELF, then deciding we don't need such things
> anyway.  And various other little code cleanups.  Bootstrapped and
> regression tested powerpc-linux.
>
> gcc/
>        * config/rs6000/rs6000 (SAVE_INLINE_VRS, REST_INLINE_VRS,
>        V_SAVE_INLINE, SAVRES_LR, SAVRES_SAVE, SAVRES_REG,
>        SAVRES_GPR, SAVRES_FPR, SAVRES_VR): Define.
>        (no_global_regs_above): Delete.
>        (no_global_regs): New function.
>        (rs6000_savres_strategy): Handle vector regs.  Use proper lr_save_p
>        value for load multiple test.
>        (savres_routine_syms): Increase size.
>        (rs6000_savres_routine_name, rs6000_savres_routine_sym,
>        ptr_regno_for_savres, rs6000_emit_savres_rtx): Pass in int selector
>        rather than a number of boolean flags.  Update all callers.
>        (rs6000_savres_routine_name): Generate vector save/restore names.
>        (rs6000_savres_routine_sym): Handle vector regs.  Delete forward decl.
>        (ptr_regno_for_savres, rs6000_emit_savres_rtx): Likewise.
>        (rs6000_emit_prologue): Delete saving_FPRs_inline, saving_GPRs_inline
>        and using_store_multiple.  Expand uses.  Don't always use r11 as
>        frame reg when needed for out-of-line saves.  Set up initial offset
>        for out-of-line vector saves when buying stack frame.  Handle pointer
>        reg setup for out-of-line fp save.  Emit call to out-of-line vector
>        save function.  Choose r11 or r12 for vrsave reg when available for
>        better scheduling.
>        (rs6000_output_function_prologue): Don't emit .extern for ELF.
>        (rs6000_emit_epilogue): Choose a better frame reg when restoring
>        from back-chain to suit out-of-line vector restore functions.  Emit
>        call to out-of-line vector restore function.  Adjust register used
>        for cr restore.  Tweak pointer register setup for gpr restore.
>        * config/rs6000/rs6000.h (FIRST_SAVED_GP_REGNO): Take into account
>        FIXED_R13.
>        * config/rs6000/sysv4.h (FP_SAVE_INLINE, GP_SAVE_INLINE): Simplify.
>        (V_SAVE_INLINE): Define.
>        * config/rs6000/altivec.md (save_vregs_*, restore_vregs_*): New insns.
> libgcc/
>        * config/rs6000/crtsavevr.S: New file.
>        * config/rs6000/crtrestvr.S: New file.
>        * config/rs6000/t-savresfgpr: Build the above.
>        * config/rs6000/t-netbsd: Likewise.

This patch is okay with the macro usage fix.

Thanks, David

^ permalink raw reply	[flat|nested] 14+ messages in thread

* PowerPC prologue and epilogue 6
  2012-04-17 15:08 PowerPC prologue and epilogue Alan Modra
@ 2012-04-21  6:49 ` Alan Modra
  2012-04-24 23:19   ` David Edelsohn
  0 siblings, 1 reply; 14+ messages in thread
From: Alan Modra @ 2012-04-21  6:49 UTC (permalink / raw)
  To: gcc-patches, David Edelsohn

This patch adds out-of-line vector saves and restores.  To do this I
made some infrastructure changes to various functions like
rs6000_emit_savres_rtx that currently take boolean parameters (savep,
gpr, and lr).  Rather than add yet another boolean to specify vector
regs, I chose to lump them all together in a bitmask.  This made the
patch a little larger but overall is a better interface, I think.

I also revert a change I made in
http://gcc.gnu.org/ml/gcc-patches/2012-04/msg01014.html to always use
r11 as a frame reg whenever abiv4 emits out-of-line saves.  Code
quality in functions with small frames is better without that
particular change.  This however meant some changes are required later
when setting up pointer regs for gpr and fpr out-of-line saves.

What else is here?  Improved register selection when saving vrsave in
the prologue and when restoring cr in the epilogue, allowing better
scheduling.  A fix to rs6000_output_function_prologue to output the
correct .extern for ELF, then deciding we don't need such things
anyway.  And various other little code cleanups.  Bootstrapped and
regression tested powerpc-linux.

gcc/
	* config/rs6000/rs6000 (SAVE_INLINE_VRS, REST_INLINE_VRS,
	V_SAVE_INLINE, SAVRES_LR, SAVRES_SAVE, SAVRES_REG,
	SAVRES_GPR, SAVRES_FPR, SAVRES_VR): Define.
	(no_global_regs_above): Delete.
	(no_global_regs): New function.
	(rs6000_savres_strategy): Handle vector regs.  Use proper lr_save_p
	value for load multiple test.
	(savres_routine_syms): Increase size.
	(rs6000_savres_routine_name, rs6000_savres_routine_sym,
	ptr_regno_for_savres, rs6000_emit_savres_rtx): Pass in int selector
	rather than a number of boolean flags.  Update all callers.
	(rs6000_savres_routine_name): Generate vector save/restore names.
	(rs6000_savres_routine_sym): Handle vector regs.  Delete forward decl.
	(ptr_regno_for_savres, rs6000_emit_savres_rtx): Likewise.
	(rs6000_emit_prologue): Delete saving_FPRs_inline, saving_GPRs_inline
	and using_store_multiple.  Expand uses.  Don't always use r11 as
	frame reg when needed for out-of-line saves.  Set up initial offset
	for out-of-line vector saves when buying stack frame.  Handle pointer
	reg setup for out-of-line fp save.  Emit call to out-of-line vector
	save function.  Choose r11 or r12 for vrsave reg when available for
	better scheduling.
	(rs6000_output_function_prologue): Don't emit .extern for ELF.
	(rs6000_emit_epilogue): Choose a better frame reg when restoring
	from back-chain to suit out-of-line vector restore functions.  Emit
	call to out-of-line vector restore function.  Adjust register used
	for cr restore.  Tweak pointer register setup for gpr restore.
	* config/rs6000/rs6000.h (FIRST_SAVED_GP_REGNO): Take into account
	FIXED_R13.
	* config/rs6000/sysv4.h (FP_SAVE_INLINE, GP_SAVE_INLINE): Simplify.
	(V_SAVE_INLINE): Define.
	* config/rs6000/altivec.md (save_vregs_*, restore_vregs_*): New insns.
libgcc/
	* config/rs6000/crtsavevr.S: New file.
	* config/rs6000/crtrestvr.S: New file.
	* config/rs6000/t-savresfgpr: Build the above.
	* config/rs6000/t-netbsd: Likewise.

diff -urpN gcc-alan5/gcc/config/rs6000/rs6000.c gcc-alan6/gcc/config/rs6000/rs6000.c
--- gcc-alan5/gcc/config/rs6000/rs6000.c	2012-04-19 20:55:02.214727782 +0930
+++ gcc-alan6/gcc/config/rs6000/rs6000.c	2012-04-21 15:47:44.193462791 +0930
@@ -937,7 +937,6 @@ static bool legitimate_small_data_p (enu
 static bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int);
 static struct machine_function * rs6000_init_machine_status (void);
 static bool rs6000_assemble_integer (rtx, unsigned int, int);
-static bool no_global_regs_above (int, bool);
 #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
 static void rs6000_assemble_visibility (tree, int);
 #endif
@@ -950,7 +949,6 @@ static tree rs6000_handle_struct_attribu
 static void rs6000_eliminate_indexed_memrefs (rtx operands[2]);
 static const char *rs6000_mangle_type (const_tree);
 static void rs6000_set_default_type_attributes (tree);
-static rtx rs6000_savres_routine_sym (rs6000_stack_t *, bool, bool, bool);
 static bool rs6000_reg_live_or_pic_offset_p (int);
 static tree rs6000_builtin_vectorized_libmass (tree, tree, tree);
 static tree rs6000_builtin_vectorized_function (tree, tree, tree);
@@ -17405,6 +17403,21 @@ is_altivec_return_reg (rtx reg, void *xy
 }
 
 \f
+/* Look for user-defined global regs in the range FIRST to LAST-1.
+   We should not restore these, and so cannot use lmw or out-of-line
+   restore functions if there are any.  We also can't save them
+   (well, emit frame notes for them), because frame unwinding during
+   exception handling will restore saved registers.  */
+
+static bool
+global_regs_p (unsigned first, unsigned last)
+{
+  while (first < last)
+    if (global_regs[first++])
+      return true;
+  return false;
+}
+
 /* Determine the strategy for savings/restoring registers.  */
 
 enum {
@@ -17415,41 +17428,54 @@ enum {
   REST_INLINE_GPRS = 0x10,
   SAVE_NOINLINE_GPRS_SAVES_LR = 0x20,
   SAVE_NOINLINE_FPRS_SAVES_LR = 0x40,
-  REST_NOINLINE_FPRS_DOESNT_RESTORE_LR = 0x80
+  REST_NOINLINE_FPRS_DOESNT_RESTORE_LR = 0x80,
+  SAVE_INLINE_VRS = 0x100,
+  REST_INLINE_VRS = 0x200
 };
 
+#ifndef V_SAVE_INLINE
+#define V_SAVE_INLINE(FIRST_REG) 1
+#endif
+
 static int
 rs6000_savres_strategy (rs6000_stack_t *info,
 			bool using_static_chain_p)
 {
   int strategy = 0;
+  bool lr_save_p;
 
   if (TARGET_MULTIPLE
       && !TARGET_POWERPC64
       && !(TARGET_SPE_ABI && info->spe_64bit_regs_used)
       && info->first_gp_reg_save < 31
-      && no_global_regs_above (info->first_gp_reg_save, /*gpr=*/true))
+      && !global_regs_p (info->first_gp_reg_save, 32))
     strategy |= SAVRES_MULTIPLE;
 
   if (crtl->calls_eh_return
       || cfun->machine->ra_need_lr)
     strategy |= (SAVE_INLINE_FPRS | REST_INLINE_FPRS
-		 | SAVE_INLINE_GPRS | REST_INLINE_GPRS);
+		 | SAVE_INLINE_GPRS | REST_INLINE_GPRS
+		 | SAVE_INLINE_VRS | REST_INLINE_VRS);
 
   if (info->first_fp_reg_save == 64
       || FP_SAVE_INLINE (info->first_fp_reg_save)
       /* 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)
-      || !no_global_regs_above (info->first_fp_reg_save, /*gpr=*/false))
+      || global_regs_p (info->first_fp_reg_save, 64))
     strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS;
 
   if (info->first_gp_reg_save == 32
       || GP_SAVE_INLINE (info->first_gp_reg_save)
-      || !((strategy & SAVRES_MULTIPLE)
-	   || no_global_regs_above (info->first_gp_reg_save, /*gpr=*/true)))
+      || (!(strategy & SAVRES_MULTIPLE)
+	  && global_regs_p (info->first_gp_reg_save, 32)))
     strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
 
+  if (info->first_altivec_reg_save == LAST_ALTIVEC_REGNO + 1
+      || V_SAVE_INLINE (info->first_altivec_reg_save)
+      || global_regs_p (info->first_altivec_reg_save, LAST_ALTIVEC_REGNO + 1))
+    strategy |= SAVE_INLINE_VRS | REST_INLINE_VRS;
+
   /* Don't bother to try to save things out-of-line if r11 is occupied
      by the static chain.  It would require too much fiddling and the
      static chain is rarely used anyway.  FPRs are saved w.r.t the stack
@@ -17457,7 +17483,8 @@ rs6000_savres_strategy (rs6000_stack_t *
   if (using_static_chain_p && DEFAULT_ABI != ABI_AIX)
     strategy |= ((DEFAULT_ABI == ABI_DARWIN
 		  ? 0 : SAVE_INLINE_FPRS | REST_INLINE_FPRS)
-		 | SAVE_INLINE_GPRS);
+		 | SAVE_INLINE_GPRS
+		 | SAVE_INLINE_VRS | REST_INLINE_VRS);
 
   /* If we are going to use store multiple, then don't even bother
      with the out-of-line routines, since the store-multiple
@@ -17465,6 +17492,16 @@ rs6000_savres_strategy (rs6000_stack_t *
   if ((strategy & SAVRES_MULTIPLE))
     strategy |= SAVE_INLINE_GPRS;
 
+  /* info->lr_save_p isn't yet set if the only reason lr needs to be
+     saved is an out-of-line save or restore.  Set up the value for
+     the next test (excluding out-of-line gpr restore).  */
+  lr_save_p = (info->lr_save_p
+	       || !(strategy & SAVE_INLINE_GPRS)
+	       || !(strategy & SAVE_INLINE_FPRS)
+	       || !(strategy & SAVE_INLINE_VRS)
+	       || !(strategy & REST_INLINE_FPRS)
+	       || !(strategy & REST_INLINE_VRS));
+
   /* The situation is more complicated with load multiple.  We'd
      prefer to use the out-of-line routines for restores, since the
      "exit" out-of-line routines can handle the restore of LR and the
@@ -17474,7 +17511,7 @@ rs6000_savres_strategy (rs6000_stack_t *
      have saved some fprs; In those cases it is advantageous to use
      load multiple when available.  */
   if ((strategy & SAVRES_MULTIPLE)
-      && (!info->lr_save_p
+      && (!lr_save_p
 	  || info->first_fp_reg_save != 64))
     strategy |= REST_INLINE_GPRS;
 
@@ -17868,8 +17905,10 @@ rs6000_stack_info (void)
 
   if (!(info_ptr->savres_strategy & SAVE_INLINE_GPRS)
       || !(info_ptr->savres_strategy & SAVE_INLINE_FPRS)
+      || !(info_ptr->savres_strategy & SAVE_INLINE_VRS)
       || !(info_ptr->savres_strategy & REST_INLINE_GPRS)
-      || !(info_ptr->savres_strategy & REST_INLINE_FPRS))
+      || !(info_ptr->savres_strategy & REST_INLINE_FPRS)
+      || !(info_ptr->savres_strategy & REST_INLINE_VRS))
     info_ptr->lr_save_p = 1;
 
   if (info_ptr->lr_save_p)
@@ -18965,30 +19004,25 @@ gen_frame_mem_offset (enum machine_mode
   return gen_frame_mem (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
 }
 
-/* Look for user-defined global regs.  We should not save and restore these,
-   and cannot use stmw/lmw if there are any in its range.  */
-
-static bool
-no_global_regs_above (int first, bool gpr)
-{
-  int i;
-  int last = gpr ? 32 : 64;
-  for (i = first; i < last; i++)
-    if (global_regs[i])
-      return false;
-  return true;
-}
-
 #ifndef TARGET_FIX_AND_CONTINUE
 #define TARGET_FIX_AND_CONTINUE 0
 #endif
 
-/* It's really GPR 13 and FPR 14, but we need the smaller of the two.  */
+/* It's really GPR 13 or 14, FPR 14 and VR 20.  We need the smallest.  */
 #define FIRST_SAVRES_REGISTER FIRST_SAVED_GP_REGNO
 #define LAST_SAVRES_REGISTER 31
 #define N_SAVRES_REGISTERS (LAST_SAVRES_REGISTER - FIRST_SAVRES_REGISTER + 1)
 
-static GTY(()) rtx savres_routine_syms[N_SAVRES_REGISTERS][8];
+enum {
+  SAVRES_LR = 0x1,
+  SAVRES_SAVE = 0x2,
+  SAVRES_REG = 0x0c,
+  SAVRES_GPR = 0,
+  SAVRES_FPR = 4,
+  SAVRES_VR  = 8
+};
+
+static GTY(()) rtx savres_routine_syms[N_SAVRES_REGISTERS][12];
 
 /* Temporary holding space for an out-of-line register save/restore
    routine name.  */
@@ -18998,8 +19032,7 @@ static char savres_routine_name[30];
    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)
+rs6000_savres_routine_name (rs6000_stack_t *info, int regno, int sel)
 {
   const char *prefix = "";
   const char *suffix = "";
@@ -19035,14 +19068,14 @@ rs6000_savres_routine_name (rs6000_stack
   if (TARGET_SPE)
     {
       /* No floating point saves on the SPE.  */
-      gcc_assert (gpr);
+      gcc_assert ((sel & SAVRES_REG) == SAVRES_GPR);
 
-      if (savep)
+      if ((sel & SAVRES_SAVE))
 	prefix = info->spe_64bit_regs_used ? "_save64gpr_" : "_save32gpr_";
       else
 	prefix = info->spe_64bit_regs_used ? "_rest64gpr_" : "_rest32gpr_";
 
-      if (lr)
+      if ((sel & SAVRES_LR))
 	suffix = "_x";
     }
   else if (DEFAULT_ABI == ABI_V4)
@@ -19050,35 +19083,46 @@ rs6000_savres_routine_name (rs6000_stack
       if (TARGET_64BIT)
 	goto aix_names;
 
-      if (gpr)
-	prefix = savep ? "_savegpr_" : "_restgpr_";
+      if ((sel & SAVRES_REG) == SAVRES_GPR)
+	prefix = (sel & SAVRES_SAVE) ? "_savegpr_" : "_restgpr_";
+      else if ((sel & SAVRES_REG) == SAVRES_FPR)
+	prefix = (sel & SAVRES_SAVE) ? "_savefpr_" : "_restfpr_";
+      else if ((sel & SAVRES_REG) == SAVRES_VR)
+	prefix = (sel & SAVRES_SAVE) ? "_savevr_" : "_restvr_";
       else
-	prefix = savep ? "_savefpr_" : "_restfpr_";
+	abort ();
 
-      if (lr)
+      if ((sel & SAVRES_LR))
 	suffix = "_x";
     }
   else if (DEFAULT_ABI == ABI_AIX)
     {
 #if !defined (POWERPC_LINUX) && !defined (POWERPC_FREEBSD)
       /* No out-of-line save/restore routines for GPRs on AIX.  */
-      gcc_assert (!TARGET_AIX || !gpr);
+      gcc_assert (!TARGET_AIX || (sel & SAVRES_REG) != SAVRES_GPR);
 #endif
 
     aix_names:
-      if (gpr)
-	prefix = (savep
-		  ? (lr ? "_savegpr0_" : "_savegpr1_")
-		  : (lr ? "_restgpr0_" : "_restgpr1_"));
+      if ((sel & SAVRES_REG) == SAVRES_GPR)
+	prefix = ((sel & SAVRES_SAVE)
+		  ? ((sel & SAVRES_LR) ? "_savegpr0_" : "_savegpr1_")
+		  : ((sel & SAVRES_LR) ? "_restgpr0_" : "_restgpr1_"));
+      else if ((sel & SAVRES_REG) == SAVRES_FPR)
+	{
 #if defined (POWERPC_LINUX) || defined (POWERPC_FREEBSD)
-      else if (lr)
-	prefix = (savep ? "_savefpr_" : "_restfpr_");
+	  if ((sel & SAVRES_LR))
+	    prefix = ((sel & SAVRES_SAVE) ? "_savefpr_" : "_restfpr_");
+	  else
 #endif
-      else
-	{
-	  prefix = savep ? SAVE_FP_PREFIX : RESTORE_FP_PREFIX;
-	  suffix = savep ? SAVE_FP_SUFFIX : RESTORE_FP_SUFFIX;
+	    {
+	      prefix = (sel & SAVRES_SAVE) ? SAVE_FP_PREFIX : RESTORE_FP_PREFIX;
+	      suffix = (sel & SAVRES_SAVE) ? SAVE_FP_SUFFIX : RESTORE_FP_SUFFIX;
+	    }
 	}
+      else if ((sel & SAVRES_REG) == SAVRES_VR)
+	prefix = (sel & SAVRES_SAVE) ? "_savevr_" : "_restvr_";
+      else
+	abort ();
     }
 
    if (DEFAULT_ABI == ABI_DARWIN)
@@ -19088,14 +19132,19 @@ rs6000_savres_routine_name (rs6000_stack
 	 single symbol for the start of save sequence, and the code here
 	 embeds an offset into that code on the basis of the first register
 	 to be saved.  */
-      prefix = savep ? "save" : "rest" ;
-      if (gpr)
-	sprintf (savres_routine_name, "*%sGPR%s%s%.0d ; %s r%d-r31",
-	       prefix, (lr ? "x" : ""), (regno == 13 ? "" : "+"),
-	       (regno-13) * 4, prefix, regno);
+      prefix = (sel & SAVRES_SAVE) ? "save" : "rest" ;
+      if ((sel & SAVRES_REG) == SAVRES_GPR)
+	sprintf (savres_routine_name, "*%sGPR%s%s%.0d ; %s r%d-r31", prefix,
+		 ((sel & SAVRES_LR) ? "x" : ""), (regno == 13 ? "" : "+"),
+		 (regno - 13) * 4, prefix, regno);
+      else if ((sel & SAVRES_REG) == SAVRES_FPR)
+	sprintf (savres_routine_name, "*%sFP%s%.0d ; %s f%d-f31", prefix,
+		 (regno == 14 ? "" : "+"), (regno - 14) * 4, prefix, regno);
+      else if ((sel & SAVRES_REG) == SAVRES_VR)
+	sprintf (savres_routine_name, "*%sVEC%s%.0d ; %s v%d-v31", prefix,
+		 (regno == 20 ? "" : "+"), (regno - 20) * 8, prefix, regno);
       else
-	sprintf (savres_routine_name, "*%sFP%s%.0d ; %s f%d-f31",
-	       prefix, (regno == 14 ? "" : "+"),  (regno-14) * 4, prefix, regno);
+	abort ();
     }
   else
     sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix);
@@ -19107,22 +19156,28 @@ rs6000_savres_routine_name (rs6000_stack
    We are saving/restoring GPRs if GPR is true.  */
 
 static rtx
-rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep,
-			   bool gpr, bool lr)
+rs6000_savres_routine_sym (rs6000_stack_t *info, int sel)
 {
-  int regno = gpr ? info->first_gp_reg_save : (info->first_fp_reg_save - 32);
+  int regno = ((sel & SAVRES_REG) == SAVRES_GPR
+	       ? info->first_gp_reg_save
+	       : (sel & SAVRES_REG) == SAVRES_FPR
+	       ? info->first_fp_reg_save - 32
+	       : (sel & SAVRES_REG) == SAVRES_VR
+	       ? info->first_altivec_reg_save - FIRST_ALTIVEC_REGNO
+	       : -1);
   rtx sym;
-  int select = ((savep ? 1 : 0) << 2
-		| ((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));
+  int select = sel;
+
+  /* On the SPE, we never have any FPRs, but we do have 32/64-bit
+     versions of the gpr routines.  */
+  if (TARGET_SPE_ABI && (sel & SAVRES_REG) == SAVRES_GPR
+      && info->spe_64bit_regs_used)
+    select ^= SAVRES_FPR ^ SAVRES_GPR;
 
   /* Don't generate bogus routine names.  */
   gcc_assert (FIRST_SAVRES_REGISTER <= regno
-	      && regno <= LAST_SAVRES_REGISTER);
+	      && regno <= LAST_SAVRES_REGISTER
+	      && select >= 0 && select <= 12);
 
   sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select];
 
@@ -19130,7 +19185,7 @@ rs6000_savres_routine_sym (rs6000_stack_
     {
       char *name;
 
-      name = rs6000_savres_routine_name (info, regno, savep, gpr, lr);
+      name = rs6000_savres_routine_name (info, regno, sel);
 
       sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select]
 	= gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
@@ -19176,11 +19231,11 @@ rs6000_emit_stack_reset (rs6000_stack_t
 }
 
 static inline unsigned
-ptr_regno_for_savres (bool gpr, bool lr)
+ptr_regno_for_savres (int sel)
 {
   if (DEFAULT_ABI == ABI_AIX)
-    return !gpr || lr ? 1 : 12;
-  return DEFAULT_ABI == ABI_DARWIN && !gpr ? 1 : 11;
+    return (sel & SAVRES_REG) == SAVRES_FPR || (sel & SAVRES_LR) ? 1 : 12;
+  return DEFAULT_ABI == ABI_DARWIN && (sel & SAVRES_REG) == SAVRES_FPR ? 1 : 11;
 }
 
 /* Construct a parallel rtx describing the effect of a call to an
@@ -19190,8 +19245,7 @@ ptr_regno_for_savres (bool gpr, bool lr)
 static rtx
 rs6000_emit_savres_rtx (rs6000_stack_t *info,
 			rtx frame_reg_rtx, int save_area_offset, int lr_offset,
-			enum machine_mode reg_mode,
-			bool savep, bool gpr, bool lr)
+			enum machine_mode reg_mode, int sel)
 {
   int i;
   int offset, start_reg, end_reg, n_regs, use_reg;
@@ -19201,25 +19255,46 @@ rs6000_emit_savres_rtx (rs6000_stack_t *
   rtx par, insn;
 
   offset = 0;
-  start_reg = (gpr
+  start_reg = ((sel & SAVRES_REG) == SAVRES_GPR
 	       ? info->first_gp_reg_save
-	       : info->first_fp_reg_save);
-  end_reg = gpr ? 32 : 64;
+	       : (sel & SAVRES_REG) == SAVRES_FPR
+	       ? info->first_fp_reg_save
+	       : (sel & SAVRES_REG) == SAVRES_VR
+	       ? info->first_altivec_reg_save
+	       : -1);
+  end_reg = ((sel & SAVRES_REG) == SAVRES_GPR
+	     ? 32
+	     : (sel & SAVRES_REG) == SAVRES_FPR
+	     ? 64
+	     : (sel & SAVRES_REG) == SAVRES_VR
+	     ? LAST_ALTIVEC_REGNO + 1
+	     : -1);
   n_regs = end_reg - start_reg;
-  p = rtvec_alloc ((lr ? 4 : 3) + n_regs);
+  p = rtvec_alloc (3 + ((sel & SAVRES_LR) ? 1 : 0)
+		   + ((sel & SAVRES_REG) == SAVRES_VR ? 1 : 0)
+		   + n_regs);
 
-  if (!savep && lr)
+  if (!(sel & SAVRES_SAVE) && (sel & SAVRES_LR))
     RTVEC_ELT (p, offset++) = ret_rtx;
 
   RTVEC_ELT (p, offset++)
     = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
 
-  sym = rs6000_savres_routine_sym (info, savep, gpr, lr);
+  sym = rs6000_savres_routine_sym (info, sel);
   RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, sym);
-  use_reg = ptr_regno_for_savres (gpr, lr);
-  RTVEC_ELT (p, offset++)
-    = gen_rtx_USE (VOIDmode,
-		   gen_rtx_REG (Pmode, use_reg));
+
+  use_reg = ptr_regno_for_savres (sel);
+  if ((sel & SAVRES_REG) == SAVRES_VR)
+    {
+      /* Vector regs are saved/restored using [reg+reg] addressing.  */
+      RTVEC_ELT (p, offset++)
+	= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, use_reg));
+      RTVEC_ELT (p, offset++)
+	= gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 0));
+    }
+  else
+    RTVEC_ELT (p, offset++)
+      = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, use_reg));
 
   for (i = 0; i < end_reg - start_reg; i++)
     {
@@ -19230,11 +19305,11 @@ rs6000_emit_savres_rtx (rs6000_stack_t *
       mem = gen_frame_mem (reg_mode, addr);
 
       RTVEC_ELT (p, i + offset) = gen_rtx_SET (VOIDmode,
-					       savep ? mem : reg,
-					       savep ? reg : mem);
+					       (sel & SAVRES_SAVE) ? mem : reg,
+					       (sel & SAVRES_SAVE) ? reg : mem);
     }
 
-  if (savep && lr)
+  if ((sel & SAVRES_SAVE) && (sel & SAVRES_LR))
     {
       rtx addr, reg, mem;
       reg = gen_rtx_REG (Pmode, 0);
@@ -19246,7 +19321,7 @@ rs6000_emit_savres_rtx (rs6000_stack_t *
 
   par = gen_rtx_PARALLEL (VOIDmode, p);
 
-  if (!savep && lr)
+  if (!(sel & SAVRES_SAVE) && (sel & SAVRES_LR))
     {
       insn = emit_jump_insn (par);
       JUMP_LABEL (insn) = ret_rtx;
@@ -19291,9 +19366,6 @@ rs6000_emit_prologue (void)
   rtx cr_save_rtx = NULL_RTX;
   rtx insn;
   int strategy;
-  int saving_FPRs_inline;
-  int saving_GPRs_inline;
-  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]);
@@ -19469,9 +19541,6 @@ rs6000_emit_prologue (void)
     }
 
   strategy = info->savres_strategy;
-  using_store_multiple = strategy & SAVRES_MULTIPLE;
-  saving_FPRs_inline = strategy & SAVE_INLINE_FPRS;
-  saving_GPRs_inline = strategy & SAVE_INLINE_GPRS;
 
   /* For V.4, update stack before we do any saving and set back pointer.  */
   if (! WORLD_SAVE_P (info)
@@ -19480,18 +19549,19 @@ rs6000_emit_prologue (void)
 	  || crtl->calls_eh_return))
     {
       bool need_r11 = (TARGET_SPE
-		       ? (!saving_GPRs_inline
+		       ? (!(strategy & SAVE_INLINE_GPRS)
 			  && info->spe_64bit_regs_used == 0)
-		       : (!saving_FPRs_inline || !saving_GPRs_inline));
+		       : (!(strategy & SAVE_INLINE_FPRS)
+			  || !(strategy & SAVE_INLINE_GPRS)
+			  || !(strategy & SAVE_INLINE_VRS)));
+      int ptr_regno = -1;
       rtx ptr_reg = NULL_RTX;
+      int ptr_off = 0;
 
-      if (need_r11)
-	{
-	  ptr_reg = gen_rtx_REG (Pmode, 11);
-	  START_USE (11);
-	}
-      else if (info->total_size < 32767)
+      if (info->total_size < 32767)
 	frame_off = info->total_size;
+      else if (need_r11)
+	ptr_regno = 11;
       else if (info->cr_save_p
 	       || info->lr_save_p
 	       || info->first_fp_reg_save < 64
@@ -19499,10 +19569,7 @@ rs6000_emit_prologue (void)
 	       || info->altivec_size != 0
 	       || info->vrsave_mask != 0
 	       || crtl->calls_eh_return)
-	{
-	  ptr_reg = gen_rtx_REG (Pmode, 12);
-	  START_USE (12);
-	}
+	ptr_regno = 12;
       else
 	{
 	  /* The prologue won't be saving any regs so there is no need
@@ -19512,17 +19579,22 @@ rs6000_emit_prologue (void)
 	     changes to this function.  */
 	  frame_off = info->total_size;
 	}
-      if (ptr_reg != NULL_RTX)
+      if (ptr_regno != -1)
 	{
 	  /* Set up the frame offset to that needed by the first
 	     out-of-line save function.  */
+	  START_USE (ptr_regno);
+	  ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
 	  frame_reg_rtx = ptr_reg;
-	  if (!saving_FPRs_inline && info->first_fp_reg_save < 64)
+	  if (!(strategy & SAVE_INLINE_FPRS) && info->fp_size != 0)
 	    gcc_checking_assert (info->fp_save_offset + info->fp_size == 0);
-	  else if (!saving_GPRs_inline && info->first_gp_reg_save < 32)
-	    frame_off = -(info->gp_save_offset + info->gp_size);
+	  else if (!(strategy & SAVE_INLINE_GPRS) && info->first_gp_reg_save < 32)
+	    ptr_off = info->gp_save_offset + info->gp_size;
+	  else if (!(strategy & SAVE_INLINE_VRS) && info->altivec_size != 0)
+	    ptr_off = info->altivec_save_offset + info->altivec_size;
+	  frame_off = -ptr_off;
 	}
-      rs6000_emit_allocate_stack (info->total_size, ptr_reg, -frame_off);
+      rs6000_emit_allocate_stack (info->total_size, ptr_reg, ptr_off);
       sp_off = info->total_size;
       if (frame_reg_rtx != sp_reg_rtx)
 	rs6000_emit_stack_tie (frame_reg_rtx, false);
@@ -19584,7 +19656,7 @@ rs6000_emit_prologue (void)
 
   /* Do any required saving of fpr's.  If only one or two to save, do
      it ourselves.  Otherwise, call function.  */
-  if (!WORLD_SAVE_P (info) && saving_FPRs_inline)
+  if (!WORLD_SAVE_P (info) && (strategy & SAVE_INLINE_FPRS))
     {
       int i;
       for (i = 0; i < 64 - info->first_fp_reg_save; i++)
@@ -19600,17 +19672,24 @@ rs6000_emit_prologue (void)
   else if (!WORLD_SAVE_P (info) && info->first_fp_reg_save != 64)
     {
       bool lr = (strategy & SAVE_NOINLINE_FPRS_SAVES_LR) != 0;
-      unsigned ptr_regno = ptr_regno_for_savres (/*gpr=*/false, lr);
+      int sel = SAVRES_SAVE | SAVRES_FPR | (lr ? SAVRES_LR : 0);
+      unsigned ptr_regno = ptr_regno_for_savres (sel);
+      rtx ptr_reg = frame_reg_rtx;
 
-      gcc_checking_assert (ptr_regno == REGNO (frame_reg_rtx)
-			   && info->fp_save_offset + info->fp_size == 0
-			   && frame_off == 0);
-      insn = rs6000_emit_savres_rtx (info, frame_reg_rtx,
+      if (REGNO (frame_reg_rtx) == ptr_regno)
+	gcc_checking_assert (frame_off == 0);
+      else
+	{
+	  ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
+	  NOT_INUSE (ptr_regno);
+	  emit_insn (gen_add3_insn (ptr_reg,
+				    frame_reg_rtx, GEN_INT (frame_off)));
+	}
+      insn = rs6000_emit_savres_rtx (info, ptr_reg,
 				     info->fp_save_offset,
 				     info->lr_save_offset,
-				     DFmode,
-				     /*savep=*/true, /*gpr=*/false, lr);
-      rs6000_frame_related (insn, frame_reg_rtx, sp_off,
+				     DFmode, sel);
+      rs6000_frame_related (insn, ptr_reg, sp_off,
 			    NULL_RTX, NULL_RTX);
       if (lr)
 	END_USE (0);
@@ -19634,7 +19713,7 @@ rs6000_emit_prologue (void)
       int spe_regs_addressable
 	= (SPE_CONST_OFFSET_OK (info->spe_gp_save_offset + frame_off
 				+ reg_size * (32 - info->first_gp_reg_save - 1))
-	   && saving_GPRs_inline);
+	   && (strategy & SAVE_INLINE_GPRS));
 
       if (spe_regs_addressable)
 	{
@@ -19648,7 +19727,7 @@ rs6000_emit_prologue (void)
 	     it is, then temporarily save it in r0.  */
 	  HOST_WIDE_INT offset;
 
-	  if (!saving_GPRs_inline)
+	  if (!(strategy & SAVE_INLINE_GPRS))
 	    ool_adjust = 8 * (info->first_gp_reg_save
 			      - (FIRST_SAVRES_REGISTER + 1));
 	  offset = info->spe_gp_save_offset + frame_off - ool_adjust;
@@ -19673,7 +19752,7 @@ rs6000_emit_prologue (void)
 	    frame_off = -info->spe_gp_save_offset + ool_adjust;
 	}
 
-      if (saving_GPRs_inline)
+      if ((strategy & SAVE_INLINE_GPRS))
 	{
 	  for (i = 0; i < 32 - info->first_gp_reg_save; i++)
 	    if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
@@ -19687,10 +19766,8 @@ rs6000_emit_prologue (void)
 	{
 	  insn = rs6000_emit_savres_rtx (info, spe_save_area_ptr,
 					 info->spe_gp_save_offset + save_off,
-					 info->lr_save_offset + save_off,
-					 reg_mode,
-					 /*savep=*/true, /*gpr=*/true,
-					 /*lr=*/false);
+					 0, reg_mode,
+					 SAVRES_SAVE | SAVRES_GPR);
 
 	  rs6000_frame_related (insn, spe_save_area_ptr, sp_off - save_off,
 				NULL_RTX, NULL_RTX);
@@ -19708,10 +19785,11 @@ rs6000_emit_prologue (void)
 	    END_USE (11);
 	}
     }
-  else if (!WORLD_SAVE_P (info) && !saving_GPRs_inline)
+  else if (!WORLD_SAVE_P (info) && !(strategy & SAVE_INLINE_GPRS))
     {
       bool lr = (strategy & SAVE_NOINLINE_GPRS_SAVES_LR) != 0;
-      unsigned ptr_regno = ptr_regno_for_savres (/*gpr=*/true, lr);
+      int sel = SAVRES_SAVE | SAVRES_GPR | (lr ? SAVRES_LR : 0);
+      unsigned ptr_regno = ptr_regno_for_savres (sel);
       rtx ptr_reg = frame_reg_rtx;
       bool ptr_set_up = REGNO (ptr_reg) == ptr_regno;
       int end_save = info->gp_save_offset + info->gp_size;
@@ -19740,14 +19818,13 @@ rs6000_emit_prologue (void)
       insn = rs6000_emit_savres_rtx (info, ptr_reg,
 				     info->gp_save_offset + ptr_off,
 				     info->lr_save_offset + ptr_off,
-				     reg_mode,
-				     /*savep=*/true, /*gpr=*/true, lr);
+				     reg_mode, sel);
       rs6000_frame_related (insn, ptr_reg, sp_off - ptr_off,
 			    NULL_RTX, NULL_RTX);
       if (lr)
 	END_USE (0);
     }
-  else if (!WORLD_SAVE_P (info) && using_store_multiple)
+  else if (!WORLD_SAVE_P (info) && (strategy & SAVRES_MULTIPLE))
     {
       rtvec p;
       int i;
@@ -19907,24 +19984,31 @@ rs6000_emit_prologue (void)
       && !(DEFAULT_ABI == ABI_V4 || crtl->calls_eh_return))
     {
       rtx ptr_reg = NULL;
+      int ptr_off = 0;
 
       /* If saving altivec regs we need to be able to address all save
 	 locations using a 16-bit offset.  */
-      if ((info->altivec_size != 0
-	   && (info->altivec_save_offset + info->altivec_size - 16
-	       + info->total_size - frame_off) > 32767)
+      if ((strategy & SAVE_INLINE_VRS) == 0
+	  || (info->altivec_size != 0
+	      && (info->altivec_save_offset + info->altivec_size - 16
+		  + info->total_size - frame_off) > 32767)
 	  || (info->vrsave_mask != 0
 	      && (info->vrsave_save_offset
 		  + info->total_size - frame_off) > 32767))
 	{
-	  START_USE (12);
-	  ptr_reg = gen_rtx_REG (Pmode, 12);
+	  int sel = SAVRES_SAVE | SAVRES_VR;
+	  unsigned ptr_regno = ptr_regno_for_savres (sel);
+
+	  if (REGNO (frame_reg_rtx) != ptr_regno)
+	    START_USE (ptr_regno);
+	  ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
 	  frame_reg_rtx = ptr_reg;
-	  frame_off = -(info->altivec_save_offset + info->altivec_size);
+	  ptr_off = info->altivec_save_offset + info->altivec_size;
+	  frame_off = -ptr_off;
 	}
       else if (REGNO (frame_reg_rtx) == 1)
 	frame_off = info->total_size;
-      rs6000_emit_allocate_stack (info->total_size, ptr_reg, -frame_off);
+      rs6000_emit_allocate_stack (info->total_size, ptr_reg, ptr_off);
       sp_off = info->total_size;
       if (frame_reg_rtx != sp_reg_rtx)
 	rs6000_emit_stack_tie (frame_reg_rtx, false);
@@ -19939,13 +20023,48 @@ rs6000_emit_prologue (void)
     }
 
   /* Save AltiVec registers if needed.  Save here because the red zone does
-     not include AltiVec registers.  */
-  if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
+     not always include AltiVec registers.  */
+  if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI
+      && info->altivec_size != 0 && (strategy & SAVE_INLINE_VRS) == 0)
+    {
+      int end_save = info->altivec_save_offset + info->altivec_size;
+      int ptr_off;
+      /* Oddly, the vector save/restore functions point r0 at the end
+	 of the save area, then use r11 or r12 to load offsets for
+	 [reg+reg] addressing.  */
+      rtx ptr_reg = gen_rtx_REG (Pmode, 0);
+      int scratch_regno = ptr_regno_for_savres (SAVRES_SAVE | SAVRES_VR);
+      rtx scratch_reg = gen_rtx_REG (Pmode, scratch_regno);
+
+      gcc_checking_assert (scratch_regno == 11 || scratch_regno == 12);
+      NOT_INUSE (0);
+      if (end_save + frame_off != 0)
+	{
+	  rtx offset = GEN_INT (end_save + frame_off);
+
+	  emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx, offset));
+	}
+      else
+	emit_move_insn (ptr_reg, frame_reg_rtx);
+
+      ptr_off = -end_save;
+      insn = rs6000_emit_savres_rtx (info, scratch_reg,
+				     info->altivec_save_offset + ptr_off,
+				     0, V4SImode, SAVRES_SAVE | SAVRES_VR);
+      rs6000_frame_related (insn, scratch_reg, sp_off - ptr_off,
+			    NULL_RTX, NULL_RTX);
+      if (REGNO (frame_reg_rtx) == REGNO (scratch_reg))
+	{
+	  /* The oddity mentioned above clobbered our frame reg.  */
+	  emit_move_insn (frame_reg_rtx, ptr_reg);
+	  frame_off = ptr_off;
+	}
+    }
+  else if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI
+	   && info->altivec_size != 0)
     {
       int i;
 
-      /* There should be a non inline version of this, for when we
-	 are saving lots of vector registers.  */
       for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
 	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
 	  {
@@ -19986,12 +20105,23 @@ rs6000_emit_prologue (void)
     {
       rtx reg, mem, vrsave;
       int offset;
+      int save_regno;
 
       /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
 	 as frame_reg_rtx and r11 as the static chain pointer for
 	 nested functions.  */
-      NOT_INUSE (0);
-      reg = gen_rtx_REG (SImode, 0);
+      save_regno = 12;
+      if (DEFAULT_ABI == ABI_AIX && !using_static_chain_p)
+	save_regno = 11;
+      else if (REGNO (frame_reg_rtx) == 12)
+	{
+	  save_regno = 11;
+	  if (using_static_chain_p)
+	    save_regno = 0;
+	}
+
+      NOT_INUSE (save_regno);
+      reg = gen_rtx_REG (SImode, save_regno);
       vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
       if (TARGET_MACHO)
 	emit_insn (gen_get_vrsave_internal (reg));
@@ -20104,21 +20234,25 @@ rs6000_output_function_prologue (FILE *f
   /* Write .extern for any function we will call to save and restore
      fp values.  */
   if (info->first_fp_reg_save < 64
-      && !TARGET_MACHO)
+      && !TARGET_MACHO
+      && !TARGET_ELF)
     {
       char *name;
       int regno = info->first_fp_reg_save - 32;
 
       if ((info->savres_strategy & SAVE_INLINE_FPRS) == 0)
 	{
-	  name = rs6000_savres_routine_name (info, regno, /*savep=*/true,
-					     /*gpr=*/false, /*lr=*/false);
+	  bool lr = (info->savres_strategy & SAVE_NOINLINE_FPRS_SAVES_LR) != 0;
+	  int sel = SAVRES_SAVE | SAVRES_FPR | (lr ? SAVRES_LR : 0);
+	  name = rs6000_savres_routine_name (info, regno, sel);
 	  fprintf (file, "\t.extern %s\n", name);
 	}
       if ((info->savres_strategy & REST_INLINE_FPRS) == 0)
 	{
-	  name = rs6000_savres_routine_name (info, regno, /*savep=*/false,
-					     /*gpr=*/false, /*lr=*/true);
+	  bool lr = (info->savres_strategy
+		     & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0;
+	  int sel = SAVRES_FPR | (lr ? SAVRES_LR : 0);
+	  name = rs6000_savres_routine_name (info, regno, sel);
 	  fprintf (file, "\t.extern %s\n", name);
 	}
     }
@@ -20397,10 +20531,20 @@ rs6000_emit_epilogue (int sibcall)
 	      && offset_below_red_zone_p (info->altivec_save_offset))))
     {
       int i;
+      int scratch_regno = ptr_regno_for_savres (SAVRES_VR);
 
+      gcc_checking_assert (scratch_regno == 11 || scratch_regno == 12);
       if (use_backchain_to_restore_sp)
 	{
-	  frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+	  int frame_regno = 11;
+
+	  if ((strategy & SAVE_INLINE_VRS) == 0)
+	    {
+	      /* Of r11 and r12, select the one not clobbered by an
+		 out-of-line restore function for the frame register.  */
+	      frame_regno = 11 + 12 - scratch_regno;
+	    }
+	  frame_reg_rtx = gen_rtx_REG (Pmode, frame_regno);
 	  emit_move_insn (frame_reg_rtx,
 			  gen_rtx_MEM (Pmode, sp_reg_rtx));
 	  frame_off = 0;
@@ -20408,29 +20552,59 @@ rs6000_emit_epilogue (int sibcall)
       else if (frame_pointer_needed)
 	frame_reg_rtx = hard_frame_pointer_rtx;
 
-      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
-	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
-	  {
-	    rtx addr, areg, mem, reg;
+      if ((strategy & SAVE_INLINE_VRS) == 0)
+	{
+	  int end_save = info->altivec_save_offset + info->altivec_size;
+	  int ptr_off;
+	  rtx ptr_reg = gen_rtx_REG (Pmode, 0);
+	  rtx scratch_reg = gen_rtx_REG (Pmode, scratch_regno);
 
-	    areg = gen_rtx_REG (Pmode, 0);
-	    emit_move_insn
-	      (areg, GEN_INT (info->altivec_save_offset
-			      + frame_off
-			      + 16 * (i - info->first_altivec_reg_save)));
+	  if (end_save + frame_off != 0)
+	    {
+	      rtx offset = GEN_INT (end_save + frame_off);
 
-	    /* AltiVec addressing mode is [reg+reg].  */
-	    addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
-	    mem = gen_frame_mem (V4SImode, addr);
+	      emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx, offset));
+	    }
+	  else
+	    emit_move_insn (ptr_reg, frame_reg_rtx);
 
-	    reg = gen_rtx_REG (V4SImode, i);
-	    emit_move_insn (reg, mem);
-	    if (flag_shrink_wrap
-		|| offset_below_red_zone_p (info->altivec_save_offset
-					    + (i - info->first_altivec_reg_save)
-					    * 16))
-	      cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
-					     cfa_restores);
+	  ptr_off = -end_save;
+	  insn = rs6000_emit_savres_rtx (info, scratch_reg,
+					 info->altivec_save_offset + ptr_off,
+					 0, V4SImode, SAVRES_VR);
+	}
+      else
+	{
+	  for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+	    if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
+	      {
+		rtx addr, areg, mem, reg;
+
+		areg = gen_rtx_REG (Pmode, 0);
+		emit_move_insn
+		  (areg, GEN_INT (info->altivec_save_offset
+				  + frame_off
+				  + 16 * (i - info->first_altivec_reg_save)));
+
+		/* AltiVec addressing mode is [reg+reg].  */
+		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+		mem = gen_frame_mem (V4SImode, addr);
+
+		reg = gen_rtx_REG (V4SImode, i);
+		emit_move_insn (reg, mem);
+	      }
+	}
+
+      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+	if (((strategy & SAVE_INLINE_VRS) == 0
+	     || (info->vrsave_mask & ALTIVEC_REG_BIT (i)) != 0)
+	    && (flag_shrink_wrap
+		|| (offset_below_red_zone_p
+		    (info->altivec_save_offset
+		     + 16 * (i - info->first_altivec_reg_save)))))
+	  {
+	    rtx reg = gen_rtx_REG (V4SImode, i);
+	    cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
 	  }
     }
 
@@ -20540,26 +20714,94 @@ rs6000_emit_epilogue (int sibcall)
     {
       int i;
 
-      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
-	if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
-	  {
-	    rtx addr, areg, mem, reg;
+      if ((strategy & SAVE_INLINE_VRS) == 0)
+	{
+	  int end_save = info->altivec_save_offset + info->altivec_size;
+	  int ptr_off;
+	  rtx ptr_reg = gen_rtx_REG (Pmode, 0);
+	  int scratch_regno = ptr_regno_for_savres (SAVRES_VR);
+	  rtx scratch_reg = gen_rtx_REG (Pmode, scratch_regno);
 
-	    areg = gen_rtx_REG (Pmode, 0);
-	    emit_move_insn
-	      (areg, GEN_INT (info->altivec_save_offset
-			      + frame_off
-			      + 16 * (i - info->first_altivec_reg_save)));
+	  if (end_save + frame_off != 0)
+	    {
+	      rtx offset = GEN_INT (end_save + frame_off);
 
-	    /* AltiVec addressing mode is [reg+reg].  */
-	    addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
-	    mem = gen_frame_mem (V4SImode, addr);
+	      emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx, offset));
+	    }
+	  else
+	    emit_move_insn (ptr_reg, frame_reg_rtx);
 
-	    reg = gen_rtx_REG (V4SImode, i);
-	    emit_move_insn (reg, mem);
-	    if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
-	      cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
-					     cfa_restores);
+	  ptr_off = -end_save;
+	  insn = rs6000_emit_savres_rtx (info, scratch_reg,
+					 info->altivec_save_offset + ptr_off,
+					 0, V4SImode, SAVRES_VR);
+	  if (REGNO (frame_reg_rtx) == REGNO (scratch_reg))
+	    {
+	      /* Frame reg was clobbered by out-of-line save.  Restore it
+		 from ptr_reg, and if we are calling out-of-line gpr or
+		 fpr restore set up the correct pointer and offset.  */
+	      unsigned newptr_regno = 1;
+	      if (!restoring_GPRs_inline)
+		{
+		  bool lr = info->gp_save_offset + info->gp_size == 0;
+		  int sel = SAVRES_GPR | (lr ? SAVRES_LR : 0);
+		  newptr_regno = ptr_regno_for_savres (sel);
+		  end_save = info->gp_save_offset + info->gp_size;
+		}
+	      else if (!restoring_FPRs_inline)
+		{
+		  bool lr = !(strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR);
+		  int sel = SAVRES_FPR | (lr ? SAVRES_LR : 0);
+		  newptr_regno = ptr_regno_for_savres (sel);
+		  end_save = info->gp_save_offset + info->gp_size;
+		}
+
+	      if (newptr_regno != 1 && REGNO (frame_reg_rtx) != newptr_regno)
+		frame_reg_rtx = gen_rtx_REG (Pmode, newptr_regno);
+		
+	      if (end_save + ptr_off != 0)
+		{
+		  rtx offset = GEN_INT (end_save + ptr_off);
+
+		  frame_off = -end_save;
+		  emit_insn (gen_add3_insn (frame_reg_rtx, ptr_reg, offset));
+		}
+	      else
+		{
+		  frame_off = ptr_off;
+		  emit_move_insn (frame_reg_rtx, ptr_reg);
+		}
+	    }
+	}
+      else
+	{
+	  for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+	    if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
+	      {
+		rtx addr, areg, mem, reg;
+
+		areg = gen_rtx_REG (Pmode, 0);
+		emit_move_insn
+		  (areg, GEN_INT (info->altivec_save_offset
+				  + frame_off
+				  + 16 * (i - info->first_altivec_reg_save)));
+
+		/* AltiVec addressing mode is [reg+reg].  */
+		addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+		mem = gen_frame_mem (V4SImode, addr);
+
+		reg = gen_rtx_REG (V4SImode, i);
+		emit_move_insn (reg, mem);
+	      }
+	}
+
+      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+	if (((strategy & SAVE_INLINE_VRS) == 0
+	     || (info->vrsave_mask & ALTIVEC_REG_BIT (i)) != 0)
+	    && (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap))
+	  {
+	    rtx reg = gen_rtx_REG (V4SImode, i);
+	    cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
 	  }
     }
 
@@ -20598,12 +20840,24 @@ rs6000_emit_epilogue (int sibcall)
       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
 			       GEN_INT (info->cr_save_offset + frame_off));
       rtx mem = gen_frame_mem (SImode, addr);
+      unsigned cr_save_regno = 12;
+
+      if (!restoring_GPRs_inline)
+	{
+	  /* Ensure we don't use the register used by the out-of-line
+	     gpr register restore below.  */
+	  bool lr = info->gp_save_offset + info->gp_size == 0;
+	  int sel = SAVRES_GPR | (lr ? SAVRES_LR : 0);
+	  int gpr_ptr_regno = ptr_regno_for_savres (sel);
+
+	  if (gpr_ptr_regno == 12)
+	    cr_save_regno = 11;
+	  gcc_checking_assert (REGNO (frame_reg_rtx) != cr_save_regno);
+	}
+      else if (REGNO (frame_reg_rtx) == 12)
+	cr_save_regno = 11;
 
-      cr_save_reg = gen_rtx_REG (SImode,
-				 DEFAULT_ABI == ABI_AIX
-				 && !restoring_GPRs_inline
-				 && info->first_fp_reg_save < 64
-				 ? 11 : 12);
+      cr_save_reg = gen_rtx_REG (SImode, cr_save_regno);
       emit_move_insn (cr_save_reg, mem);
     }
 
@@ -20704,8 +20958,7 @@ rs6000_emit_epilogue (int sibcall)
 				info->spe_gp_save_offset + frame_off,
 				info->lr_save_offset + frame_off,
 				reg_mode,
-				/*savep=*/false, /*gpr=*/true,
-				/*lr=*/true);
+				SAVRES_GPR | SAVRES_LR);
     }
   else if (!restoring_GPRs_inline)
     {
@@ -20713,16 +20966,19 @@ rs6000_emit_epilogue (int sibcall)
       rtx ptr_reg;
       int end_save = info->gp_save_offset + info->gp_size;
       bool can_use_exit = end_save == 0;
+      int sel = SAVRES_GPR | (can_use_exit ? SAVRES_LR : 0);
       int ptr_off;
 
       /* Emit stack reset code if we need it.  */
-      ptr_regno = ptr_regno_for_savres (/*gpr=*/true, can_use_exit);
+      ptr_regno = ptr_regno_for_savres (sel);
       ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
       if (can_use_exit)
 	rs6000_emit_stack_reset (info, frame_reg_rtx, frame_off, ptr_regno);
-      else
+      else if (end_save + frame_off != 0)
 	emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx,
 				  GEN_INT (end_save + frame_off)));
+      else if (REGNO (frame_reg_rtx) != ptr_regno)
+	emit_move_insn (ptr_reg, frame_reg_rtx);
       if (REGNO (frame_reg_rtx) == ptr_regno)
 	frame_off = -end_save;
 
@@ -20733,9 +20989,7 @@ rs6000_emit_epilogue (int sibcall)
       rs6000_emit_savres_rtx (info, ptr_reg,
 			      info->gp_save_offset + ptr_off,
 			      info->lr_save_offset + ptr_off,
-			      reg_mode,
-			      /*savep=*/false, /*gpr=*/true,
-			      /*lr=*/can_use_exit);
+			      reg_mode, sel);
     }
   else if (using_load_multiple)
     {
@@ -20872,7 +21126,8 @@ rs6000_emit_epilogue (int sibcall)
   if (!restoring_FPRs_inline)
     {
       bool lr = (strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0;
-      ptr_regno = ptr_regno_for_savres (/*gpr=*/false, lr);
+      int sel = SAVRES_FPR | (lr ? SAVRES_LR : 0);
+      ptr_regno = ptr_regno_for_savres (sel);
     }
 
   insn = rs6000_emit_stack_reset (info, frame_reg_rtx, frame_off, ptr_regno);
@@ -20950,9 +21205,7 @@ rs6000_emit_epilogue (int sibcall)
 					   cfa_restores);
 
 	  sym = rs6000_savres_routine_sym (info,
-					   /*savep=*/false,
-					   /*gpr=*/false,
-					   /*lr=*/lr);
+					   SAVRES_FPR | (lr ? SAVRES_LR : 0));
 	  RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode, sym);
 	  RTVEC_ELT (p, 3) = gen_rtx_USE (VOIDmode,
 					  gen_rtx_REG (Pmode,
diff -urpN gcc-alan5/gcc/config/rs6000/rs6000.h gcc-alan6/gcc/config/rs6000/rs6000.h
--- gcc-alan5/gcc/config/rs6000/rs6000.h	2012-04-18 14:02:34.816129379 +0930
+++ gcc-alan6/gcc/config/rs6000/rs6000.h	2012-04-20 12:56:24.208754281 +0930
@@ -909,8 +909,8 @@ extern unsigned rs6000_pointer_size;
 #define TOTAL_ALTIVEC_REGS	(LAST_ALTIVEC_REGNO - FIRST_ALTIVEC_REGNO + 1)
 
 #define FIRST_SAVED_ALTIVEC_REGNO (FIRST_ALTIVEC_REGNO+20)
-#define FIRST_SAVED_FP_REGNO    (14+32)
-#define FIRST_SAVED_GP_REGNO 13
+#define FIRST_SAVED_FP_REGNO	  (14+32)
+#define FIRST_SAVED_GP_REGNO	  (FIXED_R13 ? 14 : 13)
 
 /* List the order in which to allocate registers.  Each register must be
    listed once, even those in FIXED_REGISTERS.
diff -urpN gcc-alan5/gcc/config/rs6000/sysv4.h gcc-alan6/gcc/config/rs6000/sysv4.h
--- gcc-alan5/gcc/config/rs6000/sysv4.h	2012-04-18 14:02:34.864127368 +0930
+++ gcc-alan6/gcc/config/rs6000/sysv4.h	2012-04-20 12:56:24.076759807 +0930
@@ -245,13 +245,16 @@ do {									\
 
 /* Define cutoff for using external functions to save floating point.
    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)
+#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) == 62			\
+				   || (FIRST_REG) == 63			\
+				   || !optimize_size)
+
 /* And similarly for general purpose registers.  */
-#define GP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 32	\
-				   && !optimize_size)
+#define GP_SAVE_INLINE(FIRST_REG) (!optimize_size)
+
+/* And vector registers.  */
+#define V_SAVE_INLINE(FIRST_REG) ((FIRST_REG) == LAST_ALTIVEC_REGNO	\
+				  || !optimize_size)
 
 /* Put jump tables in read-only memory, rather than in .text.  */
 #define JUMP_TABLES_IN_TEXT_SECTION 0
diff -urpN gcc-alan5/gcc/config/rs6000/altivec.md gcc-alan6/gcc/config/rs6000/altivec.md
--- gcc-alan5/gcc/config/rs6000/altivec.md	2012-04-18 01:13:00.597291534 +0930
+++ gcc-alan6/gcc/config/rs6000/altivec.md	2012-04-20 13:06:23.379624233 +0930
@@ -313,6 +313,68 @@
  "TARGET_MACHO && (DEFAULT_ABI == ABI_DARWIN) && TARGET_32BIT"
  "b %z1")
 
+;; The save_vregs and restore_vregs patterns don't use memory_operand
+;; because (plus (reg) (const_int)) is not a valid vector address.
+;; This way is more compact than describing exactly what happens in
+;; the out-of-line functions, ie. loading the constant into r11/r12
+;; then using indexed addressing, and requires less editing of rtl
+;; to describe the operation to dwarf2out_frame_debug_expr.
+(define_insn "*save_vregs_<mode>_r11"
+  [(match_parallel 0 "any_parallel_operand"
+     [(clobber (reg:P 65))
+      (use (match_operand:P 1 "symbol_ref_operand" "s"))
+      (clobber (reg:P 11))
+      (use (reg:P 0))
+      (set (mem:V4SI (plus:P (match_operand:P 2 "gpc_reg_operand" "b")
+			     (match_operand:P 3 "short_cint_operand" "I")))
+	   (match_operand:V4SI 4 "gpc_reg_operand" "v"))])]
+  ""
+  "bl %1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*save_vregs_<mode>_r12"
+  [(match_parallel 0 "any_parallel_operand"
+     [(clobber (reg:P 65))
+      (use (match_operand:P 1 "symbol_ref_operand" "s"))
+      (clobber (reg:P 12))
+      (use (reg:P 0))
+      (set (mem:V4SI (plus:P (match_operand:P 2 "gpc_reg_operand" "b")
+			     (match_operand:P 3 "short_cint_operand" "I")))
+	   (match_operand:V4SI 4 "gpc_reg_operand" "v"))])]
+  ""
+  "bl %1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*restore_vregs_<mode>_r11"
+  [(match_parallel 0 "any_parallel_operand"
+     [(clobber (reg:P 65))
+      (use (match_operand:P 1 "symbol_ref_operand" "s"))
+      (clobber (reg:P 11))
+      (use (reg:P 0))
+      (set (match_operand:V4SI 2 "gpc_reg_operand" "=v")
+	   (mem:V4SI (plus:P (match_operand:P 3 "gpc_reg_operand" "b")
+			     (match_operand:P 4 "short_cint_operand" "I"))))])]
+  ""
+  "bl %1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*restore_vregs_<mode>_r12"
+  [(match_parallel 0 "any_parallel_operand"
+     [(clobber (reg:P 65))
+      (use (match_operand:P 1 "symbol_ref_operand" "s"))
+      (clobber (reg:P 12))
+      (use (reg:P 0))
+      (set (match_operand:V4SI 2 "gpc_reg_operand" "=v")
+	   (mem:V4SI (plus:P (match_operand:P 3 "gpc_reg_operand" "b")
+			     (match_operand:P 4 "short_cint_operand" "I"))))])]
+  ""
+  "bl %1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
 ;; Simple binary operations.
 
 ;; add
diff -urpN gcc-alan5/libgcc/config/rs6000/crtrestvr.S gcc-alan6/libgcc/config/rs6000/crtrestvr.S
--- gcc-alan5/libgcc/config/rs6000/crtrestvr.S	1970-01-01 09:30:00.000000000 +0930
+++ gcc-alan6/libgcc/config/rs6000/crtrestvr.S	2012-04-20 13:09:59.642535365 +0930
@@ -0,0 +1,88 @@
+/* Routines for restoring vector registers.
+
+   Copyright (C) 2012
+   Free Software Foundation, Inc.
+   Written by Alan Modra, IBM
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* On PowerPC64 Linux, these functions are provided by the linker.  */
+#ifndef __powerpc64__
+
+#undef __ALTIVEC__
+#define __ALTIVEC__ 1
+	#include "ppc-asm.h"
+
+/* Called with r0 pointing just beyond the end of the vector save area.  */
+
+	.section ".text"
+CFI_STARTPROC
+HIDDEN_FUNC(_restvr_20)
+	li r11,-192
+	lvx v20,r11,r0
+HIDDEN_FUNC(_restvr_21)
+	li r11,-176
+	lvx v21,r11,r0
+HIDDEN_FUNC(_restvr_22)
+	li r11,-160
+	lvx v22,r11,r0
+HIDDEN_FUNC(_restvr_23)
+	li r11,-144
+	lvx v23,r11,r0
+HIDDEN_FUNC(_restvr_24)
+	li r11,-128
+	lvx v24,r11,r0
+HIDDEN_FUNC(_restvr_25)
+	li r11,-112
+	lvx v25,r11,r0
+HIDDEN_FUNC(_restvr_26)
+	li r11,-96
+	lvx v26,r11,r0
+HIDDEN_FUNC(_restvr_27)
+	li r11,-80
+	lvx v27,r11,r0
+HIDDEN_FUNC(_restvr_28)
+	li r11,-64
+	lvx v28,r11,r0
+HIDDEN_FUNC(_restvr_29)
+	li r11,-48
+	lvx v29,r11,r0
+HIDDEN_FUNC(_restvr_30)
+	li r11,-32
+	lvx v30,r11,r0
+HIDDEN_FUNC(_restvr_31)
+	li r11,-16
+	lvx v31,r11,r0
+	blr
+FUNC_END(_restvr_31)
+FUNC_END(_restvr_30)
+FUNC_END(_restvr_29)
+FUNC_END(_restvr_28)
+FUNC_END(_restvr_27)
+FUNC_END(_restvr_26)
+FUNC_END(_restvr_25)
+FUNC_END(_restvr_24)
+FUNC_END(_restvr_23)
+FUNC_END(_restvr_22)
+FUNC_END(_restvr_21)
+FUNC_END(_restvr_20)
+CFI_ENDPROC
+
+#endif
diff -urpN gcc-alan5/libgcc/config/rs6000/crtsavevr.S gcc-alan6/libgcc/config/rs6000/crtsavevr.S
--- gcc-alan5/libgcc/config/rs6000/crtsavevr.S	1970-01-01 09:30:00.000000000 +0930
+++ gcc-alan6/libgcc/config/rs6000/crtsavevr.S	2012-04-20 13:09:59.702532848 +0930
@@ -0,0 +1,88 @@
+/* Routines for saving vector registers.
+
+   Copyright (C) 2012
+   Free Software Foundation, Inc.
+   Written by Alan Modra, IBM
+
+   This file is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 3, or (at your option) any
+   later version.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* On PowerPC64 Linux, these functions are provided by the linker.  */
+#ifndef __powerpc64__
+
+#undef __ALTIVEC__
+#define __ALTIVEC__ 1
+	#include "ppc-asm.h"
+
+/* Called with r0 pointing just beyond the end of the vector save area.  */
+
+	.section ".text"
+CFI_STARTPROC
+HIDDEN_FUNC(_savevr_20)
+	li r11,-192
+	stvx v20,r11,r0
+HIDDEN_FUNC(_savevr_21)
+	li r11,-176
+	stvx v21,r11,r0
+HIDDEN_FUNC(_savevr_22)
+	li r11,-160
+	stvx v22,r11,r0
+HIDDEN_FUNC(_savevr_23)
+	li r11,-144
+	stvx v23,r11,r0
+HIDDEN_FUNC(_savevr_24)
+	li r11,-128
+	stvx v24,r11,r0
+HIDDEN_FUNC(_savevr_25)
+	li r11,-112
+	stvx v25,r11,r0
+HIDDEN_FUNC(_savevr_26)
+	li r11,-96
+	stvx v26,r11,r0
+HIDDEN_FUNC(_savevr_27)
+	li r11,-80
+	stvx v27,r11,r0
+HIDDEN_FUNC(_savevr_28)
+	li r11,-64
+	stvx v28,r11,r0
+HIDDEN_FUNC(_savevr_29)
+	li r11,-48
+	stvx v29,r11,r0
+HIDDEN_FUNC(_savevr_30)
+	li r11,-32
+	stvx v30,r11,r0
+HIDDEN_FUNC(_savevr_31)
+	li r11,-16
+	stvx v31,r11,r0
+	blr
+FUNC_END(_savevr_31)
+FUNC_END(_savevr_30)
+FUNC_END(_savevr_29)
+FUNC_END(_savevr_28)
+FUNC_END(_savevr_27)
+FUNC_END(_savevr_26)
+FUNC_END(_savevr_25)
+FUNC_END(_savevr_24)
+FUNC_END(_savevr_23)
+FUNC_END(_savevr_22)
+FUNC_END(_savevr_21)
+FUNC_END(_savevr_20)
+CFI_ENDPROC
+
+#endif
diff -urpN gcc-alan5/libgcc/config/rs6000/t-netbsd gcc-alan6/libgcc/config/rs6000/t-netbsd
--- gcc-alan5/libgcc/config/rs6000/t-netbsd	2011-11-03 12:52:56.000000000 +1030
+++ gcc-alan6/libgcc/config/rs6000/t-netbsd	2012-04-20 10:00:45.181520105 +0930
@@ -6,4 +6,6 @@ LIB2ADD_ST = \
 	$(srcdir)/config/rs6000/crtsavgpr.S \
 	$(srcdir)/config/rs6000/crtresgpr.S \
 	$(srcdir)/config/rs6000/crtresxfpr.S \
-	$(srcdir)/config/rs6000/crtresxgpr.S
+	$(srcdir)/config/rs6000/crtresxgpr.S \
+	$(srcdir)/config/rs6000/crtsavevr.S \
+	$(srcdir)/config/rs6000/crtrestvr.S
diff -urpN gcc-alan5/libgcc/config/rs6000/t-savresfgpr gcc-alan6/libgcc/config/rs6000/t-savresfgpr
--- gcc-alan5/libgcc/config/rs6000/t-savresfgpr	2011-11-30 11:11:42.000000000 +1030
+++ gcc-alan6/libgcc/config/rs6000/t-savresfgpr	2012-04-20 10:00:48.741366921 +0930
@@ -6,6 +6,8 @@ LIB2ADD_ST += \
 	   $(srcdir)/config/rs6000/crtresgpr.S \
 	   $(srcdir)/config/rs6000/crtresxfpr.S \
 	   $(srcdir)/config/rs6000/crtresxgpr.S \
+	   $(srcdir)/config/rs6000/crtsavevr.S \
+	   $(srcdir)/config/rs6000/crtrestvr.S \
 	   $(srcdir)/config/rs6000/e500crtres32gpr.S \
 	   $(srcdir)/config/rs6000/e500crtres64gpr.S \
 	   $(srcdir)/config/rs6000/e500crtres64gprctr.S \

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2012-05-31 17:18 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-29 19:26 PowerPC prologue and epilogue 6 Dominique Dhumieres
2012-05-30 11:42 ` Alan Modra
2012-05-30 13:22   ` Dominique Dhumieres
2012-05-31  0:13     ` Alan Modra
2012-05-31  1:11       ` Alan Modra
2012-05-31  8:39         ` Alan Modra
2012-05-31 12:16           ` Dominique Dhumieres
2012-05-31 13:26             ` Alan Modra
2012-05-31 13:42               ` Dominique Dhumieres
2012-05-31 17:18                 ` Mike Stump
  -- strict thread matches above, loose matches on Subject: below --
2012-04-17 15:08 PowerPC prologue and epilogue Alan Modra
2012-04-21  6:49 ` PowerPC prologue and epilogue 6 Alan Modra
2012-04-24 23:19   ` David Edelsohn
2012-04-25  5:21     ` Alan Modra
2012-04-25 12:53       ` David Edelsohn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).