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 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 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);
/* Hash table stuff for keeping track of TOC entries. */
#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
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,
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)
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
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),
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
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)
{
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
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 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);
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. */
}
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;
-
/* Need to adjust r11 (r12) if we saved any FPRs. */
if (info->first_fp_reg_save != 64)
{
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, TOC_REGNUM,
- 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);
}
#endif
- /* If we need to, save the TOC register after doing the stack setup. */
+ /* 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 ())
- emit_frame_save (sp_reg_rtx, sp_reg_rtx, reg_mode, TOC_REGNUM,
- 5 * reg_size, info->total_size);
+ {
+ 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. */
: 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,
- sp_offset, can_use_exit);
+ {
+ rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
+ sp_offset, can_use_exit);
+ 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. */
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 = '_';
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;
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");
/* 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->calls_setjmp && !cfun->has_nonlocal_label
- && !cfun->can_throw_non_call_exceptions
- && ((flags_from_decl_or_type (cfun->decl) & ECF_NOTHROW) == ECF_NOTHROW))
+ if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
cfun->machine->save_toc_in_prologue = true;
else
insn = call_func (func_addr, flag, func_toc_mem, stack_toc_mem);
emit_call_insn (insn);
- return;
}
/* Return whether we need to always update the saved TOC pointer when we update
the stack pointer. */
-bool
+static bool
rs6000_save_toc_in_prologue_p (void)
{
return (cfun && cfun->machine && cfun->machine->save_toc_in_prologue);