[PATCH][UPDATED] PR target/34814 Force SDmode function args into FP registers per the ABI
Peter Bergner
bergner@vnet.ibm.com
Fri Jan 25 10:06:00 GMT 2008
On Thu, Jan 24, 2008 at 11:54:41AM -0800, Ian Lance Taylor wrote:
> I'm not very good with names. This is really a hook--it doesn't
> really have anything to do with variables--so maybe something like
> expand_to_rtl_hook? I hope somebody else has a better suggestion.
Ian / David,
Here's an updated patch that I'm bootstrapping and regtesting now.
Is this ok assuming no bootstrap or regresstion problems?
Peter
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 (UNSPEC_MOVSD_LOAD): New constant.
(UNSPEC_MOVSD_STORE): Likewise.
(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.
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi (revision 131741)
+++ gcc/doc/tm.texi (working copy)
@@ -1507,6 +1507,20 @@ Returns true if the target supports deci
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
Index: gcc/target.h
===================================================================
--- gcc/target.h (revision 131741)
+++ gcc/target.h (working copy)
@@ -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
Index: gcc/function.c
===================================================================
--- gcc/function.c (revision 131741)
+++ gcc/function.c (working copy)
@@ -1568,8 +1568,8 @@ instantiate_virtual_regs_in_insn (rtx in
/* 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_su
{
*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;
Index: gcc/function.h
===================================================================
--- gcc/function.h (revision 131741)
+++ gcc/function.h (working copy)
@@ -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)
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c (revision 131741)
+++ gcc/cfgexpand.c (working copy)
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.
#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 ();
Index: gcc/target-def.h
===================================================================
--- gcc/target-def.h (revision 131741)
+++ gcc/target-def.h (working copy)
@@ -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, \
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h (revision 131741)
+++ gcc/config/rs6000/rs6000-protos.h (working copy)
@@ -103,6 +103,7 @@ extern void rs6000_fatal_bad_address (rt
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 *);
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c (revision 131741)
+++ gcc/config/rs6000/rs6000.c (working copy)
@@ -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_in
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, en
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
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,
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,
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,
/* 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 *c
{
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 *c
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
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, tre
&& (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, tre
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, tre
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 mem
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. */
@@ -11106,6 +11275,22 @@ rs6000_secondary_reload_class (enum reg_
else
regno = -1;
+ if ((class != NO_REGS) && (mode == SDmode))
+ {
+ if (class == FLOAT_REGS)
+ {
+ if (regno == -1 || FP_REGNO_P (regno))
+ return GENERAL_REGS;
+ return NO_REGS;
+ }
+ else if (class == GENERAL_REGS
+ || class == BASE_REGS
+ || class == SPECIAL_REGS)
+ return NO_REGS;
+
+ gcc_unreachable();
+ }
+
/* We can place anything into GENERAL_REGS and can put GENERAL_REGS
into anything. */
if (class == GENERAL_REGS || class == BASE_REGS
@@ -16727,6 +16912,7 @@ rs6000_output_function_epilogue (FILE *f
switch (mode)
{
case SFmode:
+ case SDmode:
bits = 0x2;
break;
@@ -21513,29 +21699,9 @@ rs6000_function_value (const_tree valtyp
|| 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 +21742,9 @@ rs6000_libcall_value (enum machine_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;
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h (revision 131741)
+++ gcc/config/rs6000/rs6000.h (working copy)
@@ -622,7 +622,7 @@ extern enum rs6000_nop_insertion rs6000_
#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.
Index: gcc/config/rs6000/dfp.md
===================================================================
--- gcc/config/rs6000/dfp.md (revision 131741)
+++ gcc/config/rs6000/dfp.md (working copy)
@@ -20,6 +20,138 @@
;; along with GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>.
+;;
+;; 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 @@ (define_insn "*movdd_hardfloat64_mfpgpr"
(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"))]
More information about the Gcc-patches
mailing list