]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Add mips16/nomips16 function attributes and -mflip-mips16 option for testing mixed...
authorSandra Loosemore <sandra@codesourcery.com>
Wed, 5 Sep 2007 14:40:04 +0000 (10:40 -0400)
committerSandra Loosemore <sandra@gcc.gnu.org>
Wed, 5 Sep 2007 14:40:04 +0000 (10:40 -0400)
2007-09-05  Sandra Loosemore  <sandra@codesourcery.com>
    David Ung  <davidu@mips.com>
            Nigel Stephens <nigel@mips.com>

Add mips16/nomips16 function attributes and -mflip-mips16 option
for testing mixed-mode compilation.

gcc/

* config/mips/mips.opt (mflip-mips16): New.

* config/mips/mips.h (SYMBOL_FLAG_MIPS16_FUNC): Define.
(SYMBOL_FLAG_MIPS16_FUNC_P): Define.

* config/mips/mips.c (mips_base_target_flags): New.
(mips_base_mips16): New.
(mips_base_schedule_insns): New.
(mips_base_reorder_blocks_and_partition): New.
(mips_base_align_loops): New.
(mips_base_align_jumps): New.
(mips_base_align_functions): New.
(mips16_flipper): New.
(mips_attribute_table): Add "mips16" and "nomips16" entries.
(TARGET_SET_CURRENT_FUNCTION): Define.
(mips_mips16_type_p, mips_nomips16_type_p): New.
(mips_comp_type_attributes): Check mips16/nomips16 attributes.
(mips_function_ok_for_sibcall): Make it deal with functions with
mips16 attributes.
(mips_init_split_addresses): New, split out from override_options.
(mips_init_relocs): New, split out from override_options.
(was_mips16_p): New.
(mips_set_mips16_mode): New, split out from override_options.
(mips_set_current_function): New.
(override_options):  Add sorry for unsupported mips16/pic
combination.  Remove error for mips16/dsp combination. Save
base option settings.
(mips_file_start): Move mips16 mode setting output from here....
(mips_output_function_prologue): ....to here.
(mips_output_mi_thunk): Check for mips16 function.
(build_mips16_function_stub): Don't set .mips16 here.
(build_mips16_call_stub): Likewise.
(mips_expand_builtin): Error in mips16 mode.
(mips_use_mips16_mode_p): New.
(mips_encode_section_info): Check for mips16 function, and set
SYMBOL_REF_FLAGS accordingly.

* doc/extend.texi (Function Attributes): Document new
mips16/nomips16 attributes.
* doc/invoke.texi (Option Summary): Add -mflip-mips16.
(MIPS Options): Document -mflip-mips16.

gcc/testsuite/
* gcc.target/mips/mips16-attributes.c: New.

Co-Authored-By: David Ung <davidu@mips.com>
Co-Authored-By: Nigel Stephens <nigel@mips.com>
From-SVN: r128134

gcc/ChangeLog
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.opt
gcc/doc/extend.texi
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/mips16-attributes.c [new file with mode: 0644]

index b32119985697da8aa49761ab134c56746a26caf4..2051ef1a05c513fed192154706861a2ccd9f72ae 100644 (file)
@@ -1,6 +1,54 @@
+2007-09-05  Sandra Loosemore  <sandra@codesourcery.com>
+           David Ung  <davidu@mips.com>
+            Nigel Stephens <nigel@mips.com>
+
+       Add mips16/nomips16 function attributes and -mflip-mips16 option
+       for testing mixed-mode compilation.
+
+       * config/mips/mips.opt (mflip-mips16): New.
+
+       * config/mips/mips.h (SYMBOL_FLAG_MIPS16_FUNC): Define.
+       (SYMBOL_FLAG_MIPS16_FUNC_P): Define.
+
+       * config/mips/mips.c (mips_base_target_flags): New.
+       (mips_base_mips16): New.
+       (mips_base_schedule_insns): New.
+       (mips_base_reorder_blocks_and_partition): New.
+       (mips_base_align_loops): New.
+       (mips_base_align_jumps): New.
+       (mips_base_align_functions): New.
+       (mips16_flipper): New.
+       (mips_attribute_table): Add "mips16" and "nomips16" entries.
+       (TARGET_SET_CURRENT_FUNCTION): Define.
+       (mips_mips16_type_p, mips_nomips16_type_p): New.
+       (mips_comp_type_attributes): Check mips16/nomips16 attributes.
+       (mips_function_ok_for_sibcall): Make it deal with functions with
+       mips16 attributes.
+       (mips_init_split_addresses): New, split out from override_options.
+       (mips_init_relocs): New, split out from override_options.
+       (was_mips16_p): New.
+       (mips_set_mips16_mode): New, split out from override_options.
+       (mips_set_current_function): New.
+       (override_options):  Add sorry for unsupported mips16/pic
+       combination.  Remove error for mips16/dsp combination.  Save
+       base option settings.  
+       (mips_file_start): Move mips16 mode setting output from here....
+       (mips_output_function_prologue): ....to here.
+       (mips_output_mi_thunk): Check for mips16 function.
+       (build_mips16_function_stub): Don't set .mips16 here.
+       (build_mips16_call_stub): Likewise.
+       (mips_expand_builtin): Error in mips16 mode.
+       (mips_use_mips16_mode_p): New.
+       (mips_encode_section_info): Check for mips16 function, and set
+       SYMBOL_REF_FLAGS accordingly.
+
+       * doc/extend.texi (Function Attributes): Document new
+       mips16/nomips16 attributes.
+       * doc/invoke.texi (Option Summary): Add -mflip-mips16.
+       (MIPS Options): Document -mflip-mips16.
+
 2007-09-05  Sandra Loosemore  <sandra@codesourcery.com>
 
