This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch to implement IA64 __fpreg


This patch implements a cut-down version of the IA64 __fpreg type (as
implemented by the HP compiler) for the internal 82-bit floating-point
register format.

The more general form of __fpreg is described at
<http://gcc.gnu.org/wiki/ia64%20floating%20point> and was discussed in
a thread at <http://gcc.gnu.org/ml/gcc/2004-11/subjects.html#00136>.
The passive rounding part of the __fpreg semantics was controversial;
this version is cut-down to avoid that by not allowing arithmetic on
__fpreg or conversion to or from __fpreg.  Thus __fpreg values can be
copied around, and system headers using __fpreg can be used without
the potentially inaccurate ABI which arose with the prior definition
of __fpreg as an alias for __float80, but more substantial use of
__fpreg cannot be made.

This does not of course stop anyone else from implementing other parts
of the IA64 floating-point model (including a less-restricted __fpreg)
if they wish to, but in any case the ia64-fp-model-branch should be
considered dead.

Bootstrapped with no regressions on ia64-hp-hpux11.23.  The patched
compiler also passes the attached tests of ABI compatibility between
the compiler and itself and between GCC and the HP compiler (1936000
tests total, although this includes some cases which are effectively
just testing that the HP compiler is compatible with itself).  OK to
commit?

-- 
Joseph S. Myers               http://www.srcf.ucam.org/~jsm28/gcc/
    jsm@polyomino.org.uk (personal mail)
    joseph@codesourcery.com (CodeSourcery mail)
    jsm28@gcc.gnu.org (Bugzilla assignments and CCs)

2005-06-28  Joseph S. Myers  <joseph@codesourcery.com>

	* target.h (invalid_conversion, invalid_unary_op,
	invalid_binary_op): New hooks.
	* target-def.h (TARGET_INVALID_CONVERSION,
	TARGET_INVALID_UNARY_OP, TARGET_INVALID_BINARY_OP,
	TARGET_INITIALIZER): Likewise.
	* hooks.h (hook_constcharptr_tree_tree_null,
	hook_constcharptr_int_tree_null,
	hook_constcharptr_int_tree_tree_null): New.
	* hooks.c (hook_constcharptr_tree_tree_null,
	hook_constcharptr_int_tree_null,
	hook_constcharptr_int_tree_tree_null): Likewise.
	* gcc/doc/tm.texi (TARGET_INVALID_CONVERSION,
	TARGET_INVALID_UNARY_OP, TARGET_INVALID_BINARY_OP): Document.
	* c-convert.c (convert): Use invalid_conversion hook.
	* c-typeck.c (build_unary_op): Use invalid_unary_op hook.
	(build_binary_op): Use invalid_binary_op hook.
	* config/ia64/ia64-modes.def: Define RFmode.
	* config/ia64/ia64-protos.h (spill_xfmode_operand): Remove.
	(ia64_expand_movxf_movrf): New.
	* config/ia64/ia64.md (movxf): Move code to
	ia64_expand_movxf_movrf.
	(movrf, movrf_internal): New.
	* ia64.c (ia64_invalid_conversion, ia64_invalid_unary_op,
	ia64_invalid_binary_op, TARGET_INVALID_CONVERSION,
	TARGET_INVALID_UNARY_OP, TARGET_INVALID_BINARY_OP): New.
	(spill_xfmode_operand): Rename to spill_xfmode_rfmode_operand.
	Add mode parameter.  Make static.
	(ia64_expand_movxf_movrf): New, moved from ia64.md.  Handle RFmode
	as well as XFmode.
	(ia64_function_arg, ia64_function_value, ia64_register_move_cost,
	ia64_scalar_mode_supported_p): Handle RFmode as well as XFmode.
	(ia64_init_builtins): Set up __fpreg as RFmode.
	(ia64_mangle_fundamental_type): Mangle __fpreg as u7__fpreg.

cp:
2005-06-28  Joseph S. Myers  <joseph@codesourcery.com>

	* cvt.c (ocp_convert): Use invalid_conversion hook.
	* typeck.c (build_binary_op): Use invalid_binary_op hook.
	(build_unary_op): Use invalid_unary_op hook.

testsuite:
2005-06-28  Joseph S. Myers  <joseph@codesourcery.com>

	* g++.dg/ext/fpreg1.C, gcc.target/ia64/fpreg-1.c,
	gcc.target/ia64/fpreg-2.c: New tests.

diff -rupN GCC.orig/gcc/c-convert.c GCC/gcc/c-convert.c
--- GCC.orig/gcc/c-convert.c	2005-03-30 09:27:09.000000000 +0000
+++ GCC/gcc/c-convert.c	2005-06-23 16:32:05.000000000 +0000
@@ -36,6 +36,7 @@ Software Foundation, 59 Temple Place - S
 #include "c-tree.h"
 #include "langhooks.h"
 #include "toplev.h"
