OSDN Git Service

* config/mep/mep.c (mep_encode_section_info): Copy weakness
[pf3gnuchains/gcc-fork.git] / gcc / config / mep / mep.c
index 71755a3..80d3995 100644 (file)
@@ -87,6 +87,7 @@ struct GTY(()) machine_function
   int arg_regs_to_save;
   int regsave_filler;
   int frame_filler;
+  int frame_locked;
   
   /* Records __builtin_return address.  */
   rtx eh_stack_adjust;
@@ -129,6 +130,10 @@ static GTY(()) section * farbss_section;
 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);
@@ -170,7 +175,7 @@ static tree mep_validate_interrupt (tree *, tree, tree, int, bool *);
 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);
@@ -223,6 +228,7 @@ static rtx mep_expand_builtin_saveregs (void);
 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.  */
 
@@ -236,8 +242,8 @@ static tree mep_gimplify_va_arg_expr (tree, tree, tree *, tree *);
 #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
@@ -294,6 +300,8 @@ static tree mep_gimplify_va_arg_expr (tree, tree, tree *, tree *);
 #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
@@ -1182,6 +1190,20 @@ mep_vliw_mode_match (rtx tgt)
   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)
 {
@@ -2544,7 +2566,7 @@ mep_interrupt_saved_reg (int r)
 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;
 
@@ -2591,6 +2613,16 @@ mep_reg_size (int regno)
   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)
 {
@@ -2599,7 +2631,8 @@ 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.
@@ -2759,31 +2792,17 @@ mep_reload_pointer (int regno, const char *symbol)
   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))
       {
@@ -2791,7 +2810,7 @@ mep_expand_prologue (void)
 
        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;
@@ -2807,6 +2826,32 @@ mep_expand_prologue (void)
            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)
@@ -2894,7 +2939,12 @@ mep_expand_prologue (void)
       }
   
   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);
 
@@ -2969,7 +3019,12 @@ mep_start_function (FILE *file, HOST_WIDE_INT hwi_local)
       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);
@@ -3018,14 +3073,7 @@ mep_expand_epilogue (void)
   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)
     {
@@ -3249,6 +3297,7 @@ const conversions[] =
   { 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)" },
@@ -3511,15 +3560,23 @@ mep_expand_builtin_saveregs (void)
   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++)
        {
@@ -3608,7 +3665,9 @@ mep_expand_va_start (tree valist, rtx nextarg)
   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);
@@ -3773,9 +3832,19 @@ mep_pass_by_reference (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED,
                       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
@@ -3791,8 +3860,8 @@ mep_return_in_memory (const_tree type, const_tree decl ATTRIBUTE_UNUSED)
 {
   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
@@ -4110,19 +4179,17 @@ mep_function_attribute_inlinable_p (const_tree callee)
 }
 
 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
@@ -4497,6 +4564,8 @@ mep_encode_section_info (tree decl, rtx rtl, int first)
       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)
        {
@@ -4526,38 +4595,6 @@ mep_encode_section_info (tree decl, rtx rtl, int first)
                   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 *
@@ -4579,6 +4616,7 @@ mep_select_section (tree decl, int reloc ATTRIBUTE_UNUSED,
                    unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
   int readonly = 1;
+  int encoding;
 
   switch (TREE_CODE (decl))
     {
@@ -4599,6 +4637,30 @@ mep_select_section (tree decl, int reloc ATTRIBUTE_UNUSED,
       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);
@@ -4653,7 +4715,9 @@ mep_unique_section (tree decl, int reloc)
     { ".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;
@@ -4665,7 +4729,12 @@ mep_unique_section (tree decl, int reloc)
     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 */
 
@@ -4685,6 +4754,8 @@ mep_unique_section (tree decl, int reloc)
        case 'f':
          if (sec == 0)
            sec = 6; /* .ftext */
+         else if (sec == 9)
+           sec = 10; /* .vftext */
          else if (sec == 1)
            sec = 7; /* .frodata */
          else
@@ -5833,6 +5904,12 @@ static void
 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.  */
@@ -5851,6 +5928,8 @@ mep_reorg (void)
 
   /* This may delete *insns so make sure it's last.  */
   mep_reorg_noframe (insns);
+
+  df_finish_pass (false);
 }
 
 \f
@@ -6187,7 +6266,9 @@ mep_legitimize_arg (const struct insn_operand_data *operand, rtx arg,
   /* 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);
 
@@ -7324,6 +7405,18 @@ mep_asm_init_sections (void)
     = 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"