int toc_save_p; /* true if the TOC needs to be saved */
int push_p; /* true if we need to allocate stack space */
int calls_p; /* true if the function makes any calls */
+ int world_save_p; /* true if we're saving *everything*:
+ r13-r31, cr, f14-f31, vrsave, v20-v31 */
enum rs6000_abi abi; /* which ABI to use */
int gp_save_offset; /* offset to save GP regs from initial SP */
int fp_save_offset; /* offset to save FP regs from initial SP */
/* ABI string from -mabi= option. */
const char *rs6000_abi_string;
+/* Whether to use variant of AIX ABI for PowerPC64 Linux. */
+int dot_symbols;
+
/* Debug flags */
const char *rs6000_debug_name;
int rs6000_debug_stack; /* debug stack applications */
const char *const name;
const enum rs6000_builtins code;
};
+\f
+/* Target cpu costs. */
+
+struct processor_costs {
+ const int mulsi; /* cost of SImode multiplication. */
+ const int mulsi_const; /* cost of SImode multiplication by constant. */
+ const int mulsi_const9; /* cost of SImode mult by short constant. */
+ const int muldi; /* cost of DImode multiplication. */
+ const int divsi; /* cost of SImode division. */
+ const int divdi; /* cost of DImode division. */
+ const int fp; /* cost of simple SFmode and DFmode insns. */
+ const int dmul; /* cost of DFmode multiplication (and fmadd). */
+ const int sdiv; /* cost of SFmode division (fdivs). */
+ const int ddiv; /* cost of DFmode division (fdiv). */
+};
+
+const struct processor_costs *rs6000_cost;
+
+/* Processor costs (relative to an add) */
+
+/* Instruction size costs on 32bit processors. */
+static const
+struct processor_costs size32_cost = {
+ COSTS_N_INSNS (1), /* mulsi */
+ COSTS_N_INSNS (1), /* mulsi_const */
+ COSTS_N_INSNS (1), /* mulsi_const9 */
+ COSTS_N_INSNS (1), /* muldi */
+ COSTS_N_INSNS (1), /* divsi */
+ COSTS_N_INSNS (1), /* divdi */
+ COSTS_N_INSNS (1), /* fp */
+ COSTS_N_INSNS (1), /* dmul */
+ COSTS_N_INSNS (1), /* sdiv */
+ COSTS_N_INSNS (1), /* ddiv */
+};
+
+/* Instruction size costs on 64bit processors. */
+static const
+struct processor_costs size64_cost = {
+ COSTS_N_INSNS (1), /* mulsi */
+ COSTS_N_INSNS (1), /* mulsi_const */
+ COSTS_N_INSNS (1), /* mulsi_const9 */
+ COSTS_N_INSNS (1), /* muldi */
+ COSTS_N_INSNS (1), /* divsi */
+ COSTS_N_INSNS (1), /* divdi */
+ COSTS_N_INSNS (1), /* fp */
+ COSTS_N_INSNS (1), /* dmul */
+ COSTS_N_INSNS (1), /* sdiv */
+ COSTS_N_INSNS (1), /* ddiv */
+};
+
+/* Instruction costs on RIOS1 processors. */
+static const
+struct processor_costs rios1_cost = {
+ COSTS_N_INSNS (5), /* mulsi */
+ COSTS_N_INSNS (4), /* mulsi_const */
+ COSTS_N_INSNS (3), /* mulsi_const9 */
+ COSTS_N_INSNS (5), /* muldi */
+ COSTS_N_INSNS (19), /* divsi */
+ COSTS_N_INSNS (19), /* divdi */
+ COSTS_N_INSNS (2), /* fp */
+ COSTS_N_INSNS (2), /* dmul */
+ COSTS_N_INSNS (19), /* sdiv */
+ COSTS_N_INSNS (19), /* ddiv */
+};
+
+/* Instruction costs on RIOS2 processors. */
+static const
+struct processor_costs rios2_cost = {
+ COSTS_N_INSNS (2), /* mulsi */
+ COSTS_N_INSNS (2), /* mulsi_const */
+ COSTS_N_INSNS (2), /* mulsi_const9 */
+ COSTS_N_INSNS (2), /* muldi */
+ COSTS_N_INSNS (13), /* divsi */
+ COSTS_N_INSNS (13), /* divdi */
+ COSTS_N_INSNS (2), /* fp */
+ COSTS_N_INSNS (2), /* dmul */
+ COSTS_N_INSNS (17), /* sdiv */
+ COSTS_N_INSNS (17), /* ddiv */
+};
+
+/* Instruction costs on RS64A processors. */
+static const
+struct processor_costs rs64a_cost = {
+ COSTS_N_INSNS (20), /* mulsi */
+ COSTS_N_INSNS (12), /* mulsi_const */
+ COSTS_N_INSNS (8), /* mulsi_const9 */
+ COSTS_N_INSNS (34), /* muldi */
+ COSTS_N_INSNS (65), /* divsi */
+ COSTS_N_INSNS (67), /* divdi */
+ COSTS_N_INSNS (4), /* fp */
+ COSTS_N_INSNS (4), /* dmul */
+ COSTS_N_INSNS (31), /* sdiv */
+ COSTS_N_INSNS (31), /* ddiv */
+};
+
+/* Instruction costs on MPCCORE processors. */
+static const
+struct processor_costs mpccore_cost = {
+ COSTS_N_INSNS (2), /* mulsi */
+ COSTS_N_INSNS (2), /* mulsi_const */
+ COSTS_N_INSNS (2), /* mulsi_const9 */
+ COSTS_N_INSNS (2), /* muldi */
+ COSTS_N_INSNS (6), /* divsi */
+ COSTS_N_INSNS (6), /* divdi */
+ COSTS_N_INSNS (4), /* fp */
+ COSTS_N_INSNS (5), /* dmul */
+ COSTS_N_INSNS (10), /* sdiv */
+ COSTS_N_INSNS (17), /* ddiv */
+};
+
+/* Instruction costs on PPC403 processors. */
+static const
+struct processor_costs ppc403_cost = {
+ COSTS_N_INSNS (4), /* mulsi */
+ COSTS_N_INSNS (4), /* mulsi_const */
+ COSTS_N_INSNS (4), /* mulsi_const9 */
+ COSTS_N_INSNS (4), /* muldi */
+ COSTS_N_INSNS (33), /* divsi */
+ COSTS_N_INSNS (33), /* divdi */
+ COSTS_N_INSNS (11), /* fp */
+ COSTS_N_INSNS (11), /* dmul */
+ COSTS_N_INSNS (11), /* sdiv */
+ COSTS_N_INSNS (11), /* ddiv */
+};
+
+/* Instruction costs on PPC405 processors. */
+static const
+struct processor_costs ppc405_cost = {
+ COSTS_N_INSNS (5), /* mulsi */
+ COSTS_N_INSNS (4), /* mulsi_const */
+ COSTS_N_INSNS (3), /* mulsi_const9 */
+ COSTS_N_INSNS (5), /* muldi */
+ COSTS_N_INSNS (35), /* divsi */
+ COSTS_N_INSNS (35), /* divdi */
+ COSTS_N_INSNS (11), /* fp */
+ COSTS_N_INSNS (11), /* dmul */
+ COSTS_N_INSNS (11), /* sdiv */
+ COSTS_N_INSNS (11), /* ddiv */
+};
+
+/* Instruction costs on PPC440 processors. */
+static const
+struct processor_costs ppc440_cost = {
+ COSTS_N_INSNS (3), /* mulsi */
+ COSTS_N_INSNS (2), /* mulsi_const */
+ COSTS_N_INSNS (2), /* mulsi_const9 */
+ COSTS_N_INSNS (3), /* muldi */
+ COSTS_N_INSNS (34), /* divsi */
+ COSTS_N_INSNS (34), /* divdi */
+ COSTS_N_INSNS (5), /* fp */
+ COSTS_N_INSNS (5), /* dmul */
+ COSTS_N_INSNS (19), /* sdiv */
+ COSTS_N_INSNS (33), /* ddiv */
+};
+
+/* Instruction costs on PPC601 processors. */
+static const
+struct processor_costs ppc601_cost = {
+ COSTS_N_INSNS (5), /* mulsi */
+ COSTS_N_INSNS (5), /* mulsi_const */
+ COSTS_N_INSNS (5), /* mulsi_const9 */
+ COSTS_N_INSNS (5), /* muldi */
+ COSTS_N_INSNS (36), /* divsi */
+ COSTS_N_INSNS (36), /* divdi */
+ COSTS_N_INSNS (4), /* fp */
+ COSTS_N_INSNS (5), /* dmul */
+ COSTS_N_INSNS (17), /* sdiv */
+ COSTS_N_INSNS (31), /* ddiv */
+};
+
+/* Instruction costs on PPC603 processors. */
+static const
+struct processor_costs ppc603_cost = {
+ COSTS_N_INSNS (5), /* mulsi */
+ COSTS_N_INSNS (3), /* mulsi_const */
+ COSTS_N_INSNS (2), /* mulsi_const9 */
+ COSTS_N_INSNS (5), /* muldi */
+ COSTS_N_INSNS (37), /* divsi */
+ COSTS_N_INSNS (37), /* divdi */
+ COSTS_N_INSNS (3), /* fp */
+ COSTS_N_INSNS (4), /* dmul */
+ COSTS_N_INSNS (18), /* sdiv */
+ COSTS_N_INSNS (33), /* ddiv */
+};
+
+/* Instruction costs on PPC604 processors. */
+static const
+struct processor_costs ppc604_cost = {
+ COSTS_N_INSNS (4), /* mulsi */
+ COSTS_N_INSNS (4), /* mulsi_const */
+ COSTS_N_INSNS (4), /* mulsi_const9 */
+ COSTS_N_INSNS (4), /* muldi */
+ COSTS_N_INSNS (20), /* divsi */
+ COSTS_N_INSNS (20), /* divdi */
+ COSTS_N_INSNS (3), /* fp */
+ COSTS_N_INSNS (3), /* dmul */
+ COSTS_N_INSNS (18), /* sdiv */
+ COSTS_N_INSNS (32), /* ddiv */
+};
+
+/* Instruction costs on PPC604e processors. */
+static const
+struct processor_costs ppc604e_cost = {
+ COSTS_N_INSNS (2), /* mulsi */
+ COSTS_N_INSNS (2), /* mulsi_const */
+ COSTS_N_INSNS (2), /* mulsi_const9 */
+ COSTS_N_INSNS (2), /* muldi */
+ COSTS_N_INSNS (20), /* divsi */
+ COSTS_N_INSNS (20), /* divdi */
+ COSTS_N_INSNS (3), /* fp */
+ COSTS_N_INSNS (3), /* dmul */
+ COSTS_N_INSNS (18), /* sdiv */
+ COSTS_N_INSNS (32), /* ddiv */
+};
+
+/* Instruction costs on PPC620 processors. */
+static const
+struct processor_costs ppc620_cost = {
+ COSTS_N_INSNS (5), /* mulsi */
+ COSTS_N_INSNS (4), /* mulsi_const */
+ COSTS_N_INSNS (3), /* mulsi_const9 */
+ COSTS_N_INSNS (7), /* muldi */
+ COSTS_N_INSNS (21), /* divsi */
+ COSTS_N_INSNS (37), /* divdi */
+ COSTS_N_INSNS (3), /* fp */
+ COSTS_N_INSNS (3), /* dmul */
+ COSTS_N_INSNS (18), /* sdiv */
+ COSTS_N_INSNS (32), /* ddiv */
+};
+
+/* Instruction costs on PPC630 processors. */
+static const
+struct processor_costs ppc630_cost = {
+ COSTS_N_INSNS (5), /* mulsi */
+ COSTS_N_INSNS (4), /* mulsi_const */
+ COSTS_N_INSNS (3), /* mulsi_const9 */
+ COSTS_N_INSNS (7), /* muldi */
+ COSTS_N_INSNS (21), /* divsi */
+ COSTS_N_INSNS (37), /* divdi */
+ COSTS_N_INSNS (3), /* fp */
+ COSTS_N_INSNS (3), /* dmul */
+ COSTS_N_INSNS (17), /* sdiv */
+ COSTS_N_INSNS (21), /* ddiv */
+};
+
+/* Instruction costs on PPC750 and PPC7400 processors. */
+static const
+struct processor_costs ppc750_cost = {
+ COSTS_N_INSNS (5), /* mulsi */
+ COSTS_N_INSNS (3), /* mulsi_const */
+ COSTS_N_INSNS (2), /* mulsi_const9 */
+ COSTS_N_INSNS (5), /* muldi */
+ COSTS_N_INSNS (17), /* divsi */
+ COSTS_N_INSNS (17), /* divdi */
+ COSTS_N_INSNS (3), /* fp */
+ COSTS_N_INSNS (3), /* dmul */
+ COSTS_N_INSNS (17), /* sdiv */
+ COSTS_N_INSNS (31), /* ddiv */
+};
+
+/* Instruction costs on PPC7450 processors. */
+static const
+struct processor_costs ppc7450_cost = {
+ COSTS_N_INSNS (4), /* mulsi */
+ COSTS_N_INSNS (3), /* mulsi_const */
+ COSTS_N_INSNS (3), /* mulsi_const9 */
+ COSTS_N_INSNS (4), /* muldi */
+ COSTS_N_INSNS (23), /* divsi */
+ COSTS_N_INSNS (23), /* divdi */
+ COSTS_N_INSNS (5), /* fp */
+ COSTS_N_INSNS (5), /* dmul */
+ COSTS_N_INSNS (21), /* sdiv */
+ COSTS_N_INSNS (35), /* ddiv */
+};
+
+/* Instruction costs on PPC8540 processors. */
+static const
+struct processor_costs ppc8540_cost = {
+ COSTS_N_INSNS (4), /* mulsi */
+ COSTS_N_INSNS (4), /* mulsi_const */
+ COSTS_N_INSNS (4), /* mulsi_const9 */
+ COSTS_N_INSNS (4), /* muldi */
+ COSTS_N_INSNS (19), /* divsi */
+ COSTS_N_INSNS (19), /* divdi */
+ COSTS_N_INSNS (4), /* fp */
+ COSTS_N_INSNS (4), /* dmul */
+ COSTS_N_INSNS (29), /* sdiv */
+ COSTS_N_INSNS (29), /* ddiv */
+};
+
+/* Instruction costs on POWER4 and POWER5 processors. */
+static const
+struct processor_costs power4_cost = {
+ COSTS_N_INSNS (3), /* mulsi */
+ COSTS_N_INSNS (2), /* mulsi_const */
+ COSTS_N_INSNS (2), /* mulsi_const9 */
+ COSTS_N_INSNS (4), /* muldi */
+ COSTS_N_INSNS (18), /* divsi */
+ COSTS_N_INSNS (34), /* divdi */
+ COSTS_N_INSNS (3), /* fp */
+ COSTS_N_INSNS (3), /* dmul */
+ COSTS_N_INSNS (17), /* sdiv */
+ COSTS_N_INSNS (17), /* ddiv */
+};
+\f
static bool rs6000_function_ok_for_sibcall (tree, tree);
static int num_insns_constant_wide (HOST_WIDE_INT);
static void validate_condition_mode (enum rtx_code, enum machine_mode);
static void rs6000_parse_yes_no_option (const char *, const char *, int *);
static int first_altivec_reg_to_save (void);
static unsigned int compute_vrsave_mask (void);
+static void compute_save_world_info(rs6000_stack_t *info_ptr);
static void is_altivec_return_reg (rtx, void *);
static rtx generate_set_vrsave (rtx, rs6000_stack_t *, int);
int easy_vector_constant (rtx, enum machine_mode);
static void setup_incoming_varargs (CUMULATIVE_ARGS *,
enum machine_mode, tree,
int *, int);
+static bool rs6000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+ tree, bool);
#if TARGET_MACHO
static void macho_branch_islands (void);
static void add_compiler_branch_island (tree, tree, int);
static tree rs6000_build_builtin_va_list (void);
static tree rs6000_gimplify_va_arg (tree, tree, tree *, tree *);
+static bool rs6000_must_pass_in_stack (enum machine_mode, tree);
+
+static enum machine_mode rs6000_eh_return_filter_mode (void);
/* Hash table stuff for keeping track of TOC entries. */
#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"
#undef TARGET_ASM_UNALIGNED_SI_OP
#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
+#undef TARGET_ASM_UNALIGNED_DI_OP
+#define TARGET_ASM_UNALIGNED_DI_OP "\t.quad\t"
+#undef TARGET_ASM_ALIGNED_DI_OP
+#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
#endif
#endif
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue
-#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE hook_int_void_1
#undef TARGET_SCHED_VARIABLE_ISSUE
#define TARGET_SCHED_VARIABLE_ISSUE rs6000_variable_issue
#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true
#undef TARGET_SPLIT_COMPLEX_ARG
#define TARGET_SPLIT_COMPLEX_ARG hook_bool_tree_true
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK rs6000_must_pass_in_stack
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE rs6000_pass_by_reference
#undef TARGET_BUILD_BUILTIN_VA_LIST
#define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list
#undef TARGET_GIMPLIFY_VA_ARG_EXPR
#define TARGET_GIMPLIFY_VA_ARG_EXPR rs6000_gimplify_va_arg
+#undef TARGET_EH_RETURN_FILTER_MODE
+#define TARGET_EH_RETURN_FILTER_MODE rs6000_eh_return_filter_mode
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
rs6000_hard_regno_mode_ok_p[m][r] = true;
}
+/* If not otherwise specified by a target, make 'long double' equivalent to
+ 'double'. */
+
+#ifndef RS6000_DEFAULT_LONG_DOUBLE_SIZE
+#define RS6000_DEFAULT_LONG_DOUBLE_SIZE 64
+#endif
+
/* Override command line options. Mostly we process the processor
type and sometimes adjust other TARGET_ options. */
}
/* Set size of long double */
- rs6000_long_double_type_size = 64;
+ rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
if (rs6000_long_double_size_string)
{
char *tail;
if (rs6000_isel_string == 0)
rs6000_isel = 0;
if (rs6000_long_double_size_string == 0)
- rs6000_long_double_type_size = 64;
+ rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
}
rs6000_always_hint = (rs6000_cpu != PROCESSOR_POWER4
Linux and Darwin ABIs at the moment. For now, only AIX is fixed. */
if (DEFAULT_ABI != ABI_AIX)
targetm.calls.split_complex_arg = NULL;
+
+ /* Initialize rs6000_cost with the appropriate target costs. */
+ if (optimize_size)
+ rs6000_cost = TARGET_POWERPC64 ? &size64_cost : &size32_cost;
+ else
+ switch (rs6000_cpu)
+ {
+ case PROCESSOR_RIOS1:
+ rs6000_cost = &rios1_cost;
+ break;
+
+ case PROCESSOR_RIOS2:
+ rs6000_cost = &rios2_cost;
+ break;
+
+ case PROCESSOR_RS64A:
+ rs6000_cost = &rs64a_cost;
+ break;
+
+ case PROCESSOR_MPCCORE:
+ rs6000_cost = &mpccore_cost;
+ break;
+
+ case PROCESSOR_PPC403:
+ rs6000_cost = &ppc403_cost;
+ break;
+
+ case PROCESSOR_PPC405:
+ rs6000_cost = &ppc405_cost;
+ break;
+
+ case PROCESSOR_PPC440:
+ rs6000_cost = &ppc440_cost;
+ break;
+
+ case PROCESSOR_PPC601:
+ rs6000_cost = &ppc601_cost;
+ break;
+
+ case PROCESSOR_PPC603:
+ rs6000_cost = &ppc603_cost;
+ break;
+
+ case PROCESSOR_PPC604:
+ rs6000_cost = &ppc604_cost;
+ break;
+
+ case PROCESSOR_PPC604e:
+ rs6000_cost = &ppc604e_cost;
+ break;
+
+ case PROCESSOR_PPC620:
+ rs6000_cost = &ppc620_cost;
+ break;
+
+ case PROCESSOR_PPC630:
+ rs6000_cost = &ppc630_cost;
+ break;
+
+ case PROCESSOR_PPC750:
+ case PROCESSOR_PPC7400:
+ rs6000_cost = &ppc750_cost;
+ break;
+
+ case PROCESSOR_PPC7450:
+ rs6000_cost = &ppc7450_cost;
+ break;
+
+ case PROCESSOR_PPC8540:
+ rs6000_cost = &ppc8540_cost;
+ break;
+
+ case PROCESSOR_POWER4:
+ case PROCESSOR_POWER5:
+ rs6000_cost = &power4_cost;
+ break;
+
+ default:
+ abort ();
+ }
}
/* Handle generic options of the form -mfoo=yes/no.
return 1;
}
+/* Returns 1 always. */
+
+int
+any_parallel_operand (rtx op ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
+
/* Returns 1 if op is the count register. */
+
int
count_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
}
/* Returns 1 if op is an altivec register. */
+
int
altivec_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return false;
if (GET_MODE_NUNITS (mode) != 1)
return false;
- if (GET_MODE_BITSIZE (mode) > 32
- && !(TARGET_HARD_FLOAT && TARGET_FPRS && mode == DFmode))
+ if (GET_MODE_BITSIZE (mode) > 64)
return false;
return CONSTANT_P (x);
tmp1 = gen_reg_rtx (Pmode);
tmp2 = gen_reg_rtx (Pmode);
tmp3 = gen_reg_rtx (Pmode);
- mem = gen_rtx_MEM (Pmode, tmp1);
- RTX_UNCHANGING_P (mem) = 1;
+ mem = gen_const_mem (Pmode, tmp1);
first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, lab,
gsym));
{
rtx offset = gen_rtx_CONST (Pmode,
gen_rtx_MINUS (Pmode, x,
- gen_rtx_SYMBOL_REF (Pmode,
- machopic_function_base_name ())));
+ machopic_function_base_sym ()));
x = gen_rtx_LO_SUM (GET_MODE (x),
gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
gen_rtx_HIGH (Pmode, offset)), offset);
return;
}
#endif
- emit_insn (gen_macho_high (target, operands[1]));
- emit_insn (gen_macho_low (operands[0], target, operands[1]));
+ if (mode == DImode)
+ {
+ emit_insn (gen_macho_high_di (target, operands[1]));
+ emit_insn (gen_macho_low_di (operands[0], target, operands[1]));
+ }
+ else
+ {
+ emit_insn (gen_macho_high (target, operands[1]));
+ emit_insn (gen_macho_low (operands[0], target, operands[1]));
+ }
return;
}
get_pool_mode (XEXP (operands[1], 0))))
{
operands[1]
- = gen_rtx_MEM (mode,
- create_TOC_reference (XEXP (operands[1], 0)));
+ = gen_const_mem (mode,
+ create_TOC_reference (XEXP (operands[1], 0)));
set_mem_alias_set (operands[1], get_TOC_alias_set ());
- RTX_UNCHANGING_P (operands[1]) = 1;
}
}
break;
}
}
\f
+/* Return true if TYPE must be passed on the stack and not in registers. */
+
+static bool
+rs6000_must_pass_in_stack (enum machine_mode mode, tree type)
+{
+ if (DEFAULT_ABI == ABI_AIX || TARGET_64BIT)
+ return must_pass_in_stack_var_size (mode, type);
+ else
+ return must_pass_in_stack_var_size_or_pad (mode, type);
+}
+
/* If defined, a C expression which determines whether, and in which
direction, to pad out an argument with extra space. The value
should be of type `enum direction': either `upward' to pad above
As an extension to all ABIs, variable sized types are passed by
reference. */
-int
-function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED,
- tree type, int named ATTRIBUTE_UNUSED)
+static bool
+rs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ tree type, bool named ATTRIBUTE_UNUSED)
{
if ((DEFAULT_ABI == ABI_V4
&& ((type && AGGREGATE_TYPE_P (type))
save_area = virtual_incoming_args_rtx;
cfun->machine->sysv_varargs_p = 0;
- if (MUST_PASS_IN_STACK (mode, type))
+ if (targetm.calls.must_pass_in_stack (mode, type))
first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
}
HOST_WIDE_INT_PRINT_DEC", n_fpr = "HOST_WIDE_INT_PRINT_DEC"\n",
words, n_gpr, n_fpr);
- t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_2 (n_gpr, 0));
+ t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr,
+ build_int_cst (NULL_TREE, n_gpr, 0));
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_2 (n_fpr, 0));
+ t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr,
+ build_int_cst (NULL_TREE, n_fpr, 0));
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
if (words != 0)
t = build (PLUS_EXPR, TREE_TYPE (ovf), t,
- build_int_2 (words * UNITS_PER_WORD, 0));
+ build_int_cst (NULL_TREE, words * UNITS_PER_WORD, 0));
t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
/* Find the register save area. */
t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
t = build (PLUS_EXPR, TREE_TYPE (sav), t,
- build_int_2 (-RS6000_VARARGS_SIZE, -1));
+ build_int_cst (NULL_TREE, -RS6000_VARARGS_SIZE, -1));
t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
{
tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
tree gpr, fpr, ovf, sav, reg, t, u;
- int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale;
+ int size, rsize, n_reg, sav_ofs, sav_scale;
tree lab_false, lab_over, addr;
int align;
tree ptrtype = build_pointer_type (type);
+ if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
+ {
+ t = rs6000_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
+ return build_fold_indirect_ref (t);
+ }
+
if (DEFAULT_ABI != ABI_V4)
{
- /* Variable sized types are passed by reference, as are AltiVec
- vectors when 32-bit and not using the AltiVec ABI extension. */
- if (int_size_in_bytes (type) < 0
- || (TARGET_32BIT
- && !TARGET_ALTIVEC_ABI
- && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
- {
- /* Args grow upward. */
- t = build2 (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist,
- build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
- t = build1 (NOP_EXPR, build_pointer_type (ptrtype), t);
- t = build_fold_indirect_ref (t);
- return build_fold_indirect_ref (t);
- }
- if (targetm.calls.split_complex_arg
- && TREE_CODE (type) == COMPLEX_TYPE)
+ if (targetm.calls.split_complex_arg && TREE_CODE (type) == COMPLEX_TYPE)
{
tree elem_type = TREE_TYPE (type);
enum machine_mode elem_mode = TYPE_MODE (elem_type);
rsize = (size + 3) / 4;
align = 1;
- if (AGGREGATE_TYPE_P (type)
- || TYPE_MODE (type) == TFmode
- || (!TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
- {
- /* Aggregates, long doubles, and AltiVec vectors are passed by
- reference. */
- indirect_p = 1;
- reg = gpr;
- n_reg = 1;
- sav_ofs = 0;
- sav_scale = 4;
- size = 4;
- rsize = 1;
- }
- else if (TARGET_HARD_FLOAT && TARGET_FPRS
- && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode))
+ if (TARGET_HARD_FLOAT && TARGET_FPRS
+ && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode))
{
/* FP args go in FP registers, if present. */
- indirect_p = 0;
reg = fpr;
n_reg = 1;
sav_ofs = 8*4;
else
{
/* Otherwise into GP registers. */
- indirect_p = 0;
reg = gpr;
n_reg = rsize;
sav_ofs = 0;
if (n_reg == 2)
{
u = build2 (BIT_AND_EXPR, TREE_TYPE (reg), reg,
- build_int_2 (n_reg - 1, 0));
+ size_int (n_reg - 1));
u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u);
}
- t = build_int_2 (8 - n_reg + 1, 0);
- TREE_TYPE (t) = TREE_TYPE (reg);
+ t = fold_convert (TREE_TYPE (reg), size_int (8 - n_reg + 1));
t = build2 (GE_EXPR, boolean_type_node, u, t);
u = build1 (GOTO_EXPR, void_type_node, lab_false);
t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
t = sav;
if (sav_ofs)
- t = build2 (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
+ t = build2 (PLUS_EXPR, ptr_type_node, sav, size_int (sav_ofs));
- u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg,
- build_int_2 (n_reg, 0));
+ u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, size_int (n_reg));
u = build1 (CONVERT_EXPR, integer_type_node, u);
- u = build2 (MULT_EXPR, integer_type_node, u, build_int_2 (sav_scale, 0));
+ u = build2 (MULT_EXPR, integer_type_node, u, size_int (sav_scale));
t = build2 (PLUS_EXPR, ptr_type_node, t, u);
t = build2 (MODIFY_EXPR, void_type_node, addr, t);
{
/* Ensure that we don't find any more args in regs.
Alignment has taken care of the n_reg == 2 case. */
- t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, build_int_2 (8, 0));
+ t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, size_int (8));
gimplify_and_add (t, pre_p);
}
}
t = ovf;
if (align != 1)
{
- t = build2 (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (align - 1, 0));
- t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
+ t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (align - 1));
+ t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
+ build_int_cst (NULL_TREE, -align, -1));
}
gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
u = build2 (MODIFY_EXPR, void_type_node, addr, t);
gimplify_and_add (u, pre_p);
- t = build2 (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
+ t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
gimplify_and_add (t, pre_p);
append_to_statement_list (t, pre_p);
}
- if (indirect_p)
- {
- addr = fold_convert (build_pointer_type (ptrtype), addr);
- addr = build_fold_indirect_ref (addr);
- }
- else
- addr = fold_convert (ptrtype, addr);
-
+ addr = fold_convert (ptrtype, addr);
return build_fold_indirect_ref (addr);
}
/* Builtins. */
-#define def_builtin(MASK, NAME, TYPE, CODE) \
-do { \
- if ((MASK) & target_flags) \
- builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
- NULL, NULL_TREE); \
+#define def_builtin(MASK, NAME, TYPE, CODE) \
+do { \
+ if ((MASK) & target_flags) \
+ lang_hooks.builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
+ NULL, NULL_TREE); \
} while (0)
/* Simple ternary operations: VECd = foo (VECa, VECb, VECc). */
= build_function_type (V8HI_type_node, void_list_node);
tree void_ftype_void
= build_function_type (void_type_node, void_list_node);
- tree void_ftype_qi
- = build_function_type_list (void_type_node, char_type_node, NULL_TREE);
+ tree void_ftype_int
+ = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
tree v16qi_ftype_long_pcvoid
= build_function_type_list (V16QI_type_node,
def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
- def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_qi, ALTIVEC_BUILTIN_DSS);
+ def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_int, ALTIVEC_BUILTIN_DSS);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR);
def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX);
set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq");
}
}
+
+\f
+/* Expand a block clear operation, and return 1 if successful. Return 0
+ if we should let the compiler generate normal code.
+
+ operands[0] is the destination
+ operands[1] is the length
+ operands[2] is the alignment */
+
+int
+expand_block_clear (rtx operands[])
+{
+ rtx orig_dest = operands[0];
+ rtx bytes_rtx = operands[1];
+ rtx align_rtx = operands[2];
+ int constp = (GET_CODE (bytes_rtx) == CONST_INT);
+ int align;
+ int bytes;
+ int offset;
+ int clear_bytes;
+
+ /* If this is not a fixed size move, just call memcpy */
+ if (! constp)
+ return 0;
+
+ /* If this is not a fixed size alignment, abort */
+ if (GET_CODE (align_rtx) != CONST_INT)
+ abort ();
+ align = INTVAL (align_rtx) * BITS_PER_UNIT;
+
+ /* Anything to clear? */
+ bytes = INTVAL (bytes_rtx);
+ if (bytes <= 0)
+ return 1;
+
+ if (bytes > (TARGET_POWERPC64 && align >= 32 ? 64 : 32))
+ return 0;
+
+ if (optimize_size && bytes > 16)
+ return 0;
+
+ for (offset = 0; bytes > 0; offset += clear_bytes, bytes -= clear_bytes)
+ {
+ rtx (*mov) (rtx, rtx);
+ enum machine_mode mode = BLKmode;
+ rtx dest;
+
+ if (bytes >= 8 && TARGET_POWERPC64
+ /* 64-bit loads and stores require word-aligned
+ displacements. */
+ && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
+ {
+ clear_bytes = 8;
+ mode = DImode;
+ mov = gen_movdi;
+ }
+ else if (bytes >= 4 && !STRICT_ALIGNMENT)
+ { /* move 4 bytes */
+ clear_bytes = 4;
+ mode = SImode;
+ mov = gen_movsi;
+ }
+ else if (bytes == 2 && !STRICT_ALIGNMENT)
+ { /* move 2 bytes */
+ clear_bytes = 2;
+ mode = HImode;
+ mov = gen_movhi;
+ }
+ else /* move 1 byte at a time */
+ {
+ clear_bytes = 1;
+ mode = QImode;
+ mov = gen_movqi;
+ }
+
+ dest = adjust_address (orig_dest, mode, offset);
+
+ emit_insn ((*mov) (dest, const0_rtx));
+ }
+
+ return 1;
+}
+
\f
/* Expand a block move operation, and return 1 if successful. Return 0
if we should let the compiler generate normal code.
/* If this is not a fixed size alignment, abort */
if (GET_CODE (align_rtx) != CONST_INT)
abort ();
- align = INTVAL (align_rtx);
+ align = INTVAL (align_rtx) * BITS_PER_UNIT;
/* Anything to move? */
bytes = INTVAL (bytes_rtx);
for (offset = 0; bytes > 0; offset += move_bytes, bytes -= move_bytes)
{
union {
- rtx (*movstrsi) (rtx, rtx, rtx, rtx);
+ rtx (*movmemsi) (rtx, rtx, rtx, rtx);
rtx (*mov) (rtx, rtx);
} gen_func;
enum machine_mode mode = BLKmode;
&& ! fixed_regs[12])
{
move_bytes = (bytes > 32) ? 32 : bytes;
- gen_func.movstrsi = gen_movstrsi_8reg;
+ gen_func.movmemsi = gen_movmemsi_8reg;
}
else if (TARGET_STRING
&& bytes > 16 /* move up to 24 bytes at a time */
&& ! fixed_regs[10])
{
move_bytes = (bytes > 24) ? 24 : bytes;
- gen_func.movstrsi = gen_movstrsi_6reg;
+ gen_func.movmemsi = gen_movmemsi_6reg;
}
else if (TARGET_STRING
&& bytes > 8 /* move up to 16 bytes at a time */
&& ! fixed_regs[8])
{
move_bytes = (bytes > 16) ? 16 : bytes;
- gen_func.movstrsi = gen_movstrsi_4reg;
+ gen_func.movmemsi = gen_movmemsi_4reg;
}
else if (bytes >= 8 && TARGET_POWERPC64
/* 64-bit loads and stores require word-aligned
displacements. */
- && (align >= 8 || (! STRICT_ALIGNMENT && align >= 4)))
+ && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
{
move_bytes = 8;
mode = DImode;
else if (TARGET_STRING && bytes > 4 && !TARGET_POWERPC64)
{ /* move up to 8 bytes at a time */
move_bytes = (bytes > 8) ? 8 : bytes;
- gen_func.movstrsi = gen_movstrsi_2reg;
+ gen_func.movmemsi = gen_movmemsi_2reg;
}
- else if (bytes >= 4 && (align >= 4 || ! STRICT_ALIGNMENT))
+ else if (bytes >= 4 && !STRICT_ALIGNMENT)
{ /* move 4 bytes */
move_bytes = 4;
mode = SImode;
gen_func.mov = gen_movsi;
}
- else if (bytes == 2 && (align >= 2 || ! STRICT_ALIGNMENT))
+ else if (bytes == 2 && !STRICT_ALIGNMENT)
{ /* move 2 bytes */
move_bytes = 2;
mode = HImode;
else if (TARGET_STRING && bytes > 1)
{ /* move up to 4 bytes at a time */
move_bytes = (bytes > 4) ? 4 : bytes;
- gen_func.movstrsi = gen_movstrsi_1reg;
+ gen_func.movmemsi = gen_movmemsi_1reg;
}
else /* move 1 byte at a time */
{
if (mode == BLKmode)
{
- /* Move the address into scratch registers. The movstrsi
+ /* Move the address into scratch registers. The movmemsi
patterns require zero offset. */
if (!REG_P (XEXP (src, 0)))
{
}
set_mem_size (dest, GEN_INT (move_bytes));
- emit_insn ((*gen_func.movstrsi) (dest, src,
+ emit_insn ((*gen_func.movmemsi) (dest, src,
GEN_INT (move_bytes & 31),
align_rtx));
}
}
\f
-/* Return 1 if OP is a load multiple operation. It is known to be a
- PARALLEL and the first section will be tested. */
-
+/* Return 1 if OP is suitable for a save_world call in prologue. It is
+ known to be a PARALLEL. */
int
-load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+save_world_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
- int count = XVECLEN (op, 0);
- unsigned int dest_regno;
- rtx src_addr;
+ int index;
int i;
+ rtx elt;
+ int count = XVECLEN (op, 0);
- /* Perform a quick check so we don't blow up below. */
- if (count <= 1
- || GET_CODE (XVECEXP (op, 0, 0)) != SET
- || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
- || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
+ if (count != 55)
return 0;
- dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
- src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
+ index = 0;
+ if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
+ || GET_CODE (XVECEXP (op, 0, index++)) != USE)
+ return 0;
- for (i = 1; i < count; i++)
+ for (i=1; i <= 18; i++)
{
- rtx elt = XVECEXP (op, 0, i);
+ elt = XVECEXP (op, 0, index++);
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_DEST (elt)) != MEM
+ || ! memory_operand (SET_DEST (elt), DFmode)
+ || GET_CODE (SET_SRC (elt)) != REG
+ || GET_MODE (SET_SRC (elt)) != DFmode)
+ return 0;
+ }
+ for (i=1; i <= 12; i++)
+ {
+ elt = XVECEXP (op, 0, index++);
if (GET_CODE (elt) != SET
- || GET_CODE (SET_DEST (elt)) != REG
- || GET_MODE (SET_DEST (elt)) != SImode
- || REGNO (SET_DEST (elt)) != dest_regno + i
- || GET_CODE (SET_SRC (elt)) != MEM
- || GET_MODE (SET_SRC (elt)) != SImode
- || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
- || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
- || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
- || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
+ || GET_CODE (SET_DEST (elt)) != MEM
+ || GET_CODE (SET_SRC (elt)) != REG
+ || GET_MODE (SET_SRC (elt)) != V4SImode)
+ return 0;
+ }
+
+ for (i=1; i <= 19; i++)
+ {
+ elt = XVECEXP (op, 0, index++);
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_DEST (elt)) != MEM
+ || ! memory_operand (SET_DEST (elt), Pmode)
+ || GET_CODE (SET_SRC (elt)) != REG
+ || GET_MODE (SET_SRC (elt)) != Pmode)
return 0;
}
+ elt = XVECEXP (op, 0, index++);
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_DEST (elt)) != MEM
+ || ! memory_operand (SET_DEST (elt), Pmode)
+ || GET_CODE (SET_SRC (elt)) != REG
+ || REGNO (SET_SRC (elt)) != CR2_REGNO
+ || GET_MODE (SET_SRC (elt)) != Pmode)
+ return 0;
+
+ if (GET_CODE (XVECEXP (op, 0, index++)) != USE
+ || GET_CODE (XVECEXP (op, 0, index++)) != USE
+ || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER)
+ return 0;
return 1;
}
-/* Similar, but tests for store multiple. Here, the second vector element
- is a CLOBBER. It will be tested later. */
-
+/* Return 1 if OP is suitable for a save_world call in prologue. It is
+ known to be a PARALLEL. */
int
-store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+restore_world_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
- int count = XVECLEN (op, 0) - 1;
- unsigned int src_regno;
- rtx dest_addr;
+ int index;
int i;
+ rtx elt;
+ int count = XVECLEN (op, 0);
- /* Perform a quick check so we don't blow up below. */
- if (count <= 1
- || GET_CODE (XVECEXP (op, 0, 0)) != SET
- || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
- || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
+ if (count != 59)
return 0;
- src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
- dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
+ index = 0;
+ if (GET_CODE (XVECEXP (op, 0, index++)) != RETURN
+ || GET_CODE (XVECEXP (op, 0, index++)) != USE
+ || GET_CODE (XVECEXP (op, 0, index++)) != USE
+ || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER)
+ return 0;
- for (i = 1; i < count; i++)
+ elt = XVECEXP (op, 0, index++);
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_SRC (elt)) != MEM
+ || ! memory_operand (SET_SRC (elt), Pmode)
+ || GET_CODE (SET_DEST (elt)) != REG
+ || REGNO (SET_DEST (elt)) != CR2_REGNO
+ || GET_MODE (SET_DEST (elt)) != Pmode)
+ return 0;
+
+ for (i=1; i <= 19; i++)
{
- rtx elt = XVECEXP (op, 0, i + 1);
+ elt = XVECEXP (op, 0, index++);
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_SRC (elt)) != MEM
+ || ! memory_operand (SET_SRC (elt), Pmode)
+ || GET_CODE (SET_DEST (elt)) != REG
+ || GET_MODE (SET_DEST (elt)) != Pmode)
+ return 0;
+ }
+
+ for (i=1; i <= 12; i++)
+ {
+ elt = XVECEXP (op, 0, index++);
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_SRC (elt)) != MEM
+ || GET_CODE (SET_DEST (elt)) != REG
+ || GET_MODE (SET_DEST (elt)) != V4SImode)
+ return 0;
+ }
+
+ for (i=1; i <= 18; i++)
+ {
+ elt = XVECEXP (op, 0, index++);
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_SRC (elt)) != MEM
+ || ! memory_operand (SET_SRC (elt), DFmode)
+ || GET_CODE (SET_DEST (elt)) != REG
+ || GET_MODE (SET_DEST (elt)) != DFmode)
+ return 0;
+ }
+
+ if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
+ || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
+ || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
+ || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
+ || GET_CODE (XVECEXP (op, 0, index++)) != USE)
+ return 0;
+ return 1;
+}
+
+\f
+/* Return 1 if OP is a load multiple operation. It is known to be a
+ PARALLEL and the first section will be tested. */
+
+int
+load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ int count = XVECLEN (op, 0);
+ unsigned int dest_regno;
+ rtx src_addr;
+ int i;
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= 1
+ || GET_CODE (XVECEXP (op, 0, 0)) != SET
+ || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
+ || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
+ return 0;
+
+ dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
+ src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
+
+ for (i = 1; i < count; i++)
+ {
+ rtx elt = XVECEXP (op, 0, i);
+
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_DEST (elt)) != REG
+ || GET_MODE (SET_DEST (elt)) != SImode
+ || REGNO (SET_DEST (elt)) != dest_regno + i
+ || GET_CODE (SET_SRC (elt)) != MEM
+ || GET_MODE (SET_SRC (elt)) != SImode
+ || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
+ || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
+ || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
+ || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Similar, but tests for store multiple. Here, the second vector element
+ is a CLOBBER. It will be tested later. */
+
+int
+store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ int count = XVECLEN (op, 0) - 1;
+ unsigned int src_regno;
+ rtx dest_addr;
+ int i;
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= 1
+ || GET_CODE (XVECEXP (op, 0, 0)) != SET
+ || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
+ || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
+ return 0;
+
+ src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
+ dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
+
+ for (i = 1; i < count; i++)
+ {
+ rtx elt = XVECEXP (op, 0, i + 1);
if (GET_CODE (elt) != SET
|| GET_CODE (SET_SRC (elt)) != REG
return 0;
}
+/* Write out a function code label. */
+
+void
+rs6000_output_function_entry (FILE *file, const char *fname)
+{
+ if (fname[0] != '.')
+ {
+ switch (DEFAULT_ABI)
+ {
+ default:
+ abort ();
+
+ case ABI_AIX:
+ if (DOT_SYMBOLS)
+ putc ('.', file);
+ else
+ ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "L.");
+ break;
+
+ case ABI_V4:
+ case ABI_DARWIN:
+ break;
+ }
+ }
+ if (TARGET_AIX)
+ RS6000_OUTPUT_BASENAME (file, fname);
+ else
+ assemble_name (file, fname);
+}
+
/* Print an operand. Recognize special options, documented below. */
#if TARGET_ELF
return;
case 'D':
- /* Like 'J' but get to the GT bit. */
+ /* Like 'J' but get to the EQ bit. */
if (GET_CODE (x) != REG)
abort ();
- /* Bit 1 is GT bit. */
- i = 4 * (REGNO (x) - CR0_REGNO) + 1;
+ /* Bit 1 is EQ bit. */
+ i = 4 * (REGNO (x) - CR0_REGNO) + 2;
/* If we want bit 31, write a shift count of zero, not 32. */
fprintf (file, "%d", i == 31 ? 0 : i + 1);
if (SYMBOL_REF_DECL (x))
mark_decl_referenced (SYMBOL_REF_DECL (x));
- if (XSTR (x, 0)[0] != '.')
- {
- switch (DEFAULT_ABI)
- {
- default:
- abort ();
-
- case ABI_AIX:
- putc ('.', file);
- break;
-
- case ABI_V4:
- case ABI_DARWIN:
- break;
- }
- }
- /* For macho, we need to check it see if we need a stub. */
+ /* For macho, check to see if we need a stub. */
if (TARGET_MACHO)
{
const char *name = XSTR (x, 0);
#if TARGET_MACHO
if (MACHOPIC_INDIRECT
- && machopic_classify_name (name) == MACHOPIC_UNDEFINED_FUNCTION)
- name = machopic_stub_name (name);
+ && machopic_classify_symbol (x) == MACHOPIC_UNDEFINED_FUNCTION)
+ name = machopic_indirection_name (x, /*stub_p=*/true);
#endif
assemble_name (file, name);
}
- else if (TARGET_AIX)
- RS6000_OUTPUT_BASENAME (file, XSTR (x, 0));
- else
+ else if (!DOT_SYMBOLS)
assemble_name (file, XSTR (x, 0));
+ else
+ rs6000_output_function_entry (file, XSTR (x, 0));
return;
case 'Z':
{
/* Functions need to have their entry point symbol visibility set as
well as their descriptor symbol visibility. */
- if (DEFAULT_ABI == ABI_AIX && TREE_CODE (decl) == FUNCTION_DECL)
+ if (DEFAULT_ABI == ABI_AIX
+ && DOT_SYMBOLS
+ && TREE_CODE (decl) == FUNCTION_DECL)
{
static const char * const visibility_types[] = {
NULL, "internal", "hidden", "protected"
abort ();
if (cond_code == NE)
- emit_insn (gen_e500_flip_gt_bit (t, t));
+ emit_insn (gen_e500_flip_eq_bit (t, t));
- emit_insn (gen_move_from_CR_gt_bit (result, t));
+ emit_insn (gen_move_from_CR_eq_bit (result, t));
return;
}
return string;
}
-/* Return the string to flip the GT bit on a CR. */
+/* Return the string to flip the EQ bit on a CR. */
char *
-output_e500_flip_gt_bit (rtx dst, rtx src)
+output_e500_flip_eq_bit (rtx dst, rtx src)
{
static char string[64];
int a, b;
|| GET_CODE (src) != REG || ! CR_REGNO_P (REGNO (src)))
abort ();
- /* GT bit. */
- a = 4 * (REGNO (dst) - CR0_REGNO) + 1;
- b = 4 * (REGNO (src) - CR0_REGNO) + 1;
+ /* EQ bit. */
+ a = 4 * (REGNO (dst) - CR0_REGNO) + 2;
+ b = 4 * (REGNO (src) - CR0_REGNO) + 2;
sprintf (string, "crnot %d,%d", a, b);
return string;
int j = -1;
bool used_update = false;
- if (GET_CODE (src) == MEM && INT_REGNO_P (reg))
+ if (MEM_P (src) && INT_REGNO_P (reg))
{
rtx breg;
: gen_adddi3 (breg, breg, delta_rtx));
src = gen_rtx_MEM (mode, breg);
}
+ else if (! offsettable_memref_p (src))
+ {
+ rtx newsrc, basereg;
+ basereg = gen_rtx_REG (Pmode, reg);
+ emit_insn (gen_rtx_SET (VOIDmode, basereg, XEXP (src, 0)));
+ newsrc = gen_rtx_MEM (GET_MODE (src), basereg);
+ MEM_COPY_ATTRIBUTES (newsrc, src);
+ src = newsrc;
+ }
/* We have now address involving an base register only.
If we use one of the registers to address memory,
: gen_adddi3 (breg, breg, delta_rtx));
dst = gen_rtx_MEM (mode, breg);
}
+ else if (! offsettable_memref_p (dst))
+ abort ();
}
for (i = 0; i < nregs; i++)
return mask;
}
+/* For a very restricted set of circumstances, we can cut down the
+ size of prologs/epilogs by calling our own save/restore-the-world
+ routines. */
+
+static void
+compute_save_world_info(rs6000_stack_t *info_ptr)
+{
+ info_ptr->world_save_p =
+ (DEFAULT_ABI == ABI_DARWIN)
+ && ! (current_function_calls_setjmp && flag_exceptions)
+ && info_ptr->first_fp_reg_save == FIRST_SAVED_FP_REGNO
+ && info_ptr->first_gp_reg_save == FIRST_SAVED_GP_REGNO
+ && info_ptr->first_altivec_reg_save == FIRST_SAVED_ALTIVEC_REGNO
+ && info_ptr->cr_save_p;
+
+ /* This will not work in conjunction with sibcalls. Make sure there
+ are none. (This check is expensive, but seldom executed.) */
+ if ( info_ptr->world_save_p )
+ {
+ rtx insn;
+ for ( insn = get_last_insn_anywhere (); insn; insn = PREV_INSN (insn))
+ if ( GET_CODE (insn) == CALL_INSN
+ && SIBLING_CALL_P (insn))
+ {
+ info_ptr->world_save_p = 0;
+ break;
+ }
+ }
+
+ if (info_ptr->world_save_p)
+ {
+ /* Even if we're not touching VRsave, make sure there's room on the
+ stack for it, if it looks like we're calling SAVE_WORLD, which
+ will attempt to save it. */
+ info_ptr->vrsave_size = 4;
+
+ /* "Save" the VRsave register too if we're saving the world. */
+ if (info_ptr->vrsave_mask == 0)
+ info_ptr->vrsave_mask = compute_vrsave_mask ();
+
+ /* Because the Darwin register save/restore routines only handle
+ F14 .. F31 and V20 .. V31 as per the ABI, perform a consistancy
+ check and abort if there's something worng. */
+ if (info_ptr->first_fp_reg_save < FIRST_SAVED_FP_REGNO
+ || info_ptr->first_altivec_reg_save < FIRST_SAVED_ALTIVEC_REGNO)
+ abort ();
+ }
+ return;
+}
+
+
static void
is_altivec_return_reg (rtx reg, void *xyes)
{
else
info_ptr->vrsave_size = 0;
+ compute_save_world_info (info_ptr);
+
/* Calculate the offsets. */
switch (DEFAULT_ABI)
{
return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
}
+#ifndef TARGET_FIX_AND_CONTINUE
+#define TARGET_FIX_AND_CONTINUE 0
+#endif
+
/* Emit function prologue as insns. */
void
int using_store_multiple;
HOST_WIDE_INT sp_offset = 0;
- if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
- {
- reg_mode = V2SImode;
- reg_size = 8;
- }
+ if (TARGET_FIX_AND_CONTINUE)
+ {
+ /* gdb on darwin arranges to forward a function from the old
+ address by modifying the first 4 instructions of the function
+ to branch to the overriding function. This is necessary to
+ permit function pointers that point to the old function to
+ actually forward to the new function. */
+ emit_insn (gen_nop ());
+ emit_insn (gen_nop ());
+ emit_insn (gen_nop ());
+ emit_insn (gen_nop ());
+ }
+
+ if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
+ {
+ reg_mode = V2SImode;
+ reg_size = 8;
+ }
using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
&& (!TARGET_SPE_ABI
rs6000_emit_stack_tie ();
}
+ /* Handle world saves specially here. */
+ if (info->world_save_p)
+ {
+ int i, j, sz;
+ rtx treg;
+ rtvec p;
+
+ /* save_world expects lr in r0. */
+ if (info->lr_save_p)
+ {
+ insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
+ gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ /* The SAVE_WORLD and RESTORE_WORLD routines make a number of
+ assumptions about the offsets of various bits of the stack
+ frame. Abort if things aren't what they should be. */
+ if (info->gp_save_offset != -220
+ || info->fp_save_offset != -144
+ || info->lr_save_offset != 8
+ || info->cr_save_offset != 4
+ || !info->push_p
+ || !info->lr_save_p
+ || (current_function_calls_eh_return && info->ehrd_offset != -432)
+ || (info->vrsave_save_offset != -224
+ || info->altivec_save_offset != (-224 -16 -192)))
+ abort ();
+
+ treg = gen_rtx_REG (SImode, 11);
+ emit_move_insn (treg, GEN_INT (-info->total_size));
+
+ /* SAVE_WORLD takes the caller's LR in R0 and the frame size
+ in R11. It also clobbers R12, so beware! */
+
+ /* Preserve CR2 for save_world prologues */
+ sz = 6;
+ sz += 32 - info->first_gp_reg_save;
+ sz += 64 - info->first_fp_reg_save;
+ sz += LAST_ALTIVEC_REGNO - info->first_altivec_reg_save + 1;
+ p = rtvec_alloc (sz);
+ j = 0;
+ RTVEC_ELT (p, j++) = gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_REG (Pmode,
+ LINK_REGISTER_REGNUM));
+ RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
+ gen_rtx_SYMBOL_REF (Pmode,
+ "*save_world"));
+ /* We do floats first so that the instruction pattern matches
+ properly. */
+ for (i = 0; i < 64 - info->first_fp_reg_save; i++)
+ {
+ rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
+ rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->fp_save_offset
+ + sp_offset + 8 * i));
+ rtx mem = gen_rtx_MEM (DFmode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+ }
+ for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
+ {
+ rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
+ rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->altivec_save_offset
+ + sp_offset + 16 * i));
+ rtx mem = gen_rtx_MEM (V4SImode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+ }
+ for (i = 0; i < 32 - info->first_gp_reg_save; i++)
+ {
+ rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+ rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->gp_save_offset
+ + sp_offset + reg_size * i));
+ rtx mem = gen_rtx_MEM (reg_mode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+ }
+
+ {
+ /* CR register traditionally saved as CR2. */
+ rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
+ rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->cr_save_offset
+ + sp_offset));
+ rtx mem = gen_rtx_MEM (reg_mode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+ }
+ /* Prevent any attempt to delete the setting of r0 and treg! */
+ RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 0));
+ RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, treg);
+ RTVEC_ELT (p, j++) = gen_rtx_CLOBBER (VOIDmode, sp_reg_rtx);
+
+ insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
+ rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+ NULL_RTX, NULL_RTX);
+
+ if (current_function_calls_eh_return)
+ {
+ unsigned int i;
+ for (i = 0; ; ++i)
+ {
+ unsigned int regno = EH_RETURN_DATA_REGNO (i);
+ if (regno == INVALID_REGNUM)
+ break;
+ emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
+ info->ehrd_offset + sp_offset
+ + reg_size * (int) i,
+ info->total_size);
+ }
+ }
+ }
+
/* Save AltiVec registers if needed. */
- if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
+ if (! info->world_save_p && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
{
int i;
epilogue. */
if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
- && info->vrsave_mask != 0)
+ && ! info->world_save_p && info->vrsave_mask != 0)
{
rtx reg, mem, vrsave;
int offset;
}
/* If we use the link register, get it into r0. */
- if (info->lr_save_p)
+ if (! info->world_save_p && info->lr_save_p)
{
insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
}
/* If we need to save CR, put it into r12. */
- if (info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
+ if (! info->world_save_p && info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
{
rtx set;
/* Do any required saving of fpr's. If only one or two to save, do
it ourselves. Otherwise, call function. */
- if (saving_FPRs_inline)
+ if (! info->world_save_p && saving_FPRs_inline)
{
int i;
for (i = 0; i < 64 - info->first_fp_reg_save; i++)
info->fp_save_offset + sp_offset + 8 * i,
info->total_size);
}
- else if (info->first_fp_reg_save != 64)
+ else if (! info->world_save_p && info->first_fp_reg_save != 64)
{
int i;
char rname[30];
/* Save GPRs. This is done as a PARALLEL if we are using
the store-multiple instructions. */
- if (using_store_multiple)
+ if (! info->world_save_p && using_store_multiple)
{
rtvec p;
int i;
rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
NULL_RTX, NULL_RTX);
}
- else
+ else if (! info->world_save_p)
{
int i;
for (i = 0; i < 32 - info->first_gp_reg_save; i++)
/* ??? There's no need to emit actual instructions here, but it's the
easiest way to get the frame unwind information emitted. */
- if (current_function_calls_eh_return)
+ if (! info->world_save_p && current_function_calls_eh_return)
{
unsigned int i, regno;
}
/* Save lr if we used it. */
- if (info->lr_save_p)
+ if (! info->world_save_p && info->lr_save_p)
{
rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
GEN_INT (info->lr_save_offset + sp_offset));
}
/* Save CR if we use any that must be preserved. */
- if (info->cr_save_p)
+ if (! info->world_save_p && info->cr_save_p)
{
rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
GEN_INT (info->cr_save_offset + sp_offset));
/* Update stack and set back pointer unless this is V.4,
for which it was done previously. */
- if (info->push_p
+ if (! info->world_save_p && info->push_p
&& !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
rs6000_emit_allocate_stack (info->total_size, FALSE);
&& flag_pic && current_function_uses_pic_offset_table)
{
rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
- const char *picbase = machopic_function_base_name ();
- rtx src = gen_rtx_SYMBOL_REF (Pmode, picbase);
+ rtx src = machopic_function_base_sym ();
rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (lr, src)));
|| rs6000_cpu == PROCESSOR_PPC750
|| optimize_size);
+ if (info->world_save_p)
+ {
+ int i, j;
+ char rname[30];
+ const char *alloc_rname;
+ rtvec p;
+
+ /* eh_rest_world_r10 will return to the location saved in the LR
+ stack slot (which is not likely to be our caller.)
+ Input: R10 -- stack adjustment. Clobbers R0, R11, R12, R7, R8.
+ rest_world is similar, except any R10 parameter is ignored.
+ The exception-handling stuff that was here in 2.95 is no
+ longer necessary. */
+
+ p = rtvec_alloc (9
+ + 1
+ + 32 - info->first_gp_reg_save
+ + LAST_ALTIVEC_REGNO + 1 - info->first_altivec_reg_save
+ + 63 + 1 - info->first_fp_reg_save);
+
+ strcpy (rname, (current_function_calls_eh_return) ?
+ "*eh_rest_world_r10" : "*rest_world");
+ alloc_rname = ggc_strdup (rname);
+
+ j = 0;
+ RTVEC_ELT (p, j++) = gen_rtx_RETURN (VOIDmode);
+ RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
+ gen_rtx_REG (Pmode,
+ LINK_REGISTER_REGNUM));
+ RTVEC_ELT (p, j++)
+ = gen_rtx_USE (VOIDmode, gen_rtx_SYMBOL_REF (Pmode, alloc_rname));
+ /* The instruction pattern requires a clobber here;
+ it is shared with the restVEC helper. */
+ RTVEC_ELT (p, j++)
+ = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 11));
+
+ {
+ /* CR register traditionally saved as CR2. */
+ rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
+ rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->cr_save_offset));
+ rtx mem = gen_rtx_MEM (reg_mode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+ }
+
+ for (i = 0; i < 32 - info->first_gp_reg_save; i++)
+ {
+ rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+ rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->gp_save_offset
+ + reg_size * i));
+ rtx mem = gen_rtx_MEM (reg_mode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+ }
+ for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
+ {
+ rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
+ rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->altivec_save_offset
+ + 16 * i));
+ rtx mem = gen_rtx_MEM (V4SImode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+ }
+ for (i = 0; info->first_fp_reg_save + i <= 63; i++)
+ {
+ rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
+ rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->fp_save_offset
+ + 8 * i));
+ rtx mem = gen_rtx_MEM (DFmode, addr);
+ set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+ RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+ }
+ RTVEC_ELT (p, j++)
+ = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 0));
+ RTVEC_ELT (p, j++)
+ = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 12));
+ RTVEC_ELT (p, j++)
+ = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 7));
+ RTVEC_ELT (p, j++)
+ = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 8));
+ RTVEC_ELT (p, j++)
+ = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, 10));
+ emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
+
+ return;
+ }
+
/* If we have a frame pointer, a call to alloca, or a large stack
frame, restore the old stack pointer using the backchain. Otherwise,
we know what size to update it with. */
/* Offset from start of code to tb table. */
fputs ("\t.long ", file);
ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
-#if TARGET_AIX
- RS6000_OUTPUT_BASENAME (file, fname);
-#else
- assemble_name (file, fname);
-#endif
- fputs ("-.", file);
-#if TARGET_AIX
- RS6000_OUTPUT_BASENAME (file, fname);
-#else
- assemble_name (file, fname);
-#endif
+ if (TARGET_AIX)
+ RS6000_OUTPUT_BASENAME (file, fname);
+ else
+ assemble_name (file, fname);
+ putc ('-', file);
+ rs6000_output_function_entry (file, fname);
putc ('\n', file);
/* Interrupt handler mask. */
#if TARGET_MACHO
/* For PIC code, set up a stub and collect the caller's address
from r0, which is where the prologue puts it. */
- if (MACHOPIC_INDIRECT)
- {
- mcount_name = machopic_stub_name (mcount_name);
- if (current_function_uses_pic_offset_table)
- caller_addr_regno = 0;
- }
+ if (MACHOPIC_INDIRECT
+ && current_function_uses_pic_offset_table)
+ caller_addr_regno = 0;
#endif
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, mcount_name),
0, VOIDmode, 1,
add_compiler_branch_island (tree label_name, tree function_name, int line_number)
{
tree branch_island = build_tree_list (function_name, label_name);
- TREE_TYPE (branch_island) = build_int_2 (line_number, 0);
+ TREE_TYPE (branch_island) = build_int_cst (NULL_TREE, line_number, 0);
TREE_CHAIN (branch_island) = branch_island_list;
branch_island_list = branch_island;
}
const char *label =
IDENTIFIER_POINTER (BRANCH_ISLAND_LABEL_NAME (branch_island));
const char *name =
- darwin_strip_name_encoding (
- IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island)));
+ IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island));
char name_buf[512];
/* Cheap copy of the details from the Darwin ASM_OUTPUT_LABELREF(). */
if (name[0] == '*' || name[0] == '&')
machopic_picsymbol_stub1_section ();
else
machopic_symbol_stub1_section ();
- fprintf (file, "\t.align 2\n");
-
- fprintf (file, "%s:\n", stub);
- fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
if (flag_pic == 2)
{
+ fprintf (file, "\t.align 5\n");
+
+ fprintf (file, "%s:\n", stub);
+ fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
+
label++;
local_label_0 = alloca (sizeof("\"L0000000000$spb\""));
sprintf (local_label_0, "\"L%011d$spb\"", label);
fprintf (file, "\tbctr\n");
}
else
- {
- fprintf (file, "\tlis r11,ha16(%s)\n", lazy_ptr_name);
- fprintf (file, "\tlwzu r12,lo16(%s)(r11)\n", lazy_ptr_name);
- fprintf (file, "\tmtctr r12\n");
- fprintf (file, "\tbctr\n");
- }
+ {
+ fprintf (file, "\t.align 4\n");
+
+ fprintf (file, "%s:\n", stub);
+ fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
+
+ fprintf (file, "\tlis r11,ha16(%s)\n", lazy_ptr_name);
+ fprintf (file, "\tlwzu r12,lo16(%s)(r11)\n", lazy_ptr_name);
+ fprintf (file, "\tmtctr r12\n");
+ fprintf (file, "\tbctr\n");
+ }
machopic_lazy_symbol_ptr_section ();
fprintf (file, "%s:\n", lazy_ptr_name);
fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
- fprintf (file, "\t.long dyld_stub_binding_helper\n");
+ fprintf (file, "%sdyld_stub_binding_helper\n",
+ (TARGET_64BIT ? DOUBLE_INT_ASM_OP : "\t.long\t"));
}
/* Legitimize PIC addresses. If the address is already
fputs ("\t.section\t\".opd\",\"aw\"\n\t.align 3\n", file);
ASM_OUTPUT_LABEL (file, name);
fputs (DOUBLE_INT_ASM_OP, file);
- putc ('.', file);
- assemble_name (file, name);
- fputs (",.TOC.@tocbase,0\n\t.previous\n\t.size\t", file);
- assemble_name (file, name);
- fputs (",24\n\t.type\t.", file);
- assemble_name (file, name);
- fputs (",@function\n", file);
- if (TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
+ rs6000_output_function_entry (file, name);
+ fputs (",.TOC.@tocbase,0\n\t.previous\n", file);
+ if (DOT_SYMBOLS)
{
- fputs ("\t.globl\t.", file);
+ fputs ("\t.size\t", file);
+ assemble_name (file, name);
+ fputs (",24\n\t.type\t.", file);
assemble_name (file, name);
- putc ('\n', file);
+ fputs (",@function\n", file);
+ if (TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
+ {
+ fputs ("\t.globl\t.", file);
+ assemble_name (file, name);
+ putc ('\n', file);
+ }
}
+ else
+ ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
- putc ('.', file);
- ASM_OUTPUT_LABEL (file, name);
+ rs6000_output_function_entry (file, name);
+ fputs (":\n", file);
return;
}
rs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
int *total)
{
+ enum machine_mode mode = GET_MODE (x);
+
switch (code)
{
- /* On the RS/6000, if it is valid in the insn, it is free.
- So this always returns 0. */
+ /* On the RS/6000, if it is valid in the insn, it is free. */
case CONST_INT:
- case CONST:
- case LABEL_REF:
- case SYMBOL_REF:
- case CONST_DOUBLE:
- case HIGH:
- *total = 0;
- return true;
-
- case PLUS:
- *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
- && ((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1))
- + 0x8000) >= 0x10000)
- && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
- ? COSTS_N_INSNS (2)
- : COSTS_N_INSNS (1));
- return true;
-
- case MINUS:
- *total = COSTS_N_INSNS (1);
- return true;
-
- case AND:
- case IOR:
- case XOR:
- *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
- && (INTVAL (XEXP (x, 1)) & (~ (HOST_WIDE_INT) 0xffff)) != 0
- && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
- ? COSTS_N_INSNS (2)
- : COSTS_N_INSNS (1));
- return true;
-
- case MULT:
- if (optimize_size)
+ if (((outer_code == SET
+ || outer_code == PLUS
+ || outer_code == MINUS)
+ && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
+ || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')))
+ || ((outer_code == IOR || outer_code == XOR)
+ && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
+ || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')))
+ || ((outer_code == DIV || outer_code == UDIV
+ || outer_code == MOD || outer_code == UMOD)
+ && exact_log2 (INTVAL (x)) >= 0)
+ || (outer_code == AND
+ && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
+ || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')
+ || mask_operand (x, VOIDmode)))
+ || outer_code == ASHIFT
+ || outer_code == ASHIFTRT
+ || outer_code == LSHIFTRT
+ || outer_code == ROTATE
+ || outer_code == ROTATERT
+ || outer_code == ZERO_EXTRACT
+ || (outer_code == MULT
+ && CONST_OK_FOR_LETTER_P (INTVAL (x), 'I'))
+ || (outer_code == COMPARE
+ && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
+ || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))))
{
- *total = COSTS_N_INSNS (2);
+ *total = 0;
return true;
}
- switch (rs6000_cpu)
+ else if ((outer_code == PLUS
+ && reg_or_add_cint64_operand (x, VOIDmode))
+ || (outer_code == MINUS
+ && reg_or_sub_cint64_operand (x, VOIDmode))
+ || ((outer_code == SET
+ || outer_code == IOR
+ || outer_code == XOR)
+ && (INTVAL (x)
+ & ~ (unsigned HOST_WIDE_INT) 0xffffffff) == 0))
{
- case PROCESSOR_RIOS1:
- case PROCESSOR_PPC405:
- *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
- ? COSTS_N_INSNS (5)
- : (INTVAL (XEXP (x, 1)) >= -256
- && INTVAL (XEXP (x, 1)) <= 255)
- ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
- return true;
-
- case PROCESSOR_PPC440:
- *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
- ? COSTS_N_INSNS (3)
- : COSTS_N_INSNS (2));
- return true;
-
- case PROCESSOR_RS64A:
- *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
- ? GET_MODE (XEXP (x, 1)) != DImode
- ? COSTS_N_INSNS (20) : COSTS_N_INSNS (34)
- : (INTVAL (XEXP (x, 1)) >= -256
- && INTVAL (XEXP (x, 1)) <= 255)
- ? COSTS_N_INSNS (8) : COSTS_N_INSNS (12));
- return true;
-
- case PROCESSOR_RIOS2:
- case PROCESSOR_MPCCORE:
- case PROCESSOR_PPC604e:
- *total = COSTS_N_INSNS (2);
+ *total = COSTS_N_INSNS (1);
return true;
+ }
+ /* FALLTHRU */
- case PROCESSOR_PPC601:
- *total = COSTS_N_INSNS (5);
+ case CONST_DOUBLE:
+ if (mode == DImode
+ && ((outer_code == AND
+ && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
+ || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')
+ || mask64_operand (x, DImode)))
+ || ((outer_code == IOR || outer_code == XOR)
+ && CONST_DOUBLE_HIGH (x) == 0
+ && (CONST_DOUBLE_LOW (x)
+ & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0)))
+ {
+ *total = 0;
return true;
-
- case PROCESSOR_PPC603:
- case PROCESSOR_PPC7400:
- case PROCESSOR_PPC750:
- *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
- ? COSTS_N_INSNS (5)
- : (INTVAL (XEXP (x, 1)) >= -256
- && INTVAL (XEXP (x, 1)) <= 255)
- ? COSTS_N_INSNS (2) : COSTS_N_INSNS (3));
+ }
+ else if (mode == DImode
+ && (outer_code == SET
+ || outer_code == IOR
+ || outer_code == XOR)
+ && CONST_DOUBLE_HIGH (x) == 0)
+ {
+ *total = COSTS_N_INSNS (1);
return true;
+ }
+ /* FALLTHRU */
- case PROCESSOR_PPC7450:
- *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
- ? COSTS_N_INSNS (4)
- : COSTS_N_INSNS (3));
- return true;
+ case CONST:
+ case HIGH:
+ case SYMBOL_REF:
+ case MEM:
+ /* When optimizing for size, MEM should be slightly more expensive
+ than generating address, e.g., (plus (reg) (const)).
+ L1 cache latecy is about two instructions. */
+ *total = optimize_size ? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (2);
+ return true;
- case PROCESSOR_PPC403:
- case PROCESSOR_PPC604:
- case PROCESSOR_PPC8540:
- *total = COSTS_N_INSNS (4);
- return true;
+ case LABEL_REF:
+ *total = 0;
+ return true;
- case PROCESSOR_PPC620:
- case PROCESSOR_PPC630:
- *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
- ? GET_MODE (XEXP (x, 1)) != DImode
- ? COSTS_N_INSNS (5) : COSTS_N_INSNS (7)
- : (INTVAL (XEXP (x, 1)) >= -256
- && INTVAL (XEXP (x, 1)) <= 255)
- ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
- return true;
+ case PLUS:
+ if (mode == DFmode)
+ {
+ if (GET_CODE (XEXP (x, 0)) == MULT)
+ {
+ /* FNMA accounted in outer NEG. */
+ if (outer_code == NEG)
+ *total = rs6000_cost->dmul - rs6000_cost->fp;
+ else
+ *total = rs6000_cost->dmul;
+ }
+ else
+ *total = rs6000_cost->fp;
+ }
+ else if (mode == SFmode)
+ {
+ /* FNMA accounted in outer NEG. */
+ if (outer_code == NEG && GET_CODE (XEXP (x, 0)) == MULT)
+ *total = 0;
+ else
+ *total = rs6000_cost->fp;
+ }
+ else if (GET_CODE (XEXP (x, 0)) == MULT)
+ {
+ /* The rs6000 doesn't have shift-and-add instructions. */
+ rs6000_rtx_costs (XEXP (x, 0), MULT, PLUS, total);
+ *total += COSTS_N_INSNS (1);
+ }
+ else
+ *total = COSTS_N_INSNS (1);
+ return false;
- case PROCESSOR_POWER4:
- case PROCESSOR_POWER5:
- *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
- ? GET_MODE (XEXP (x, 1)) != DImode
- ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4)
- : COSTS_N_INSNS (2));
- return true;
+ case MINUS:
+ if (mode == DFmode)
+ {
+ if (GET_CODE (XEXP (x, 0)) == MULT)
+ {
+ /* FNMA accounted in outer NEG. */
+ if (outer_code == NEG)
+ *total = 0;
+ else
+ *total = rs6000_cost->dmul;
+ }
+ else
+ *total = rs6000_cost->fp;
+ }
+ else if (mode == SFmode)
+ {
+ /* FNMA accounted in outer NEG. */
+ if (outer_code == NEG && GET_CODE (XEXP (x, 0)) == MULT)
+ *total = 0;
+ else
+ *total = rs6000_cost->fp;
+ }
+ else if (GET_CODE (XEXP (x, 0)) == MULT)
+ {
+ /* The rs6000 doesn't have shift-and-sub instructions. */
+ rs6000_rtx_costs (XEXP (x, 0), MULT, MINUS, total);
+ *total += COSTS_N_INSNS (1);
+ }
+ else
+ *total = COSTS_N_INSNS (1);
+ return false;
- default:
- abort ();
+ case MULT:
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ if (INTVAL (XEXP (x, 1)) >= -256
+ && INTVAL (XEXP (x, 1)) <= 255)
+ *total = rs6000_cost->mulsi_const9;
+ else
+ *total = rs6000_cost->mulsi_const;
}
+ /* FMA accounted in outer PLUS/MINUS. */
+ else if ((mode == DFmode || mode == SFmode)
+ && (outer_code == PLUS || outer_code == MINUS))
+ *total = 0;
+ else if (mode == DFmode)
+ *total = rs6000_cost->dmul;
+ else if (mode == SFmode)
+ *total = rs6000_cost->fp;
+ else if (mode == DImode)
+ *total = rs6000_cost->muldi;
+ else
+ *total = rs6000_cost->mulsi;
+ return false;
case DIV:
case MOD:
- if (GET_CODE (XEXP (x, 1)) == CONST_INT
- && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
+ if (FLOAT_MODE_P (mode))
{
- *total = COSTS_N_INSNS (2);
- return true;
+ *total = mode == DFmode ? rs6000_cost->ddiv
+ : rs6000_cost->sdiv;
+ return false;
}
/* FALLTHRU */
case UDIV:
case UMOD:
- switch (rs6000_cpu)
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
{
- case PROCESSOR_RIOS1:
- *total = COSTS_N_INSNS (19);
- return true;
-
- case PROCESSOR_RIOS2:
- *total = COSTS_N_INSNS (13);
- return true;
-
- case PROCESSOR_RS64A:
- *total = (GET_MODE (XEXP (x, 1)) != DImode
- ? COSTS_N_INSNS (65)
- : COSTS_N_INSNS (67));
- return true;
-
- case PROCESSOR_MPCCORE:
- *total = COSTS_N_INSNS (6);
- return true;
-
- case PROCESSOR_PPC403:
- *total = COSTS_N_INSNS (33);
- return true;
-
- case PROCESSOR_PPC405:
- *total = COSTS_N_INSNS (35);
- return true;
+ if (code == DIV || code == MOD)
+ /* Shift, addze */
+ *total = COSTS_N_INSNS (2);
+ else
+ /* Shift */
+ *total = COSTS_N_INSNS (1);
+ }
+ else
+ {
+ if (GET_MODE (XEXP (x, 1)) == DImode)
+ *total = rs6000_cost->divdi;
+ else
+ *total = rs6000_cost->divsi;
+ }
+ /* Add in shift and subtract for MOD. */
+ if (code == MOD || code == UMOD)
+ *total += COSTS_N_INSNS (2);
+ return false;
- case PROCESSOR_PPC440:
- *total = COSTS_N_INSNS (34);
- return true;
+ case FFS:
+ *total = COSTS_N_INSNS (4);
+ return false;
- case PROCESSOR_PPC601:
- *total = COSTS_N_INSNS (36);
- return true;
+ case NOT:
+ if (outer_code == AND || outer_code == IOR || outer_code == XOR)
+ {
+ *total = 0;
+ return false;
+ }
+ /* FALLTHRU */
- case PROCESSOR_PPC603:
- *total = COSTS_N_INSNS (37);
- return true;
+ case AND:
+ case IOR:
+ case XOR:
+ case ZERO_EXTRACT:
+ *total = COSTS_N_INSNS (1);
+ return false;
- case PROCESSOR_PPC604:
- case PROCESSOR_PPC604e:
- *total = COSTS_N_INSNS (20);
+ case ASHIFT:
+ case ASHIFTRT:
+ case LSHIFTRT:
+ case ROTATE:
+ case ROTATERT:
+ /* Handle mul_highpart. */
+ if (outer_code == TRUNCATE
+ && GET_CODE (XEXP (x, 0)) == MULT)
+ {
+ if (mode == DImode)
+ *total = rs6000_cost->muldi;
+ else
+ *total = rs6000_cost->mulsi;
return true;
+ }
+ else if (outer_code == AND)
+ *total = 0;
+ else
+ *total = COSTS_N_INSNS (1);
+ return false;
- case PROCESSOR_PPC620:
- case PROCESSOR_PPC630:
- *total = (GET_MODE (XEXP (x, 1)) != DImode
- ? COSTS_N_INSNS (21)
- : COSTS_N_INSNS (37));
- return true;
+ case SIGN_EXTEND:
+ case ZERO_EXTEND:
+ if (GET_CODE (XEXP (x, 0)) == MEM)
+ *total = 0;
+ else
+ *total = COSTS_N_INSNS (1);
+ return false;
- case PROCESSOR_PPC750:
- case PROCESSOR_PPC8540:
- case PROCESSOR_PPC7400:
- *total = COSTS_N_INSNS (19);
- return true;
+ case COMPARE:
+ case NEG:
+ case ABS:
+ if (!FLOAT_MODE_P (mode))
+ {
+ *total = COSTS_N_INSNS (1);
+ return false;
+ }
+ /* FALLTHRU */
- case PROCESSOR_PPC7450:
- *total = COSTS_N_INSNS (23);
- return true;
+ case FLOAT:
+ case UNSIGNED_FLOAT:
+ case FIX:
+ case UNSIGNED_FIX:
+ case FLOAT_EXTEND:
+ case FLOAT_TRUNCATE:
+ *total = rs6000_cost->fp;
+ return false;
- case PROCESSOR_POWER4:
- case PROCESSOR_POWER5:
- *total = (GET_MODE (XEXP (x, 1)) != DImode
- ? COSTS_N_INSNS (18)
- : COSTS_N_INSNS (34));
+ case UNSPEC:
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_FRSP:
+ *total = rs6000_cost->fp;
return true;
default:
- abort ();
+ break;
}
+ break;
- case FFS:
- *total = COSTS_N_INSNS (4);
- return true;
+ case CALL:
+ case IF_THEN_ELSE:
+ if (optimize_size)
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ else if (FLOAT_MODE_P (mode)
+ && TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS)
+ {
+ *total = rs6000_cost->fp;
+ return false;
+ }
- case MEM:
- /* MEM should be slightly more expensive than (plus (reg) (const)). */
- *total = 5;
- return true;
+ break;
default:
- return false;
+ break;
}
+
+ return false;
}
/* A C expression returning the cost of moving data from a register of class
&& targetm.calls.split_complex_arg)
return rs6000_complex_function_value (mode);
else if (TREE_CODE (valtype) == VECTOR_TYPE
- && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
+ && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI
+ && ALTIVEC_VECTOR_MODE(mode))
regno = ALTIVEC_ARG_RETURN;
else
regno = GP_ARG_RETURN;
abort ();
}
+/* target hook eh_return_filter_mode */
+static enum machine_mode
+rs6000_eh_return_filter_mode (void)
+{
+ return TARGET_32BIT ? SImode : word_mode;
+}
+
#include "gt-rs6000.h"