+#include "target.h"
 
 /* Change of width--truncation and extension of integers or reals--
    is represented with NOP_EXPR.  Proper functioning of many things
@@ -69,10 +70,21 @@ convert (tree type, tree expr)
 {
   tree e = expr;
   enum tree_code code = TREE_CODE (type);
+  const char *invalid_conv_diag;
 
-  if (type == TREE_TYPE (expr)
-      || TREE_CODE (expr) == ERROR_MARK
-      || code == ERROR_MARK || TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)
+  if (type == error_mark_node
+      || expr == error_mark_node
+      || TREE_TYPE (expr) == error_mark_node)
+    return error_mark_node;
+
+  if ((invalid_conv_diag
+       = targetm.invalid_conversion (TREE_TYPE (expr), type)))
+    {
+      error (invalid_conv_diag);
+      return error_mark_node;
+    }
+
+  if (type == TREE_TYPE (expr))
     return expr;
 
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
diff -rupN GCC.orig/gcc/c-typeck.c GCC/gcc/c-typeck.c
--- GCC.orig/gcc/c-typeck.c	2005-06-21 22:46:35.000000000 +0000
+++ GCC/gcc/c-typeck.c	2005-06-22 21:19:42.000000000 +0000
@@ -2498,12 +2498,20 @@ build_unary_op (enum tree_code code, tre
   enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
   tree val;
   int noconvert = flag;
+  const char *invalid_op_diag;
 
   if (typecode == ERROR_MARK)
     return error_mark_node;
   if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE)
     typecode = INTEGER_TYPE;
 
+  if ((invalid_op_diag
+       = targetm.invalid_unary_op (code, TREE_TYPE (xarg))))
+    {
+      error (invalid_op_diag);
+      return error_mark_node;
+    }
+
   switch (code)
     {
     case CONVERT_EXPR:
@@ -7389,6 +7397,7 @@ build_binary_op (enum tree_code code, tr
   tree type0, type1;
   enum tree_code code0, code1;
   tree op0, op1;
+  const char *invalid_op_diag;
 
   /* Expression code to give to the expression when it is built.
      Normally this is CODE, which is what the caller asked for,
@@ -7464,6 +7473,13 @@ build_binary_op (enum tree_code code, tr
   if (code0 == ERROR_MARK || code1 == ERROR_MARK)
     return error_mark_node;
 
+  if ((invalid_op_diag
+       = targetm.invalid_binary_op (code, type0, type1)))
+    {
+      error (invalid_op_diag);
+      return error_mark_node;
+    }
+
   objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
 
   switch (code)
diff -rupN GCC.orig/gcc/config/ia64/ia64-modes.def GCC/gcc/config/ia64/ia64-modes.def
--- GCC.orig/gcc/config/ia64/ia64-modes.def	2005-01-20 16:20:11.000000000 +0000
+++ GCC/gcc/config/ia64/ia64-modes.def	2005-06-09 00:28:37.000000000 +0000
@@ -23,9 +23,12 @@ Boston, MA 02111-1307, USA.  */
 /* IA64 requires both XF and TF modes.
    XFmode is __float80 is IEEE extended; TFmode is __float128
    is IEEE quad.  Both these modes occupy 16 bytes, but XFmode
-   only has 80 significant bits.  */
+   only has 80 significant bits.  RFmode is __fpreg is IA64 internal
+   register format with 82 significant bits but otherwise handled like
+   XFmode.  */
 
 FRACTIONAL_FLOAT_MODE (XF, 80, 16, ieee_extended_intel_128_format);
+FRACTIONAL_FLOAT_MODE (RF, 82, 16, ieee_extended_intel_128_format);
 FLOAT_MODE (TF, 16, ieee_quad_format);
 
 /* The above produces:
@@ -54,6 +57,12 @@ ADJUST_FLOAT_FORMAT (XF, (TARGET_ILP32 &
 ADJUST_BYTESIZE  (XF, (TARGET_ILP32 && !TARGET_HPUX) ? 12 : 16);
 ADJUST_ALIGNMENT (XF, (TARGET_ILP32 && !TARGET_HPUX) ?  4 : 16);
 
+ADJUST_FLOAT_FORMAT (RF, (TARGET_ILP32 && !TARGET_HPUX)
+			 ? &ieee_extended_intel_96_format
+			 : &ieee_extended_intel_128_format);
+ADJUST_BYTESIZE  (RF, (TARGET_ILP32 && !TARGET_HPUX) ? 12 : 16);
+ADJUST_ALIGNMENT (RF, (TARGET_ILP32 && !TARGET_HPUX) ?  4 : 16);
+
 ADJUST_ALIGNMENT (TF, (TARGET_ILP32 &&  TARGET_HPUX) ?  8 : 16);
 
 /* 256-bit integer mode is needed for STACK_SAVEAREA_MODE.  */
diff -rupN GCC.orig/gcc/config/ia64/ia64-protos.h GCC/gcc/config/ia64/ia64-protos.h
--- GCC.orig/gcc/config/ia64/ia64-protos.h	2005-06-08 16:22:20.000000000 +0000
+++ GCC/gcc/config/ia64/ia64-protos.h	2005-06-27 21:16:02.000000000 +0000
@@ -45,7 +45,7 @@ extern int addp4_optimize_ok (rtx, rtx);
 extern void ia64_emit_cond_move (rtx, rtx, rtx);
 extern int ia64_depz_field_mask (rtx, rtx);
 extern void ia64_split_tmode_move (rtx[]);
-extern rtx spill_xfmode_operand (rtx, int);
+extern bool ia64_expand_movxf_movrf (enum machine_mode, rtx[]);
 extern rtx ia64_expand_compare (enum rtx_code, enum machine_mode);
 extern void ia64_expand_vecint_cmov (rtx[]);
 extern bool ia64_expand_vecint_minmax (enum rtx_code, enum machine_mode, rtx[]);
diff -rupN GCC.orig/gcc/config/ia64/ia64.c GCC/gcc/config/ia64/ia64.c
--- GCC.orig/gcc/config/ia64/ia64.c	2005-06-19 20:08:40.000000000 +0000
+++ GCC/gcc/config/ia64/ia64.c	2005-06-27 21:17:00.000000000 +0000
@@ -52,6 +52,7 @@ Boston, MA 02111-1307, USA.  */
 #include "langhooks.h"
 #include "cfglayout.h"
 #include "tree-gimple.h"
+#include "intl.h"
 
 /* This is used for communication between ASM_OUTPUT_LABEL and
    ASM_OUTPUT_LABELREF.  */
@@ -263,6 +264,9 @@ static bool ia64_scalar_mode_supported_p
 static bool ia64_vector_mode_supported_p (enum machine_mode mode);
 static bool ia64_cannot_force_const_mem (rtx);
 static const char *ia64_mangle_fundamental_type (tree);
+static const char *ia64_invalid_conversion (tree, tree);
+static const char *ia64_invalid_unary_op (int, tree);
+static const char *ia64_invalid_binary_op (int, tree, tree);
 
 /* Table of valid machine attributes.  */
 static const struct attribute_spec ia64_attribute_table[] =
