diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000.c')
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 240 |
1 files changed, 185 insertions, 55 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 83d8dbd..586c481 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; |