Patchwork Add attribute((target("..."))) and pragma target to PowerPC

login
register
mail settings
Submitter Michael Meissner
Date Nov. 1, 2010, 11:15 p.m.
Message ID <20101101231522.GA22461@hungry-tiger.westford.ibm.com>
Download mbox | patch
Permalink /patch/69854/
State New
Headers show

Comments

Michael Meissner - Nov. 1, 2010, 11:15 p.m.
On Mon, Nov 01, 2010 at 01:49:06PM -0400, Michael Meissner wrote:
> The simplest way to fix this is to require the user on 32-bit to use an
> explicit -maltivec-abi switch if they want to switch to a power7 cpu or enable
> altivec (similarly for the rs6000_spe_abi, rs6000_float_gprs, and
> rs6000_darwin64_abi variables).

Whoops, that should be -mabi=altivec.

The following patch applied on top of my previous patch, will give an error if
any option changes the various abi's.  It also changes the debug information
somewhat.  Does this answer your objection?

[gcc]
2010-11-01  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* config/rs6000/rs6000.c (rs6000_debug_reg_global): Add more
	debugging information for -mdebug=reg (cpu, tuning, the status of
	various abis, tls size, and long double size).
	(rs6000_init_hard_regno_mode_ok): Only print debug information for
	-mdebug=reg for the global initialization, not for target
	attributes, unless -mdebug=target is used.
	(rs6000_option_override_internal): Update rs6000_cpu_index and
	rs6000_tune_index when default choices are made.  If a target
	attribute changes the cpu, but does not change the tuning, use the
	cpu specified instead of the default specified on the command
	line.  Silently disable power7 generating vsx/altivec by default
	if 32-bit and -maltivec-abi was not used.  Given an error if a
	target attribute changes an option that would involve changing the
	abi, such as Altivec, SPE, darwin64, etc.
	(rs6000_conditional_register_usage): Just print trace if
	-mdebug=target, not -mdebug=reg.
	(rs6000_valid_attribute_p): Reset default cpu/tune before parsing
	target attributes/pragmas.
	(rs6000_pragma_target_parse): Ditto.

	* doc/extend.texi (Function Attributes): Describe restriction on
	not using Altivec/VSX if altivec abi was not enabled.  Describe
	using the cpu= attribute/pragma default for tuning if tune=
	attribute/pragma was not specified.

[gcc/testsuite]
2010-11-01  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* gcc.target/powerpc/ppc-target-1.c: Add -mabi=altivec to compile
	switches.
	* gcc.target/powerpc/ppc-target-2.c: Ditto.

	* gcc.target/powerpc/ppc-target-3.c: New test, test that target
	attribute cpu=power7 does not enable VSX, Altivec on 32-bit
	without -mabi=altivec.
Joseph S. Myers - Nov. 1, 2010, 11:52 p.m.
On Mon, 1 Nov 2010, Michael Meissner wrote:

> On Mon, Nov 01, 2010 at 01:49:06PM -0400, Michael Meissner wrote:
> > The simplest way to fix this is to require the user on 32-bit to use an
> > explicit -maltivec-abi switch if they want to switch to a power7 cpu or enable
> > altivec (similarly for the rs6000_spe_abi, rs6000_float_gprs, and
> > rs6000_darwin64_abi variables).
> 
> Whoops, that should be -mabi=altivec.
> 
> The following patch applied on top of my previous patch, will give an error if
> any option changes the various abi's.  It also changes the debug information
> somewhat.  Does this answer your objection?

It looks like it.  Note that there are problems with diagnostic 
formatting:

> +	error ("You cannot change long double size within a target attribute "
> +	       "or pragma");

Diagnostics should not start with a capital letter, and "You cannot" is 
not the normal style; I'd think the message should be something like

  error ("target attribute or pragma changes long double size");

or use sorry () if you think the feature should be supported (that's more 
likely with the AltiVec ABI, though maybe that should be a separate 
attribute instead) and the lack of support is a limitation of the 
implementation.