@@ -433,6 +437,13 @@ static const struct attribute_spec ia64_
 #undef TARGET_MANGLE_FUNDAMENTAL_TYPE
 #define TARGET_MANGLE_FUNDAMENTAL_TYPE ia64_mangle_fundamental_type
 
+#undef TARGET_INVALID_CONVERSION
+#define TARGET_INVALID_CONVERSION ia64_invalid_conversion
+#undef TARGET_INVALID_UNARY_OP
+#define TARGET_INVALID_UNARY_OP ia64_invalid_unary_op
+#undef TARGET_INVALID_BINARY_OP
+#define TARGET_INVALID_BINARY_OP ia64_invalid_binary_op
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 typedef enum
@@ -1285,8 +1296,8 @@ ia64_split_tmode_move (rtx operands[])
    This solution attempts to prevent this situation from occurring.  When
    we see something like the above, we spill the inner register to memory.  */
 
-rtx
-spill_xfmode_operand (rtx in, int force)
+static rtx
+spill_xfmode_rfmode_operand (rtx in, int force, enum machine_mode mode)
 {
   if (GET_CODE (in) == SUBREG
       && GET_MODE (SUBREG_REG (in)) == TImode
@@ -1294,11 +1305,11 @@ spill_xfmode_operand (rtx in, int force)
     {
       rtx memt = assign_stack_temp (TImode, 16, 0);
       emit_move_insn (memt, SUBREG_REG (in));
-      return adjust_address (memt, XFmode, 0);
+      return adjust_address (memt, mode, 0);
     }
   else if (force && GET_CODE (in) == REG)
     {
-      rtx memx = assign_stack_temp (XFmode, 16, 0);
+      rtx memx = assign_stack_temp (mode, 16, 0);
       emit_move_insn (memx, in);
       return memx;
     }
@@ -1306,6 +1317,132 @@ spill_xfmode_operand (rtx in, int force)
     return in;
 }
 
+/* Expand the movxf or movrf pattern (MODE says which) with the given
+   OPERANDS, returning true if the pattern should then invoke
+   DONE.  */
+
+bool
+ia64_expand_movxf_movrf (enum machine_mode mode, rtx operands[])
+{
+  rtx op0 = operands[0];
+
+  if (GET_CODE (op0) == SUBREG)
+    op0 = SUBREG_REG (op0);
+
+  /* We must support XFmode loads into general registers for stdarg/vararg,
+     unprototyped calls, and a rare case where a long double is passed as
+     an argument after a float HFA fills the FP registers.  We split them into
+     DImode loads for convenience.  We also need to support XFmode stores
+     for the last case.  This case does not happen for stdarg/vararg routines,
+     because we do a block store to memory of unnamed arguments.  */
+
+  if (GET_CODE (op0) == REG && GR_REGNO_P (REGNO (op0)))
+    {
+      rtx out[2];
+
+      /* We're hoping to transform everything that deals with XFmode
+	 quantities and GR registers early in the compiler.  */
+      gcc_assert (!no_new_pseudos);
+
+      /* Struct to register can just use TImode instead.  */
+      if ((GET_CODE (operands[1]) == SUBREG
+	   && GET_MODE (SUBREG_REG (operands[1])) == TImode)
+	  || (GET_CODE (operands[1]) == REG
+	      && GR_REGNO_P (REGNO (operands[1]))))
+	{
+	  rtx op1 = operands[1];
+
+	  if (GET_CODE (op1) == SUBREG)
+	    op1 = SUBREG_REG (op1);
+	  else
+	    op1 = gen_rtx_REG (TImode, REGNO (op1));
+
+	  emit_move_insn (gen_rtx_REG (TImode, REGNO (op0)), op1);
+	  return true;
+	}
+
+      if (GET_CODE (operands[1]) == CONST_DOUBLE)
+	{
+	  emit_move_insn (gen_rtx_REG (DImode, REGNO (op0)),
+			  operand_subword (operands[1], 0, 0, mode));
+	  emit_move_insn (gen_rtx_REG (DImode, REGNO (op0) + 1),
+			  operand_subword (operands[1], 1, 0, mode));
+	  return true;
+	}
+
+      /* If the quantity is in a register not known to be GR, spill it.  */
+      if (register_operand (operands[1], mode))
+	operands[1] = spill_xfmode_rfmode_operand (operands[1], 1, mode);
+
+      gcc_assert (GET_CODE (operands[1]) == MEM);
+
+      out[WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (op0));
+      out[!WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (op0) + 1);
+
+      emit_move_insn (out[0], adjust_address (operands[1], DImode, 0));
+      emit_move_insn (out[1], adjust_address (operands[1], DImode, 8));
+      return true;
+    }
+
+  if (GET_CODE (operands[1]) == REG && GR_REGNO_P (REGNO (operands[1])))
+    {
+      /* We're hoping to transform everything that deals with XFmode
+	 quantities and GR registers early in the compiler.  */
+      gcc_assert (!no_new_pseudos);
+
+      /* Op0 can't be a GR_REG here, as that case is handled above.
+	 If op0 is a register, then we spill op1, so that we now have a
+	 MEM operand.  This requires creating an XFmode subreg of a TImode reg
+	 to force the spill.  */
+      if (register_operand (operands[0], mode))
+	{
+	  rtx op1 = gen_rtx_REG (TImode, REGNO (operands[1]));
+	  op1 = gen_rtx_SUBREG (mode, op1, 0);
+	  operands[1] = spill_xfmode_rfmode_operand (op1, 0, mode);
+	}
+
+      else
+	{
+	  rtx in[2];
+
+          gcc_assert (GET_CODE (operands[0]) == MEM);
+	  in[WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (operands[1]));
+	  in[!WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (operands[1]) + 1);
+
+	  emit_move_insn (adjust_address (operands[0], DImode, 0), in[0]);
+	  emit_move_insn (adjust_address (operands[0], DImode, 8), in[1]);
+	  return true;
+	}
+    }
+
+  if (!reload_in_progress && !reload_completed)
+    {
+      operands[1] = spill_xfmode_rfmode_operand (operands[1], 0, mode);
+
+      if (GET_MODE (op0) == TImode && GET_CODE (op0) == REG)
+	{
+	  rtx memt, memx, in = operands[1];
+	  if (CONSTANT_P (in))
+	    in = validize_mem (force_const_mem (mode, in));
+	  if (GET_CODE (in) == MEM)
+	    memt = adjust_address (in, TImode, 0);
+	  else
+	    {
+	      memt = assign_stack_temp (TImode, 16, 0);
+	      memx = adjust_address (memt, mode, 0);
+	      emit_move_insn (memx, in);
+	    }
+	  emit_move_insn (op0, memt);
+	  return true;
+	}
+
+      if (!ia64_move_ok (operands[0], operands[1]))
+	operands[1] = force_reg (mode, operands[1]);
+    }
+
+  return false;
+}
+
 /* Emit comparison instruction if necessary, returning the expression
    that holds the compare result in the proper mode.  */
 
@@ -3837,9 +3974,9 @@ ia64_function_arg (CUMULATIVE_ARGS *cum,
                    gen_rtx_EXPR_LIST (VOIDmode,
 		     gen_rtx_REG (DImode, basereg + cum->words + offset),
 				      const0_rtx)));