-       gcc/
        * config/mips/mips.c (mips_legitimize_tls_address): Call sorry
        if we encounter TLS address in MIPS16 mode.
        (mips_legitimize_const_move):  Check cannot_force_const_mem for
index 937f5904550c35d4769c3bc24f712f8ee588a888..ae412dea64131d436a4c8d3b8dcb183c889c5635 100644 (file)
@@ -424,6 +424,8 @@ static rtx mips_expand_builtin_bposge (enum mips_builtin_type, rtx);
 static void mips_encode_section_info (tree, rtx, int);
 static void mips_extra_live_on_entry (bitmap);
 static int mips_comp_type_attributes (const_tree, const_tree);
+static void mips_set_mips16_mode (int);
+static void mips_set_current_function (tree);
 static int mips_mode_rep_extended (enum machine_mode, enum machine_mode);
 static bool mips_offset_within_alignment_p (rtx, HOST_WIDE_INT);
 static void mips_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
@@ -617,6 +619,18 @@ int mips_abi = MIPS_ABI_DEFAULT;
 /* Cost information to use.  */
 const struct mips_rtx_cost_data *mips_cost;
 
+/* Remember the ambient target flags, excluding mips16.  */
+static int mips_base_target_flags;
+/* The mips16 command-line target flags only.  */
+static bool mips_base_mips16;
+/* Similar copies of option settings.  */
+static int mips_base_schedule_insns; /* flag_schedule_insns */
+static int mips_base_reorder_blocks_and_partition; /* flag_reorder... */
+static int mips_base_align_loops; /* align_loops */
+static int mips_base_align_jumps; /* align_jumps */
+static int mips_base_align_functions; /* align_functions */
+static GTY(()) int mips16_flipper;
+
 /* The -mtext-loads setting.  */
 enum mips_code_readable_setting mips_code_readable = CODE_READABLE_YES;
 
@@ -715,6 +729,9 @@ const struct attribute_spec mips_attribute_table[] =
   { "long_call",   0, 0, false, true,  true,  NULL },
   { "far",                0, 0, false, true,  true,  NULL },
   { "near",        0, 0, false, true,  true,  NULL },
+  /* Switch MIPS16 ASE on and off per-function.  */
+  { "mips16",     0, 0, false, true,  true,  NULL },
+  { "nomips16",    0, 0, false, true,  true,  NULL },
   { NULL,         0, 0, false, false, false, NULL }
 };
 \f
@@ -1251,6 +1268,9 @@ static const unsigned char mips16e_save_restore_regs[] = {
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL mips_function_ok_for_sibcall
 
+#undef TARGET_SET_CURRENT_FUNCTION
+#define TARGET_SET_CURRENT_FUNCTION mips_set_current_function
+
 #undef TARGET_VALID_POINTER_MODE
 #define TARGET_VALID_POINTER_MODE mips_valid_pointer_mode
 #undef TARGET_RTX_COSTS
@@ -1369,6 +1389,19 @@ mips_far_type_p (const_tree type)
          || lookup_attribute ("far", TYPE_ATTRIBUTES (type)) != NULL);
 }
 
+/* Similar predicates for "mips16"/"nomips16" attributes.  */
+
+static bool
+mips_mips16_type_p (const_tree type)
+{
+  return lookup_attribute ("mips16", TYPE_ATTRIBUTES (type)) != NULL;
+}
+
+static bool
+mips_nomips16_type_p (const_tree type)
+{
+  return lookup_attribute ("nomips16", TYPE_ATTRIBUTES (type)) != NULL;
+}
 
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
@@ -1387,6 +1420,11 @@ mips_comp_type_attributes (const_tree type1, const_tree type2)
   if (mips_near_type_p (type1) && mips_far_type_p (type2))
     return 0;
 
+  /* Mips16/nomips16 attributes must match exactly.  */
+  if (mips_nomips16_type_p (type1) != mips_nomips16_type_p (type2)
+      || mips_mips16_type_p (type1) != mips_mips16_type_p (type2))
+    return 0;
+
   return 1;
 }
 \f
@@ -3789,13 +3827,22 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p)
 }
 
 
-/* We can handle any sibcall when TARGET_SIBCALLS is true.  */
+/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
 
 static bool
