From 7a979707f55fcaf9f028bba6c7a39dd169329dd3 Mon Sep 17 00:00:00 2001 From: jsm28 Date: Tue, 28 Jun 2005 21:55:24 +0000 Subject: [PATCH 1/1] * 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: * 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: * g++.dg/ext/fpreg1.C, gcc.target/ia64/fpreg-1.c, gcc.target/ia64/fpreg-2.c: New tests. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@101391 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 36 ++++++ gcc/c-convert.c | 18 ++- gcc/c-typeck.c | 16 +++ gcc/config/ia64/ia64-modes.def | 11 +- gcc/config/ia64/ia64-protos.h | 2 +- gcc/config/ia64/ia64.c | 202 ++++++++++++++++++++++++++++++-- gcc/config/ia64/ia64.md | 137 ++++------------------ gcc/cp/ChangeLog | 6 + gcc/cp/cvt.c | 9 ++ gcc/cp/typeck.c | 19 +++ gcc/doc/tm.texi | 20 ++++ gcc/hooks.c | 22 ++++ gcc/hooks.h | 3 + gcc/target-def.h | 7 ++ gcc/target.h | 12 ++ gcc/testsuite/ChangeLog | 5 + gcc/testsuite/g++.dg/ext/fpreg1.C | 82 +++++++++++++ gcc/testsuite/gcc.target/ia64/fpreg-1.c | 82 +++++++++++++ gcc/testsuite/gcc.target/ia64/fpreg-2.c | 21 ++++ 19 files changed, 578 insertions(+), 132 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/fpreg1.C create mode 100644 gcc/testsuite/gcc.target/ia64/fpreg-1.c create mode 100644 gcc/testsuite/gcc.target/ia64/fpreg-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 225451d70f8..cb6775571ae 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,39 @@ +2005-06-28 Joseph S. Myers + + * 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. + 2006-06-28 Adrian Straetling * builtins.c: (expand_builtin_memset): Rewrite to support diff --git a/gcc/c-convert.c b/gcc/c-convert.c index 8b783838b1c..50bb923bae2 100644 --- a/gcc/c-convert.c +++ b/gcc/c-convert.c @@ -36,6 +36,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #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 --git a/gcc/c-typeck.c b/gcc/c-typeck.c index da826d44114..34f94d14205 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -2501,12 +2501,20 @@ build_unary_op (enum tree_code code, tree xarg, int flag) 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: @@ -7397,6 +7405,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, 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, @@ -7472,6 +7481,13 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, 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 --git a/gcc/config/ia64/ia64-modes.def b/gcc/config/ia64/ia64-modes.def index 04e41080b3f..c7e992777a4 100644 --- a/gcc/config/ia64/ia64-modes.def +++ b/gcc/config/ia64/ia64-modes.def @@ -23,9 +23,12 @@ Boston, MA 02110-1301, 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 && !TARGET_HPUX) 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 --git a/gcc/config/ia64/ia64-protos.h b/gcc/config/ia64/ia64-protos.h index 1fe645b1266..86846495def 100644 --- a/gcc/config/ia64/ia64-protos.h +++ b/gcc/config/ia64/ia64-protos.h @@ -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 --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 5109d4f768b..7ebe2938d75 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -52,6 +52,7 @@ Boston, MA 02110-1301, 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 (enum machine_mode mode); 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_attribute_table[] = #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. */ @@ -3839,9 +3976,9 @@ ia64_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, 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, @@ -4159,7 +4296,7 @@ ia64_function_value (tree valtype, tree func ATTRIBUTE_UNUSED) 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) @@ -4574,7 +4711,7 @@ ia64_register_move_cost (enum machine_mode mode, enum reg_class from, 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); @@ -8058,9 +8195,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"); @@ -8549,6 +8684,7 @@ ia64_scalar_mode_supported_p (enum machine_mode mode) case SFmode: case DFmode: case XFmode: + case RFmode: return true; case TFmode: @@ -8659,6 +8795,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 --git a/gcc/config/ia64/ia64.md b/gcc/config/ia64/ia64.md index 57cd70beba5..18e6cb3ace6 100644 --- a/gcc/config/ia64/ia64.md +++ b/gcc/config/ia64/ia64.md @@ -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 --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 128ea648dfe..a9736222b87 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2005-06-28 Joseph S. Myers + + * 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. + 2005-06-28 Paul Brook * Make-lang.in (cp/except.o): Depend on $(TARGET_H) diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 5b4cc3b61fa..de0792aca47 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -36,6 +36,7 @@ Boston, MA 02110-1301, 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 convtype, int flags) { 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 convtype, int flags) 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 --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index edf1519f965..32d3f0439d5 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2736,6 +2736,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, 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, @@ -2845,6 +2846,13 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, 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: @@ -3725,10 +3733,21 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) 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 --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index bbca6b9a699..dca9ad63459 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -9606,6 +9606,26 @@ illegal to pass argument @var{val} to function @var{funcdecl} 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 --git a/gcc/hooks.c b/gcc/hooks.c index 65b347e3fea..78871a47858 100644 --- a/gcc/hooks.c +++ b/gcc/hooks.c @@ -256,3 +256,25 @@ hook_constcharptr_rtx_null (rtx r ATTRIBUTE_UNUSED) { 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 --git a/gcc/hooks.h b/gcc/hooks.h index 318af087ce0..eebda9a41fd 100644 --- a/gcc/hooks.h +++ b/gcc/hooks.h @@ -66,4 +66,7 @@ extern tree hook_tree_tree_tree_tree_3rd_identity (tree, tree, tree); 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 --git a/gcc/target-def.h b/gcc/target-def.h index 9998a19b5aa..447b5c3cd92 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -379,6 +379,10 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #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 @@ -581,6 +585,9 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. TARGET_STACK_PROTECT_FAIL, \ TARGET_INVALID_WITHIN_DOLOOP, \ TARGET_CALLS, \ + TARGET_INVALID_CONVERSION, \ + TARGET_INVALID_UNARY_OP, \ + TARGET_INVALID_BINARY_OP, \ TARGET_CXX, \ TARGET_UNWIND_TABLES_DEFAULT, \ TARGET_HAVE_NAMED_SECTIONS, \ diff --git a/gcc/target.h b/gcc/target.h index 364e95afbbd..65e50caef29 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -598,6 +598,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 --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 39a5c27821d..1794a3bd268 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-06-28 Joseph S. Myers + + * g++.dg/ext/fpreg1.C, gcc.target/ia64/fpreg-1.c, + gcc.target/ia64/fpreg-2.c: New tests. + 2005-06-28 Francois-Xavier Coudert * gfortran.dg/dev_null.f90: Run test only on linux and solaris. diff --git a/gcc/testsuite/g++.dg/ext/fpreg1.C b/gcc/testsuite/g++.dg/ext/fpreg1.C new file mode 100644 index 00000000000..72b81134fb8 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/fpreg1.C @@ -0,0 +1,82 @@ +// Test permitted and invalid uses of __fpreg, for C++. +// Origin: Joseph Myers +// { 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 --git a/gcc/testsuite/gcc.target/ia64/fpreg-1.c b/gcc/testsuite/gcc.target/ia64/fpreg-1.c new file mode 100644 index 00000000000..022fb94461e --- /dev/null +++ b/gcc/testsuite/gcc.target/ia64/fpreg-1.c @@ -0,0 +1,82 @@ +/* Test permitted and invalid uses of __fpreg. */ +/* Origin: Joseph Myers */ +/* { 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 --git a/gcc/testsuite/gcc.target/ia64/fpreg-2.c b/gcc/testsuite/gcc.target/ia64/fpreg-2.c new file mode 100644 index 00000000000..a21bd0fb231 --- /dev/null +++ b/gcc/testsuite/gcc.target/ia64/fpreg-2.c @@ -0,0 +1,21 @@ +/* Test __fpreg ABI. */ +/* Origin: Joseph Myers */ +/* { 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)]; -- 2.11.0