-      /* Similarly, an anonymous XFmode value must be split into two
-	 registers and padded appropriately.  */
-      else if (BYTES_BIG_ENDIAN && mode == XFmode)
+      /* Similarly, an anonymous XFmode or RFmode value must be split
+	 into two registers and padded appropriately.  */
+      else if (BYTES_BIG_ENDIAN && (mode == XFmode || mode == RFmode))
 	{
 	  rtx loc[2];
 	  loc[0] = gen_rtx_EXPR_LIST (VOIDmode,
@@ -4157,7 +4294,7 @@ ia64_function_value (tree valtype, tree 
 	 the middle-end will give it XFmode anyway, and XFmode values
 	 don't normally fit in integer registers.  So we need to smuggle
 	 the value inside a parallel.  */
-      else if (mode == XFmode || mode == XCmode)
+      else if (mode == XFmode || mode == XCmode || mode == RFmode)
 	need_parallel = true;
 
       if (need_parallel)
@@ -4572,7 +4709,7 @@ ia64_register_move_cost (enum machine_mo
      so that we get secondary memory reloads.  Between FR_REGS,
      we have to make this at least as expensive as MEMORY_MOVE_COST
      to avoid spectacularly poor register class preferencing.  */
-  if (mode == XFmode)
+  if (mode == XFmode || mode == RFmode)
     {
       if (to != GR_REGS || from != GR_REGS)
         return MEMORY_MOVE_COST (mode, to, 0);
@@ -8056,9 +8193,7 @@ ia64_init_builtins (void)
 
   /* The __fpreg type.  */
   fpreg_type = make_node (REAL_TYPE);
-  /* ??? The back end should know to load/save __fpreg variables using
-     the ldf.fill and stf.spill instructions.  */
-  TYPE_PRECISION (fpreg_type) = 80;
+  TYPE_PRECISION (fpreg_type) = 82;
   layout_type (fpreg_type);
   (*lang_hooks.types.register_builtin_type) (fpreg_type, "__fpreg");
 
@@ -8547,6 +8682,7 @@ ia64_scalar_mode_supported_p (enum machi
     case SFmode:
     case DFmode:
     case XFmode:
+    case RFmode:
       return true;
 
     case TFmode:
@@ -8657,6 +8793,48 @@ ia64_mangle_fundamental_type (tree type)
      double is 80 bits.  */
   if (TYPE_MODE (type) == XFmode)
     return TARGET_HPUX ? "u9__float80" : "e";
+  if (TYPE_MODE (type) == RFmode)
+    return "u7__fpreg";
+  return NULL;
+}
+
+/* Return the diagnostic message string if conversion from FROMTYPE to
+   TOTYPE is not allowed, NULL otherwise.  */
+static const char *
+ia64_invalid_conversion (tree fromtype, tree totype)
+{
+  /* Reject nontrivial conversion to or from __fpreg.  */
+  if (TYPE_MODE (fromtype) == RFmode
+      && TYPE_MODE (totype) != RFmode
+      && TYPE_MODE (totype) != VOIDmode)
+    return N_("invalid conversion from %<__fpreg%>");
+  if (TYPE_MODE (totype) == RFmode
+      && TYPE_MODE (fromtype) != RFmode)
+    return N_("invalid conversion to %<__fpreg%>");
+  return NULL;
+}
+
+/* Return the diagnostic message string if the unary operation OP is
+   not permitted on TYPE, NULL otherwise.  */
+static const char *
+ia64_invalid_unary_op (int op, tree type)
+{
+  /* Reject operations on __fpreg other than unary + or &.  */
+  if (TYPE_MODE (type) == RFmode
+      && op != CONVERT_EXPR
+      && op != ADDR_EXPR)
+    return N_("invalid operation on %<__fpreg%>");
+  return NULL;
+}
+
+/* Return the diagnostic message string if the binary operation OP is
+   not permitted on TYPE1 and TYPE2, NULL otherwise.  */
+static const char *
+ia64_invalid_binary_op (int op ATTRIBUTE_UNUSED, tree type1, tree type2)
+{
+  /* Reject operations on __fpreg.  */
+  if (TYPE_MODE (type1) == RFmode || TYPE_MODE (type2) == RFmode)
+    return N_("invalid operation on %<__fpreg%>");
   return NULL;
 }
 
diff -rupN GCC.orig/gcc/config/ia64/ia64.md GCC/gcc/config/ia64/ia64.md
--- GCC.orig/gcc/config/ia64/ia64.md	2005-06-19 20:08:14.000000000 +0000
+++ GCC/gcc/config/ia64/ia64.md	2005-06-27 21:13:29.000000000 +0000
@@ -736,121 +736,8 @@
 	(match_operand:XF 1 "general_operand" ""))]
   ""
 {
-  rtx op0 = operands[0];
-
-  if (GET_CODE (op0) == SUBREG)
-    op0 = SUBREG_REG (op0);
-
-  /* We must support XFmode loads into general registers for stdarg/vararg,
-     unprototyped calls, and a rare case where a long double is passed as
-     an argument after a float HFA fills the FP registers.  We split them into
-     DImode loads for convenience.  We also need to support XFmode stores
-     for the last case.  This case does not happen for stdarg/vararg routines,
-     because we do a block store to memory of unnamed arguments.  */
-
-  if (GET_CODE (op0) == REG && GR_REGNO_P (REGNO (op0)))
-    {
-      rtx out[2];
-
-      /* We're hoping to transform everything that deals with XFmode
-	 quantities and GR registers early in the compiler.  */
-      gcc_assert (!no_new_pseudos);
-
-      /* Struct to register can just use TImode instead.  */
-      if ((GET_CODE (operands[1]) == SUBREG
-	   && GET_MODE (SUBREG_REG (operands[1])) == TImode)
-	  || (GET_CODE (operands[1]) == REG
-	      && GR_REGNO_P (REGNO (operands[1]))))
-	{
-	  rtx op1 = operands[1];
-
-	  if (GET_CODE (op1) == SUBREG)
-	    op1 = SUBREG_REG (op1);
-	  else
-	    op1 = gen_rtx_REG (TImode, REGNO (op1));
-
-	  emit_move_insn (gen_rtx_REG (TImode, REGNO (op0)), op1);
-	  DONE;
-	}
-
-      if (GET_CODE (operands[1]) == CONST_DOUBLE)
-	{
-	  emit_move_insn (gen_rtx_REG (DImode, REGNO (op0)),
-			  operand_subword (operands[1], 0, 0, XFmode));
-	  emit_move_insn (gen_rtx_REG (DImode, REGNO (op0) + 1),
-			  operand_subword (operands[1], 1, 0, XFmode));
-	  DONE;
-	}
-
-      /* If the quantity is in a register not known to be GR, spill it.  */
-      if (register_operand (operands[1], XFmode))
-	operands[1] = spill_xfmode_operand (operands[1], 1);
-
-      gcc_assert (GET_CODE (operands[1]) == MEM);
-
-      out[WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (op0));
-      out[!WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (op0) + 1);
-
-      emit_move_insn (out[0], adjust_address (operands[1], DImode, 0));
-      emit_move_insn (out[1], adjust_address (operands[1], DImode, 8));
-      DONE;
-    }
-
-  if (GET_CODE (operands[1]) == REG && GR_REGNO_P (REGNO (operands[1])))
-    {
-      /* We're hoping to transform everything that deals with XFmode
-	 quantities and GR registers early in the compiler.  */
-      gcc_assert (!no_new_pseudos);
-
-      /* Op0 can't be a GR_REG here, as that case is handled above.
-	 If op0 is a register, then we spill op1, so that we now have a
-	 MEM operand.  This requires creating an XFmode subreg of a TImode reg
-	 to force the spill.  */
-      if (register_operand (operands[0], XFmode))
-	{
-	  rtx op1 = gen_rtx_REG (TImode, REGNO (operands[1]));
-	  op1 = gen_rtx_SUBREG (XFmode, op1, 0);
-	  operands[1] = spill_xfmode_operand (op1, 0);
-	}
-
-      else
-	{
-	  rtx in[2];
-
-          gcc_assert (GET_CODE (operands[0]) == MEM);
-	  in[WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (operands[1]));
-	  in[!WORDS_BIG_ENDIAN] = gen_rtx_REG (DImode, REGNO (operands[1]) + 1);
-
-	  emit_move_insn (adjust_address (operands[0], DImode, 0), in[0]);
-	  emit_move_insn (adjust_address (operands[0], DImode, 8), in[1]);
-	  DONE;
-	}
-    }
-
-  if (! reload_in_progress && ! reload_completed)
-    {
-      operands[1] = spill_xfmode_operand (operands[1], 0);
-
-      if (GET_MODE (op0) == TImode && GET_CODE (op0) == REG)
-	{
-	  rtx memt, memx, in = operands[1];
-	  if (CONSTANT_P (in))
-	    in = validize_mem (force_const_mem (XFmode, in));
-	  if (GET_CODE (in) == MEM)
-	    memt = adjust_address (in, TImode, 0);
-	  else
-	    {
-	      memt = assign_stack_temp (TImode, 16, 0);
-	      memx = adjust_address (memt, XFmode, 0);
-	      emit_move_insn (memx, in);
-	    }
-	  emit_move_insn (op0, memt);
-	  DONE;
-	}
-
-      if (! ia64_move_ok (operands[0], operands[1]))
-	operands[1] = force_reg (XFmode, operands[1]);
-    }
+  if (ia64_expand_movxf_movrf (XFmode, operands))
+    DONE;
 })
 
 ;; ??? There's no easy way to mind volatile acquire/release semantics.
@@ -865,6 +752,26 @@
    stfe %0 = %F1%P0"
   [(set_attr "itanium_class" "fmisc,fld,stf")])
 
+;; Same as for movxf, but for RFmode.
+(define_expand "movrf"
+  [(set (match_operand:RF 0 "general_operand" "")
+	(match_operand:RF 1 "general_operand" ""))]
+  ""
+{
+  if (ia64_expand_movxf_movrf (RFmode, operands))
+    DONE;
+})
+
+(define_insn "*movrf_internal"
+  [(set (match_operand:RF 0 "destination_operand" "=f,f, m")
+	(match_operand:RF 1 "general_operand"     "fG,m,fG"))]
+  "ia64_move_ok (operands[0], operands[1])"
+  "@
+   mov %0 = %F1
+   ldf.fill %0 = %1%P1
+   stf.spill %0 = %F1%P0"
+  [(set_attr "itanium_class" "fmisc,fld,stf")])
+
 ;; Better code generation via insns that deal with TFmode register pairs
 ;; directly.  Same concerns apply as for TImode.
 (define_expand "movtf"
diff -rupN GCC.orig/gcc/cp/cvt.c GCC/gcc/cp/cvt.c
--- GCC.orig/gcc/cp/cvt.c	2005-06-15 15:47:22.000000000 +0000
+++ GCC/gcc/cp/cvt.c	2005-06-22 21:33:01.000000000 +0000
@@ -36,6 +36,7 @@ Boston, MA 02111-1307, USA.  */
 #include "convert.h"
 #include "toplev.h"
 #include "decl.h"
+#include "target.h"
 
 static tree cp_convert_to_pointer (tree, tree, bool);
 static tree convert_to_pointer_force (tree, tree);
@@ -601,6 +602,7 @@ ocp_convert (tree type, tree expr, int c
 {
   tree e = expr;
   enum tree_code code = TREE_CODE (type);
+  const char *invalid_conv_diag;
 
   if (error_operand_p (e) || type == error_mark_node)
     return error_mark_node;
@@ -608,6 +610,13 @@ ocp_convert (tree type, tree expr, int c
   complete_type (type);
   complete_type (TREE_TYPE (expr));
 
+  if ((invalid_conv_diag
+       = targetm.invalid_conversion (TREE_TYPE (expr), type)))
+    {
+      error (invalid_conv_diag);
+      return error_mark_node;
+    }
+
   e = integral_constant_value (e);
 
   if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP)
diff -rupN GCC.orig/gcc/cp/typeck.c GCC/gcc/cp/typeck.c
--- GCC.orig/gcc/cp/typeck.c	2005-06-19 20:08:14.000000000 +0000
+++ GCC/gcc/cp/typeck.c	2005-06-23 21:17:45.000000000 +0000
@@ -2735,6 +2735,7 @@ build_binary_op (enum tree_code code, tr
   tree op0, op1;
   enum tree_code code0, code1;
   tree type0, type1;
+  const char *invalid_op_diag;
 
   /* Expression code to give to the expression when it is built.
      Normally this is CODE, which is what the caller asked for,
@@ -2844,6 +2845,13 @@ build_binary_op (enum tree_code code, tr
   if (code0 == ERROR_MARK || code1 == ERROR_MARK)
     return error_mark_node;
 
+  if ((invalid_op_diag
+       = targetm.invalid_binary_op (code, type0, type1)))
+    {
+      error (invalid_op_diag);
+      return error_mark_node;
+    }
+
   switch (code)
     {
     case PLUS_EXPR:
@@ -3724,10 +3732,21 @@ build_unary_op (enum tree_code code, tre
   tree argtype = 0;
   const char *errstring = NULL;
   tree val;
+  const char *invalid_op_diag;
 
   if (arg == error_mark_node)
     return error_mark_node;
 
+  if ((invalid_op_diag
+       = targetm.invalid_unary_op ((code == UNARY_PLUS_EXPR
+				    ? CONVERT_EXPR
+				    : code),
+				   TREE_TYPE (xarg))))
+    {
+      error (invalid_op_diag);
+      return error_mark_node;
+    }
+
   switch (code)
     {
     case UNARY_PLUS_EXPR:
diff -rupN GCC.orig/gcc/doc/tm.texi GCC/gcc/doc/tm.texi
--- GCC.orig/gcc/doc/tm.texi	2005-06-08 16:22:34.000000000 +0000
+++ GCC/gcc/doc/tm.texi	2005-06-23 21:22:49.000000000 +0000
@@ -9560,6 +9560,26 @@ illegal to pass argument @var{val} to fu
 with prototype @var{typelist}.
 @end deftypefn
 
+@deftypefn {Target Hook} {const char *} TARGET_INVALID_CONVERSION (tree @var{fromtype}, tree @var{totype})
+If defined, this macro returns the diagnostic message when it is
+invalid to convert from @var{fromtype} to @var{totype}, or @code{NULL}
+if validity should be determined by the front end.
+@end deftypefn
+
+@deftypefn {Target Hook} {const char *} TARGET_INVALID_UNARY_OP (int @var{op}, tree @var{type})
+If defined, this macro returns the diagnostic message when it is
+invalid to apply operation @var{op} (where unary plus is denoted by
+@code{CONVERT_EXPR}) to an operand of type @var{type}, or @code{NULL}
+if validity should be determined by the front end.
+@end deftypefn
+
+@deftypefn {Target Hook} {const char *} TARGET_INVALID_BINARY_OP (int @var{op}, tree @var{type1}, tree @var{type2})
+If defined, this macro returns the diagnostic message when it is
+invalid to apply operation @var{op} to operands of types @var{type1}
+and @var{type2}, or @code{NULL} if validity should be determined by
+the front end.
+@end deftypefn
+
 @defmac TARGET_USE_JCR_SECTION
 This macro determines whether to use the JCR section to register Java
 classes. By default, TARGET_USE_JCR_SECTION is defined to 1 if both
diff -rupN GCC.orig/gcc/hooks.c GCC/gcc/hooks.c
--- GCC.orig/gcc/hooks.c	2005-06-10 09:02:59.000000000 +0000
+++ GCC/gcc/hooks.c	2005-06-22 21:19:42.000000000 +0000
@@ -256,3 +256,25 @@ hook_constcharptr_rtx_null (rtx r ATTRIB
 {
   return NULL;
 }
+
+const char *
+hook_constcharptr_tree_tree_null (tree t0 ATTRIBUTE_UNUSED,
+				  tree t1 ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
+
+const char *
+hook_constcharptr_int_tree_null (int i ATTRIBUTE_UNUSED,
+				 tree t0 ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
+
+const char *
+hook_constcharptr_int_tree_tree_null (int i ATTRIBUTE_UNUSED,
+				      tree t0 ATTRIBUTE_UNUSED,
+				      tree t1 ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
diff -rupN GCC.orig/gcc/hooks.h GCC/gcc/hooks.h
--- GCC.orig/gcc/hooks.h	2005-06-10 09:02:59.000000000 +0000
+++ GCC/gcc/hooks.h	2005-06-22 21:20:25.000000000 +0000
@@ -66,4 +66,7 @@ extern tree hook_tree_tree_tree_tree_3rd
 extern const char *hook_constcharptr_tree_null (tree);
 extern tree hook_tree_tree_tree_bool_null (tree, tree, bool);
 extern const char *hook_constcharptr_rtx_null (rtx);
+extern const char *hook_constcharptr_tree_tree_null (tree, tree);
+extern const char *hook_constcharptr_int_tree_null (int, tree);
+extern const char *hook_constcharptr_int_tree_tree_null (int, tree, tree);
 #endif
diff -rupN GCC.orig/gcc/target-def.h GCC/gcc/target-def.h
--- GCC.orig/gcc/target-def.h	2005-06-10 09:03:03.000000000 +0000
+++ GCC/gcc/target-def.h	2005-06-22 21:19:42.000000000 +0000
@@ -374,6 +374,10 @@ Foundation, 59 Temple Place - Suite 330,
 #define TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN hook_invalid_arg_for_unprototyped_fn
 #endif
 
+#define TARGET_INVALID_CONVERSION hook_constcharptr_tree_tree_null
+#define TARGET_INVALID_UNARY_OP hook_constcharptr_int_tree_null
+#define TARGET_INVALID_BINARY_OP hook_constcharptr_int_tree_tree_null
+
 #define TARGET_FIXED_CONDITION_CODE_REGS hook_bool_uintp_uintp_false
 
 #define TARGET_CC_MODES_COMPATIBLE default_cc_modes_compatible
@@ -566,6 +570,9 @@ Foundation, 59 Temple Place - Suite 330,
   TARGET_STDARG_OPTIMIZE_HOOK,			\
   TARGET_INVALID_WITHIN_DOLOOP,			\
   TARGET_CALLS,					\
+  TARGET_INVALID_CONVERSION,			\
+  TARGET_INVALID_UNARY_OP,			\
+  TARGET_INVALID_BINARY_OP,			\
   TARGET_CXX,					\
   TARGET_HAVE_NAMED_SECTIONS,			\
   TARGET_HAVE_CTORS_DTORS,			\
diff -rupN GCC.orig/gcc/target.h GCC/gcc/target.h
--- GCC.orig/gcc/target.h	2005-06-10 09:03:03.000000000 +0000
+++ GCC/gcc/target.h	2005-06-22 21:40:11.000000000 +0000
@@ -586,6 +586,18 @@ struct gcc_target
 					     	    tree funcdecl, tree val);
   } calls;
 
+  /* Return the diagnostic message string if conversion from FROMTYPE
+     to TOTYPE is not allowed, NULL otherwise.  */
+  const char *(*invalid_conversion) (tree fromtype, tree totype);
+
+  /* Return the diagnostic message string if the unary operation OP is
+     not permitted on TYPE, NULL otherwise.  */
+  const char *(*invalid_unary_op) (int op, tree type);
+
+  /* Return the diagnostic message string if the binary operation OP
+     is not permitted on TYPE1 and TYPE2, NULL otherwise.  */
+  const char *(*invalid_binary_op) (int op, tree type1, tree type2);
+
   /* Functions specific to the C++ frontend.  */
   struct cxx {
     /* Return the integer type used for guard variables.  */
diff -rupN GCC.orig/gcc/testsuite/g++.dg/ext/fpreg1.C GCC/gcc/testsuite/g++.dg/ext/fpreg1.C
--- GCC.orig/gcc/testsuite/g++.dg/ext/fpreg1.C	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/g++.dg/ext/fpreg1.C	2005-06-23 21:15:10.000000000 +0000
@@ -0,0 +1,82 @@
+// Test permitted and invalid uses of __fpreg, for C++.
+// Origin: Joseph Myers <joseph@codesourcery.com>
+// { dg-do compile { target ia64-*-* } }
+// { dg-options "" }
+
+__float80 f80;
+double d;
+// Default initialized __fpreg is OK.
+__fpreg fpreg, fpreg2;
+// But explicitly zero-initialized is an invalid conversion.
+__fpreg fi = 0; // { dg-error "error: invalid conversion to '__fpreg'" }
+
+__fpreg f0 (__fpreg);
+int f1 (__float80);
+
+// __fpreg in a structure is OK.
+struct s {
+  __float80 b;
+  __fpreg a;
+} x;
+
+void
+f (void)
+{
+  __fpreg *p;
+  // Valid operations.
+  fpreg = fpreg2;
+  fpreg2 = (__fpreg) fpreg;
+  fpreg = f0 (fpreg2);
+  fpreg = +fpreg2;
+  p = &fpreg;
+  (void) fpreg;
+  fpreg = x.a;
+  fpreg2 = (struct s) { 0 }.a;
+  fpreg = (d ? fpreg : fpreg2);
+  d = sizeof (fpreg);
+  (void)(fpreg, fpreg);
+  // Invalid operations.
+  ++fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  --fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  fpreg++; // { dg-error "error: invalid operation on '__fpreg'" }
+  fpreg--; // { dg-error "error: invalid operation on '__fpreg'" }
+  fpreg = -fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  fpreg = ~fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = !fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = *fpreg; // { dg-error "error: invalid type argument" }
+  if (fpreg) // { dg-error "error: invalid conversion from '__fpreg'" }
+    return;
+  d = fpreg; // { dg-error "error: invalid conversion from '__fpreg'" }
+  d = (double) fpreg; // { dg-error "error: invalid conversion from '__fpreg'" }
+  fpreg = (__fpreg) d; // { dg-error "error: invalid conversion to '__fpreg'" }
+  fpreg = fpreg * fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  fpreg = fpreg / fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  fpreg = fpreg % fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  fpreg = fpreg + fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  fpreg = fpreg - fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  fpreg = fpreg << fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  fpreg = fpreg >> fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = fpreg < fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = fpreg > fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = fpreg <= fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = fpreg >= fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = fpreg == fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = fpreg != fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = fpreg & fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = fpreg ^ fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = fpreg | fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = fpreg && fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = fpreg || fpreg; // { dg-error "error: invalid operation on '__fpreg'" }
+  d = (fpreg ? 1 : 2); // { dg-error "error: invalid conversion from '__fpreg'" }
+  fpreg = (d ? fpreg : d); // { dg-error "error: invalid conversion to '__fpreg'" }
+  fpreg *= fpreg; // { dg-error "error: invalid operation on '__fpreg'|in evaluation" }
+  fpreg /= fpreg; // { dg-error "error: invalid operation on '__fpreg'|in evaluation" }
+  fpreg %= fpreg; // { dg-error "error: invalid operation on '__fpreg'|in evaluation" }
+  fpreg += fpreg; // { dg-error "error: invalid operation on '__fpreg'|in evaluation" }
+  fpreg -= fpreg; // { dg-error "error: invalid operation on '__fpreg'|in evaluation" }
+  fpreg <<= fpreg; // { dg-error "error: invalid operation on '__fpreg'|in evaluation" }
+  fpreg >>= fpreg; // { dg-error "error: invalid operation on '__fpreg'|in evaluation" }
+  fpreg &= fpreg; // { dg-error "error: invalid operation on '__fpreg'|in evaluation" }
+  fpreg ^= fpreg; // { dg-error "error: invalid operation on '__fpreg'|in evaluation" }
+  fpreg |= fpreg; // { dg-error "error: invalid operation on '__fpreg'|in evaluation" }
+}
diff -rupN GCC.orig/gcc/testsuite/gcc.target/ia64/fpreg-1.c GCC/gcc/testsuite/gcc.target/ia64/fpreg-1.c
--- GCC.orig/gcc/testsuite/gcc.target/ia64/fpreg-1.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.target/ia64/fpreg-1.c	2005-06-23 21:12:08.000000000 +0000
@@ -0,0 +1,82 @@
+/* Test permitted and invalid uses of __fpreg.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+__float80 f80;
+double d;
+/* Default initialized __fpreg is OK.  */
+__fpreg fpreg, fpreg2;
+/* But explicitly zero-initialized is an invalid conversion.  */
+__fpreg fi = 0; /* { dg-error "error: invalid conversion to '__fpreg'" } */
+
+__fpreg f0 (__fpreg);
+int f1 (__float80);
+
+/* __fpreg in a structure is OK.  */
+struct s {
+  __float80 b;
+  __fpreg a;
+} x;
+
+void
+f (void)
+{
+  __fpreg *p;
+  /* Valid operations.  */
+  fpreg = fpreg2;
+  fpreg2 = (__fpreg) fpreg;
+  fpreg = f0 (fpreg2);
+  fpreg = +fpreg2;
+  p = &fpreg;
+  (void) fpreg;
+  fpreg = x.a;
+  fpreg2 = (struct s) { 0 }.a;
+  fpreg = (d ? fpreg : fpreg2);
+  d = sizeof (fpreg);
+  (void)(fpreg, fpreg);
+  /* Invalid operations.  */
+  ++fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  --fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg++; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg--; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg = -fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg = ~fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = !fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = *fpreg; /* { dg-error "error: invalid type argument" } */
+  if (fpreg) /* { dg-error "error: invalid operation on '__fpreg'" } */
+    return;
+  d = fpreg; /* { dg-error "error: invalid conversion from '__fpreg'" } */
+  d = (double) fpreg; /* { dg-error "error: invalid conversion from '__fpreg'" } */
+  fpreg = (__fpreg) d; /* { dg-error "error: invalid conversion to '__fpreg'" } */
+  fpreg = fpreg * fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg = fpreg / fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg = fpreg % fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg = fpreg + fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg = fpreg - fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg = fpreg << fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg = fpreg >> fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = fpreg < fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = fpreg > fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = fpreg <= fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = fpreg >= fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = fpreg == fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = fpreg != fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = fpreg & fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = fpreg ^ fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = fpreg | fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = fpreg && fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = fpreg || fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  d = (fpreg ? 1 : 2); /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg = (d ? fpreg : d); /* { dg-error "error: invalid conversion to '__fpreg'" } */
+  fpreg *= fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg /= fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg %= fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg += fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg -= fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg <<= fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg >>= fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg &= fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg ^= fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+  fpreg |= fpreg; /* { dg-error "error: invalid operation on '__fpreg'" } */
+}
diff -rupN GCC.orig/gcc/testsuite/gcc.target/ia64/fpreg-2.c GCC/gcc/testsuite/gcc.target/ia64/fpreg-2.c
--- GCC.orig/gcc/testsuite/gcc.target/ia64/fpreg-2.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.target/ia64/fpreg-2.c	2005-06-19 00:22:50.000000000 +0000
@@ -0,0 +1,21 @@
+/* Test __fpreg ABI.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-final { scan-assembler "ldf.fill" } } */
+/* { dg-final { scan-assembler "stf.spill" } } */
+
+__fpreg x;
+
+void f (void);
+
+void
+g (void)
+{
+  __fpreg b = x;
+  f ();
+  x = b;
+}
+
+char t1[(sizeof (__fpreg) == sizeof (__float80) ? 1 : -1)];
+char t2[(__alignof (__fpreg) == __alignof (__float80) ? 1 : -1)];

Attachment: fpreg-test.tar.gz
Description: Binary data


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]