From bc5e6ea1ac530e2099416c425cf4dd492421997b Mon Sep 17 00:00:00 2001 From: bergner Date: Sat, 26 Jan 2008 17:18:35 +0000 Subject: [PATCH] PR target/34814 * doc/tm.texi (TARGET_EXPAND_TO_RTL_HOOK): Document. (TARGET_INSTANTIATE_DECLS): Likewise. * target.h (expand_to_rtl_hook): New target hook. (instantiate_decls): Likewise. * function.c (instantiate_decl): Make non-static. Rename to... (instantiate_decl_rtl): ... this. (instantiate_expr): Use instantiate_decl_rtl. (instantiate_decls_1): Likewise. (instantiate_decls): Likewise. (instantiate_virtual_regs: Call new instantiate_decls taget hook. * function.h (instantiate_decl_rtl): Add prototype. * cfgexpand.c (target.h): New include. (tree_expand_cfg): Call new expand_to_rtl_hook target hook. * target-def.h (TARGET_EXPAND_TO_RTL_HOOK): New define. (TARGET_INSTANTIATE_DECLS): Likewise. (TARGET_INITIALIZER): New target hooks added. * config/rs6000/rs6000-protos.h (rs6000_secondary_memory_needed_rtx): New prototype. * config/rs6000/rs6000.c (tree-flow.h): New include. (machine_function): Add sdmode_stack_slot field. (rs6000_alloc_sdmode_stack_slot): New function. (rs6000_instantiate_decls): Likewise. (rs6000_secondary_memory_needed_rtx): Likewise. (rs6000_check_sdmode): Likewise. (TARGET_EXPAND_TO_RTL_HOOK): Target macro defined. (TARGET_INSTANTIATE_DECLS): Likewise. (rs6000_hard_regno_mode_ok): Allow SDmode. (num_insns_constant): Likewise. Handle _Decimal32 constants. (rs6000_emit_move): Handle SDmode. (function_arg_advance): Likewise. (function_arg): Likewise. (rs6000_gimplify_va_arg): Likewise. Add special handling of SDmode var args for 32-bit compiles. (rs6000_secondary_reload_class): Handle SDmode. (rs6000_output_function_epilogue): Likewise. (rs6000_function_value): Simplify if statement. (rs6000_libcall_value): Likewise. * config/rs6000/rs6000.h (SLOW_UNALIGNED_ACCESS): Handle SDmode. (SECONDARY_MEMORY_NEEDED_RTX): Add define. * config/rs6000/dfp.md (movsd): New define_expand and splitter. (movsd_hardfloat): New define_insn. (movsd_softfloat): Likewise. (movsd_store): Likewise. (movsd_load): Likewise. (extendsddd2): Likewise. (extendsdtd2): Likewise. (truncddsd2): Likewise. (movdd_hardfloat64): Fixup comment. (UNSPEC_MOVSD_LOAD): New constant. (UNSPEC_MOVSD_STORE): Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@131869 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 55 +++++++++ gcc/cfgexpand.c | 3 + gcc/config/rs6000/dfp.md | 134 ++++++++++++++++++++- gcc/config/rs6000/rs6000-protos.h | 1 + gcc/config/rs6000/rs6000.c | 240 +++++++++++++++++++++++++++++--------- gcc/config/rs6000/rs6000.h | 9 +- gcc/doc/tm.texi | 14 +++ gcc/function.c | 18 +-- gcc/function.h | 1 + gcc/target-def.h | 10 ++ gcc/target.h | 9 ++ 11 files changed, 429 insertions(+), 65 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 13135a9f5e9..6a6e9fc6e4a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,58 @@ +2007-01-26 Peter Bergner + Janis Johnson + + PR target/34814 + * doc/tm.texi (TARGET_EXPAND_TO_RTL_HOOK): Document. + (TARGET_INSTANTIATE_DECLS): Likewise. + * target.h (expand_to_rtl_hook): New target hook. + (instantiate_decls): Likewise. + * function.c (instantiate_decl): Make non-static. Rename to... + (instantiate_decl_rtl): ... this. + (instantiate_expr): Use instantiate_decl_rtl. + (instantiate_decls_1): Likewise. + (instantiate_decls): Likewise. + (instantiate_virtual_regs: Call new instantiate_decls taget hook. + * function.h (instantiate_decl_rtl): Add prototype. + * cfgexpand.c (target.h): New include. + (tree_expand_cfg): Call new expand_to_rtl_hook target hook. + * target-def.h (TARGET_EXPAND_TO_RTL_HOOK): New define. + (TARGET_INSTANTIATE_DECLS): Likewise. + (TARGET_INITIALIZER): New target hooks added. + * config/rs6000/rs6000-protos.h (rs6000_secondary_memory_needed_rtx): + New prototype. + * config/rs6000/rs6000.c (tree-flow.h): New include. + (machine_function): Add sdmode_stack_slot field. + (rs6000_alloc_sdmode_stack_slot): New function. + (rs6000_instantiate_decls): Likewise. + (rs6000_secondary_memory_needed_rtx): Likewise. + (rs6000_check_sdmode): Likewise. + (TARGET_EXPAND_TO_RTL_HOOK): Target macro defined. + (TARGET_INSTANTIATE_DECLS): Likewise. + (rs6000_hard_regno_mode_ok): Allow SDmode. + (num_insns_constant): Likewise. Handle _Decimal32 constants. + (rs6000_emit_move): Handle SDmode. + (function_arg_advance): Likewise. + (function_arg): Likewise. + (rs6000_gimplify_va_arg): Likewise. Add special handling of + SDmode var args for 32-bit compiles. + (rs6000_secondary_reload_class): Handle SDmode. + (rs6000_output_function_epilogue): Likewise. + (rs6000_function_value): Simplify if statement. + (rs6000_libcall_value): Likewise. + * config/rs6000/rs6000.h (SLOW_UNALIGNED_ACCESS): Handle SDmode. + (SECONDARY_MEMORY_NEEDED_RTX): Add define. + * config/rs6000/dfp.md (movsd): New define_expand and splitter. + (movsd_hardfloat): New define_insn. + (movsd_softfloat): Likewise. + (movsd_store): Likewise. + (movsd_load): Likewise. + (extendsddd2): Likewise. + (extendsdtd2): Likewise. + (truncddsd2): Likewise. + (movdd_hardfloat64): Fixup comment. + (UNSPEC_MOVSD_LOAD): New constant. + (UNSPEC_MOVSD_STORE): Likewise. + 2008-01-26 Jakub Jelinek PR c++/34965 diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 0a4e2ca91e6..d22facbabe3 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "tree-inline.h" #include "value-prof.h" +#include "target.h" /* Verify that there is exactly single jump instruction since last and attach REG_BR_PROB note specifying probability. @@ -1873,6 +1874,8 @@ tree_expand_cfg (void) /* Mark arrays indexed with non-constant indices with TREE_ADDRESSABLE. */ discover_nonconstant_array_refs (); + targetm.expand_to_rtl_hook (); + /* Expand the variables recorded during gimple lowering. */ expand_used_vars (); diff --git a/gcc/config/rs6000/dfp.md b/gcc/config/rs6000/dfp.md index fa20f7d0652..2d111b8df64 100644 --- a/gcc/config/rs6000/dfp.md +++ b/gcc/config/rs6000/dfp.md @@ -20,6 +20,138 @@ ;; along with GCC; see the file COPYING3. If not see ;; . +;; +;; UNSPEC usage +;; + +(define_constants + [(UNSPEC_MOVSD_LOAD 400) + (UNSPEC_MOVSD_STORE 401) + ]) + + +(define_expand "movsd" + [(set (match_operand:SD 0 "nonimmediate_operand" "") + (match_operand:SD 1 "any_operand" ""))] + "TARGET_HARD_FLOAT && TARGET_FPRS" + "{ rs6000_emit_move (operands[0], operands[1], SDmode); DONE; }") + +(define_split + [(set (match_operand:SD 0 "gpc_reg_operand" "") + (match_operand:SD 1 "const_double_operand" ""))] + "reload_completed + && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31) + || (GET_CODE (operands[0]) == SUBREG + && GET_CODE (SUBREG_REG (operands[0])) == REG + && REGNO (SUBREG_REG (operands[0])) <= 31))" + [(set (match_dup 2) (match_dup 3))] + " +{ + long l; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); + REAL_VALUE_TO_TARGET_DECIMAL32 (rv, l); + + if (! TARGET_POWERPC64) + operands[2] = operand_subword (operands[0], 0, 0, SDmode); + else + operands[2] = gen_lowpart (SImode, operands[0]); + + operands[3] = gen_int_mode (l, SImode); +}") + +(define_insn "movsd_hardfloat" + [(set (match_operand:SD 0 "nonimmediate_operand" "=r,r,m,f,*c*l,*q,!r,*h,!r,!r") + (match_operand:SD 1 "input_operand" "r,m,r,f,r,r,h,0,G,Fn"))] + "(gpc_reg_operand (operands[0], SDmode) + || gpc_reg_operand (operands[1], SDmode)) + && (TARGET_HARD_FLOAT && TARGET_FPRS)" + "@ + mr %0,%1 + {l%U1%X1|lwz%U1%X1} %0,%1 + {st%U0%X0|stw%U0%X0} %1,%0 + fmr %0,%1 + mt%0 %1 + mt%0 %1 + mf%1 %0 + {cror 0,0,0|nop} + # + #" + [(set_attr "type" "*,load,store,fp,mtjmpr,*,mfjmpr,*,*,*") + (set_attr "length" "4,4,4,4,4,4,4,4,4,8")]) + +(define_insn "movsd_softfloat" + [(set (match_operand:SD 0 "nonimmediate_operand" "=r,cl,q,r,r,m,r,r,r,r,r,*h") + (match_operand:SD 1 "input_operand" "r,r,r,h,m,r,I,L,R,G,Fn,0"))] + "(gpc_reg_operand (operands[0], SDmode) + || gpc_reg_operand (operands[1], SDmode)) + && (TARGET_SOFT_FLOAT || !TARGET_FPRS)" + "@ + mr %0,%1 + mt%0 %1 + mt%0 %1 + mf%1 %0 + {l%U1%X1|lwz%U1%X1} %0,%1 + {st%U0%X0|stw%U0%X0} %1,%0 + {lil|li} %0,%1 + {liu|lis} %0,%v1 + {cal|la} %0,%a1 + # + # + {cror 0,0,0|nop}" + [(set_attr "type" "*,mtjmpr,*,mfjmpr,load,store,*,*,*,*,*,*") + (set_attr "length" "4,4,4,4,4,4,4,4,4,4,8,4")]) + +(define_insn "movsd_store" + [(set (match_operand:DD 0 "nonimmediate_operand" "=m") + (unspec:DD [(match_operand:SD 1 "input_operand" "f")] + UNSPEC_MOVSD_STORE))] + "(gpc_reg_operand (operands[0], DDmode) + || gpc_reg_operand (operands[1], SDmode)) + && TARGET_HARD_FLOAT && TARGET_FPRS" + "stfd%U0%X0 %1,%0" + [(set_attr "type" "fpstore") + (set_attr "length" "4")]) + +(define_insn "movsd_load" + [(set (match_operand:SD 0 "nonimmediate_operand" "=f") + (unspec:SD [(match_operand:DD 1 "input_operand" "m")] + UNSPEC_MOVSD_LOAD))] + "(gpc_reg_operand (operands[0], SDmode) + || gpc_reg_operand (operands[1], DDmode)) + && TARGET_HARD_FLOAT && TARGET_FPRS" + "lfd%U1%X1 %0,%1" + [(set_attr "type" "fpload") + (set_attr "length" "4")]) + +;; Hardware support for decimal floating point operations. + +(define_insn "extendsddd2" + [(set (match_operand:DD 0 "gpc_reg_operand" "=f") + (float_extend:DD (match_operand:SD 1 "gpc_reg_operand" "f")))] + "TARGET_DFP" + "dctdp %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "extendsdtd2" + [(set (match_operand:TD 0 "gpc_reg_operand" "=f") + (float_extend:TD (match_operand:SD 1 "gpc_reg_operand" "f")))] + "TARGET_DFP" +{ + rtx tmp = gen_reg_rtx (DDmode); + emit_insn (gen_extendsddd2 (tmp, operands[1])); + emit_insn (gen_extendddtd2 (operands[0], tmp)); + DONE; +}) + +(define_insn "truncddsd2" + [(set (match_operand:SD 0 "gpc_reg_operand" "=f") + (float_truncate:SD (match_operand:DD 1 "gpc_reg_operand" "f")))] + "TARGET_DFP" + "drsp %0,%1" + [(set_attr "type" "fp")]) + (define_expand "negdd2" [(set (match_operand:DD 0 "gpc_reg_operand" "") (neg:DD (match_operand:DD 1 "gpc_reg_operand" "")))] @@ -309,7 +441,7 @@ (set_attr "length" "4,4,4,4,4,4,4,4,4,8,12,16,4,4")]) ; ld/std require word-aligned displacements -> 'Y' constraint. -; List Y->r and r->Y before r->r for reload.(define_insn "*movdd_hardfloat64" +; List Y->r and r->Y before r->r for reload. (define_insn "*movdd_hardfloat64" [(set (match_operand:DD 0 "nonimmediate_operand" "=Y,r,!r,f,f,m,*c*l,!r,*h,!r,!r,!r") (match_operand:DD 1 "input_operand" "r,Y,r,f,m,f,r,h,0,G,H,F"))] diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 4c031e7de63..762f784ed69 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -103,6 +103,7 @@ extern void rs6000_fatal_bad_address (rtx); extern rtx create_TOC_reference (rtx); extern void rs6000_split_multireg_move (rtx, rtx); extern void rs6000_emit_move (rtx, rtx, enum machine_mode); +extern rtx rs6000_secondary_memory_needed_rtx (enum machine_mode); extern rtx rs6000_legitimize_address (rtx, rtx, enum machine_mode); extern rtx rs6000_legitimize_reload_address (rtx, enum machine_mode, int, int, int, int *); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 83d8dbdc0d9..586c4814668 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -53,6 +53,7 @@ #include "cfglayout.h" #include "sched-int.h" #include "tree-gimple.h" +#include "tree-flow.h" #include "intl.h" #include "params.h" #include "tm-constrs.h" @@ -125,6 +126,10 @@ typedef struct machine_function GTY(()) /* Offset from virtual_stack_vars_rtx to the start of the ABI_V4 varargs save area. */ HOST_WIDE_INT varargs_save_offset; + /* Temporary stack slot to use for SDmode copies. This slot is + 64-bits wide and is allocated early enough so that the offset + does not overflow the 16-bit load/store offset field. */ + rtx sdmode_stack_slot; } machine_function; /* Target cpu type */ @@ -754,6 +759,8 @@ static void rs6000_elf_encode_section_info (tree, rtx, int) ATTRIBUTE_UNUSED; #endif static bool rs6000_use_blocks_for_constant_p (enum machine_mode, const_rtx); +static void rs6000_alloc_sdmode_stack_slot (void); +static void rs6000_instantiate_decls (void); #if TARGET_XCOFF static void rs6000_xcoff_asm_output_anchor (rtx); static void rs6000_xcoff_asm_globalize_label (FILE *, const char *); @@ -1221,6 +1228,12 @@ static const char alt_reg_names[][8] = #undef TARGET_BUILTIN_RECIPROCAL #define TARGET_BUILTIN_RECIPROCAL rs6000_builtin_reciprocal +#undef TARGET_EXPAND_TO_RTL_HOOK +#define TARGET_EXPAND_TO_RTL_HOOK rs6000_alloc_sdmode_stack_slot + +#undef TARGET_INSTANTIATE_DECLS +#define TARGET_INSTANTIATE_DECLS rs6000_instantiate_decls + struct gcc_target targetm = TARGET_INITIALIZER; @@ -1240,7 +1253,6 @@ rs6000_hard_regno_mode_ok (int regno, enum machine_mode mode) return ((SCALAR_FLOAT_MODE_P (mode) && (mode != TDmode || (regno % 2) == 0) - && mode != SDmode && FP_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1)) || (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD) @@ -2460,13 +2472,16 @@ num_insns_constant (rtx op, enum machine_mode mode) return num_insns_constant_wide (INTVAL (op)); case CONST_DOUBLE: - if (mode == SFmode) + if (mode == SFmode || mode == SDmode) { long l; REAL_VALUE_TYPE rv; REAL_VALUE_FROM_CONST_DOUBLE (rv, op); - REAL_VALUE_TO_TARGET_SINGLE (rv, l); + if (DECIMAL_FLOAT_MODE_P (mode)) + REAL_VALUE_TO_TARGET_DECIMAL32 (rv, l); + else + REAL_VALUE_TO_TARGET_SINGLE (rv, l); return num_insns_constant_wide ((HOST_WIDE_INT) l); } @@ -4697,6 +4712,55 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode) return; } + if (reload_in_progress && cfun->machine->sdmode_stack_slot != NULL_RTX) + cfun->machine->sdmode_stack_slot = + eliminate_regs (cfun->machine->sdmode_stack_slot, VOIDmode, NULL_RTX); + + if (reload_in_progress + && mode == SDmode + && MEM_P (operands[0]) + && rtx_equal_p (operands[0], cfun->machine->sdmode_stack_slot) + && REG_P (operands[1])) + { + if (FP_REGNO_P (REGNO (operands[1]))) + { + rtx mem = adjust_address_nv (operands[0], DDmode, 0); + mem = eliminate_regs (mem, VOIDmode, NULL_RTX); + emit_insn (gen_movsd_store (mem, operands[1])); + } + else if (INT_REGNO_P (REGNO (operands[1]))) + { + rtx mem = adjust_address_nv (operands[0], mode, 4); + mem = eliminate_regs (mem, VOIDmode, NULL_RTX); + emit_insn (gen_movsd_hardfloat (mem, operands[1])); + } + else + gcc_unreachable(); + return; + } + if (reload_in_progress + && mode == SDmode + && REG_P (operands[0]) + && MEM_P (operands[1]) + && rtx_equal_p (operands[1], cfun->machine->sdmode_stack_slot)) + { + if (FP_REGNO_P (REGNO (operands[0]))) + { + rtx mem = adjust_address_nv (operands[1], DDmode, 0); + mem = eliminate_regs (mem, VOIDmode, NULL_RTX); + emit_insn (gen_movsd_load (operands[0], mem)); + } + else if (INT_REGNO_P (REGNO (operands[0]))) + { + rtx mem = adjust_address_nv (operands[1], mode, 4); + mem = eliminate_regs (mem, VOIDmode, NULL_RTX); + emit_insn (gen_movsd_hardfloat (operands[0], mem)); + } + else + gcc_unreachable(); + return; + } + /* FIXME: In the long term, this switch statement should go away and be replaced by a sequence of tests based on things like mode == Pmode. */ @@ -4717,6 +4781,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode) case DFmode: case DDmode: case SFmode: + case SDmode: if (CONSTANT_P (operands[1]) && ! easy_fp_constant (operands[1], mode)) operands[1] = force_const_mem (mode, operands[1]); @@ -4929,7 +4994,6 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode) /* Nonzero if we can use a floating-point register to pass this arg. */ #define USE_FP_FOR_ARG_P(CUM,MODE,TYPE) \ (SCALAR_FLOAT_MODE_P (MODE) \ - && (MODE) != SDmode \ && (CUM)->fregno <= FP_ARG_MAX_REG \ && TARGET_HARD_FLOAT && TARGET_FPRS) @@ -5409,7 +5473,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, { if (TARGET_HARD_FLOAT && TARGET_FPRS && (mode == SFmode || mode == DFmode - || mode == DDmode || mode == TDmode + || mode == SDmode || mode == DDmode || mode == TDmode || (mode == TFmode && !TARGET_IEEEQUAD))) { /* _Decimal128 must use an even/odd register pair. This assumes @@ -5476,7 +5540,6 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, cum->words = align_words + n_words; if (SCALAR_FLOAT_MODE_P (mode) - && mode != SDmode && TARGET_HARD_FLOAT && TARGET_FPRS) { /* _Decimal128 must be passed in an even/odd float register pair. @@ -5978,7 +6041,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, if (TARGET_HARD_FLOAT && TARGET_FPRS && (mode == SFmode || mode == DFmode || (mode == TFmode && !TARGET_IEEEQUAD) - || mode == DDmode || mode == TDmode)) + || mode == SDmode || mode == DDmode || mode == TDmode)) { /* _Decimal128 must use an even/odd register pair. This assumes that the register number is odd when fregno is odd. */ @@ -6652,6 +6715,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode || TYPE_MODE (type) == TFmode + || TYPE_MODE (type) == SDmode || TYPE_MODE (type) == DDmode || TYPE_MODE (type) == TDmode)) { @@ -6660,7 +6724,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) n_reg = (size + 7) / 8; sav_ofs = 8*4; sav_scale = 8; - if (TYPE_MODE (type) != SFmode) + if (TYPE_MODE (type) != SFmode && TYPE_MODE (type) != SDmode) align = 8; } else @@ -6724,6 +6788,11 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) u = build2 (MULT_EXPR, sizetype, u, size_int (sav_scale)); t = build2 (POINTER_PLUS_EXPR, ptr_type_node, t, u); + /* _Decimal32 varargs are located in the second word of the 64-bit + FP register for 32-bit binaries. */ + if (!TARGET_POWERPC64 && TYPE_MODE (type) == SDmode) + t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (size)); + t = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, t); gimplify_and_add (t, pre_p); @@ -11055,6 +11124,106 @@ mems_ok_for_quad_peep (rtx mem1, rtx mem2) return 1; } + +rtx +rs6000_secondary_memory_needed_rtx (enum machine_mode mode) +{ + static bool eliminated = false; + if (mode != SDmode) + return assign_stack_local (mode, GET_MODE_SIZE (mode), 0); + else + { + rtx mem = cfun->machine->sdmode_stack_slot; + gcc_assert (mem != NULL_RTX); + + if (!eliminated) + { + mem = eliminate_regs (mem, VOIDmode, NULL_RTX); + cfun->machine->sdmode_stack_slot = mem; + eliminated = true; + } + return mem; + } +} + +static tree +rs6000_check_sdmode (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) +{ + /* Don't walk into types. */ + if (*tp == NULL_TREE || *tp == error_mark_node || TYPE_P (*tp)) + { + *walk_subtrees = 0; + return NULL_TREE; + } + + switch (TREE_CODE (*tp)) + { + case VAR_DECL: + case PARM_DECL: + case FIELD_DECL: + case RESULT_DECL: + case REAL_CST: + if (TYPE_MODE (TREE_TYPE (*tp)) == SDmode) + return *tp; + break; + default: + break; + } + + return NULL_TREE; +} + + +/* Allocate a 64-bit stack slot to be used for copying SDmode + values through if this function has any SDmode references. */ + +static void +rs6000_alloc_sdmode_stack_slot (void) +{ + tree t; + basic_block bb; + block_stmt_iterator bsi; + + gcc_assert (cfun->machine->sdmode_stack_slot == NULL_RTX); + + FOR_EACH_BB (bb) + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree ret = walk_tree_without_duplicates (bsi_stmt_ptr (bsi), + rs6000_check_sdmode, NULL); + if (ret) + { + rtx stack = assign_stack_local (DDmode, GET_MODE_SIZE (DDmode), 0); + cfun->machine->sdmode_stack_slot = adjust_address_nv (stack, + SDmode, 0); + return; + } + } + + /* Check for any SDmode parameters of the function. */ + for (t = DECL_ARGUMENTS (cfun->decl); t; t = TREE_CHAIN (t)) + { + if (TREE_TYPE (t) == error_mark_node) + continue; + + if (TYPE_MODE (TREE_TYPE (t)) == SDmode + || TYPE_MODE (DECL_ARG_TYPE (t)) == SDmode) + { + rtx stack = assign_stack_local (DDmode, GET_MODE_SIZE (DDmode), 0); + cfun->machine->sdmode_stack_slot = adjust_address_nv (stack, + SDmode, 0); + return; + } + } +} + +static void +rs6000_instantiate_decls (void) +{ + if (cfun->machine->sdmode_stack_slot != NULL_RTX) + instantiate_decl_rtl (cfun->machine->sdmode_stack_slot); +} + /* Return the register class of a scratch register needed to copy IN into or out of a register in CLASS in MODE. If it can be done directly, NO_REGS is returned. */ @@ -11115,7 +11284,7 @@ rs6000_secondary_reload_class (enum reg_class class, /* Constants, memory, and FP registers can go into FP registers. */ if ((regno == -1 || FP_REGNO_P (regno)) && (class == FLOAT_REGS || class == NON_SPECIAL_REGS)) - return NO_REGS; + return (mode != SDmode) ? NO_REGS : GENERAL_REGS; /* Memory, and AltiVec registers can go into AltiVec registers. */ if ((regno == -1 || ALTIVEC_REGNO_P (regno)) @@ -16727,6 +16896,7 @@ rs6000_output_function_epilogue (FILE *file, switch (mode) { case SFmode: + case SDmode: bits = 0x2; break; @@ -21513,29 +21683,9 @@ rs6000_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED) || POINTER_TYPE_P (valtype)) mode = TARGET_32BIT ? SImode : DImode; - if (DECIMAL_FLOAT_MODE_P (mode)) - { - if (TARGET_HARD_FLOAT && TARGET_FPRS) - { - switch (mode) - { - default: - gcc_unreachable (); - case SDmode: - regno = GP_ARG_RETURN; - break; - case DDmode: - regno = FP_ARG_RETURN; - break; - case TDmode: - /* Use f2:f3 specified by the ABI. */ - regno = FP_ARG_RETURN + 1; - break; - } - } - else - regno = GP_ARG_RETURN; - } + if (DECIMAL_FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS) + /* _Decimal128 must use an even/odd register pair. */ + regno = (mode == TDmode) ? FP_ARG_RETURN + 1 : FP_ARG_RETURN; else if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS) regno = FP_ARG_RETURN; else if (TREE_CODE (valtype) == COMPLEX_TYPE @@ -21576,29 +21726,9 @@ rs6000_libcall_value (enum machine_mode mode) GEN_INT (4)))); } - if (DECIMAL_FLOAT_MODE_P (mode)) - { - if (TARGET_HARD_FLOAT && TARGET_FPRS) - { - switch (mode) - { - default: - gcc_unreachable (); - case SDmode: - regno = GP_ARG_RETURN; - break; - case DDmode: - regno = FP_ARG_RETURN; - break; - case TDmode: - /* Use f2:f3 specified by the ABI. */ - regno = FP_ARG_RETURN + 1; - break; - } - } - else - regno = GP_ARG_RETURN; - } + if (DECIMAL_FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS) + /* _Decimal128 must use an even/odd register pair. */ + regno = (mode == TDmode) ? FP_ARG_RETURN + 1 : FP_ARG_RETURN; else if (SCALAR_FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS) regno = FP_ARG_RETURN; diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index f820cf06e76..6a64eae3dd9 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -622,7 +622,7 @@ extern enum rs6000_nop_insertion rs6000_sched_insert_nops; #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) \ (STRICT_ALIGNMENT \ || (((MODE) == SFmode || (MODE) == DFmode || (MODE) == TFmode \ - || (MODE) == DDmode || (MODE) == TDmode \ + || (MODE) == SDmode || (MODE) == DDmode || (MODE) == TDmode \ || (MODE) == DImode) \ && (ALIGN) < 32)) @@ -1173,6 +1173,13 @@ enum reg_class || (CLASS1) == ALTIVEC_REGS \ || (CLASS2) == ALTIVEC_REGS)) +/* For cpus that cannot load/store SDmode values from the 64-bit + FP registers without using a full 64-bit load/store, we need + to allocate a full 64-bit stack slot for them. */ + +#define SECONDARY_MEMORY_NEEDED_RTX(MODE) \ + rs6000_secondary_memory_needed_rtx (MODE) + /* Return the maximum number of consecutive registers needed to represent mode MODE in a register of class CLASS. diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index e6449225e82..74aa90c251f 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -1502,6 +1502,20 @@ Returns true if the target supports decimal floating point. Returns true if the target supports fixed-point arithmetic. @end deftypefn +@deftypefn {Target Hook} void TARGET_EXPAND_TO_RTL_HOOK (void) +This hook is called just before expansion into rtl, allowing the target +to perform additional initializations or analysis before the expansion. +For example, the rs6000 port uses it to allocate a scratch stack slot +for use in copying SDmode values between memory and floating point +registers whenever the function being expanded has any SDmode +usage. +@end deftypefn + +@deftypefn {Target Hook} void TARGET_INSTANTIATE_DECLS (void) +This hook allows the backend to perform additional instantiations on rtl +that are not actually in any insns yet, but will be later. +@end deftypefn + @deftypefn {Target Hook} {const char *} TARGET_MANGLE_TYPE (tree @var{type}) If your target defines any fundamental types, or any types your target uses should be mangled differently from the default, define this hook diff --git a/gcc/function.c b/gcc/function.c index d89a0405924..401bb21bac6 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -1568,8 +1568,8 @@ instantiate_virtual_regs_in_insn (rtx insn) /* Subroutine of instantiate_decls. Given RTL representing a decl, do any instantiation required. */ -static void -instantiate_decl (rtx x) +void +instantiate_decl_rtl (rtx x) { rtx addr; @@ -1579,8 +1579,8 @@ instantiate_decl (rtx x) /* If this is a CONCAT, recurse for the pieces. */ if (GET_CODE (x) == CONCAT) { - instantiate_decl (XEXP (x, 0)); - instantiate_decl (XEXP (x, 1)); + instantiate_decl_rtl (XEXP (x, 0)); + instantiate_decl_rtl (XEXP (x, 1)); return; } @@ -1610,7 +1610,7 @@ instantiate_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) { *walk_subtrees = 0; if (DECL_P (t) && DECL_RTL_SET_P (t)) - instantiate_decl (DECL_RTL (t)); + instantiate_decl_rtl (DECL_RTL (t)); } return NULL; } @@ -1626,7 +1626,7 @@ instantiate_decls_1 (tree let) for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t)) { if (DECL_RTL_SET_P (t)) - instantiate_decl (DECL_RTL (t)); + instantiate_decl_rtl (DECL_RTL (t)); if (TREE_CODE (t) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (t)) { tree v = DECL_VALUE_EXPR (t); @@ -1650,8 +1650,8 @@ instantiate_decls (tree fndecl) /* Process all parameters of the function. */ for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl)) { - instantiate_decl (DECL_RTL (decl)); - instantiate_decl (DECL_INCOMING_RTL (decl)); + instantiate_decl_rtl (DECL_RTL (decl)); + instantiate_decl_rtl (DECL_INCOMING_RTL (decl)); if (DECL_HAS_VALUE_EXPR_P (decl)) { tree v = DECL_VALUE_EXPR (decl); @@ -1715,6 +1715,8 @@ instantiate_virtual_regs (void) /* Instantiate the virtual registers in the DECLs for debugging purposes. */ instantiate_decls (current_function_decl); + targetm.instantiate_decls (); + /* Indicate that, from now on, assign_stack_local should use frame_pointer_rtx. */ virtuals_instantiated = 1; diff --git a/gcc/function.h b/gcc/function.h index abc2303bcf7..fbaa17d0d47 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -491,6 +491,7 @@ extern int trampolines_created; extern void set_cfun (struct function *new_cfun); extern void push_cfun (struct function *new_cfun); extern void pop_cfun (void); +extern void instantiate_decl_rtl (rtx x); /* For backward compatibility... eventually these should all go away. */ #define current_function_pops_args (cfun->pops_args) diff --git a/gcc/target-def.h b/gcc/target-def.h index e15b5d9cc09..118e9791b19 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -604,6 +604,14 @@ #define TARGET_SECONDARY_RELOAD default_secondary_reload #endif +#ifndef TARGET_EXPAND_TO_RTL_HOOK +#define TARGET_EXPAND_TO_RTL_HOOK hook_void_void +#endif + +#ifndef TARGET_INSTANTIATE_DECLS +#define TARGET_INSTANTIATE_DECLS hook_void_void +#endif + /* C specific. */ #ifndef TARGET_C_MODE_FOR_SUFFIX #define TARGET_C_MODE_FOR_SUFFIX default_mode_for_suffix @@ -771,6 +779,8 @@ TARGET_INVALID_UNARY_OP, \ TARGET_INVALID_BINARY_OP, \ TARGET_SECONDARY_RELOAD, \ + TARGET_EXPAND_TO_RTL_HOOK, \ + TARGET_INSTANTIATE_DECLS, \ TARGET_C, \ TARGET_CXX, \ TARGET_EXTRA_LIVE_ON_ENTRY, \ diff --git a/gcc/target.h b/gcc/target.h index 12b01da362c..128a0292a15 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -849,6 +849,15 @@ struct gcc_target enum machine_mode, struct secondary_reload_info *); + /* This target hook allows the backend to perform additional + processing while initializing for variable expansion. */ + void (* expand_to_rtl_hook) (void); + + /* This target hook allows the backend to perform additional + instantiations on rtx that are not actually in insns yet, + but will be later. */ + void (* instantiate_decls) (void); + /* Functions specific to the C family of frontends. */ struct c { /* Return machine mode for non-standard suffix -- 2.11.4.GIT