> +	error ("You cannot switch to the altivec abi within a target "

"AltiVec" and "ABI".  Likewise elsewhere.

Patch

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 166106)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -2014,16 +2014,25 @@  rs6000_debug_reg_print (int first_regno,
     }
 }
 
+#define DEBUG_FMT_D "%-32s= %d\n"
+#define DEBUG_FMT_S "%-32s= %s\n"
+
 /* Print various interesting information with -mdebug=reg.  */
 static void
 rs6000_debug_reg_global (void)
 {
+  static const char *const tf[2] = { "false", "true" };
   const char *nl = (const char *)0;
   int m;
   char costly_num[20];
   char nop_num[20];
   const char *costly_str;
   const char *nop_str;
+  const char *trace_str;
+  const char *cmodel_str;
 
   /* Map enum rs6000_vector to string.  */
   static const char *rs6000_debug_vector_unit[] = {
@@ -2103,6 +2110,14 @@  rs6000_debug_reg_global (void)
       fputs ("\n", stderr);
     }
 
+  if (rs6000_cpu_index >= 0)
+    fprintf (stderr, DEBUG_FMT_S, "cpu",
+	     processor_target_table[rs6000_cpu_index].name);
+
+  if (rs6000_tune_index >= 0)
+    fprintf (stderr, DEBUG_FMT_S, "tune",
+	     processor_target_table[rs6000_tune_index].name);
+
   switch (rs6000_sched_costly_dep)
     {
     case max_dep_latency:
@@ -2131,6 +2146,8 @@  rs6000_debug_reg_global (void)
       break;
     }
 
+  fprintf (stderr, DEBUG_FMT_S, "sched_costly_dep", costly_str);
+
   switch (rs6000_sched_insert_nops)
     {
     case sched_finish_regroup_exact:
@@ -2151,21 +2168,83 @@  rs6000_debug_reg_global (void)
       break;
     }
 
-  fprintf (stderr,
-	   "always_hint                     = %s\n"
-	   "align_branch_targets            = %s\n"
-	   "sched_restricted_insns_priority = %d\n"
-	   "sched_costly_dep                = %s\n"
-	   "sched_insert_nops               = %s\n\n",
-	   rs6000_always_hint ? "true" : "false",
-	   rs6000_align_branch_targets ? "true" : "false",
-	   (int)rs6000_sched_restricted_insns_priority,
-	   costly_str, nop_str);
+  fprintf (stderr, DEBUG_FMT_S, "sched_insert_nops", nop_str);
+
+  switch (rs6000_sdata)
+    {
+    default:
+    case SDATA_NONE:
+      break;
+
+    case SDATA_DATA:
+      fprintf (stderr, DEBUG_FMT_S, "sdata", "data");
+      break;
+
+    case SDATA_SYSV:
+      fprintf (stderr, DEBUG_FMT_S, "sdata", "sysv");
+      break;
+
+    case SDATA_EABI:
+      fprintf (stderr, DEBUG_FMT_S, "sdata", "eabi");
+      break;
+
+    }
+
+  switch (rs6000_traceback)
+    {
+    case traceback_default:	trace_str = "default";	break;
+    case traceback_none:	trace_str = "none";	break;
+    case traceback_part:	trace_str = "part";	break;
+    case traceback_full:	trace_str = "full";	break;
+    default:			trace_str = "unknown";	break;
+    }
+
+  fprintf (stderr, DEBUG_FMT_S, "traceback", trace_str);
+
+  switch (rs6000_current_cmodel)
+    {
+    case CMODEL_SMALL:	cmodel_str = "small";	break;
+    case CMODEL_MEDIUM:	cmodel_str = "medium";	break;
+    case CMODEL_LARGE:	cmodel_str = "large";	break;
+    default:		cmodel_str = "unknown";	break;
+    }
+
+  fprintf (stderr, DEBUG_FMT_S, "cmodel", cmodel_str);
+
+  switch (rs6000_current_abi)
+    {
+    case ABI_NONE:	abi_str = "none";	break;
+    case ABI_AIX:	abi_str = "aix";	break;
+    case ABI_V4:	abi_str = "V4";		break;
+    case ABI_DARWIN:	abi_str = "darwin";	break;
+    default:		abi_str = "unknown";	break;
+    }
+
+  fprintf (stderr, DEBUG_FMT_S, "abi", abi_str);
+
+  if (rs6000_altivec_abi)
+    fprintf (stderr, DEBUG_FMT_S, "altivec_abi", "true");
+
+  if (rs6000_spe_abi)
+    fprintf (stderr, DEBUG_FMT_S, "spe_abi", "true");
+
+  if (rs6000_darwin64_abi)
+    fprintf (stderr, DEBUG_FMT_S, "darwin64_abi", "true");
+
+  if (rs6000_float_gprs)
+    fprintf (stderr, DEBUG_FMT_S, "float_gprs", "true");
+
+  fprintf (stderr, DEBUG_FMT_S, "always_hint", tf[!!rs6000_always_hint]);
+  fprintf (stderr, DEBUG_FMT_S, "align_branch",
+	   tf[!!rs6000_align_branch_targets]);
+  fprintf (stderr, DEBUG_FMT_D, "tls_size", rs6000_tls_size);
+  fprintf (stderr, DEBUG_FMT_D, "long_double_size",
+	   rs6000_long_double_type_size);
+  fprintf (stderr, DEBUG_FMT_D, "sched_restricted_insns_priority",
+	   (int)rs6000_sched_restricted_insns_priority);
 }
 
 /* Initialize the various global tables that are based on register size.  */
 static void
