int arg_regs_to_save;
int regsave_filler;
int frame_filler;
+ int frame_locked;
/* Records __builtin_return address. */
rtx eh_stack_adjust;
static GTY(()) section * frodata_section;
static GTY(()) section * srodata_section;
+static GTY(()) section * vtext_section;
+static GTY(()) section * vftext_section;
+static GTY(()) section * ftext_section;
+
static void mep_set_leaf_registers (int);
static bool symbol_p (rtx);
static bool symbolref_p (rtx);
static tree mep_validate_io_cb (tree *, tree, tree, int, bool *);
static tree mep_validate_vliw (tree *, tree, tree, int, bool *);
static bool mep_function_attribute_inlinable_p (const_tree);
-static bool mep_option_can_inline_p (tree, tree);
+static bool mep_can_inline_p (tree, tree);
static bool mep_lookup_pragma_disinterrupt (const char *);
static int mep_multiple_address_regions (tree, bool);
static int mep_attrlist_to_encoding (tree, tree);
static tree mep_build_builtin_va_list (void);
static void mep_expand_va_start (tree, rtx);
static tree mep_gimplify_va_arg_expr (tree, tree, tree *, tree *);
+static bool mep_can_eliminate (const int, const int);
\f
/* Initialize the GCC target structure. */
#define TARGET_INSERT_ATTRIBUTES mep_insert_attributes
#undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P
#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P mep_function_attribute_inlinable_p
-#undef TARGET_OPTION_CAN_INLINE_P
-#define TARGET_OPTION_CAN_INLINE_P mep_option_can_inline_p
+#undef TARGET_CAN_INLINE_P
+#define TARGET_CAN_INLINE_P mep_can_inline_p
#undef TARGET_SECTION_TYPE_FLAGS
#define TARGET_SECTION_TYPE_FLAGS mep_section_type_flags
#undef TARGET_ASM_NAMED_SECTION
#define TARGET_EXPAND_BUILTIN_VA_START mep_expand_va_start
#undef TARGET_GIMPLIFY_VA_ARG_EXPR
#define TARGET_GIMPLIFY_VA_ARG_EXPR mep_gimplify_va_arg_expr
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE mep_can_eliminate
struct gcc_target targetm = TARGET_INITIALIZER;
\f
return src_vliw == tgt_vliw;
}
+/* Like the above, but also test for near/far mismatches. */
+
+bool
+mep_vliw_jmp_match (rtx tgt)
+{
+ bool src_vliw = mep_vliw_function_p (cfun->decl);
+ bool tgt_vliw = INTVAL (tgt);
+
+ if (mep_section_tag (DECL_RTL (cfun->decl)) == 'f')
+ return false;
+
+ return src_vliw == tgt_vliw;
+}
+
bool
mep_multi_slot (rtx x)
{
static bool
mep_call_saves_register (int r)
{
- /* if (cfun->machine->reg_saved[r] == MEP_SAVES_UNKNOWN)*/
+ if (! cfun->machine->frame_locked)
{
int rv = MEP_SAVES_NO;
return 4;
}
+/* Worker function for TARGET_CAN_ELIMINATE. */
+
+bool
+mep_can_eliminate (const int from, const int to)
+{
+ return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
+ ? ! frame_pointer_needed
+ : true);
+}
+
int
mep_elimination_offset (int from, int to)
{
int frame_size = get_frame_size () + crtl->outgoing_args_size;
int total_size;
- memset (cfun->machine->reg_saved, 0, sizeof (cfun->machine->reg_saved));
+ if (!cfun->machine->frame_locked)
+ memset (cfun->machine->reg_saved, 0, sizeof (cfun->machine->reg_saved));
/* We don't count arg_regs_to_save in the arg pointer offset, because
gcc thinks the arg pointer has moved along with the saved regs.
emit_insn (gen_movsi_botsym_s (reg, reg, sym));
}
-void
-mep_expand_prologue (void)
+/* Assign save slots for any register not already saved. DImode
+ registers go at the end of the reg save area; the rest go at the
+ beginning. This is for alignment purposes. Returns true if a frame
+ is really needed. */
+static bool
+mep_assign_save_slots (int reg_save_size)
{
- int i, rss, sp_offset = 0;
- int reg_save_size;
- int frame_size;
- int really_need_stack_frame = frame_size;
+ bool really_need_stack_frame = false;
int di_ofs = 0;
+ int i;
- /* We must not allow register renaming in interrupt functions,
- because that invalidates the correctness of the set of call-used
- registers we're going to save/restore. */
- mep_set_leaf_registers (mep_interrupt_p () ? 0 : 1);
-
- if (mep_disinterrupt_p ())
- emit_insn (gen_mep_disable_int ());
-
- cfun->machine->mep_frame_pointer_needed = frame_pointer_needed;
-
- reg_save_size = mep_elimination_offset (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM);
- frame_size = mep_elimination_offset (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM);
-
- /* Assign save slots for any register not already saved. DImode
- registers go at the end of the reg save area; the rest go at the
- beginning. This is for alignment purposes. */
for (i=0; i<FIRST_PSEUDO_REGISTER; i++)
if (mep_call_saves_register(i))
{
if ((i != TP_REGNO && i != GP_REGNO && i != LP_REGNO)
|| mep_reg_set_in_function (i))
- really_need_stack_frame = 1;
+ really_need_stack_frame = true;
if (cfun->machine->reg_save_slot[i])
continue;
di_ofs += 8;
}
}
+ cfun->machine->frame_locked = 1;
+ return really_need_stack_frame;
+}
+
+void
+mep_expand_prologue (void)
+{
+ int i, rss, sp_offset = 0;
+ int reg_save_size;
+ int frame_size;
+ int really_need_stack_frame = frame_size;
+
+ /* We must not allow register renaming in interrupt functions,
+ because that invalidates the correctness of the set of call-used
+ registers we're going to save/restore. */
+ mep_set_leaf_registers (mep_interrupt_p () ? 0 : 1);
+
+ if (mep_disinterrupt_p ())
+ emit_insn (gen_mep_disable_int ());
+
+ cfun->machine->mep_frame_pointer_needed = frame_pointer_needed;
+
+ reg_save_size = mep_elimination_offset (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM);
+ frame_size = mep_elimination_offset (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM);
+
+ really_need_stack_frame |= mep_assign_save_slots (reg_save_size);
sp_offset = reg_save_size;
if (sp_offset + frame_size < 128)
}
if (frame_pointer_needed)
- add_constant (FP_REGNO, SP_REGNO, sp_offset - frame_size, 1);
+ {
+ /* We've already adjusted down by sp_offset. Total $sp change
+ is reg_save_size + frame_size. We want a net change here of
+ just reg_save_size. */
+ add_constant (FP_REGNO, SP_REGNO, sp_offset - reg_save_size, 1);
+ }
add_constant (SP_REGNO, SP_REGNO, sp_offset-(reg_save_size+frame_size), 1);
int r = slot_map[i];
int rss = cfun->machine->reg_save_slot[r];
- if (!rss)
+ if (!mep_call_saves_register (r))
+ continue;
+
+ if ((r == TP_REGNO || r == GP_REGNO || r == LP_REGNO)
+ && (!mep_reg_set_in_function (r)
+ && !mep_interrupt_p ()))
continue;
rsize = mep_reg_size(r);
reg_save_size = mep_elimination_offset (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM);
frame_size = mep_elimination_offset (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM);
- /* All save slots are set by mep_expand_prologue. */
- for (i=0; i<FIRST_PSEUDO_REGISTER; i++)
- if (mep_call_saves_register(i))
- {
- if ((i != TP_REGNO && i != GP_REGNO && i != LP_REGNO)
- || mep_reg_set_in_function (i))
- really_need_stack_frame = 1;
- }
+ really_need_stack_frame |= mep_assign_save_slots (reg_save_size);
if (frame_pointer_needed)
{
{ 0, "m+ri", "3(2)" },
{ 0, "mr", "(1)" },
{ 0, "ms", "(1)" },
+ { 0, "ml", "(1)" },
{ 0, "mLrs", "%lo(3)(2)" },
{ 0, "mLr+si", "%lo(4+5)(2)" },
{ 0, "m+ru2s", "%tpoff(5)(2)" },
rtx regbuf;
ns = cfun->machine->arg_regs_to_save;
- bufsize = ns * (TARGET_IVC2 ? 12 : 4);
- regbuf = assign_stack_local (SImode, bufsize, 32);
+ if (TARGET_IVC2)
+ {
+ bufsize = 8 * ((ns + 1) / 2) + 8 * ns;
+ regbuf = assign_stack_local (SImode, bufsize, 64);
+ }
+ else
+ {
+ bufsize = ns * 4;
+ regbuf = assign_stack_local (SImode, bufsize, 32);
+ }
move_block_from_reg (5-ns, regbuf, ns);
if (TARGET_IVC2)
{
rtx tmp = gen_rtx_MEM (DImode, XEXP (regbuf, 0));
- int ofs = 4 * ns;
+ int ofs = 8 * ((ns+1)/2);
for (i=0; i<ns; i++)
{
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- /* va_list.next_cop = va_list.next_gp_limit; */
+ u = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, u,
+ size_int (8 * ((ns+1)/2)));
+ /* va_list.next_cop = ROUND_UP(va_list.next_gp_limit,8); */
t = build2 (MODIFY_EXPR, ptr_type_node, next_cop, u);
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
bool named ATTRIBUTE_UNUSED)
{
int size = bytesize (type, mode);
- if (type && TARGET_IVC2 && cum->nregs < 4 && VECTOR_TYPE_P (type))
- return size <= 0 || size > 8;
- return size <= 0 || size > 4;
+
+ /* This is non-obvious, but yes, large values passed after we've run
+ out of registers are *still* passed by reference - we put the
+ address of the parameter on the stack, as well as putting the
+ parameter itself elsewhere on the stack. */
+
+ if (size <= 0 || size > 8)
+ return true;
+ if (size <= 4)
+ return false;
+ if (TARGET_IVC2 && cum->nregs < 4 && type != NULL_TREE && VECTOR_TYPE_P (type))
+ return false;
+ return true;
}
void
{
int size = bytesize (type, BLKmode);
if (TARGET_IVC2 && VECTOR_TYPE_P (type))
- return size >= 0 && size <= 8 ? 0 : 1;
- return size >= 0 && size <= 4 ? 0 : 1;
+ return size > 0 && size <= 8 ? 0 : 1;
+ return size > 0 && size <= 4 ? 0 : 1;
}
static bool
}
static bool
-mep_option_can_inline_p (tree caller, tree callee)
+mep_can_inline_p (tree caller, tree callee)
{
if (TREE_CODE (callee) == ADDR_EXPR)
callee = TREE_OPERAND (callee, 0);
- if (TREE_CODE (callee) == FUNCTION_DECL
- && DECL_DECLARED_INLINE_P (callee)
- && !mep_vliw_function_p (caller)
+ if (!mep_vliw_function_p (caller)
&& mep_vliw_function_p (callee))
{
- return true;
+ return false;
}
- return false;
+ return true;
}
#define FUNC_CALL 1
idp = get_identifier (newname);
XEXP (rtl, 0) =
gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
+ SYMBOL_REF_WEAK (XEXP (rtl, 0)) = DECL_WEAK (decl);
+ SET_SYMBOL_REF_DECL (XEXP (rtl, 0), decl);
switch (encoding)
{
maxsize);
}
}
-
- /* Functions do not go through select_section, so we force it here
- by using the DECL_SECTION_NAME as if the user specified the
- .vtext or .ftext sections. */
- if (! DECL_SECTION_NAME (decl)
- && TREE_CODE (decl) == FUNCTION_DECL)
- {
- tree secname;
-
- if (lookup_attribute ("vliw", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
- {
- if (encoding == 'f')
- DECL_SECTION_NAME (decl) = build_string (7, ".vftext");
- else
- DECL_SECTION_NAME (decl) = build_string (6, ".vtext");
- }
- else if (encoding == 'f')
- {
- if (flag_function_sections || DECL_ONE_ONLY (decl))
- mep_unique_section (decl, 0);
- else
- DECL_SECTION_NAME (decl) = build_string (6, ".ftext");
- }
-
- /* This is so we can control inlining. It does not matter what
- attribute we add, just that it has one. */
- secname = build_tree_list (get_identifier ("section"), DECL_SECTION_NAME (decl));
- if (TYPE_P (decl))
- TYPE_ATTRIBUTES (decl) = chainon (TYPE_ATTRIBUTES (decl), secname);
- else
- DECL_ATTRIBUTES (decl) = chainon (DECL_ATTRIBUTES (decl), secname);
- }
}
const char *
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
{
int readonly = 1;
+ int encoding;
switch (TREE_CODE (decl))
{
break;
}
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+
+ if (name[0] == '@' && name[2] == '.')
+ encoding = name[1];
+ else
+ encoding = 0;
+
+ if (flag_function_sections || DECL_ONE_ONLY (decl))
+ mep_unique_section (decl, 0);
+ else if (lookup_attribute ("vliw", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
+ {
+ if (encoding == 'f')
+ return vftext_section;
+ else
+ return vtext_section;
+ }
+ else if (encoding == 'f')
+ return ftext_section;
+ else
+ return text_section;
+ }
+
if (TREE_CODE (decl) == VAR_DECL)
{
const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
{ ".far.", ".gnu.linkonce.far." },
{ ".ftext.", ".gnu.linkonce.ft." },
{ ".frodata.", ".gnu.linkonce.frd." },
- { ".srodata.", ".gnu.linkonce.srd." }
+ { ".srodata.", ".gnu.linkonce.srd." },
+ { ".vtext.", ".gnu.linkonce.v." },
+ { ".vftext.", ".gnu.linkonce.vf." }
};
int sec = 2; /* .data */
int len;
name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
if (TREE_CODE (decl) == FUNCTION_DECL)
- sec = 0; /* .text */
+ {
+ if (lookup_attribute ("vliw", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
+ sec = 9; /* .vtext */
+ else
+ sec = 0; /* .text */
+ }
else if (decl_readonly_section (decl, reloc))
sec = 1; /* .rodata */
case 'f':
if (sec == 0)
sec = 6; /* .ftext */
+ else if (sec == 9)
+ sec = 10; /* .vftext */
else if (sec == 1)
sec = 7; /* .frodata */
else
mep_reorg (void)
{
rtx insns = get_insns ();
+
+ /* We require accurate REG_DEAD notes. */
+ compute_bb_for_insn ();
+ df_note_add_problem ();
+ df_analyze ();
+
mep_reorg_addcombine (insns);
#if EXPERIMENTAL_REGMOVE_REORG
/* VLIW packing has been done already, so we can't just delete things. */
/* This may delete *insns so make sure it's last. */
mep_reorg_noframe (insns);
+
+ df_finish_pass (false);
}
\f
/* But not for control registers. */
if (operand->constraint[0] == '='
&& (! REG_P (arg)
- || ! (CCR_REGNO_P (REGNO (arg)) || CR_REGNO_P (REGNO (arg)))
+ || ! (CONTROL_REGNO_P (REGNO (arg))
+ || CCR_REGNO_P (REGNO (arg))
+ || CR_REGNO_P (REGNO (arg)))
))
return gen_reg_rtx (operand->mode);
= get_unnamed_section (0, output_section_asm_op,
"\t.section .srodata,\"a\"");
+ vtext_section
+ = get_unnamed_section (SECTION_CODE | SECTION_MEP_VLIW, output_section_asm_op,
+ "\t.section .vtext,\"axv\"\n\t.vliw");
+
+ vftext_section
+ = get_unnamed_section (SECTION_CODE | SECTION_MEP_VLIW, output_section_asm_op,
+ "\t.section .vftext,\"axv\"\n\t.vliw");
+
+ ftext_section
+ = get_unnamed_section (SECTION_CODE, output_section_asm_op,
+ "\t.section .ftext,\"ax\"\n\t.core");
+
}
#include "gt-mep.h"