#include "tm_p.h"
#include "target.h"
#include "target-def.h"
+#include "common/common-target.h"
#include "langhooks.h"
#include "reload.h"
#include "cfglayout.h"
int ra_need_lr;
/* Cache lr_save_p after expansion of builtin_eh_return. */
int lr_save_state;
+ /* Whether we need to save the TOC to the reserved stack location in the
+ function prologue. */
+ bool save_toc_in_prologue;
/* Offset from virtual_stack_vars_rtx to the start of the ABI_V4
varargs save area. */
HOST_WIDE_INT varargs_save_offset;
rtx sdmode_stack_slot;
} machine_function;
-/* Target cpu type */
-
-struct rs6000_cpu_select rs6000_select[3] =
-{
- /* switch name, tune arch */
- { (const char *)0, "--with-cpu=", 1, 1 },
- { (const char *)0, "-mcpu=", 1, 1 },
- { (const char *)0, "-mtune=", 1, 0 },
-};
-
/* Support targetm.vectorize.builtin_mask_for_load. */
static GTY(()) tree altivec_builtin_mask_for_load;
/* Reload functions based on the type and the vector unit. */
static enum insn_code rs6000_vector_reload[NUM_MACHINE_MODES][2];
+static int dbg_cost_ctrl;
+
/* Built in types. */
tree rs6000_builtin_types[RS6000_BTI_MAX];
tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT];
static bool rs6000_debug_legitimate_address_p (enum machine_mode, rtx, bool);
static rtx rs6000_generate_compare (rtx, enum machine_mode);
static void rs6000_emit_stack_tie (void);
-static void rs6000_frame_related (rtx, rtx, HOST_WIDE_INT, rtx, rtx);
static bool spe_func_has_64bit_regs_p (void);
-static void emit_frame_save (rtx, rtx, enum machine_mode, unsigned int,
- int, HOST_WIDE_INT);
static rtx gen_frame_mem_offset (enum machine_mode, rtx, int);
static unsigned rs6000_hash_constant (rtx);
static unsigned toc_hash_function (const void *);
static struct machine_function * rs6000_init_machine_status (void);
static bool rs6000_assemble_integer (rtx, unsigned int, int);
static bool no_global_regs_above (int, bool);
-#ifdef HAVE_GAS_HIDDEN
+#if defined (HAVE_GAS_HIDDEN) && !defined (TARGET_MACHO)
static void rs6000_assemble_visibility (tree, int);
#endif
static int rs6000_ra_ever_killed (void);
static void rs6000_set_default_type_attributes (tree);
static rtx rs6000_savres_routine_sym (rs6000_stack_t *, bool, bool, bool);
static rtx rs6000_emit_stack_reset (rs6000_stack_t *, rtx, rtx, int, bool);
-static rtx rs6000_make_savres_rtx (rs6000_stack_t *, rtx, int,
- enum machine_mode, bool, bool, bool);
static bool rs6000_reg_live_or_pic_offset_p (int);
static tree rs6000_builtin_vectorized_libmass (tree, tree, tree);
static tree rs6000_builtin_vectorized_function (tree, tree, tree);
static int rs6000_register_move_cost (enum machine_mode,
reg_class_t, reg_class_t);
static int rs6000_memory_move_cost (enum machine_mode, reg_class_t, bool);
-static bool rs6000_rtx_costs (rtx, int, int, int *, bool);
-static bool rs6000_debug_rtx_costs (rtx, int, int, int *, bool);
+static bool rs6000_rtx_costs (rtx, int, int, int, int *, bool);
+static bool rs6000_debug_rtx_costs (rtx, int, int, int, int *, bool);
static int rs6000_debug_address_cost (rtx, bool);
static int rs6000_adjust_cost (rtx, rtx, rtx, int);
static int rs6000_debug_adjust_cost (rtx, rtx, rtx, int);
static tree rs6000_builtin_mul_widen_even (tree);
static tree rs6000_builtin_mul_widen_odd (tree);
static tree rs6000_builtin_conversion (unsigned int, tree, tree);
-static tree rs6000_builtin_vec_perm (tree, tree *);
static bool rs6000_builtin_support_vector_misalignment (enum
machine_mode,
const_tree,
static rtx altivec_expand_vec_ext_builtin (tree, rtx);
static int get_element_number (tree, tree);
static void rs6000_option_override (void);
-static void rs6000_option_init_struct (struct gcc_options *);
-static void rs6000_option_default_params (void);
-static bool rs6000_handle_option (struct gcc_options *, struct gcc_options *,
- const struct cl_decoded_option *,
- location_t);
static int rs6000_loop_align_max_skip (rtx);
static int first_altivec_reg_to_save (void);
static unsigned int compute_vrsave_mask (void);
rtx[], int *);
static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, const_tree, bool, bool);
static rtx rs6000_mixed_function_arg (enum machine_mode, const_tree, int);
-static void rs6000_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
+static void rs6000_function_arg_advance (cumulative_args_t, enum machine_mode,
const_tree, bool);
-static rtx rs6000_function_arg (CUMULATIVE_ARGS *, enum machine_mode,
+static rtx rs6000_function_arg (cumulative_args_t, enum machine_mode,
const_tree, bool);
static unsigned int rs6000_function_arg_boundary (enum machine_mode,
const_tree);
static void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
-static void setup_incoming_varargs (CUMULATIVE_ARGS *,
+static void setup_incoming_varargs (cumulative_args_t,
enum machine_mode, tree,
int *, int);
-static bool rs6000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+static bool rs6000_pass_by_reference (cumulative_args_t, enum machine_mode,
const_tree, bool);
-static int rs6000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+static int rs6000_arg_partial_bytes (cumulative_args_t, enum machine_mode,
tree, bool);
static const char *invalid_arg_for_unprototyped_fn (const_tree, const_tree, const_tree);
#if TARGET_MACHO
static void rs6000_trampoline_init (rtx, tree, rtx);
static bool rs6000_cannot_force_const_mem (enum machine_mode, rtx);
static bool rs6000_legitimate_constant_p (enum machine_mode, rtx);
+static bool rs6000_save_toc_in_prologue_p (void);
+static void rs6000_code_end (void) ATTRIBUTE_UNUSED;
/* Hash table stuff for keeping track of TOC entries. */
#endif
{ NULL, 0, 0, false, false, false, NULL, false }
};
-
-/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
-static const struct default_options rs6000_option_optimization_table[] =
- {
- { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
- { OPT_LEVELS_NONE, 0, NULL, 0 }
- };
\f
#ifndef MASK_STRICT_ALIGN
#define MASK_STRICT_ALIGN 0
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER rs6000_assemble_integer
-#ifdef HAVE_GAS_HIDDEN
+#if defined (HAVE_GAS_HIDDEN) && !defined (TARGET_MACHO)
#undef TARGET_ASM_ASSEMBLE_VISIBILITY
#define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility
#endif
#define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD rs6000_builtin_mul_widen_odd
#undef TARGET_VECTORIZE_BUILTIN_CONVERSION
#define TARGET_VECTORIZE_BUILTIN_CONVERSION rs6000_builtin_conversion
-#undef TARGET_VECTORIZE_BUILTIN_VEC_PERM
-#define TARGET_VECTORIZE_BUILTIN_VEC_PERM rs6000_builtin_vec_perm
#undef TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT
#define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
rs6000_builtin_support_vector_misalignment
#undef TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN
#define TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN invalid_arg_for_unprototyped_fn
-#undef TARGET_HANDLE_OPTION
-#define TARGET_HANDLE_OPTION rs6000_handle_option
-
#undef TARGET_ASM_LOOP_ALIGN_MAX_SKIP
#define TARGET_ASM_LOOP_ALIGN_MAX_SKIP rs6000_loop_align_max_skip
#undef TARGET_OPTION_OVERRIDE
#define TARGET_OPTION_OVERRIDE rs6000_option_override
-#undef TARGET_OPTION_INIT_STRUCT
-#define TARGET_OPTION_INIT_STRUCT rs6000_option_init_struct
-
-#undef TARGET_OPTION_DEFAULT_PARAMS
-#define TARGET_OPTION_DEFAULT_PARAMS rs6000_option_default_params
-
-#undef TARGET_OPTION_OPTIMIZATION_TABLE
-#define TARGET_OPTION_OPTIMIZATION_TABLE rs6000_option_optimization_table
-
#undef TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION
#define TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION \
rs6000_builtin_vectorized_function
-#undef TARGET_DEFAULT_TARGET_FLAGS
-#define TARGET_DEFAULT_TARGET_FLAGS \
- (TARGET_DEFAULT)
-
+#ifndef TARGET_MACHO
#undef TARGET_STACK_PROTECT_FAIL
#define TARGET_STACK_PROTECT_FAIL rs6000_stack_protect_fail
+#endif
/* MPC604EUM 3.5.2 Weak Consistency between Multiple Processors
The PowerPC architecture requires only weak consistency among
#undef TARGET_LEGITIMATE_CONSTANT_P
#define TARGET_LEGITIMATE_CONSTANT_P rs6000_legitimate_constant_p
-struct gcc_target targetm = TARGET_INITIALIZER;
\f
/* Simplifications for entries below. */
| MASK_VSX)
};
-/* This table occasionally claims that a processor does not support a
- particular feature even though it does, but the feature is slower than the
- alternative. Thus, it shouldn't be relied on as a complete description of
- the processor's support.
-
- Please keep this list in order, and don't forget to update the documentation
- in invoke.texi when adding a new processor or flag. */
-
struct rs6000_ptt
{
const char *const name; /* Canonical processor name. */
static struct rs6000_ptt const processor_target_table[] =
{
- {"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
- {"403", PROCESSOR_PPC403,
- POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN},
- {"405", PROCESSOR_PPC405,
- POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
- {"405fp", PROCESSOR_PPC405,
- POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
- {"440", PROCESSOR_PPC440,
- POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
- {"440fp", PROCESSOR_PPC440,
- POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
- {"464", PROCESSOR_PPC440,
- POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
- {"464fp", PROCESSOR_PPC440,
- POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
- {"476", PROCESSOR_PPC476,
- POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_PPC_GFXOPT | MASK_MFCRF
- | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_MULHW | MASK_DLMZB},
- {"476fp", PROCESSOR_PPC476,
- POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POPCNTB
- | MASK_FPRND | MASK_CMPB | MASK_MULHW | MASK_DLMZB},
- {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK},
- {"601", PROCESSOR_PPC601,
- MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING},
- {"602", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
- {"603", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
- {"603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
- {"604", PROCESSOR_PPC604, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
- {"604e", PROCESSOR_PPC604e, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
- {"620", PROCESSOR_PPC620,
- POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
- {"630", PROCESSOR_PPC630,
- POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
- {"740", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
- {"7400", PROCESSOR_PPC7400, POWERPC_7400_MASK},
- {"7450", PROCESSOR_PPC7450, POWERPC_7400_MASK},
- {"750", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
- {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
- {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
- {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
- {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN
- | MASK_ISEL},
- /* 8548 has a dummy entry for now. */
- {"8548", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN
- | MASK_ISEL},
- {"a2", PROCESSOR_PPCA2,
- POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_POPCNTB
- | MASK_CMPB | MASK_NO_UPDATE },
- {"e300c2", PROCESSOR_PPCE300C2, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
- {"e300c3", PROCESSOR_PPCE300C3, POWERPC_BASE_MASK},
- {"e500mc", PROCESSOR_PPCE500MC, POWERPC_BASE_MASK | MASK_PPC_GFXOPT
- | MASK_ISEL},
- {"e500mc64", PROCESSOR_PPCE500MC64, POWERPC_BASE_MASK | MASK_POWERPC64
- | MASK_PPC_GFXOPT | MASK_ISEL},
- {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
- {"970", PROCESSOR_POWER4,
- POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
- {"cell", PROCESSOR_CELL,
- POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
- {"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS},
- {"ec603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
- {"G3", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
- {"G4", PROCESSOR_PPC7450, POWERPC_7400_MASK},
- {"G5", PROCESSOR_POWER4,
- POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
- {"titan", PROCESSOR_TITAN,
- POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
- {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
- {"power2", PROCESSOR_POWER,
- MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
- {"power3", PROCESSOR_PPC630,
- POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
- {"power4", PROCESSOR_POWER4,
- POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
- | MASK_MFCRF},
- {"power5", PROCESSOR_POWER5,
- POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
- | MASK_MFCRF | MASK_POPCNTB},
- {"power5+", PROCESSOR_POWER5,
- POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
- | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND},
- {"power6", PROCESSOR_POWER6,
- POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
- | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP
- | MASK_RECIP_PRECISION},
- {"power6x", PROCESSOR_POWER6,
- POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
- | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP
- | MASK_MFPGPR | MASK_RECIP_PRECISION},
- {"power7", PROCESSOR_POWER7, /* Don't add MASK_ISEL by default */
- POWERPC_7400_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_MFCRF
- | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP | MASK_POPCNTD
- | MASK_VSX | MASK_RECIP_PRECISION},
- {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
- {"powerpc64", PROCESSOR_POWERPC64,
- POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
- {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
- {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
- {"rios2", PROCESSOR_RIOS2,
- MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
- {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
- {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
- {"rs64", PROCESSOR_RS64A,
- POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}
+#define RS6000_CPU(NAME, CPU, FLAGS) { NAME, CPU, FLAGS },
+#include "rs6000-cpus.def"
+#undef RS6000_CPU
};
/* Look up a processor name for -mcpu=xxx and -mtune=xxx. Return -1 if the
&& !flag_apple_kext
&& strverscmp (darwin_macosx_version_min, "10.5") >= 0
&& ! (target_flags_explicit & MASK_ALTIVEC)
- && ! rs6000_select[1].string)
+ && ! global_options_set.x_rs6000_cpu_index)
{
target_flags |= MASK_ALTIVEC;
}
if ((target_flags & MASK_STRING) != 0)
target_flags = target_flags & ~MASK_STRING;
}
- else if (rs6000_select[1].string != NULL)
+ else if (global_options_set.x_rs6000_cpu_index)
{
/* For the powerpc-eabispe configuration, we set all these by
default, so let's unset them if we manually set another
target_option_default_node = target_option_current_node
= build_target_option_node ();
+ /* If not explicitly specified via option, decide whether to generate the
+ extra blr's required to preserve the link stack on some cpus (eg, 476). */
+ if (TARGET_LINK_STACK == -1)
+ SET_TARGET_LINK_STACK (rs6000_cpu == PROCESSOR_PPC476 && flag_pic);
+
return ret;
}
return false;
}
-/* Implement targetm.vectorize.builtin_vec_perm. */
-tree
-rs6000_builtin_vec_perm (tree type, tree *mask_element_type)
-{
- tree inner_type = TREE_TYPE (type);
- bool uns_p = TYPE_UNSIGNED (inner_type);
- tree d;
-
- *mask_element_type = unsigned_char_type_node;
-
- switch (TYPE_MODE (type))
- {
- case V16QImode:
- d = (uns_p
- ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_16QI_UNS]
- : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_16QI]);
- break;
-
- case V8HImode:
- d = (uns_p
- ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_8HI_UNS]
- : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_8HI]);
- break;
-
- case V4SImode:
- d = (uns_p
- ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_4SI_UNS]
- : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_4SI]);
- break;
-
- case V4SFmode:
- d = rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_4SF];
- break;
-
- case V2DFmode:
- if (!TARGET_ALLOW_DF_PERMUTE)
- return NULL_TREE;
-
- d = rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_2DF];
- break;
-
- case V2DImode:
- if (!TARGET_ALLOW_DF_PERMUTE)
- return NULL_TREE;
-
- d = (uns_p
- ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_2DI_UNS]
- : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_2DI]);
- break;
-
- default:
- return NULL_TREE;
- }
-
- gcc_assert (d);
- return d;
-}
-
-
/* Implement targetm.vectorize.builtin_vectorization_cost. */
static int
rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
return word_mode;
}
-/* Implement TARGET_OPTION_INIT_STRUCT. */
-
-static void
-rs6000_option_init_struct (struct gcc_options *opts)
-{
- if (DEFAULT_ABI == ABI_DARWIN)
- /* The Darwin libraries never set errno, so we might as well
- avoid calling them when that's the only reason we would. */
- opts->x_flag_errno_math = 0;
-
- /* Enable section anchors by default. */
- if (!TARGET_MACHO)
- opts->x_flag_section_anchors = 1;
-}
-
-/* Implement TARGET_OPTION_DEFAULT_PARAMS. */
-
-static void
-rs6000_option_default_params (void)
-{
- /* Double growth factor to counter reduced min jump length. */
- set_default_param_value (PARAM_MAX_GROW_COPY_BB_INSNS, 16);
-}
-
/* Handler for the Mathematical Acceleration Subsystem (mass) interface to a
library with vectorized intrinsics. */
case BUILT_IN_SQRT:
case BUILT_IN_TAN:
case BUILT_IN_TANH:
- bdecl = implicit_built_in_decls[fn];
+ bdecl = builtin_decl_implicit (fn);
suffix = "d2"; /* pow -> powd2 */
if (el_mode != DFmode
|| n != 2)
case BUILT_IN_SQRTF:
case BUILT_IN_TANF:
case BUILT_IN_TANHF:
- bdecl = implicit_built_in_decls[fn];
+ bdecl = builtin_decl_implicit (fn);
suffix = "4"; /* powf -> powf4 */
if (el_mode != SFmode
|| n != 4)
return NULL_TREE;
}
-
-
-/* Implement TARGET_HANDLE_OPTION. */
-
-static bool
-rs6000_handle_option (struct gcc_options *opts, struct gcc_options *opts_set,
- const struct cl_decoded_option *decoded,
- location_t loc)
-{
- enum fpu_type_t fpu_type = FPU_NONE;
- char *p, *q;
- size_t code = decoded->opt_index;
- const char *arg = decoded->arg;
- int value = decoded->value;
-
- gcc_assert (opts == &global_options);
- gcc_assert (opts_set == &global_options_set);
-
- switch (code)
- {
- case OPT_mno_power:
- opts->x_target_flags &= ~(MASK_POWER | MASK_POWER2
- | MASK_MULTIPLE | MASK_STRING);
- opts_set->x_target_flags |= (MASK_POWER | MASK_POWER2
- | MASK_MULTIPLE | MASK_STRING);
- break;
- case OPT_mno_powerpc:
- opts->x_target_flags &= ~(MASK_POWERPC | MASK_PPC_GPOPT
- | MASK_PPC_GFXOPT | MASK_POWERPC64);
- opts_set->x_target_flags |= (MASK_POWERPC | MASK_PPC_GPOPT
- | MASK_PPC_GFXOPT | MASK_POWERPC64);
- break;
- case OPT_mfull_toc:
- opts->x_target_flags &= ~MASK_MINIMAL_TOC;
- opts->x_TARGET_NO_FP_IN_TOC = 0;
- opts->x_TARGET_NO_SUM_IN_TOC = 0;
- opts_set->x_target_flags |= MASK_MINIMAL_TOC;
-#ifdef TARGET_USES_SYSV4_OPT
- /* Note, V.4 no longer uses a normal TOC, so make -mfull-toc, be
- just the same as -mminimal-toc. */
- opts->x_target_flags |= MASK_MINIMAL_TOC;
- opts_set->x_target_flags |= MASK_MINIMAL_TOC;
-#endif
- break;
-
-#ifdef TARGET_USES_SYSV4_OPT
- case OPT_mtoc:
- /* Make -mtoc behave like -mminimal-toc. */
- opts->x_target_flags |= MASK_MINIMAL_TOC;
- opts_set->x_target_flags |= MASK_MINIMAL_TOC;
- break;
-#endif
-
-#ifdef TARGET_USES_AIX64_OPT
- case OPT_maix64:
-#else
- case OPT_m64:
-#endif
- opts->x_target_flags |= MASK_POWERPC64 | MASK_POWERPC;
- opts->x_target_flags |= ~opts_set->x_target_flags & MASK_PPC_GFXOPT;
- opts_set->x_target_flags |= MASK_POWERPC64 | MASK_POWERPC;
- break;
-
-#ifdef TARGET_USES_AIX64_OPT
- case OPT_maix32:
-#else
- case OPT_m32:
-#endif
- opts->x_target_flags &= ~MASK_POWERPC64;
- opts_set->x_target_flags |= MASK_POWERPC64;
- break;
-
- case OPT_mminimal_toc:
- if (value == 1)
- {
- opts->x_TARGET_NO_FP_IN_TOC = 0;
- opts->x_TARGET_NO_SUM_IN_TOC = 0;
- }
- break;
-
- case OPT_mpower:
- if (value == 1)
- {
- opts->x_target_flags |= (MASK_MULTIPLE | MASK_STRING);
- opts_set->x_target_flags |= (MASK_MULTIPLE | MASK_STRING);
- }
- break;
-
- case OPT_mpower2:
- if (value == 1)
- {
- opts->x_target_flags |= (MASK_POWER | MASK_MULTIPLE | MASK_STRING);
- opts_set->x_target_flags |= (MASK_POWER
- | MASK_MULTIPLE
- | MASK_STRING);
- }
- break;
-
- case OPT_mpowerpc_gpopt:
- case OPT_mpowerpc_gfxopt:
- if (value == 1)
- {
- opts->x_target_flags |= MASK_POWERPC;
- opts_set->x_target_flags |= MASK_POWERPC;
- }
- break;
-
- case OPT_mdebug_:
- p = ASTRDUP (arg);
- opts->x_rs6000_debug = 0;
-
- while ((q = strtok (p, ",")) != NULL)
- {
- unsigned mask = 0;
- bool invert;
-
- p = NULL;
- if (*q == '!')
- {
- invert = true;
- q++;
- }
- else
- invert = false;
-
- if (! strcmp (q, "all"))
- mask = MASK_DEBUG_ALL;
- else if (! strcmp (q, "stack"))
- mask = MASK_DEBUG_STACK;
- else if (! strcmp (q, "arg"))
- mask = MASK_DEBUG_ARG;
- else if (! strcmp (q, "reg"))
- mask = MASK_DEBUG_REG;
- else if (! strcmp (q, "addr"))
- mask = MASK_DEBUG_ADDR;
- else if (! strcmp (q, "cost"))
- mask = MASK_DEBUG_COST;
- else if (! strcmp (q, "target"))
- mask = MASK_DEBUG_TARGET;
- else
- error_at (loc, "unknown -mdebug-%s switch", q);
-
- if (invert)
- opts->x_rs6000_debug &= ~mask;
- else
- opts->x_rs6000_debug |= mask;
- }
- break;
-
-#ifdef TARGET_USES_SYSV4_OPT
- case OPT_mrelocatable:
- if (value == 1)
- {
- opts->x_target_flags |= MASK_MINIMAL_TOC;
- opts_set->x_target_flags |= MASK_MINIMAL_TOC;
- opts->x_TARGET_NO_FP_IN_TOC = 1;
- }
- break;
-
- case OPT_mrelocatable_lib:
- if (value == 1)
- {
- opts->x_target_flags |= MASK_RELOCATABLE | MASK_MINIMAL_TOC;
- opts_set->x_target_flags |= MASK_RELOCATABLE | MASK_MINIMAL_TOC;
- opts->x_TARGET_NO_FP_IN_TOC = 1;
- }
- else
- {
- opts->x_target_flags &= ~MASK_RELOCATABLE;
- opts_set->x_target_flags |= MASK_RELOCATABLE;
- }
- break;
-#endif
-
- case OPT_mabi_altivec:
- /* Enabling the AltiVec ABI turns off the SPE ABI. */
- opts->x_rs6000_spe_abi = 0;
- break;
-
- case OPT_mabi_spe:
- opts->x_rs6000_altivec_abi = 0;
- break;
-
- case OPT_mcpu_:
- rs6000_select[1].string = arg;
- opts->x_rs6000_cpu_index = rs6000_cpu_name_lookup (arg);
- if (opts->x_rs6000_cpu_index < 0)
- error_at (loc, "bad value (%s) for -mcpu", arg);
- break;
-
- case OPT_mtune_:
- rs6000_select[2].string = arg;
- opts->x_rs6000_tune_index = rs6000_cpu_name_lookup (arg);
- if (opts->x_rs6000_tune_index < 0)
- error_at (loc, "bad value (%s) for -mtune", arg);
- break;
-
- case OPT_mlong_double_:
- if (value != 64 && value != 128)
- {
- error_at (loc, "unknown switch -mlong-double-%s", arg);
- opts->x_rs6000_long_double_type_size
- = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
- return false;
- }
- break;
-
- case OPT_msingle_float:
- if (!TARGET_SINGLE_FPU)
- warning_at (loc, 0,
- "-msingle-float option equivalent to -mhard-float");
- /* -msingle-float implies -mno-double-float and TARGET_HARD_FLOAT. */
- opts->x_rs6000_double_float = 0;
- opts->x_target_flags &= ~MASK_SOFT_FLOAT;
- opts_set->x_target_flags |= MASK_SOFT_FLOAT;
- break;
-
- case OPT_mdouble_float:
- /* -mdouble-float implies -msingle-float and TARGET_HARD_FLOAT. */
- opts->x_rs6000_single_float = 1;
- opts->x_target_flags &= ~MASK_SOFT_FLOAT;
- opts_set->x_target_flags |= MASK_SOFT_FLOAT;
- break;
-
- case OPT_msimple_fpu:
- if (!TARGET_SINGLE_FPU)
- warning_at (loc, 0, "-msimple-fpu option ignored");
- break;
-
- case OPT_mhard_float:
- /* -mhard_float implies -msingle-float and -mdouble-float. */
- opts->x_rs6000_single_float = opts->x_rs6000_double_float = 1;
- break;
-
- case OPT_msoft_float:
- /* -msoft_float implies -mnosingle-float and -mnodouble-float. */
- opts->x_rs6000_single_float = opts->x_rs6000_double_float = 0;
- break;
-
- case OPT_mfpu_:
- fpu_type = (enum fpu_type_t) value;
- if (fpu_type != FPU_NONE)
- {
- /* If -mfpu is not none, then turn off SOFT_FLOAT, turn on
- HARD_FLOAT. */
- opts->x_target_flags &= ~MASK_SOFT_FLOAT;
- opts_set->x_target_flags |= MASK_SOFT_FLOAT;
- opts->x_rs6000_xilinx_fpu = 1;
- if (fpu_type == FPU_SF_LITE || fpu_type == FPU_SF_FULL)
- opts->x_rs6000_single_float = 1;
- if (fpu_type == FPU_DF_LITE || fpu_type == FPU_DF_FULL)
- opts->x_rs6000_single_float = opts->x_rs6000_double_float = 1;
- if (fpu_type == FPU_SF_LITE || fpu_type == FPU_DF_LITE)
- opts->x_rs6000_simple_fpu = 1;
- }
- else
- {
- /* -mfpu=none is equivalent to -msoft-float. */
- opts->x_target_flags |= MASK_SOFT_FLOAT;
- opts_set->x_target_flags |= MASK_SOFT_FLOAT;
- opts->x_rs6000_single_float = opts->x_rs6000_double_float = 0;
- }
- break;
-
- case OPT_mrecip:
- opts->x_rs6000_recip_name = (value) ? "default" : "none";
- break;
- }
- return true;
-}
\f
+/* Default CPU string for rs6000*_file_start functions. */
+static const char *rs6000_default_cpu;
+
/* Do anything needed at the start of the asm file. */
static void
rs6000_file_start (void)
{
- size_t i;
char buffer[80];
const char *start = buffer;
- struct rs6000_cpu_select *ptr;
- const char *default_cpu = TARGET_CPU_DEFAULT;
FILE *file = asm_out_file;
+ rs6000_default_cpu = TARGET_CPU_DEFAULT;
+
default_file_start ();
#ifdef TARGET_BI_ARCH
if ((TARGET_DEFAULT ^ target_flags) & MASK_64BIT)
- default_cpu = 0;
+ rs6000_default_cpu = 0;
#endif
if (flag_verbose_asm)
{
sprintf (buffer, "\n%s rs6000/powerpc options:", ASM_COMMENT_START);
- rs6000_select[0].string = default_cpu;
- for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
+ if (rs6000_default_cpu != 0 && rs6000_default_cpu[0] != '\0')
{
- ptr = &rs6000_select[i];
- if (ptr->string != (char *)0 && ptr->string[0] != '\0')
- {
- fprintf (file, "%s %s%s", start, ptr->name, ptr->string);
- start = "";
- }
+ fprintf (file, "%s --with-cpu=%s", start, rs6000_default_cpu);
+ start = "";
+ }
+
+ if (global_options_set.x_rs6000_cpu_index)
+ {
+ fprintf (file, "%s -mcpu=%s", start,
+ processor_target_table[rs6000_cpu_index].name);
+ start = "";
+ }
+
+ if (global_options_set.x_rs6000_tune_index)
+ {
+ fprintf (file, "%s -mtune=%s", start,
+ processor_target_table[rs6000_tune_index].name);
+ start = "";
}
if (PPC405_ERRATUM77)
for (i = 0; i < n_elts; ++i)
{
x = XVECEXP (vals, 0, i);
- if (!CONSTANT_P (x))
+ if (!(CONST_INT_P (x)
+ || GET_CODE (x) == CONST_DOUBLE
+ || GET_CODE (x) == CONST_FIXED))
++n_var;
}
if (n_var == 0)
for (i = 0; i < n_elts; ++i)
{
x = XVECEXP (vals, 0, i);
- if (!CONSTANT_P (x))
+ if (!(CONST_INT_P (x)
+ || GET_CODE (x) == CONST_DOUBLE
+ || GET_CODE (x) == CONST_FIXED))
++n_var, one_var = i;
else if (x != CONST0_RTX (inner_mode))
all_const_zero = false;
/* Store value to stack temp. Load vector element. Splat. However, splat
of 64-bit items is not supported on Altivec. */
- if (all_same && GET_MODE_SIZE (mode) <= 4)
+ if (all_same && GET_MODE_SIZE (inner_mode) <= 4)
{
mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
emit_move_insn (adjust_address_nv (mem, inner_mode, 0),
}
offset += 0x8000;
- return (offset < 0x10000) && (offset + extra < 0x10000);
+ return offset < 0x10000 - extra;
}
bool
|| TARGET_MINIMAL_TOC
|| TARGET_CMODEL != CMODEL_SMALL))
|| (TARGET_CMODEL != CMODEL_SMALL
- && GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
- && REGNO (XEXP (XEXP (x, 0), 0)) == TOC_REGISTER
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH
+ && GET_CODE (XEXP (x, 0)) == CONST
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == REG
+ && REGNO (XEXP (XEXP (XEXP (x, 0), 0), 0)) == TOC_REGISTER
+ && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == HIGH
&& rtx_equal_p (XEXP (x, 1),
- XEXP (XEXP (XEXP (x, 0), 1), 0)))))
+ XEXP (XEXP (XEXP (XEXP (x, 0), 0), 1), 0)))))
{
y = XVECEXP (y, 0, 0);
if (offset != NULL_RTX)
lab = gen_label_rtx ();
emit_insn (gen_load_toc_v4_PIC_1b (gsym, lab));
emit_move_insn (tmp1, gen_rtx_REG (Pmode, LR_REGNO));
+ if (TARGET_LINK_STACK)
+ emit_insn (gen_addsi3 (tmp1, tmp1, GEN_INT (4)));
emit_move_insn (tmp2, mem);
last = emit_insn (gen_addsi3 (got, tmp1, tmp2));
set_unique_reg_note (last, REG_EQUAL, gsym);
/* Return 1 if X contains a thread-local symbol. */
-bool
+static bool
rs6000_tls_referenced_p (rtx x)
{
if (! TARGET_HAVE_TLS)
static bool
rs6000_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
{
+ if (GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH)
+ return true;
+
return rs6000_tls_referenced_p (x);
}
&& GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
&& REGNO (XEXP (XEXP (x, 0), 0)) == TOC_REGISTER
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST
+ && GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 0)) == HIGH
&& GET_CODE (XEXP (x, 1)) == CONST
&& GET_CODE (XEXP (XEXP (x, 1), 0)) == UNSPEC
&& XINT (XEXP (XEXP (x, 1), 0), 1) == UNSPEC_TOCREL
- && rtx_equal_p (XEXP (XEXP (XEXP (x, 0), 1), 0), XEXP (x, 1)))
+ && rtx_equal_p (XEXP (XEXP (XEXP (XEXP (x, 0), 1), 0), 0), XEXP (x, 1)))
{
push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
}
else if (mode == Pmode
&& CONSTANT_P (operands[1])
+ && GET_CODE (operands[1]) != HIGH
+ && !(TARGET_CMODEL != CMODEL_SMALL
+ && GET_CODE (operands[1]) == CONST
+ && GET_CODE (XEXP (operands[1], 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == HIGH)
&& ((GET_CODE (operands[1]) != CONST_INT
&& ! easy_fp_constant (operands[1], mode))
|| (GET_CODE (operands[1]) == CONST_INT
> (TARGET_CMODEL != CMODEL_SMALL ? 3 : 2)))
|| (GET_CODE (operands[0]) == REG
&& FP_REGNO_P (REGNO (operands[0]))))
- && GET_CODE (operands[1]) != HIGH
&& ! legitimate_constant_pool_address_p (operands[1], mode,
false)
&& ! toc_relative_expr_p (operands[1])
/* Nonzero if we can use an AltiVec register to pass this arg. */
#define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE,NAMED) \
- ((ALTIVEC_VECTOR_MODE (MODE) || VSX_VECTOR_MODE (MODE)) \
+ (ALTIVEC_OR_VSX_VECTOR_MODE (MODE) \
&& (CUM)->vregno <= ALTIVEC_ARG_MAX_REG \
&& TARGET_ALTIVEC_ABI \
&& (NAMED))
/* Interesting functions that we are emitting in this object file. */
c_node = cgraph_get_node (fndecl);
+ c_node = cgraph_function_or_thunk_node (c_node, NULL);
return !cgraph_only_called_directly_p (c_node);
}
return false;
}
if (SCALAR_FLOAT_MODE_P (return_mode))
rs6000_passes_float = true;
- else if (ALTIVEC_VECTOR_MODE (return_mode)
- || VSX_VECTOR_MODE (return_mode)
+ else if (ALTIVEC_OR_VSX_VECTOR_MODE (return_mode)
|| SPE_VECTOR_MODE (return_mode))
rs6000_passes_vector = true;
}
existing library interfaces.
Doubleword align SPE vectors.
- Quadword align Altivec vectors.
+ Quadword align Altivec/VSX vectors.
Quadword align large synthetic vector types. */
static unsigned int
&& int_size_in_bytes (type) >= 8
&& int_size_in_bytes (type) < 16))
return 64;
- else if ((ALTIVEC_VECTOR_MODE (mode) || VSX_VECTOR_MODE (mode))
+ else if (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
|| (type && TREE_CODE (type) == VECTOR_TYPE
&& int_size_in_bytes (type) >= 16))
return 128;
{
if (SCALAR_FLOAT_MODE_P (mode))
rs6000_passes_float = true;
- else if (named && (ALTIVEC_VECTOR_MODE (mode) || VSX_VECTOR_MODE (mode)))
+ else if (named && ALTIVEC_OR_VSX_VECTOR_MODE (mode))
rs6000_passes_vector = true;
else if (SPE_VECTOR_MODE (mode)
&& !cum->stdarg
#endif
if (TARGET_ALTIVEC_ABI
- && (ALTIVEC_VECTOR_MODE (mode)
- || VSX_VECTOR_MODE (mode)
+ && (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
|| (type && TREE_CODE (type) == VECTOR_TYPE
&& int_size_in_bytes (type) == 16)))
{
}
static void
-rs6000_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+rs6000_function_arg_advance (cumulative_args_t cum, enum machine_mode mode,
const_tree type, bool named)
{
- rs6000_function_arg_advance_1 (cum, mode, type, named, 0);
+ rs6000_function_arg_advance_1 (get_cumulative_args (cum), mode, type, named,
+ 0);
}
static rtx
itself. */
static rtx
-rs6000_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+rs6000_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
const_tree type, bool named)
{
+ CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
enum rs6000_abi abi = DEFAULT_ABI;
/* Return a marker to indicate whether CR1 needs to set or clear the
else
return gen_rtx_REG (mode, cum->vregno);
else if (TARGET_ALTIVEC_ABI
- && (ALTIVEC_VECTOR_MODE (mode)
- || VSX_VECTOR_MODE (mode)
+ && (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
|| (type && TREE_CODE (type) == VECTOR_TYPE
&& int_size_in_bytes (type) == 16)))
{
returns the number of bytes used by the first element of the PARALLEL. */
static int
-rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+rs6000_arg_partial_bytes (cumulative_args_t cum_v, enum machine_mode mode,
tree type, bool named)
{
+ CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
int ret = 0;
int align_words;
reference. */
static bool
-rs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+rs6000_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
enum machine_mode mode, const_tree type,
bool named ATTRIBUTE_UNUSED)
{
stack and set PRETEND_SIZE to the length of the registers pushed. */
static void
-setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
tree type, int *pretend_size ATTRIBUTE_UNUSED,
int no_rtl)
{
alias_set_type set;
/* Skip the last named argument. */
- next_cum = *cum;
+ next_cum = *get_cumulative_args (cum);
rs6000_function_arg_advance_1 (&next_cum, mode, type, true, 0);
if (DEFAULT_ABI == ABI_V4)
/* Find the overflow area. */
t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
if (words != 0)
- t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovf), t,
- size_int (words * UNITS_PER_WORD));
+ t = fold_build_pointer_plus_hwi (t, words * UNITS_PER_WORD);
t = build2 (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);
if (cfun->machine->varargs_save_offset)
- t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (sav), t,
- size_int (cfun->machine->varargs_save_offset));
+ t = fold_build_pointer_plus_hwi (t, cfun->machine->varargs_save_offset);
t = build2 (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
/* This updates arg ptr by the amount that would be necessary
to align the zero-sized (but not zero-alignment) item. */
t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
- fold_build2 (POINTER_PLUS_EXPR,
- TREE_TYPE (valist),
- valist_tmp, size_int (boundary - 1)));
+ fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
gimplify_and_add (t, pre_p);
t = fold_convert (sizetype, valist_tmp);
t = sav;
if (sav_ofs)
- t = build2 (POINTER_PLUS_EXPR, ptr_type_node, sav, size_int (sav_ofs));
+ t = fold_build_pointer_plus_hwi (sav, sav_ofs);
u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), unshare_expr (reg),
build_int_cst (TREE_TYPE (reg), n_reg));
u = fold_convert (sizetype, u);
u = build2 (MULT_EXPR, sizetype, u, size_int (sav_scale));
- t = build2 (POINTER_PLUS_EXPR, ptr_type_node, t, u);
+ t = fold_build_pointer_plus (t, u);
/* _Decimal32 varargs are located in the second word of the 64-bit
FP register for 32-bit binaries. */
if (!TARGET_POWERPC64
&& TARGET_HARD_FLOAT && TARGET_FPRS
&& TYPE_MODE (type) == SDmode)
- t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
+ t = fold_build_pointer_plus_hwi (t, size);
gimplify_assign (addr, t, pre_p);
t = ovf;
if (align != 1)
{
- t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (align - 1));
- t = fold_convert (sizetype, t);
+ t = fold_build_pointer_plus_hwi (t, align - 1);
t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
- size_int (-align));
- t = fold_convert (TREE_TYPE (ovf), t);
+ build_int_cst (TREE_TYPE (t), -align));
}
gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
gimplify_assign (unshare_expr (addr), t, pre_p);
- t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
+ t = fold_build_pointer_plus_hwi (t, size);
gimplify_assign (unshare_expr (ovf), t, pre_p);
if (lab_over)
tree tmp = create_tmp_var (type, "va_arg_tmp");
tree dest_addr = build_fold_addr_expr (tmp);
- tree copy = build_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY],
+ tree copy = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMCPY),
3, dest_addr, addr, size_int (rsize * 4));
gimplify_and_add (copy, pre_p);
#if TARGET_XCOFF
/* AIX libm provides clog as __clog. */
- if (built_in_decls [BUILT_IN_CLOG])
- set_user_assembler_name (built_in_decls [BUILT_IN_CLOG], "__clog");
+ if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE)
+ set_user_assembler_name (tdecl, "__clog");
#endif
#ifdef SUBTARGET_INIT_BUILTINS
rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
src = replace_equiv_address (src, src_reg);
}
- set_mem_size (src, GEN_INT (move_bytes));
+ set_mem_size (src, move_bytes);
if (!REG_P (XEXP (dest, 0)))
{
rtx dest_reg = copy_addr_to_reg (XEXP (dest, 0));
dest = replace_equiv_address (dest, dest_reg);
}
- set_mem_size (dest, GEN_INT (move_bytes));
+ set_mem_size (dest, move_bytes);
emit_insn ((*gen_func.movmemsi) (dest, src,
GEN_INT (move_bytes & 31),
return default_assemble_integer (x, size, aligned_p);
}
-#ifdef HAVE_GAS_HIDDEN
+#if defined (HAVE_GAS_HIDDEN) && !defined (TARGET_MACHO)
/* Emit an assembler directive to set symbol visibility for DECL to
VISIBILITY_TYPE. */
op_false = tmp;
}
- cond2 = gen_rtx_fmt_ee (NE, cc_mode, mask, const0_rtx);
+ cond2 = gen_rtx_fmt_ee (NE, cc_mode, mask, CONST0_RTX (dest_mode));
emit_insn (gen_rtx_SET (VOIDmode,
dest,
gen_rtx_IF_THEN_ELSE (dest_mode,
info_ptr->world_save_p
= (WORLD_SAVE_P (info_ptr)
&& DEFAULT_ABI == ABI_DARWIN
- && ! (cfun->calls_setjmp && flag_exceptions)
+ && !cfun->has_nonlocal_label
&& 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
/* Don't bother to try to save things out-of-line if r11 is occupied
by the static chain. It would require too much fiddling and the
- static chain is rarely used anyway. */
+ static chain is rarely used anyway. FPRs are saved w.r.t the stack
+ pointer on Darwin. */
if (using_static_chain_p)
- strategy |= SAVE_INLINE_FPRS | SAVE_INLINE_GPRS;
+ strategy |= (DEFAULT_ABI == ABI_DARWIN ? 0 : SAVE_INLINE_FPRS)
+ | SAVE_INLINE_GPRS;
/* If we are going to use store multiple, then don't even bother
with the out-of-line routines, since the store-multiple
if (TARGET_AIX && !(strategy & REST_INLINE_FPRS))
strategy |= REST_NOINLINE_FPRS_DOESNT_RESTORE_LR;
#endif
+ if (TARGET_MACHO && !(strategy & SAVE_INLINE_FPRS))
+ strategy |= SAVE_NOINLINE_FPRS_SAVES_LR;
+
return strategy;
}
if (info->reg_size != 4)
fprintf (stderr, "\treg_size = %5d\n", info->reg_size);
+ fprintf (stderr, "\tsave-strategy = %04x\n", info->savres_strategy);
+
fprintf (stderr, "\n");
}
here. */
FOREACH_FUNCTION_ARGS(fntype, type, args_iter)
if (TREE_CODE (type) == VECTOR_TYPE
- && (ALTIVEC_VECTOR_MODE (TYPE_MODE (type))
- || VSX_VECTOR_MODE (TYPE_MODE (type))))
+ && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
nvreg++;
FOREACH_FUNCTION_ARGS(TREE_TYPE (current_function_decl), type, args_iter)
if (TREE_CODE (type) == VECTOR_TYPE
- && (ALTIVEC_VECTOR_MODE (TYPE_MODE (type))
- || VSX_VECTOR_MODE (TYPE_MODE (type))))
+ && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
nvreg--;
if (nvreg > 0)
lab = gen_label_rtx ();
emit_insn (gen_load_toc_v4_PIC_1b (tocsym, lab));
emit_move_insn (dest, gen_rtx_REG (Pmode, LR_REGNO));
+ if (TARGET_LINK_STACK)
+ emit_insn (gen_addsi3 (dest, dest, GEN_INT (4)));
emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
}
emit_insn (gen_addsi3 (dest, temp0, dest));
tocreg = gen_rtx_REG (Pmode, TOC_REGISTER);
if (TARGET_CMODEL != CMODEL_SMALL)
{
- rtx hi = gen_rtx_PLUS (Pmode, tocreg, gen_rtx_HIGH (Pmode, tocrel));
+ rtx hi = gen_rtx_CONST (Pmode,
+ gen_rtx_PLUS (Pmode, tocreg,
+ gen_rtx_HIGH (Pmode, tocrel)));
if (largetoc_reg != NULL)
{
emit_move_insn (largetoc_reg, hi);
output_asm_insn ("{cal %0,%1(%0)|addi %0,%0,%1}", xops);
/* Probe at TEST_ADDR and branch. */
- output_asm_insn ("{st|stw} 0,0(%0)", xops);
+ xops[1] = gen_rtx_REG (Pmode, 0);
+ output_asm_insn ("{st|stw} %1,0(%0)", xops);
fprintf (asm_out_file, "\tb ");
assemble_name_raw (asm_out_file, loop_lab);
fputc ('\n', asm_out_file);
deduce these equivalences by itself so it wasn't necessary to hold
its hand so much. */
-static void
+static rtx
rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
rtx reg2, rtx rreg)
{
RTX_FRAME_RELATED_P (insn) = 1;
add_reg_note (insn, REG_FRAME_RELATED_EXPR, real);
+
+ return insn;
}
/* Returns an insn that has a vrsave set operation with the
/* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
Save REGNO into [FRAME_REG + OFFSET] in mode MODE. */
-static void
+static rtx
emit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode,
unsigned int regno, int offset, HOST_WIDE_INT total_size)
{
/* Some cases that need register indexed addressing. */
if ((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
- || (TARGET_VSX && VSX_VECTOR_MODE (mode))
+ || (TARGET_VSX && ALTIVEC_OR_VSX_VECTOR_MODE (mode))
|| (TARGET_E500_DOUBLE && mode == DFmode)
|| (TARGET_SPE_ABI
&& SPE_VECTOR_MODE (mode)
insn = emit_move_insn (mem, reg);
- rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
+ return rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
}
/* Emit an offset memory reference suitable for a frame store, while
suffix = savep ? SAVE_FP_SUFFIX : RESTORE_FP_SUFFIX;
}
}
- else if (DEFAULT_ABI == ABI_DARWIN)
- sorry ("out-of-line save/restore routines not supported on Darwin");
- sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix);
+ if (DEFAULT_ABI == ABI_DARWIN)
+ {
+ /* The Darwin approach is (slightly) different, in order to be
+ compatible with code generated by the system toolchain. There is a
+ single symbol for the start of save sequence, and the code here
+ embeds an offset into that code on the basis of the first register
+ to be saved. */
+ prefix = savep ? "save" : "rest" ;
+ if (gpr)
+ sprintf (savres_routine_name, "*%sGPR%s%s%.0d ; %s r%d-r31",
+ prefix, (lr ? "x" : ""), (regno == 13 ? "" : "+"),
+ (regno-13) * 4, prefix, regno);
+ else
+ sprintf (savres_routine_name, "*%sFP%s%.0d ; %s f%d-f31",
+ prefix, (regno == 14 ? "" : "+"), (regno-14) * 4, prefix, regno);
+ }
+ else
+ sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix);
return savres_routine_name;
}
if (sp_offset != 0)
{
rtx dest_reg = savres ? gen_rtx_REG (Pmode, 11) : sp_reg_rtx;
- return emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx,
- GEN_INT (sp_offset)));
+ rtx insn = emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx,
+ GEN_INT (sp_offset)));
+ if (!savres)
+ return insn;
}
else if (!savres)
return emit_move_insn (sp_reg_rtx, frame_reg_rtx);
}
/* Construct a parallel rtx describing the effect of a call to an
- out-of-line register save/restore routine. */
+ out-of-line register save/restore routine, and emit the insn
+ or jump_insn as appropriate. */
static rtx
-rs6000_make_savres_rtx (rs6000_stack_t *info,
+rs6000_emit_savres_rtx (rs6000_stack_t *info,
rtx frame_reg_rtx, int save_area_offset,
enum machine_mode reg_mode,
bool savep, bool gpr, bool lr)
{
int i;
- int offset, start_reg, end_reg, n_regs;
+ int offset, start_reg, end_reg, n_regs, use_reg;
int reg_size = GET_MODE_SIZE (reg_mode);
rtx sym;
rtvec p;
+ rtx par, insn;
offset = 0;
start_reg = (gpr
RTVEC_ELT (p, offset++) = ret_rtx;
RTVEC_ELT (p, offset++)
- = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 65));
+ = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
sym = rs6000_savres_routine_sym (info, savep, gpr, lr);
RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, sym);
+ use_reg = DEFAULT_ABI == ABI_AIX ? (gpr && !lr ? 12 : 1)
+ : DEFAULT_ABI == ABI_DARWIN && !gpr ? 1
+ : 11;
RTVEC_ELT (p, offset++)
= gen_rtx_USE (VOIDmode,
- gen_rtx_REG (Pmode, DEFAULT_ABI != ABI_AIX ? 11
- : gpr && !lr ? 12
- : 1));
+ gen_rtx_REG (Pmode, use_reg));
for (i = 0; i < end_reg - start_reg; i++)
{
RTVEC_ELT (p, i + offset) = gen_rtx_SET (VOIDmode, mem, reg);
}
- return gen_rtx_PARALLEL (VOIDmode, p);
+ par = gen_rtx_PARALLEL (VOIDmode, p);
+
+ if (!savep && lr)
+ {
+ insn = emit_jump_insn (par);
+ JUMP_LABEL (insn) = ret_rtx;
+ }
+ else
+ insn = emit_insn (par);
+ return insn;
}
/* Determine whether the gp REG is really used. */
&& call_used_regs[STATIC_CHAIN_REGNUM]);
HOST_WIDE_INT sp_offset = 0;
- if (flag_stack_usage)
+ if (flag_stack_usage_info)
current_function_static_stack_size = info->total_size;
if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && info->total_size)
}
else if (!WORLD_SAVE_P (info) && info->first_fp_reg_save != 64)
{
- rtx par;
-
- par = rs6000_make_savres_rtx (info, frame_reg_rtx,
- info->fp_save_offset + sp_offset,
- DFmode,
- /*savep=*/true, /*gpr=*/false,
- /*lr=*/(strategy
- & SAVE_NOINLINE_FPRS_SAVES_LR)
- != 0);
- insn = emit_insn (par);
+ insn = rs6000_emit_savres_rtx (info, frame_reg_rtx,
+ info->fp_save_offset + sp_offset,
+ DFmode,
+ /*savep=*/true, /*gpr=*/false,
+ /*lr=*/((strategy
+ & SAVE_NOINLINE_FPRS_SAVES_LR)
+ != 0));
rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
NULL_RTX, NULL_RTX);
}
}
else
{
- rtx par;
-
- par = rs6000_make_savres_rtx (info, gen_rtx_REG (Pmode, 11),
- 0, reg_mode,
- /*savep=*/true, /*gpr=*/true,
- /*lr=*/false);
- insn = emit_insn (par);
+ insn = rs6000_emit_savres_rtx (info, gen_rtx_REG (Pmode, 11),
+ 0, reg_mode,
+ /*savep=*/true, /*gpr=*/true,
+ /*lr=*/false);
rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
NULL_RTX, NULL_RTX);
}
}
else if (!WORLD_SAVE_P (info) && !saving_GPRs_inline)
{
- rtx par;
-
+ if (DEFAULT_ABI == ABI_DARWIN)
+ {
+ rtx dest_reg = gen_rtx_REG (reg_mode, 11);
+ if (info->first_fp_reg_save == 64)
+ /* we only need a copy, no fprs were saved. */
+ emit_move_insn (dest_reg, frame_reg_rtx);
+ else
+ {
+ rtx offset = GEN_INT (sp_offset
+ + (-8 * (64-info->first_fp_reg_save)));
+ emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, offset));
+ }
+ }
/* Need to adjust r11 (r12) if we saved any FPRs. */
- if (info->first_fp_reg_save != 64)
+ else if (info->first_fp_reg_save != 64)
{
rtx dest_reg = gen_rtx_REG (reg_mode, DEFAULT_ABI == ABI_AIX
? 12 : 11);
emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, offset));
}
- par = rs6000_make_savres_rtx (info, frame_reg_rtx,
- info->gp_save_offset + sp_offset,
- reg_mode,
- /*savep=*/true, /*gpr=*/true,
- /*lr=*/(strategy
- & SAVE_NOINLINE_GPRS_SAVES_LR)
- != 0);
- insn = emit_insn (par);
+ insn = rs6000_emit_savres_rtx (info, frame_reg_rtx,
+ info->gp_save_offset + sp_offset,
+ reg_mode,
+ /*savep=*/true, /*gpr=*/true,
+ /*lr=*/((strategy
+ & SAVE_NOINLINE_GPRS_SAVES_LR)
+ != 0));
rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
NULL_RTX, NULL_RTX);
}
if (TARGET_AIX && crtl->calls_eh_return)
{
rtx tmp_reg, tmp_reg_si, hi, lo, compare_result, toc_save_done, jump;
+ rtx save_insn, join_insn, note;
long toc_restore_insn;
gcc_assert (frame_reg_rtx == frame_ptr_rtx
JUMP_LABEL (jump) = toc_save_done;
LABEL_NUSES (toc_save_done) += 1;
- emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, 2,
- sp_offset + 5 * reg_size, info->total_size);
+ save_insn = emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode,
+ TOC_REGNUM, sp_offset + 5 * reg_size,
+ info->total_size);
+
emit_label (toc_save_done);
+
+ /* ??? If we leave SAVE_INSN as marked as saving R2, then we'll
+ have a CFG that has different saves along different paths.
+ Move the note to a dummy blockage insn, which describes that
+ R2 is unconditionally saved after the label. */
+ /* ??? An alternate representation might be a special insn pattern
+ containing both the branch and the store. That might let the
+ code that minimizes the number of DW_CFA_advance opcodes better
+ freedom in placing the annotations. */
+ note = find_reg_note (save_insn, REG_FRAME_RELATED_EXPR, NULL);
+ gcc_assert (note);
+ remove_note (save_insn, note);
+ RTX_FRAME_RELATED_P (save_insn) = 0;
+
+ join_insn = emit_insn (gen_blockage ());
+ REG_NOTES (join_insn) = note;
+ RTX_FRAME_RELATED_P (join_insn) = 1;
+
if (using_static_chain_p)
emit_move_insn (tmp_reg, gen_rtx_REG (Pmode, 0));
}
insn = emit_insn (generate_set_vrsave (reg, info, 0));
}
- if (TARGET_SINGLE_PIC_BASE)
- return; /* Do not set PIC register */
-
/* If we are using RS6000_PIC_OFFSET_TABLE_REGNUM, we need to set it up. */
- if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
- || (DEFAULT_ABI == ABI_V4
- && (flag_pic == 1 || (flag_pic && TARGET_SECURE_PLT))
- && df_regs_ever_live_p (RS6000_PIC_OFFSET_TABLE_REGNUM)))
+ if (!TARGET_SINGLE_PIC_BASE
+ && ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
+ || (DEFAULT_ABI == ABI_V4
+ && (flag_pic == 1 || (flag_pic && TARGET_SECURE_PLT))
+ && df_regs_ever_live_p (RS6000_PIC_OFFSET_TABLE_REGNUM))))
{
/* If emit_load_toc_table will use the link register, we need to save
it. We use R12 for this purpose because emit_load_toc_table
rs6000_emit_load_toc_table (TRUE);
insn = emit_move_insn (lr, frame_ptr_rtx);
+ add_reg_note (insn, REG_CFA_RESTORE, lr);
RTX_FRAME_RELATED_P (insn) = 1;
}
else
}
#if TARGET_MACHO
- if (DEFAULT_ABI == ABI_DARWIN
+ if (!TARGET_SINGLE_PIC_BASE
+ && DEFAULT_ABI == ABI_DARWIN
&& flag_pic && crtl->uses_pic_offset_table)
{
rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
emit_move_insn (lr, gen_rtx_REG (Pmode, 0));
}
#endif
+
+ /* If we need to, save the TOC register after doing the stack setup.
+ Do not emit eh frame info for this save. The unwinder wants info,
+ conceptually attached to instructions in this function, about
+ register values in the caller of this function. This R2 may have
+ already been changed from the value in the caller.
+ We don't attempt to write accurate DWARF EH frame info for R2
+ because code emitted by gcc for a (non-pointer) function call
+ doesn't save and restore R2. Instead, R2 is managed out-of-line
+ by a linker generated plt call stub when the function resides in
+ a shared library. This behaviour is costly to describe in DWARF,
+ both in terms of the size of DWARF info and the time taken in the
+ unwinder to interpret it. R2 changes, apart from the
+ calls_eh_return case earlier in this function, are handled by
+ linux-unwind.h frob_update_context. */
+ if (rs6000_save_toc_in_prologue_p ())
+ {
+ rtx addr = gen_rtx_PLUS (Pmode, sp_reg_rtx, GEN_INT (5 * reg_size));
+ rtx mem = gen_frame_mem (reg_mode, addr);
+ emit_move_insn (mem, gen_rtx_REG (reg_mode, TOC_REGNUM));
+ }
}
/* Write function prologue. */
/* Write .extern for any function we will call to save and restore
fp values. */
- if (info->first_fp_reg_save < 64)
+ if (info->first_fp_reg_save < 64
+ && !TARGET_MACHO)
{
char *name;
int regno = info->first_fp_reg_save - 32;
common_mode_defined = 1;
}
- if (! HAVE_prologue)
- {
- rtx prologue;
-
- start_sequence ();
-
- /* A NOTE_INSN_DELETED is supposed to be at the start and end of
- the "toplevel" insn chain. */
- emit_note (NOTE_INSN_DELETED);
- rs6000_emit_prologue ();
- emit_note (NOTE_INSN_DELETED);
-
- /* Expand INSN_ADDRESSES so final() doesn't crash. */
- {
- rtx insn;
- unsigned addr = 0;
- for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
- {
- INSN_ADDRESSES_NEW (insn, addr);
- addr += 4;
- }
- }
-
- prologue = get_insns ();
- end_sequence ();
-
- if (TARGET_DEBUG_STACK)
- debug_rtx_list (prologue, 100);
-
- emit_insn_before_noloc (prologue, BB_HEAD (ENTRY_BLOCK_PTR->next_bb),
- ENTRY_BLOCK_PTR);
- }
-
rs6000_pic_labelno++;
}
: TARGET_32BIT ? -220 : -288);
}
+/* Append CFA_RESTORES to any existing REG_NOTES on the last insn. */
+
+static void
+emit_cfa_restores (rtx cfa_restores)
+{
+ rtx insn = get_last_insn ();
+ rtx *loc = ®_NOTES (insn);
+
+ while (*loc)
+ loc = &XEXP (*loc, 1);
+ *loc = cfa_restores;
+ RTX_FRAME_RELATED_P (insn) = 1;
+}
+
/* Emit function epilogue as insns. */
void
here will not trigger at the moment; We don't actually need a
frame pointer for alloca, but the generic parts of the compiler
give us one anyway. */
- use_backchain_to_restore_sp = (info->total_size > 32767
- || info->total_size
- + (info->lr_save_p ? info->lr_save_offset : 0)
- > 32767
+ use_backchain_to_restore_sp = (info->total_size > 32767 - info->lr_save_offset
|| (cfun->calls_alloca
&& !frame_pointer_needed));
restore_lr = (info->lr_save_p
rtx mem = gen_frame_mem (reg_mode, addr);
RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+
+ if (flag_shrink_wrap)
+ {
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+ gen_rtx_REG (Pmode, LR_REGNO),
+ cfa_restores);
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
+ }
}
for (i = 0; i < 32 - info->first_gp_reg_save; i++)
rtx mem = gen_frame_mem (reg_mode, addr);
RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+ if (flag_shrink_wrap)
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
}
for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
{
rtx mem = gen_frame_mem (V4SImode, addr);
RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+ if (flag_shrink_wrap)
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
}
for (i = 0; info->first_fp_reg_save + i <= 63; i++)
{
? DFmode : SFmode), addr);
RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+ if (flag_shrink_wrap)
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
}
RTVEC_ELT (p, j++)
= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 0));
= 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));
+ insn = emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
+ if (flag_shrink_wrap)
+ {
+ REG_NOTES (insn) = cfa_restores;
+ add_reg_note (insn, REG_CFA_DEF_CFA, sp_reg_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
return;
}
reg = gen_rtx_REG (V4SImode, i);
emit_move_insn (reg, mem);
- if (offset_below_red_zone_p (info->altivec_save_offset
- + (i - info->first_altivec_reg_save)
- * 16))
+ if (flag_shrink_wrap
+ || offset_below_red_zone_p (info->altivec_save_offset
+ + (i - info->first_altivec_reg_save)
+ * 16))
cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
cfa_restores);
}
reg = gen_rtx_REG (V4SImode, i);
emit_move_insn (reg, mem);
- if (DEFAULT_ABI == ABI_V4)
+ if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
cfa_restores);
}
emit_move_insn (cr_save_reg, mem);
}
- /* Set LR here to try to overlap restores below. LR is always saved
- above incoming stack, so it never needs REG_CFA_RESTORE. */
+ /* Set LR here to try to overlap restores below. */
if (restore_lr && restoring_GPRs_inline)
emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO),
gen_rtx_REG (Pmode, 0));
/* Restore GPRs. This is done as a PARALLEL if we are using
the load-multiple instructions. */
if (TARGET_SPE_ABI
- && info->spe_64bit_regs_used != 0
+ && info->spe_64bit_regs_used
&& info->first_gp_reg_save != 32)
{
/* Determine whether we can address all of the registers that need
int ool_adjust = (restoring_GPRs_inline
? 0
: (info->first_gp_reg_save
- - (FIRST_SAVRES_REGISTER+1))*8);
+ - (FIRST_SAVRES_REGISTER + 1)) * 8);
if (frame_reg_rtx == sp_reg_rtx)
frame_reg_rtx = gen_rtx_REG (Pmode, 11);
mem = gen_rtx_MEM (V2SImode, addr);
reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
- insn = emit_move_insn (reg, mem);
- if (DEFAULT_ABI == ABI_V4)
- {
- if (frame_pointer_needed
- && info->first_gp_reg_save + i
- == HARD_FRAME_POINTER_REGNUM)
- {
- add_reg_note (insn, REG_CFA_DEF_CFA,
- plus_constant (frame_reg_rtx,
- sp_offset));
- RTX_FRAME_RELATED_P (insn) = 1;
- }
-
- cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
- cfa_restores);
- }
+ emit_move_insn (reg, mem);
}
}
else
- {
- rtx par;
-
- par = rs6000_make_savres_rtx (info, gen_rtx_REG (Pmode, 11),
- 0, reg_mode,
- /*savep=*/false, /*gpr=*/true,
- /*lr=*/true);
- emit_jump_insn (par);
- /* We don't want anybody else emitting things after we jumped
- back. */
- return;
- }
+ rs6000_emit_savres_rtx (info, gen_rtx_REG (Pmode, 11),
+ 0, reg_mode,
+ /*savep=*/false, /*gpr=*/true,
+ /*lr=*/true);
}
else if (!restoring_GPRs_inline)
{
/* We are jumping to an out-of-line function. */
bool can_use_exit = info->first_fp_reg_save == 64;
- rtx par;
/* Emit stack reset code if we need it. */
if (can_use_exit)
- rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
+ {
+ rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
sp_offset, can_use_exit);
+ if (DEFAULT_ABI == ABI_DARWIN)
+ /* we only need a copy, no fprs were saved. */
+ emit_move_insn (gen_rtx_REG (reg_mode, 11), frame_reg_rtx);
+
+ if (info->cr_save_p)
+ rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple);
+ }
else
{
emit_insn (gen_add3_insn (gen_rtx_REG (Pmode, DEFAULT_ABI == ABI_AIX
sp_offset += info->fp_size;
}
- par = rs6000_make_savres_rtx (info, frame_reg_rtx,
- info->gp_save_offset, reg_mode,
- /*savep=*/false, /*gpr=*/true,
- /*lr=*/can_use_exit);
-
- if (can_use_exit)
- {
- if (info->cr_save_p)
- {
- rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple);
- if (DEFAULT_ABI == ABI_V4)
- cfa_restores
- = alloc_reg_note (REG_CFA_RESTORE,
- gen_rtx_REG (SImode, CR2_REGNO),
- cfa_restores);
- }
-
- emit_jump_insn (par);
-
- /* We don't want anybody else emitting things after we jumped
- back. */
- return;
- }
-
- insn = emit_insn (par);
- if (DEFAULT_ABI == ABI_V4)
- {
- if (frame_pointer_needed)
- {
- add_reg_note (insn, REG_CFA_DEF_CFA,
- plus_constant (frame_reg_rtx, sp_offset));
- RTX_FRAME_RELATED_P (insn) = 1;
- }
-
- for (i = info->first_gp_reg_save; i < 32; i++)
- cfa_restores
- = alloc_reg_note (REG_CFA_RESTORE,
- gen_rtx_REG (reg_mode, i), cfa_restores);
- }
+ rs6000_emit_savres_rtx (info, frame_reg_rtx,
+ info->gp_save_offset, reg_mode,
+ /*savep=*/false, /*gpr=*/true,
+ /*lr=*/can_use_exit);
}
else if (using_load_multiple)
{
rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, reg, mem);
- if (DEFAULT_ABI == ABI_V4)
- cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
- cfa_restores);
- }
- insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
- if (DEFAULT_ABI == ABI_V4 && frame_pointer_needed)
- {
- add_reg_note (insn, REG_CFA_DEF_CFA,
- plus_constant (frame_reg_rtx, sp_offset));
- RTX_FRAME_RELATED_P (insn) = 1;
}
+ emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
}
else
{
rtx mem = gen_frame_mem (reg_mode, addr);
rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
- insn = emit_move_insn (reg, mem);
- if (DEFAULT_ABI == ABI_V4)
- {
- if (frame_pointer_needed
- && info->first_gp_reg_save + i
- == HARD_FRAME_POINTER_REGNUM)
- {
- add_reg_note (insn, REG_CFA_DEF_CFA,
- plus_constant (frame_reg_rtx, sp_offset));
- RTX_FRAME_RELATED_P (insn) = 1;
- }
-
- cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
- cfa_restores);
- }
+ emit_move_insn (reg, mem);
}
}
+ if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
+ {
+ /* If the frame pointer was used then we can't delay emitting
+ a REG_CFA_DEF_CFA note. This must happen on the insn that
+ restores the frame pointer, r31. We may have already emitted
+ a REG_CFA_DEF_CFA note, but that's OK; A duplicate is
+ discarded by dwarf2cfi.c/dwarf2out.c, and in any case would
+ be harmless if emitted. */
+ if (frame_pointer_needed)
+ {
+ insn = get_last_insn ();
+ add_reg_note (insn, REG_CFA_DEF_CFA,
+ plus_constant (frame_reg_rtx, sp_offset));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ /* Set up cfa_restores. We always need these when
+ shrink-wrapping. If not shrink-wrapping then we only need
+ the cfa_restore when the stack location is no longer valid.
+ The cfa_restores must be emitted on or before the insn that
+ invalidates the stack, and of course must not be emitted
+ before the insn that actually does the restore. The latter
+ is why the LR cfa_restore condition below is a little
+ complicated. It's also why it is a bad idea to emit the
+ cfa_restores as a group on the last instruction here that
+ actually does a restore: That insn may be reordered with
+ respect to others doing restores. */
+ if (info->cr_save_p)
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+ gen_rtx_REG (SImode, CR2_REGNO),
+ cfa_restores);
+ if (flag_shrink_wrap
+ && (restore_lr
+ || (info->lr_save_p
+ && !restoring_GPRs_inline
+ && info->first_fp_reg_save == 64)))
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+ gen_rtx_REG (Pmode, LR_REGNO),
+ cfa_restores);
+
+ for (i = info->first_gp_reg_save; i < 32; i++)
+ if (!restoring_GPRs_inline
+ || using_load_multiple
+ || rs6000_reg_live_or_pic_offset_p (i))
+ {
+ rtx reg = gen_rtx_REG (reg_mode, i);
+
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
+ }
+ }
+
+ if (!restoring_GPRs_inline
+ && info->first_fp_reg_save == 64)
+ {
+ /* We are jumping to an out-of-line function. */
+ if (cfa_restores)
+ emit_cfa_restores (cfa_restores);
+ return;
+ }
+
if (restore_lr && !restoring_GPRs_inline)
{
rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
/* Restore fpr's if we need to do it without calling a function. */
if (restoring_FPRs_inline)
for (i = 0; i < 64 - info->first_fp_reg_save; i++)
- if ((df_regs_ever_live_p (info->first_fp_reg_save+i)
- && ! call_used_regs[info->first_fp_reg_save+i]))
+ if ((df_regs_ever_live_p (info->first_fp_reg_save + i)
+ && !call_used_regs[info->first_fp_reg_save + i]))
{
rtx addr, mem, reg;
addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
info->first_fp_reg_save + i);
emit_move_insn (reg, mem);
- if (DEFAULT_ABI == ABI_V4)
- cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
- cfa_restores);
+ if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
}
/* If we saved cr, restore it here. Just those that were used. */
if (info->cr_save_p)
- {
- rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple);
- if (DEFAULT_ABI == ABI_V4)
- cfa_restores
- = alloc_reg_note (REG_CFA_RESTORE, gen_rtx_REG (SImode, CR2_REGNO),
- cfa_restores);
- }
+ rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple);
/* If this is V.4, unwind the stack pointer after all of the loads
have been done. */
rtvec p;
bool lr = (strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0;
if (! restoring_FPRs_inline)
- p = rtvec_alloc (4 + 64 - info->first_fp_reg_save);
+ {
+ p = rtvec_alloc (4 + 64 - info->first_fp_reg_save);
+ RTVEC_ELT (p, 0) = ret_rtx;
+ }
else
- p = rtvec_alloc (2);
+ {
+ if (cfa_restores)
+ {
+ /* We can't hang the cfa_restores off a simple return,
+ since the shrink-wrap code sometimes uses an existing
+ return. This means there might be a path from
+ pre-prologue code to this return, and dwarf2cfi code
+ wants the eh_frame unwinder state to be the same on
+ all paths to any point. So we need to emit the
+ cfa_restores before the return. For -m64 we really
+ don't need epilogue cfa_restores at all, except for
+ this irritating dwarf2cfi with shrink-wrap
+ requirement; The stack red-zone means eh_frame info
+ from the prologue telling the unwinder to restore
+ from the stack is perfectly good right to the end of
+ the function. */
+ emit_insn (gen_blockage ());
+ emit_cfa_restores (cfa_restores);
+ cfa_restores = NULL_RTX;
+ }
+ p = rtvec_alloc (2);
+ RTVEC_ELT (p, 0) = simple_return_rtx;
+ }
- RTVEC_ELT (p, 0) = ret_rtx;
RTVEC_ELT (p, 1) = ((restoring_FPRs_inline || !lr)
- ? gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 65))
+ ? gen_rtx_USE (VOIDmode,
+ gen_rtx_REG (Pmode, LR_REGNO))
: gen_rtx_CLOBBER (VOIDmode,
- gen_rtx_REG (Pmode, 65)));
+ gen_rtx_REG (Pmode, LR_REGNO)));
/* If we have to restore more than two FP registers, branch to the
restore function. It will return to our caller. */
int i;
rtx sym;
+ if ((DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
+ && lr)
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+ gen_rtx_REG (Pmode, LR_REGNO),
+ cfa_restores);
+
sym = rs6000_savres_routine_sym (info,
/*savep=*/false,
/*gpr=*/false,
? 1 : 11));
for (i = 0; i < 64 - info->first_fp_reg_save; i++)
{
- rtx addr, mem;
+ rtx addr, mem, reg;
+
addr = gen_rtx_PLUS (Pmode, sp_reg_rtx,
- GEN_INT (info->fp_save_offset + 8*i));
+ GEN_INT (info->fp_save_offset + 8 * i));
mem = gen_frame_mem (DFmode, addr);
+ reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
- RTVEC_ELT (p, i+4) =
- gen_rtx_SET (VOIDmode,
- gen_rtx_REG (DFmode, info->first_fp_reg_save + i),
- mem);
+ RTVEC_ELT (p, i + 4) = gen_rtx_SET (VOIDmode, reg, mem);
+ if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
+ cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
+ cfa_restores);
}
}
emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
}
+
+ if (cfa_restores)
+ {
+ if (sibcall)
+ /* Ensure the cfa_restores are hung off an insn that won't
+ be reordered above other restores. */
+ emit_insn (gen_blockage ());
+
+ emit_cfa_restores (cfa_restores);
+ }
}
/* Write function epilogue. */
rs6000_output_function_epilogue (FILE *file,
HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
- if (! HAVE_epilogue)
- {
- rtx insn = get_last_insn ();
- /* If the last insn was a BARRIER, we don't have to write anything except
- the trace table. */
- if (GET_CODE (insn) == NOTE)
- insn = prev_nonnote_insn (insn);
- if (insn == 0 || GET_CODE (insn) != BARRIER)
- {
- /* This is slightly ugly, but at least we don't have two
- copies of the epilogue-emitting code. */
- start_sequence ();
-
- /* A NOTE_INSN_DELETED is supposed to be at the start
- and end of the "toplevel" insn chain. */
- emit_note (NOTE_INSN_DELETED);
- rs6000_emit_epilogue (FALSE);
- emit_note (NOTE_INSN_DELETED);
-
- /* Expand INSN_ADDRESSES so final() doesn't crash. */
- {
- rtx insn;
- unsigned addr = 0;
- for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
- {
- INSN_ADDRESSES_NEW (insn, addr);
- addr += 4;
- }
- }
-
- if (TARGET_DEBUG_STACK)
- debug_rtx_list (get_insns (), 100);
- final (get_insns (), file, FALSE);
- end_sequence ();
- }
- }
-
#if TARGET_MACHO
macho_branch_islands ();
/* Mach-O doesn't support labels at the end of objects, so if
gen_rtx_USE (VOIDmode,
gen_rtx_REG (SImode,
LR_REGNO)),
- ret_rtx)));
+ simple_return_rtx)));
SIBLING_CALL_P (insn) = 1;
emit_barrier ();
rs6000_xcoff_strip_dollar (const char *name)
{
char *strip, *p;
- int len;
+ const char *q;
+ size_t len;
- p = strchr (name, '$');
+ q = (const char *) strchr (name, '$');
- if (p == 0 || p == name)
+ if (q == 0 || q == name)
return name;
len = strlen (name);
- strip = (char *) alloca (len + 1);
+ strip = XALLOCAVEC (char, len + 1);
strcpy (strip, name);
- p = strchr (strip, '$');
+ p = strip + (q - name);
while (p)
{
*p = '_';
}
else if (TARGET_SECURE_PLT && flag_pic)
{
- asm_fprintf (file, "\tbcl 20,31,1f\n1:\n\t{st|stw} %s,4(%s)\n",
+ if (TARGET_LINK_STACK)
+ {
+ char name[32];
+ get_ppc476_thunk_name (name);
+ asm_fprintf (file, "\tbl %s\n", name);
+ }
+ else
+ asm_fprintf (file, "\tbcl 20,31,1f\n1:\n");
+ asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
reg_names[0], reg_names[1]);
asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
asm_fprintf (file, "\t{cau|addis} %s,%s,",
asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
reg_names[0], reg_names[1]);
/* Now, we need to get the address of the label. */
- fputs ("\tbcl 20,31,1f\n\t.long ", file);
- assemble_name (file, buf);
- fputs ("-.\n1:", file);
- asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
+ if (TARGET_LINK_STACK)
+ {
+ char name[32];
+ get_ppc476_thunk_name (name);
+ asm_fprintf (file, "\tbl %s\n\tb 1f\n\t.long ", name);
+ assemble_name (file, buf);
+ fputs ("-.\n1:", file);
+ asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
+ asm_fprintf (file, "\taddi %s,%s,4\n",
+ reg_names[11], reg_names[11]);
+ }
+ else
+ {
+ fputs ("\tbcl 20,31,1f\n\t.long ", file);
+ assemble_name (file, buf);
+ fputs ("-.\n1:", file);
+ asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
+ }
asm_fprintf (file, "\t{l|lwz} %s,0(%s)\n",
reg_names[0], reg_names[11]);
asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
val_diff = val1 - val0;
return ((REGNO (reg0) == REGNO (reg1))
- && ((MEM_SIZE (a) && val_diff == INTVAL (MEM_SIZE (a)))
- || (MEM_SIZE (b) && val_diff == -INTVAL (MEM_SIZE (b)))));
+ && ((MEM_SIZE_KNOWN_P (a) && val_diff == MEM_SIZE (a))
+ || (MEM_SIZE_KNOWN_P (b) && val_diff == -MEM_SIZE (b))));
}
return false;
/* Under AIX, just build the 3 word function descriptor */
case ABI_AIX:
{
- rtx fnmem = gen_const_mem (Pmode, force_reg (Pmode, fnaddr));
- rtx fn_reg = gen_reg_rtx (Pmode);
- rtx toc_reg = gen_reg_rtx (Pmode);
+ rtx fnmem, fn_reg, toc_reg;
+
+ if (!TARGET_POINTERS_TO_NESTED_FUNCTIONS)
+ error ("-mno-r11 must not be used if you have trampolines");
+
+ fnmem = gen_const_mem (Pmode, force_reg (Pmode, fnaddr));
+ fn_reg = gen_reg_rtx (Pmode);
+ toc_reg = gen_reg_rtx (Pmode);
/* Macro to shorten the code expansions below. */
# define MEM_PLUS(MEM, OFFSET) adjust_address (MEM, Pmode, OFFSET)
#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
if (flag_pic)
{
- strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
- strcat (tmp_buf, label);
- strcat (tmp_buf, "_pic\n");
- strcat (tmp_buf, label);
- strcat (tmp_buf, "_pic:\n\tmflr r11\n");
+ if (TARGET_LINK_STACK)
+ {
+ char name[32];
+ get_ppc64_thunk_name (name);
+ strcat (tmp_buf, ":\n\tmflr r0\n\tbl ");
+ strcat (tmp_buf, name);
+ strcat (tmp_buf, "\n");
+ strcat (tmp_buf, label);
+ strcat (tmp_buf, "_pic:\n\tmflr r11\n");
+ }
+ else
+ {
+ strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
+ strcat (tmp_buf, label);
+ strcat (tmp_buf, "_pic\n");
+ strcat (tmp_buf, label);
+ strcat (tmp_buf, "_pic:\n\tmflr r11\n");
+ }
strcat (tmp_buf, "\taddis r11,r11,ha16(");
strcat (tmp_buf, name_buf);
sprintf (local_label_0, "\"L%011d$spb\"", label);
fprintf (file, "\tmflr r0\n");
- fprintf (file, "\tbcl 20,31,%s\n", local_label_0);
- fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
+ if (TARGET_LINK_STACK)
+ {
+ char name[32];
+ get_ppc476_thunk_name (name);
+ fprintf (file, "\tbl %s\n", name);
+ fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
+ }
+ else
+ {
+ fprintf (file, "\tbcl 20,31,%s\n", local_label_0);
+ fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
+ }
fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n",
lazy_ptr_name, local_label_0);
fprintf (file, "\tmtlr r0\n");
darwin_file_start ();
/* Determine the argument to -mcpu=. Default to G3 if not specified. */
- for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
- if (rs6000_select[i].set_arch_p && rs6000_select[i].string
- && rs6000_select[i].string[0] != '\0')
- cpu_id = rs6000_select[i].string;
+
+ if (rs6000_default_cpu != 0 && rs6000_default_cpu[0] != '\0')
+ cpu_id = rs6000_default_cpu;
+
+ if (global_options_set.x_rs6000_cpu_index)
+ cpu_id = processor_target_table[rs6000_cpu_index].name;
/* Look through the mapping array. Pick the first name that either
matches the argument, has a bit set in IF_SET that is also set
scanned. In either case, *TOTAL contains the cost result. */
static bool
-rs6000_rtx_costs (rtx x, int code, int outer_code, int *total,
- bool speed)
+rs6000_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
+ int *total, bool speed)
{
enum machine_mode mode = GET_MODE (x);
/* Debug form of r6000_rtx_costs that is selected if -mdebug=cost. */
static bool
-rs6000_debug_rtx_costs (rtx x, int code, int outer_code, int *total,
+rs6000_debug_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
bool speed)
{
- bool ret = rs6000_rtx_costs (x, code, outer_code, total, speed);
+ bool ret = rs6000_rtx_costs (x, code, outer_code, opno, total, speed);
fprintf (stderr,
"\nrs6000_rtx_costs, return = %s, code = %s, outer_code = %s, "
- "total = %d, speed = %s, x:\n",
+ "opno = %d, total = %d, speed = %s, x:\n",
ret ? "complete" : "scan inner",
GET_RTX_NAME (code),
GET_RTX_NAME (outer_code),
+ opno,
*total,
speed ? "true" : "false");
{
int ret;
+ if (TARGET_DEBUG_COST)
+ dbg_cost_ctrl++;
+
/* Moves from/to GENERAL_REGS. */
if (reg_classes_intersect_p (to, GENERAL_REGS)
|| reg_classes_intersect_p (from, GENERAL_REGS))
{
+ reg_class_t rclass = from;
+
if (! reg_classes_intersect_p (to, GENERAL_REGS))
- from = to;
+ rclass = to;
- if (from == FLOAT_REGS || from == ALTIVEC_REGS || from == VSX_REGS)
- ret = (rs6000_memory_move_cost (mode, from, false)
+ if (rclass == FLOAT_REGS || rclass == ALTIVEC_REGS || rclass == VSX_REGS)
+ ret = (rs6000_memory_move_cost (mode, rclass, false)
+ rs6000_memory_move_cost (mode, GENERAL_REGS, false));
/* It's more expensive to move CR_REGS than CR0_REGS because of the
shift. */
- else if (from == CR_REGS)
+ else if (rclass == CR_REGS)
ret = 4;
- /* Power6 has slower LR/CTR moves so make them more expensive than
- memory in order to bias spills to memory .*/
- else if (rs6000_cpu == PROCESSOR_POWER6
- && reg_classes_intersect_p (from, LINK_OR_CTR_REGS))
+ /* For those processors that have slow LR/CTR moves, make them more
+ expensive than memory in order to bias spills to memory .*/
+ else if ((rs6000_cpu == PROCESSOR_POWER6
+ || rs6000_cpu == PROCESSOR_POWER7)
+ && reg_classes_intersect_p (rclass, LINK_OR_CTR_REGS))
ret = 6 * hard_regno_nregs[0][mode];
else
+ rs6000_register_move_cost (mode, from, GENERAL_REGS));
if (TARGET_DEBUG_COST)
- fprintf (stderr,
- "rs6000_register_move_cost:, ret=%d, mode=%s, from=%s, to=%s\n",
- ret, GET_MODE_NAME (mode), reg_class_names[from],
- reg_class_names[to]);
+ {
+ if (dbg_cost_ctrl == 1)
+ fprintf (stderr,
+ "rs6000_register_move_cost:, ret=%d, mode=%s, from=%s, to=%s\n",
+ ret, GET_MODE_NAME (mode), reg_class_names[from],
+ reg_class_names[to]);
+ dbg_cost_ctrl--;
+ }
return ret;
}
{
int ret;
+ if (TARGET_DEBUG_COST)
+ dbg_cost_ctrl++;
+
if (reg_classes_intersect_p (rclass, GENERAL_REGS))
ret = 4 * hard_regno_nregs[0][mode];
else if (reg_classes_intersect_p (rclass, FLOAT_REGS))
ret = 4 + rs6000_register_move_cost (mode, rclass, GENERAL_REGS);
if (TARGET_DEBUG_COST)
- fprintf (stderr,
- "rs6000_memory_move_cost: ret=%d, mode=%s, rclass=%s, in=%d\n",
- ret, GET_MODE_NAME (mode), reg_class_names[rclass], in);
+ {
+ if (dbg_cost_ctrl == 1)
+ fprintf (stderr,
+ "rs6000_memory_move_cost: ret=%d, mode=%s, rclass=%s, in=%d\n",
+ ret, GET_MODE_NAME (mode), reg_class_names[rclass], in);
+ dbg_cost_ctrl--;
+ }
return ret;
}
else if (TREE_CODE (valtype) == COMPLEX_TYPE
&& targetm.calls.split_complex_arg)
return rs6000_complex_function_value (mode);
+ /* VSX is a superset of Altivec and adds V2DImode/V2DFmode. Since the same
+ return register is used in both cases, and we won't see V2DImode/V2DFmode
+ for pure altivec, combine the two cases. */
else if (TREE_CODE (valtype) == VECTOR_TYPE
&& TARGET_ALTIVEC && TARGET_ALTIVEC_ABI
- && ALTIVEC_VECTOR_MODE (mode))
- regno = ALTIVEC_ARG_RETURN;
- else if (TREE_CODE (valtype) == VECTOR_TYPE
- && TARGET_VSX && TARGET_ALTIVEC_ABI
- && VSX_VECTOR_MODE (mode))
+ && ALTIVEC_OR_VSX_VECTOR_MODE (mode))
regno = ALTIVEC_ARG_RETURN;
else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
&& (mode == DFmode || mode == DCmode
&& TARGET_HARD_FLOAT && TARGET_FPRS
&& ((TARGET_SINGLE_FLOAT && mode == SFmode) || TARGET_DOUBLE_FLOAT))
regno = FP_ARG_RETURN;
- else if (ALTIVEC_VECTOR_MODE (mode)
+ /* VSX is a superset of Altivec and adds V2DImode/V2DFmode. Since the same
+ return register is used in both cases, and we won't see V2DImode/V2DFmode
+ for pure altivec, combine the two cases. */
+ else if (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
&& TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
regno = ALTIVEC_ARG_RETURN;
- else if (VSX_VECTOR_MODE (mode)
- && TARGET_VSX && TARGET_ALTIVEC_ABI)
- regno = ALTIVEC_ARG_RETURN;
else if (COMPLEX_MODE_P (mode) && targetm.calls.split_complex_arg)
return rs6000_complex_function_value (mode);
else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
calling __stack_chk_fail directly. Otherwise it is better to call
__stack_chk_fail directly. */
-static tree
+static tree ATTRIBUTE_UNUSED
rs6000_stack_protect_fail (void)
{
return (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
|| easy_vector_constant (x, mode));
}
+\f
+/* A function pointer under AIX is a pointer to a data area whose first word
+ contains the actual address of the function, whose second word contains a
+ pointer to its TOC, and whose third word contains a value to place in the
+ static chain register (r11). Note that if we load the static chain, our
+ "trampoline" need not have any executable code. */
+
+void
+rs6000_call_indirect_aix (rtx value, rtx func_desc, rtx flag)
+{
+ rtx func_addr;
+ rtx toc_reg;
+ rtx sc_reg;
+ rtx stack_ptr;
+ rtx stack_toc_offset;
+ rtx stack_toc_mem;
+ rtx func_toc_offset;
+ rtx func_toc_mem;
+ rtx func_sc_offset;
+ rtx func_sc_mem;
+ rtx insn;
+ rtx (*call_func) (rtx, rtx, rtx, rtx);
+ rtx (*call_value_func) (rtx, rtx, rtx, rtx, rtx);
+
+ stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+ toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM);
+
+ /* Load up address of the actual function. */
+ func_desc = force_reg (Pmode, func_desc);
+ func_addr = gen_reg_rtx (Pmode);
+ emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc));
+
+ if (TARGET_32BIT)
+ {
+
+ stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_32BIT);
+ func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_32BIT);
+ func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_32BIT);
+ if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
+ {
+ call_func = gen_call_indirect_aix32bit;
+ call_value_func = gen_call_value_indirect_aix32bit;
+ }
+ else
+ {
+ call_func = gen_call_indirect_aix32bit_nor11;
+ call_value_func = gen_call_value_indirect_aix32bit_nor11;
+ }
+ }
+ else
+ {
+ stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_64BIT);
+ func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_64BIT);
+ func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_64BIT);
+ if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
+ {
+ call_func = gen_call_indirect_aix64bit;
+ call_value_func = gen_call_value_indirect_aix64bit;
+ }
+ else
+ {
+ call_func = gen_call_indirect_aix64bit_nor11;
+ call_value_func = gen_call_value_indirect_aix64bit_nor11;
+ }
+ }
+
+ /* Reserved spot to store the TOC. */
+ stack_toc_mem = gen_frame_mem (Pmode,
+ gen_rtx_PLUS (Pmode,
+ stack_ptr,
+ stack_toc_offset));
+
+ gcc_assert (cfun);
+ gcc_assert (cfun->machine);
+
+ /* Can we optimize saving the TOC in the prologue or do we need to do it at
+ every call? */
+ if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
+ cfun->machine->save_toc_in_prologue = true;
+
+ else
+ {
+ MEM_VOLATILE_P (stack_toc_mem) = 1;
+ emit_move_insn (stack_toc_mem, toc_reg);
+ }
+
+ /* Calculate the address to load the TOC of the called function. We don't
+ actually load this until the split after reload. */
+ func_toc_mem = gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode,
+ func_desc,
+ func_toc_offset));
+
+ /* If we have a static chain, load it up. */
+ if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
+ {
+ func_sc_mem = gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode,
+ func_desc,
+ func_sc_offset));
+
+ sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+ emit_move_insn (sc_reg, func_sc_mem);
+ }
+
+ /* Create the call. */
+ if (value)
+ insn = call_value_func (value, func_addr, flag, func_toc_mem,
+ stack_toc_mem);
+ else
+ insn = call_func (func_addr, flag, func_toc_mem, stack_toc_mem);
+
+ emit_call_insn (insn);
+}
+
+/* Return whether we need to always update the saved TOC pointer when we update
+ the stack pointer. */
+
+static bool
+rs6000_save_toc_in_prologue_p (void)
+{
+ return (cfun && cfun->machine && cfun->machine->save_toc_in_prologue);
+}
+
+/* Fills in the label name that should be used for a 476 link stack thunk. */
+
+void
+get_ppc476_thunk_name (char name[32])
+{
+ gcc_assert (TARGET_LINK_STACK);
+
+ if (HAVE_GAS_HIDDEN)
+ sprintf (name, "__ppc476.get_thunk");
+ else
+ ASM_GENERATE_INTERNAL_LABEL (name, "LPPC476_", 0);
+}
+
+/* This function emits the simple thunk routine that is used to preserve
+ the link stack on the 476 cpu. */
+
+static void
+rs6000_code_end (void)
+{
+ char name[32];
+ tree decl;
+
+ if (!TARGET_LINK_STACK)
+ return;
+
+ get_ppc476_thunk_name (name);
+
+ decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, get_identifier (name),
+ build_function_type_list (void_type_node, NULL_TREE));
+ DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL,
+ NULL_TREE, void_type_node);
+ TREE_PUBLIC (decl) = 1;
+ TREE_STATIC (decl) = 1;
+
+ if (HAVE_GAS_HIDDEN)
+ {
+ DECL_COMDAT_GROUP (decl) = DECL_ASSEMBLER_NAME (decl);
+ targetm.asm_out.unique_section (decl, 0);
+ switch_to_section (get_named_section (decl, NULL, 0));
+ DECL_WEAK (decl) = 1;
+ ASM_WEAKEN_DECL (asm_out_file, decl, name, 0);
+ targetm.asm_out.globalize_label (asm_out_file, name);
+ targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN);
+ ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl);
+ }
+ else
+ {
+ switch_to_section (text_section);
+ ASM_OUTPUT_LABEL (asm_out_file, name);
+ }
+
+ DECL_INITIAL (decl) = make_node (BLOCK);
+ current_function_decl = decl;
+ init_function_start (decl);
+ first_function_block_is_cold = false;
+ /* Make sure unwind info is emitted for the thunk if needed. */
+ final_start_function (emit_barrier (), asm_out_file, 1);
+
+ fputs ("\tblr\n", asm_out_file);
+
+ final_end_function ();
+ init_insn_lengths ();
+ free_after_compilation (cfun);
+ set_cfun (NULL);
+ current_function_decl = NULL;
+}
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
#include "gt-rs6000.h"