-mips_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
-                             tree exp ATTRIBUTE_UNUSED)
+mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-  return TARGET_SIBCALLS;
+  if (!TARGET_SIBCALLS)
+    return false;
+
+  /* We can't do a sibcall if the called function is a MIPS16 function
+     because there is no direct "jx" instruction equivalent to "jalx" to
+     switch the ISA mode.  */
+  if (decl && SYMBOL_REF_MIPS16_FUNC_P (XEXP (DECL_RTL (decl), 0)))
+    return false;
+
+  /* Otherwise OK.  */
+  return true;
 }
 \f
 /* Emit code to move general operand SRC into condition-code
@@ -5038,6 +5085,231 @@ mips_set_tune (const struct mips_cpu_info *info)
     }
 }
 
+/* Initialize mips_split_addresses from the associated command-line
+   settings.
+
+   mips_split_addresses is a half-way house between explicit
+   relocations and the traditional assembler macros.  It can
+   split absolute 32-bit symbolic constants into a high/lo_sum
+   pair but uses macros for other sorts of access.
+   
+   Like explicit relocation support for REL targets, it relies
+   on GNU extensions in the assembler and the linker.
+
+   Although this code should work for -O0, it has traditionally
+   been treated as an optimization.  */
+
+static void
+mips_init_split_addresses (void)
+{
+  if (!TARGET_MIPS16 && TARGET_SPLIT_ADDRESSES
+      && optimize && !flag_pic
+      && !ABI_HAS_64BIT_SYMBOLS)
+    mips_split_addresses = 1;
+  else
+    mips_split_addresses = 0;
+}
+
+/* (Re-)Initialize information about relocs.  */
+
+static void
+mips_init_relocs (void)
+{
+  memset (mips_split_p, '\0', sizeof (mips_split_p));
+  memset (mips_hi_relocs, '\0', sizeof (mips_hi_relocs));
+  memset (mips_lo_relocs, '\0', sizeof (mips_lo_relocs));
+
+  if (ABI_HAS_64BIT_SYMBOLS)
+    {
+      if (TARGET_EXPLICIT_RELOCS)
+       {
+         mips_split_p[SYMBOL_64_HIGH] = true;
+         mips_hi_relocs[SYMBOL_64_HIGH] = "%highest(";
+         mips_lo_relocs[SYMBOL_64_HIGH] = "%higher(";
+
+         mips_split_p[SYMBOL_64_MID] = true;
+         mips_hi_relocs[SYMBOL_64_MID] = "%higher(";
+         mips_lo_relocs[SYMBOL_64_MID] = "%hi(";
+
+         mips_split_p[SYMBOL_64_LOW] = true;
+         mips_hi_relocs[SYMBOL_64_LOW] = "%hi(";
+         mips_lo_relocs[SYMBOL_64_LOW] = "%lo(";
+
+         mips_split_p[SYMBOL_ABSOLUTE] = true;
+         mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo(";
+       }
+    }
+  else
+    {
+      if (TARGET_EXPLICIT_RELOCS || mips_split_addresses || TARGET_MIPS16)
+       {
+         mips_split_p[SYMBOL_ABSOLUTE] = true;
+         mips_hi_relocs[SYMBOL_ABSOLUTE] = "%hi(";
+         mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo(";
+
+         mips_lo_relocs[SYMBOL_32_HIGH] = "%hi(";
+       }
+    }
+
+  if (TARGET_MIPS16)
+    {
+      /* The high part is provided by a pseudo copy of $gp.  */
+      mips_split_p[SYMBOL_GP_RELATIVE] = true;
+      mips_lo_relocs[SYMBOL_GP_RELATIVE] = "%gprel(";
+    }
+
+  if (TARGET_EXPLICIT_RELOCS)
+    {
+      /* Small data constants are kept whole until after reload,
+        then lowered by mips_rewrite_small_data.  */
+      mips_lo_relocs[SYMBOL_GP_RELATIVE] = "%gp_rel(";
+
+      mips_split_p[SYMBOL_GOT_PAGE_OFST] = true;
+      if (TARGET_NEWABI)
+       {
+         mips_lo_relocs[SYMBOL_GOTOFF_PAGE] = "%got_page(";
+         mips_lo_relocs[SYMBOL_GOT_PAGE_OFST] = "%got_ofst(";
+       }
+      else
+       {
+         mips_lo_relocs[SYMBOL_GOTOFF_PAGE] = "%got(";
+         mips_lo_relocs[SYMBOL_GOT_PAGE_OFST] = "%lo(";
+       }
+
+      if (TARGET_XGOT)
+       {
+         /* The HIGH and LO_SUM are matched by special .md patterns.  */
+         mips_split_p[SYMBOL_GOT_DISP] = true;
+
+         mips_split_p[SYMBOL_GOTOFF_DISP] = true;
+         mips_hi_relocs[SYMBOL_GOTOFF_DISP] = "%got_hi(";
+         mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got_lo(";
+
+         mips_split_p[SYMBOL_GOTOFF_CALL] = true;
+         mips_hi_relocs[SYMBOL_GOTOFF_CALL] = "%call_hi(";
+         mips_lo_relocs[SYMBOL_GOTOFF_CALL] = "%call_lo(";
+       }
+      else
+       {
+         if (TARGET_NEWABI)
+           mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got_disp(";
+         else
+           mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got(";
+         mips_lo_relocs[SYMBOL_GOTOFF_CALL] = "%call16(";
+       }
+    }
+
+  if (TARGET_NEWABI)
+    {
+      mips_split_p[SYMBOL_GOTOFF_LOADGP] = true;
+      mips_hi_relocs[SYMBOL_GOTOFF_LOADGP] = "%hi(%neg(%gp_rel(";
+      mips_lo_relocs[SYMBOL_GOTOFF_LOADGP] = "%lo(%neg(%gp_rel(";
+    }
+
+  /* Thread-local relocation operators.  */
+  mips_lo_relocs[SYMBOL_TLSGD] = "%tlsgd(";
+  mips_lo_relocs[SYMBOL_TLSLDM] = "%tlsldm(";
+  mips_split_p[SYMBOL_DTPREL] = 1;
+  mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
+  mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
+  mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
+  mips_split_p[SYMBOL_TPREL] = 1;
+  mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
+  mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
+
+  mips_lo_relocs[SYMBOL_HALF] = "%half(";
+}
+
+static GTY(()) int was_mips16_p = -1;
+
+/* Set up the target-dependent global state so that it matches the
+   current function's ISA mode.  */
+
+static void
+mips_set_mips16_mode (int mips16_p)
+{
+  if (mips16_p == was_mips16_p)
+    return;
+
+  /* Restore base settings of various flags.  */
+  target_flags = mips_base_target_flags;
+  align_loops = mips_base_align_loops;
+  align_jumps = mips_base_align_jumps;
+  align_functions = mips_base_align_functions;
+  flag_schedule_insns = mips_base_schedule_insns;
+  flag_reorder_blocks_and_partition = mips_base_reorder_blocks_and_partition;
+  flag_delayed_branch = mips_flag_delayed_branch;
+  
+  if (mips16_p) 
+    {
+      /* Select mips16 instruction set.  */
+      target_flags |= MASK_MIPS16;
+
+      /* Don't run the scheduler before reload, since it tends to
+         increase register pressure.  */
+      flag_schedule_insns = 0;
+
+      /* Don't do hot/cold partitioning.  The constant layout code expects
+       the whole function to be in a single section.  */
+      flag_reorder_blocks_and_partition = 0;
+
+      /* Silently disable -mexplicit-relocs since it doesn't apply
+        to mips16 code.  Even so, it would overly pedantic to warn
+        about "-mips16 -mexplicit-relocs", especially given that
+        we use a %gprel() operator.  */
+      target_flags &= ~MASK_EXPLICIT_RELOCS;
+
+      /* Silently disable DSP extensions.  */
+      target_flags &= ~MASK_DSP;
+      target_flags &= ~MASK_DSPR2;
+    }
+  else 
+    {
+      /* Reset to select base non-mips16 ISA.  */
+      target_flags &= ~MASK_MIPS16;
+
+      /* When using explicit relocs, we call dbr_schedule from within
+        mips_reorg.  */
+      if (TARGET_EXPLICIT_RELOCS)
+       flag_delayed_branch = 0;
+
+      /* Provide default values for align_* for 64-bit targets.  */
+      if (TARGET_64BIT)
+       {
+         if (align_loops == 0)
+           align_loops = 8;
+         if (align_jumps == 0)
+           align_jumps = 8;
+         if (align_functions == 0)
+           align_functions = 8;
+       }
+    }
+
+  /* (Re)initialize mips target internals for new ISA.  */
+  mips_init_split_addresses ();
+  mips_init_relocs ();
+
+  if (was_mips16_p >= 0)
+    /* Reinitialize target-dependent state.  */
+    target_reinit ();
+
+  was_mips16_p = TARGET_MIPS16;
+}
+
+/* Implement TARGET_SET_CURRENT_FUNCTION.  Decide whether the current 
+   function should use the MIPS16 ISA and switch modes accordingly.  */
+
+static void
+mips_set_current_function (tree fndecl)
+{
+  int mips16p;
+  if (fndecl)
+    mips16p = SYMBOL_REF_MIPS16_FUNC_P (XEXP (DECL_RTL (fndecl), 0));
+  else
+    mips16p = mips_base_mips16;
+  mips_set_mips16_mode (mips16p);
+}
+
 /* Implement TARGET_HANDLE_OPTION.  */
 
 static bool
@@ -5265,6 +5537,14 @@ override_options (void)
       target_flags &= ~MASK_ABICALLS;
     }
 
+  /* MIPS16 cannot generate PIC yet.  */
+  if (TARGET_MIPS16 && (flag_pic || TARGET_ABICALLS))
+    {
+      sorry ("MIPS16 PIC");
+      target_flags &= ~MASK_ABICALLS;
+      flag_pic = flag_pie = flag_shlib = 0;
+    }
+
   if (TARGET_ABICALLS)
     {
       /* We need to set flag_pic for executables as well as DSOs
@@ -5282,54 +5562,12 @@ override_options (void)
   if (TARGET_VXWORKS_RTP && mips_section_threshold > 0)
     warning (0, "-G and -mrtp are incompatible");
 
-  /* mips_split_addresses is a half-way house between explicit
-     relocations and the traditional assembler macros.  It can
-     split absolute 32-bit symbolic constants into a high/lo_sum
-     pair but uses macros for other sorts of access.
-
-     Like explicit relocation support for REL targets, it relies
-     on GNU extensions in the assembler and the linker.
-
-     Although this code should work for -O0, it has traditionally
-     been treated as an optimization.  */
-  if (!TARGET_MIPS16 && TARGET_SPLIT_ADDRESSES
-      && optimize && !flag_pic
-      && !ABI_HAS_64BIT_SYMBOLS)
-    mips_split_addresses = 1;
-  else
-    mips_split_addresses = 0;
-
   /* -mvr4130-align is a "speed over size" optimization: it usually produces
      faster code, but at the expense of more nops.  Enable it at -O3 and
      above.  */
   if (optimize > 2 && (target_flags_explicit & MASK_VR4130_ALIGN) == 0)
     target_flags |= MASK_VR4130_ALIGN;
 
-  if (TARGET_MIPS16)
-    {
-      /* Don't run the scheduler before reload, since it tends to
-         increase register pressure.  */
-      flag_schedule_insns = 0;
-
-      /* Don't do hot/cold partitioning.  The constant layout code expects
-        the whole function to be in a single section.  */
-      flag_reorder_blocks_and_partition = 0;
-
-      /* Silently disable -mexplicit-relocs since it doesn't apply
-        to mips16 code.  Even so, it would overly pedantic to warn
-        about "-mips16 -mexplicit-relocs", especially given that
-        we use a %gprel() operator.  */
-      target_flags &= ~MASK_EXPLICIT_RELOCS;
-    }
-
-  /* When using explicit relocs, we call dbr_schedule from within
-     mips_reorg.  */
-  if (TARGET_EXPLICIT_RELOCS)
-    {
-      mips_flag_delayed_branch = flag_delayed_branch;
-      flag_delayed_branch = 0;
-    }
-
   /* Prefer a call to memcpy over inline code when optimizing for size,
      though see MOVE_RATIO in mips.h.  */
   if (optimize_size && (target_flags_explicit & MASK_MEMCPY) == 0)
@@ -5363,9 +5601,6 @@ override_options (void)
   if (TARGET_DSPR2)
     target_flags |= MASK_DSP;
 
-  if (TARGET_MIPS16 && TARGET_DSP)
-    error ("-mips16 and -mdsp cannot be used together");
-
   mips_print_operand_punct['?'] = 1;
   mips_print_operand_punct['#'] = 1;
   mips_print_operand_punct['/'] = 1;
@@ -5493,120 +5728,9 @@ override_options (void)
      initialized yet, so we can't use that here.  */
   gpr_mode = TARGET_64BIT ? DImode : SImode;
 
-  /* Provide default values for align_* for 64-bit targets.  */
-  if (TARGET_64BIT && !TARGET_MIPS16)
-    {
-      if (align_loops == 0)
-       align_loops = 8;
-      if (align_jumps == 0)
-       align_jumps = 8;
-      if (align_functions == 0)
-       align_functions = 8;
-    }
-
   /* Function to allocate machine-dependent function status.  */
   init_machine_status = &mips_init_machine_status;
 
-  if (ABI_HAS_64BIT_SYMBOLS)
-    {
-      if (TARGET_EXPLICIT_RELOCS)
-       {
-         mips_split_p[SYMBOL_64_HIGH] = true;
-         mips_hi_relocs[SYMBOL_64_HIGH] = "%highest(";
-         mips_lo_relocs[SYMBOL_64_HIGH] = "%higher(";
-
-         mips_split_p[SYMBOL_64_MID] = true;
-         mips_hi_relocs[SYMBOL_64_MID] = "%higher(";
-         mips_lo_relocs[SYMBOL_64_MID] = "%hi(";
-
-         mips_split_p[SYMBOL_64_LOW] = true;
-         mips_hi_relocs[SYMBOL_64_LOW] = "%hi(";
-         mips_lo_relocs[SYMBOL_64_LOW] = "%lo(";
-
-         mips_split_p[SYMBOL_ABSOLUTE] = true;
-         mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo(";
-       }
-    }
-  else
-    {
-      if (TARGET_EXPLICIT_RELOCS || mips_split_addresses || TARGET_MIPS16)
-       {
-         mips_split_p[SYMBOL_ABSOLUTE] = true;
-         mips_hi_relocs[SYMBOL_ABSOLUTE] = "%hi(";
-         mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo(";
-
-         mips_lo_relocs[SYMBOL_32_HIGH] = "%hi(";
-       }
-    }
-
-  if (TARGET_MIPS16)
-    {
-      /* The high part is provided by a pseudo copy of $gp.  */
-      mips_split_p[SYMBOL_GP_RELATIVE] = true;
-      mips_lo_relocs[SYMBOL_GP_RELATIVE] = "%gprel(";
-    }
-
-  if (TARGET_EXPLICIT_RELOCS)
-    {
-      /* Small data constants are kept whole until after reload,
-        then lowered by mips_rewrite_small_data.  */
-      mips_lo_relocs[SYMBOL_GP_RELATIVE] = "%gp_rel(";
-
-      mips_split_p[SYMBOL_GOT_PAGE_OFST] = true;
-      if (TARGET_NEWABI)
-       {
-         mips_lo_relocs[SYMBOL_GOTOFF_PAGE] = "%got_page(";
-         mips_lo_relocs[SYMBOL_GOT_PAGE_OFST] = "%got_ofst(";
-       }
-      else
-       {
-         mips_lo_relocs[SYMBOL_GOTOFF_PAGE] = "%got(";
-         mips_lo_relocs[SYMBOL_GOT_PAGE_OFST] = "%lo(";
-       }
-
-      if (TARGET_XGOT)
-       {
-         /* The HIGH and LO_SUM are matched by special .md patterns.  */
-         mips_split_p[SYMBOL_GOT_DISP] = true;
-
-         mips_split_p[SYMBOL_GOTOFF_DISP] = true;
-         mips_hi_relocs[SYMBOL_GOTOFF_DISP] = "%got_hi(";
-         mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got_lo(";
-
-         mips_split_p[SYMBOL_GOTOFF_CALL] = true;
-         mips_hi_relocs[SYMBOL_GOTOFF_CALL] = "%call_hi(";
-         mips_lo_relocs[SYMBOL_GOTOFF_CALL] = "%call_lo(";
-       }
-      else
-       {
-         if (TARGET_NEWABI)
-           mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got_disp(";
-         else
-           mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got(";
-         mips_lo_relocs[SYMBOL_GOTOFF_CALL] = "%call16(";
-       }
-    }
-
-  if (TARGET_NEWABI)
-    {
-      mips_split_p[SYMBOL_GOTOFF_LOADGP] = true;
-      mips_hi_relocs[SYMBOL_GOTOFF_LOADGP] = "%hi(%neg(%gp_rel(";
-      mips_lo_relocs[SYMBOL_GOTOFF_LOADGP] = "%lo(%neg(%gp_rel(";
-    }
-
-  /* Thread-local relocation operators.  */
-  mips_lo_relocs[SYMBOL_TLSGD] = "%tlsgd(";
-  mips_lo_relocs[SYMBOL_TLSLDM] = "%tlsldm(";
-  mips_split_p[SYMBOL_DTPREL] = 1;
-  mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
-  mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
-  mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
-  mips_split_p[SYMBOL_TPREL] = 1;
-  mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
-  mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
-
-  mips_lo_relocs[SYMBOL_HALF] = "%half(";
-
   /* Default to working around R4000 errata only if the processor
      was selected explicitly.  */
   if ((target_flags_explicit & MASK_FIX_R4000) == 0
@@ -5618,6 +5742,19 @@ override_options (void)
   if ((target_flags_explicit & MASK_FIX_R4400) == 0
       && mips_matching_cpu_name_p (mips_arch_info->name, "r4400"))
     target_flags |= MASK_FIX_R4400;
+
+  /* Save base state of options.  */
+  mips_base_mips16 = TARGET_MIPS16;
+  mips_base_target_flags = target_flags;
+  mips_base_schedule_insns = flag_schedule_insns;
+  mips_base_reorder_blocks_and_partition = flag_reorder_blocks_and_partition;
+  mips_base_align_loops = align_loops;
+  mips_base_align_jumps = align_jumps;
+  mips_base_align_functions = align_functions;
+  mips_flag_delayed_branch = flag_delayed_branch;
+
+  /* Now select the mips16 or 32-bit instruction set, as requested.  */
+  mips_set_mips16_mode (mips_base_mips16);
 }
 
 /* Swap the register information for registers I and I + 1, which
@@ -6373,9 +6510,6 @@ mips_file_start (void)
   if (TARGET_ABICALLS)
     fprintf (asm_out_file, "\t.abicalls\n");
 
-  if (TARGET_MIPS16)
-    fprintf (asm_out_file, "\t.set\tmips16\n");
-
   if (flag_verbose_asm)
     fprintf (asm_out_file, "\n%s -G value = %d, Arch = %s, ISA = %d\n",
             ASM_COMMENT_START,
@@ -7230,6 +7364,12 @@ mips_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
       && current_function_args_info.fp_code != 0)
     build_mips16_function_stub (file);
 
+  /* Select the mips16 mode for this function.  */
+  if (TARGET_MIPS16)
+    fprintf (file, "\t.set\tmips16\n");
+  else 
+    fprintf (file, "\t.set\tnomips16\n");
+
   if (!FUNCTION_NAME_ALREADY_DECLARED)
     {
       /* Get the function name the same way that toplev.c does before calling
@@ -8186,7 +8326,6 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
        TARGET_CALL_SAVED_GP ? 15 : GLOBAL_POINTER_REGNUM;
 
       SET_REGNO (pic_offset_table_rtx, cfun->machine->global_pointer);
-
     }
 
   /* Set up the global pointer for n32 or n64 abicalls.  If
@@ -8237,7 +8376,8 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   /* Jump to the target function.  Use a sibcall if direct jumps are
      allowed, otherwise load the address into a register first.  */
   fnaddr = XEXP (DECL_RTL (function), 0);
-  if (TARGET_MIPS16 || TARGET_USE_GOT || SYMBOL_REF_LONG_CALL_P (fnaddr))
+  if (TARGET_MIPS16 || TARGET_USE_GOT || SYMBOL_REF_LONG_CALL_P (fnaddr)
+      || SYMBOL_REF_MIPS16_FUNC_P (fnaddr))
     {
       /* This is messy.  gas treats "la $25,foo" as part of a call
         sequence and may allow a global "foo" to be lazily bound.
@@ -9073,8 +9213,6 @@ build_mips16_function_stub (FILE *file)
       fputs ("\n", file);
     }
 
-  fprintf (file, "\t.set\tmips16\n");
-
   switch_to_section (function_section (current_function_decl));
 }
 
@@ -9406,8 +9544,6 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
          fputs ("\n", asm_out_file);
        }
 
-      fprintf (asm_out_file, "\t.set\tmips16\n");
-
       /* Record this stub.  */
       l = (struct mips16_stub *) xmalloc (sizeof *l);
       l->name = xstrdup (fnname);
@@ -11648,6 +11784,13 @@ mips_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   fcode = DECL_FUNCTION_CODE (fndecl);
 
+  if (TARGET_MIPS16)
+    {
+      error ("built-in function %qs not supported for MIPS16",
+            IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+      return const0_rtx;
+    }
+
   bdesc = NULL;
   for (m = bdesc_arrays; m < &bdesc_arrays[ARRAY_SIZE (bdesc_arrays)]; m++)
     {
@@ -12154,6 +12297,43 @@ mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target)
                                       const1_rtx, const0_rtx);
 }
 \f
+/* Return true if we should force MIPS16 mode for the function named by
+   the SYMBOL_REF SYMBOL, which belongs to DECL and has type TYPE.
+   FIRST is true if this is the first time handling this decl.  */
+
+static bool
+mips_use_mips16_mode_p (rtx symbol, tree decl, int first, tree type)
+{
+  tree parent;
+
+  /* Explicit function attributes take precedence.  */
+  if (mips_mips16_type_p (type))
+    return true;
+  if (mips_nomips16_type_p (type))
+    return false;
+
+  /* A nested function should inherit the MIPS16 setting from its parent.  */
+  parent = decl_function_context (decl);
+  if (parent)
+    return SYMBOL_REF_MIPS16_FUNC_P (XEXP (DECL_RTL (parent), 0));
+
+  /* Handle -mflip-mips16.  */
+  if (TARGET_FLIP_MIPS16
+      && !DECL_BUILT_IN (decl)
+      && !DECL_ARTIFICIAL (decl))
+    {
+      if (!first)
+       /* Use the setting we picked first time around.  */
+       return SYMBOL_REF_MIPS16_FUNC_P (symbol);
+
+      mips16_flipper = !mips16_flipper;
+      if (mips16_flipper)
+       return !mips_base_mips16;
+    }
+
+  return mips_base_mips16;
+}
+
 /* Set SYMBOL_REF_FLAGS for the SYMBOL_REF inside RTL, which belongs to DECL.
    FIRST is true if this is the first time handling this decl.  */
 
@@ -12165,10 +12345,19 @@ mips_encode_section_info (tree decl, rtx rtl, int first)
   if (TREE_CODE (decl) == FUNCTION_DECL)
     {
       rtx symbol = XEXP (rtl, 0);
+      tree type = TREE_TYPE (decl);
 
-      if ((TARGET_LONG_CALLS && !mips_near_type_p (TREE_TYPE (decl)))
-         || mips_far_type_p (TREE_TYPE (decl)))
+      if ((TARGET_LONG_CALLS && !mips_near_type_p (type))
+         || mips_far_type_p (type))
        SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LONG_CALL;
+
+      if (mips_use_mips16_mode_p (symbol, decl, first, type))
+       {
+         if (flag_pic || TARGET_ABICALLS)
+           sorry ("MIPS16 PIC");
+         else
+           SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_MIPS16_FUNC;
+       }
     }
 }
 
index a44460b08532cf9fc4b01cefde519057aa01685c..cc6b50011be78583ccb6f2de03214ce6bbc6de28 100644 (file)
@@ -2301,6 +2301,11 @@ typedef struct mips_args {
 #define SYMBOL_REF_LONG_CALL_P(X)                                      \
   ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_LONG_CALL) != 0)
 
+/* Flag to mark a function decl symbol a "mips16" function.  */
+#define SYMBOL_FLAG_MIPS16_FUNC        (SYMBOL_FLAG_MACH_DEP << 1)
+#define SYMBOL_REF_MIPS16_FUNC_P(RTX) \
+  ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_MIPS16_FUNC) != 0)
+
 /* True if we're generating a form of MIPS16 code in which jump tables
    are stored in the text section and encoded as 16-bit PC-relative
    offsets.  This is only possible when general text loads are allowed,
index 6f6c109187cf661a6b9c24237754398dcaa86bc4..7f60bebc7b823a4357b61da1be06349a42660cfd 100644 (file)
@@ -42,6 +42,10 @@ mbranch-likely
 Target Report Mask(BRANCHLIKELY)
 Use Branch Likely instructions, overriding the architecture default
 
+mflip-mips16
+Target Report Var(TARGET_FLIP_MIPS16)
+Switch on/off MIPS16 ASE on alternating functions for compiler testing
+
 mcheck-zero-division
 Target Report Mask(CHECK_ZERO_DIV)
 Trap on integer divide by zero
index 2016e451de578b0b318494393a06698876a0e1bd..0012740476b924b22404f75118112352f88742cd 100644 (file)
@@ -2202,6 +2202,24 @@ long as the old pointer is never referred to (including comparing it
 to the new pointer) after the function returns a non-@code{NULL}
 value.
 
+@item mips16/nomips16
+@cindex @code{mips16} attribute
+@cindex @code{nomips16} attribute
+
+On MIPS targets, you can use the @code{mips16} and @code{nomips16}
+function attributes to locally select or turn off MIPS16 code generation.
+A function with the @code{mips16} attribute is emitted as MIPS16 code, 
+while MIPS16 code generation is disabled for functions with the 
+@code{nomips16} attribute.  These attributes override the 
+@option{-mips16} and @option{-mno-mips16} options on the command line
+(@pxref{MIPS Options}).  
+
+When compiling files containing mixed MIPS16 and non-MIPS16 code, the
+preprocessor symbol @code{__mips16} reflects the setting on the command line,
+not that within individual functions.  Mixed MIPS16 and non-MIPS16 code
+may interact badly with some GCC extensions such as @code{__builtin_apply}
+(@pxref{Constructing Calls}).
+
 @item model (@var{model-name})
 @cindex function addressability on the M32R/D
 @cindex variable addressability on the IA-64
index 9164078b75f5b959749fd0d0778615106c52a0b3..734c8edfb45e58b099bea350da0d77182dacc668 100644 (file)
@@ -620,7 +620,8 @@ Objective-C and Objective-C++ Dialects}.
 @emph{MIPS Options}
 @gccoptlist{-EL  -EB  -march=@var{arch}  -mtune=@var{arch} @gol
 -mips1  -mips2  -mips3  -mips4  -mips32  -mips32r2  -mips64 @gol
--mips16  -mno-mips16  -mabi=@var{abi}  -mabicalls  -mno-abicalls @gol
+-mips16  -mno-mips16  -mflip-mips16 @gol
+-mabi=@var{abi}  -mabicalls  -mno-abicalls @gol
 -mshared  -mno-shared  -mxgot  -mno-xgot  -mgp32  -mgp64 @gol
 -mfp32  -mfp64  -mhard-float  -msoft-float @gol
 -msingle-float  -mdouble-float  -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
@@ -11626,6 +11627,16 @@ Equivalent to @samp{-march=mips64}.
 Generate (do not generate) MIPS16 code.  If GCC is targetting a
 MIPS32 or MIPS64 architecture, it will make use of the MIPS16e ASE@.
 
+MIPS16 code generation can also be controlled on a per-function basis
+by means of @code{mips16} and @code{nomips16} attributes.  
+@xref{Function Attributes}, for more information.
+
+@item -mflip-mips16
+@opindex mflip-mips16
+Generate MIPS16 code on alternating functions.  This option is provided
+for regression testing of mixed MIPS16/non-MIPS16 code generation, and is
+not intended for ordinary use in compiling user code.
+
 @item -mabi=32
 @itemx -mabi=o64
 @itemx -mabi=n32
index c6ba699c47f0119e4d8021a74ee6de41371bbffb..e00d89c5ff2625c9c24d380182bba967ae566763 100644 (file)
@@ -1,3 +1,9 @@
+2007-09-05  Sandra Loosemore  <sandra@codesourcery.com>
+           David Ung  <davidu@mips.com>
+            Nigel Stephens <nigel@mips.com>
+
+       * gcc.target/mips/mips16-attributes.c: New.
+
 2007-09-05  Paul Thomas  <pault@gcc.gnu.org>
 
        PR fortran/31564
diff --git a/gcc/testsuite/gcc.target/mips/mips16-attributes.c b/gcc/testsuite/gcc.target/mips/mips16-attributes.c
new file mode 100644 (file)
index 0000000..dca75e5
--- /dev/null
@@ -0,0 +1,82 @@
+/* Verify that mips16 and nomips16 attributes work, checking all combinations
+   of calling a nomips16/mips16/default function from a nomips16/mips16/default
+   function.  */
+/* { dg-do run { target mipsisa*-*-elf* } } */
+
+#include <stdlib.h>
+
+#define ATTR1 __attribute__ ((nomips16))
+#define ATTR2 __attribute__ ((mips16))
+#define ATTR3
+
+double ATTR1
+f1 (int i, float f, double d)
+{
+  return i + f + d;
+}
+
+double ATTR2
+f2 (int i, float f, double d)
+{
+  return i + f + d;
+}
+
+double ATTR3
+f3 (int i, float f, double d)
+{
+  return i + f + d;
+}
+
+void ATTR1
+g1 (int i, float f, double d)
+{
+  double r = i + f + d;
+
+  if (f1 (i, f, d) != r)
+    abort ();
+  if (f2 (i+1, f+1, d+1) != r + 3)
+    abort ();
+  if (f3 (i+2, f+2, d+2) != r + 6)
+    abort ();
+}
+
+void ATTR2
+g2 (int i, float f, double d)
+{
+  double r = i + f + d;
+
+  if (f1 (i, f, d) != r)
+    abort ();
+  if (f2 (i+1, f+1, d+1) != r + 3)
+    abort ();
+  if (f3 (i+2, f+2, d+2) != r + 6)
+    abort ();
+}
+
+void ATTR3
+g3 (int i, float f, double d)
+{
+  double r = i + f + d;
+
+  if (f1 (i, f, d) != r)
+    abort ();
+  if (f2 (i+1, f+1, d+1) != r + 3)
+    abort ();
+  if (f3 (i+2, f+2, d+2) != r + 6)
+    abort ();
+}
+
+int ATTR3
+main (void)
+{
+  int i = 1;
+  float f = -2.0;
+  double d = 3.0;
+
+  g1 (i, f, d);
+  g2 (i, f, d);
+  g3 (i, f, d);
+
+  exit (0);
+}
+