-rs6000_init_hard_regno_mode_ok (void)
+rs6000_init_hard_regno_mode_ok (bool global_init_p)
 {
   int r, m, c;
   int align64;
@@ -2461,40 +2540,43 @@  rs6000_init_hard_regno_mode_ok (void)
 	}
     }
 
-  if (TARGET_DEBUG_REG)
-    rs6000_debug_reg_global ();
+  if (global_init_p || TARGET_DEBUG_TARGET)
+    {
+      if (TARGET_DEBUG_REG)
+	rs6000_debug_reg_global ();
 
-  if (TARGET_DEBUG_COST || TARGET_DEBUG_REG)
-    fprintf (stderr,
-	     "SImode variable mult cost       = %d\n"
-	     "SImode constant mult cost       = %d\n"
-	     "SImode short constant mult cost = %d\n"
-	     "DImode multipliciation cost     = %d\n"
-	     "SImode division cost            = %d\n"
-	     "DImode division cost            = %d\n"
-	     "Simple fp operation cost        = %d\n"
-	     "DFmode multiplication cost      = %d\n"
-	     "SFmode division cost            = %d\n"
-	     "DFmode division cost            = %d\n"
-	     "cache line size                 = %d\n"
-	     "l1 cache size                   = %d\n"
-	     "l2 cache size                   = %d\n"
-	     "simultaneous prefetches         = %d\n"
-	     "\n",
-	     rs6000_cost->mulsi,
-	     rs6000_cost->mulsi_const,
-	     rs6000_cost->mulsi_const9,
-	     rs6000_cost->muldi,
-	     rs6000_cost->divsi,
-	     rs6000_cost->divdi,
-	     rs6000_cost->fp,
-	     rs6000_cost->dmul,
-	     rs6000_cost->sdiv,
-	     rs6000_cost->ddiv,
-	     rs6000_cost->cache_line_size,
-	     rs6000_cost->l1_cache_size,
-	     rs6000_cost->l2_cache_size,
-	     rs6000_cost->simultaneous_prefetches);
+      if (TARGET_DEBUG_COST || TARGET_DEBUG_REG)
+	fprintf (stderr,
+		 "SImode variable mult cost       = %d\n"
+		 "SImode constant mult cost       = %d\n"
+		 "SImode short constant mult cost = %d\n"
+		 "DImode multipliciation cost     = %d\n"
+		 "SImode division cost            = %d\n"
+		 "DImode division cost            = %d\n"
+		 "Simple fp operation cost        = %d\n"
+		 "DFmode multiplication cost      = %d\n"
+		 "SFmode division cost            = %d\n"
+		 "DFmode division cost            = %d\n"
+		 "cache line size                 = %d\n"
+		 "l1 cache size                   = %d\n"
+		 "l2 cache size                   = %d\n"
+		 "simultaneous prefetches         = %d\n"
+		 "\n",
+		 rs6000_cost->mulsi,
+		 rs6000_cost->mulsi_const,
+		 rs6000_cost->mulsi_const9,
+		 rs6000_cost->muldi,
+		 rs6000_cost->divsi,
+		 rs6000_cost->divdi,
+		 rs6000_cost->fp,
+		 rs6000_cost->dmul,
+		 rs6000_cost->sdiv,
+		 rs6000_cost->ddiv,
+		 rs6000_cost->cache_line_size,
+		 rs6000_cost->l1_cache_size,
+		 rs6000_cost->l2_cache_size,
+		 rs6000_cost->simultaneous_prefetches);
+    }
 }
 
 #if TARGET_MACHO
@@ -2570,9 +2652,11 @@  rs6000_option_override_internal (bool gl
   bool ret = true;
   const char *default_cpu = OPTION_TARGET_CPU_DEFAULT;
   int set_masks;
-  int defcpu_index;
   int cpu_index;
   int tune_index;
+  struct cl_target_option *main_target_opt
+    = ((global_init_p || target_option_default_node == NULL)
+       ? NULL : TREE_TARGET_OPTION (target_option_default_node));
 
   /* Numerous experiment shows that IRA based loop pressure
      calculation works better for RTL loop invariant motion on targets
@@ -2615,9 +2699,21 @@  rs6000_option_override_internal (bool gl
 	default_cpu = "powerpc";
     }
 
-  defcpu_index = rs6000_cpu_name_lookup (default_cpu);
-  cpu_index = (rs6000_cpu_index > 0) ? rs6000_cpu_index : defcpu_index;
-  tune_index = (rs6000_tune_index > 0) ? rs6000_tune_index : cpu_index;
+  /* Process the -mcpu=<xxx> and -mtune=<xxx> argument.  If the user changed
+     the cpu in a target attribute or pragma, but did not specify a tuning
+     option, use the cpu for the tuning option rather than the option specified
+     with -mtune on the command line.  */
+  if (rs6000_cpu_index > 0)
+    cpu_index = rs6000_cpu_index;
+  else if (main_target_opt != NULL && main_target_opt->x_rs6000_cpu_index > 0)
+    rs6000_cpu_index = cpu_index = main_target_opt->x_rs6000_cpu_index;
+  else
+    rs6000_cpu_index = cpu_index = rs6000_cpu_name_lookup (default_cpu);
+
+  if (rs6000_tune_index > 0)
+    tune_index = rs6000_tune_index;
+  else
+    rs6000_tune_index = tune_index = cpu_index;
 
   if (cpu_index >= 0)
     {
@@ -2790,16 +2886,37 @@  rs6000_option_override_internal (bool gl
     }
 
   if (!rs6000_explicit_options.long_double)
-    rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
+    {
+      if (main_target_opt != NULL
+	  && (main_target_opt->x_rs6000_long_double_type_size
+	      != RS6000_DEFAULT_LONG_DOUBLE_SIZE))
+	error ("You cannot change long double size within a target attribute "
+	       "or pragma");
+      else
+	rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
+    }
 
 #ifndef POWERPC_LINUX
   if (!rs6000_explicit_options.ieee)
     rs6000_ieeequad = 1;
 #endif
 
+  /* Disable VSX and Altivec silently if the user switched cpus to power7 in a
+     target attribute or pragma which automatically enables both options,
+     unless the altivec ABI was set.  This is set by default for 64-bit, but
+     not for 32-bit.  */
+  if (main_target_opt != NULL && !main_target_opt->x_rs6000_altivec_abi)
+    target_flags &= ~((MASK_VSX | MASK_ALTIVEC) & ~target_flags_explicit);
+
   /* Enable Altivec ABI for AIX -maltivec.  */
   if (TARGET_XCOFF && (TARGET_ALTIVEC || TARGET_VSX))
-    rs6000_altivec_abi = 1;
+    {
+      if (main_target_opt != NULL && !main_target_opt->x_rs6000_altivec_abi)
+	error ("You cannot switch to the altivec abi within a target "
+	       "attribute or pragma");
+      else
+	rs6000_altivec_abi = 1;
+    }
 
   /* The AltiVec ABI is the default for PowerPC-64 GNU/Linux.  For
      PowerPC-32 GNU/Linux, -maltivec implies the AltiVec ABI.  It can
@@ -2808,7 +2925,14 @@  rs6000_option_override_internal (bool gl
     {
       if (!rs6000_explicit_options.altivec_abi
 	  && (TARGET_64BIT || TARGET_ALTIVEC || TARGET_VSX))
-	rs6000_altivec_abi = 1;
+	{
+	  if (main_target_opt != NULL &&
+	      !main_target_opt->x_rs6000_altivec_abi)
+	    error ("You cannot switch to the altivec abi within a target "
+		   "attribute or pragma");
+	  else
+	    rs6000_altivec_abi = 1;
+	}
 
       /* Enable VRSAVE for AltiVec ABI, unless explicitly overridden.  */
       if (!rs6000_explicit_options.vrsave)
@@ -2821,9 +2945,15 @@  rs6000_option_override_internal (bool gl
       && DEFAULT_ABI == ABI_DARWIN 
       && TARGET_64BIT)
     {
-      rs6000_darwin64_abi = 1;
-      /* Default to natural alignment, for better performance.  */
-      rs6000_alignment_flags = MASK_ALIGN_NATURAL;
+      if (main_target_opt != NULL && !main_target_opt->x_rs6000_darwin64_abi)
+	error ("You cannot switch to the darwin64 abi within a target "
+	       "attribute or pragma");
+      else
+	{
+	  rs6000_darwin64_abi = 1;
+	  /* Default to natural alignment, for better performance.  */
+	  rs6000_alignment_flags = MASK_ALIGN_NATURAL;
+	}
     }
 
   /* Place FP constants in the constant pool instead of TOC
@@ -2854,12 +2984,21 @@  rs6000_option_override_internal (bool gl
       /* For the powerpc-eabispe configuration, we set all these by
 	 default, so let's unset them if we manually set another
 	 CPU that is not the E500.  */
-      if (!rs6000_explicit_options.spe_abi)
-	rs6000_spe_abi = 0;
-      if (!rs6000_explicit_options.spe)
-	rs6000_spe = 0;
-      if (!rs6000_explicit_options.float_gprs)
-	rs6000_float_gprs = 0;
+      if (main_target_opt != NULL
+	  && ((main_target_opt->x_rs6000_spe_abi != rs6000_spe_abi)
+	      || (main_target_opt->x_rs6000_spe != rs6000_spe)
+	      || (main_target_opt->x_rs6000_float_gprs != rs6000_float_gprs)))
+	error ("You cannot switch to the SPE abi within a target "
+	       "attribute or pragma");
+      else
+	{
+	  if (!rs6000_explicit_options.spe_abi)
+	    rs6000_spe_abi = 0;
+	  if (!rs6000_explicit_options.spe)
+	    rs6000_spe = 0;
+	  if (!rs6000_explicit_options.float_gprs)
+	    rs6000_float_gprs = 0;
+	}
       if (!(target_flags_explicit & MASK_ISEL))
 	target_flags &= ~MASK_ISEL;
     }
@@ -3164,6 +3303,16 @@  rs6000_option_override_internal (bool gl
       rs6000_single_float = rs6000_double_float = 1;
   }
 
+  if (main_target_opt)
+    {
+      if (main_target_opt->x_rs6000_single_float != rs6000_single_float)
+	error ("You are not allowed to change the single precision floating "
+	       "point unit within a target attribute or pragma");
+      if (main_target_opt->x_rs6000_double_float != rs6000_double_float)
+	error ("You are not allowed to change the double precision floating "
+	       "point unit within a target attribute or pragma");
+    }
+
   /* If not explicitly specified via option, decide whether to generate indexed
      load/store instructions.  */
   if (TARGET_AVOID_XFORM == -1)
@@ -3218,7 +3367,7 @@  rs6000_option_override_internal (bool gl
 	}
     }
 
-  rs6000_init_hard_regno_mode_ok ();
+  rs6000_init_hard_regno_mode_ok (global_init_p);
 
   /* Save the initial options in case the user does function specific options */
   if (global_init_p)
@@ -6818,7 +6967,7 @@  rs6000_conditional_register_usage (void)
 {
   int i;
 
-  if (TARGET_DEBUG_REG || TARGET_DEBUG_TARGET)
+  if (TARGET_DEBUG_TARGET)
     fprintf (stderr, "rs6000_conditional_register_usage called\n");
 
   /* Set MQ register fixed (already call_used) if not POWER
@@ -27456,6 +27605,7 @@  rs6000_valid_attribute_p (tree fndecl,
   /* The target attributes may also change some optimization flags, so update
      the optimization options if necessary.  */
   cl_target_option_save (&cur_target, &global_options);
+  rs6000_cpu_index = rs6000_tune_index = -1;
   ret = rs6000_inner_target_options (args, true);
 
   /* Set up any additional state.  */
@@ -27529,6 +27679,7 @@  rs6000_pragma_target_parse (tree args, t
     }
   else
     {
+      rs6000_cpu_index = rs6000_tune_index = -1;
       ret = rs6000_inner_target_options (args, false);
       cur_tree = build_target_option_node ();
 
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 166106)
+++ gcc/doc/extend.texi	(working copy)
@@ -3410,7 +3410,9 @@  On the PowerPC, the following options ar
 @item altivec
 @itemx no-altivec
 @cindex @code{target("altivec")} attribute
-Generate code that uses (does not use) AltiVec instructions.
+Generate code that uses (does not use) AltiVec instructions.  In
+32-bit code, you cannot enable Altivec instructions unless
+@option{-mabi=altivec} was used on the command line.
 
 @item cmpb
 @itemx no-cmpb
@@ -3527,7 +3529,9 @@  do small block moves.
 @cindex @code{target("vsx")} attribute
 Generate code that uses (does not use) vector/scalar (VSX)
 instructions, and also enable the use of built-in functions that allow
-more direct access to the VSX instruction set.
+more direct access to the VSX instruction set.  In 32-bit code, you
+cannot enable VSX or Altivec instructions unless
+@option{-mabi=altivec} was used on the command line.
 
 @item friz
 @itemx no-friz
@@ -3564,11 +3568,18 @@  away so that a longer more expensive cal
 
 @item cpu=@var{CPU}
 @cindex @code{target("cpu=@var{CPU}")} attribute
-Specify the architecture to generate code for in compiling the function.
+Specify the architecture to generate code for in compiling the
+function.  If you select @code{"target("cpu=power7)"} attribute when
+generating 32-bit code, VSX and Altivec instructions are not generated
+unless you use the @option{-mabi=altivec} option on the command line.
 
 @item tune=@var{TUNE}
 @cindex @code{target("tune=@var{TUNE}")} attribute
-Specify the architecture to tune for in compiling the function.
+Specify the architecture to tune for in compiling the function.  If
+you do not specify the @code{target("tune=@var{TUNE}")} attribute and
+you do specifiy the @code{target("cpu=@var{CPU}")} attribute,
+compilation will tune for the @var{CPU} architecture, and not the
+default tuning specified on the command line.
 @end table
 @end table
 @end table
Index: gcc/testsuite/gcc.target/powerpc/ppc-target-2.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-target-2.c	(revision 166141)
+++ gcc/testsuite/gcc.target/powerpc/ppc-target-2.c	(working copy)
@@ -1,7 +1,7 @@ 
 /* { dg-do compile { target { powerpc*-*-* } } } */
 /* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
 /* { dg-require-effective-target powerpc_vsx_ok } */
-/* { dg-options "-O2 -ffast-math -mcpu=power5" } */
+/* { dg-options "-O2 -ffast-math -mcpu=power5 -mabi=altivec" } */
 /* { dg-final { scan-assembler-times "fabs" 3 } } */
 /* { dg-final { scan-assembler-times "fnabs" 3 } } */
 /* { dg-final { scan-assembler-times "fsel" 3 } } */
Index: gcc/testsuite/gcc.target/powerpc/ppc-target-1.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-target-1.c	(revision 166141)
+++ gcc/testsuite/gcc.target/powerpc/ppc-target-1.c	(working copy)
@@ -1,7 +1,7 @@ 
 /* { dg-do compile { target { powerpc*-*-* } } } */
 /* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
 /* { dg-require-effective-target powerpc_vsx_ok } */
-/* { dg-options "-O2 -ffast-math -mcpu=power5" } */
+/* { dg-options "-O2 -ffast-math -mcpu=power5 -mabi=altivec" } */
 /* { dg-final { scan-assembler-times "fabs" 3 } } */
 /* { dg-final { scan-assembler-times "fnabs" 3 } } */
 /* { dg-final { scan-assembler-times "fsel" 3 } } */
Index: gcc/testsuite/gcc.target/powerpc/ppc-target-3.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-target-3.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-target-3.c	(revision 0)
@@ -0,0 +1,62 @@ 
+/* { dg-do compile { target { powerpc*-*-* && ilp32 } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-O2 -ffast-math -mcpu=power5 -mabi=no-altivec" } */
+/* { dg-final { scan-assembler-times "fabs" 3 } } */
+/* { dg-final { scan-assembler-times "fnabs" 3 } } */
+/* { dg-final { scan-assembler-times "fsel" 3 } } */
+/* { dg-final { scan-assembler-times "fcpsgn" 4 } } */
+/* { dg-final { scan-assembler-not "xscpsgndp" } } */
+
+/* Like ppc-target-1.c, but do not enable the altivec abi on 32-bit, so the
+   power7 code should generate fcpsgn and not xscpsgndp.  */
+
+double normal1 (double, double);
+double power5  (double, double) __attribute__((__target__("cpu=power5")));
+double power6  (double, double) __attribute__((__target__("cpu=power6")));
+double power6x (double, double) __attribute__((__target__("cpu=power6x")));
+double power7  (double, double) __attribute__((__target__("cpu=power7")));
+double power7n (double, double) __attribute__((__target__("cpu=power7,no-vsx")));
+double normal2 (double, double);
+
+/* fabs/fnabs/fsel */
+double normal1 (double a, double b)
+{
+  return __builtin_copysign (a, b);
+}
+
+/* fabs/fnabs/fsel */
+double power5  (double a, double b)
+{
+  return __builtin_copysign (a, b);
+}
+
+/* fcpsgn */
+double power6  (double a, double b)
+{
+  return __builtin_copysign (a, b);
+}
+
+/* fcpsgn */
+double power6x (double a, double b)
+{
+  return __builtin_copysign (a, b);
+}
+
+/* xscpsgndp */
+double power7  (double a, double b)
+{
+  return __builtin_copysign (a, b);
+}
+
+/* fcpsgn */
+double power7n (double a, double b)
+{
+  return __builtin_copysign (a, b);
+}
+
+/* fabs/fnabs/fsel */
+double normal2 (double a, double b)
+{
+  return __builtin_copysign (a, b);
+}