From 9a6dfb473994b6bfb33bfb7d0c8c3a6a5775ca34 Mon Sep 17 00:00:00 2001
From: Richard Sandiford <richard@codesourcery.com>
Date: Thu, 13 Sep 2007 12:44:10 +0000
Subject: [PATCH] mips.h (SYMBOL_FLAG_MIPS16_FUNC): Delete.

gcc/
2007-09-13  Richard Sandiford  <richard@codesourcery.com>
	    Sandra Loosemore <sandra@codesourcery.com>

	* config/mips/mips.h (SYMBOL_FLAG_MIPS16_FUNC): Delete.
	(SYMBOL_REF_MIPS16_FUNC_P): Delete.
	* config/mips/mips.c (mips_attribute_table): Turn mips16 and
	nomips16 into decl attributes.
	(TARGET_INSERT_ATTRIBUTES): Override.
	(TARGET_MERGE_DECL_ATTRIBUTES): Likewise.
	(TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P): Always return true.
	(mips_mips16_type_p, mips_nomips16_type_p): Delete in favor of...
	(mips_mips16_decl_p, mips_nomips16_decl_p): ...these new functions.
	(mips_comp_type_attributes): Remove mips16 and nomips16 handling.
	(mips_use_mips16_mode_p): Reimplement as a function that takes
	a decl and considers only decl attributes.  If the decl is nested
	function, use its parent attributes.
	(mips_function_ok_for_sibcall): Use mips_use_mips16_mode_p
	instead of SYMBOL_REF_MIPS16_FUNC_P.
	(mips_set_mips16_mode): Move call to sorry here from old
	mips_use_mips16_mode_p.
	(mflip_mips16_entry): New structure.
	(mflip_mips16_htab): New variable.
	(mflip_mips16_htab_hash, mflip_mips16_htab_eq): New functions.
	(mflip_mips16_use_mips16_p, mips_insert_attributes): Likewise.
	(mips_merge_decl_attributes): New function.
	(mips_set_current_function): Reinstate call to mips_set_mips16_mode.
	Use mips_use_mips16_mode_p.
	(mips_output_mi_thunk): Use mips_use_mips16_mode_p instead of
	SYMBOL_REF_MIPS16_FUNC_P.
	(mips_encode_section_info): Don't set SYMBOL_FLAG_MIPS16_FUNC.

gcc/testsuite/
	* gcc.dg/gcc-have-sync-compare-and-swap.c: Skip for -mflip-mips16.
	* gcc.target/mips/mips16-attributes-2.c: New test.
	* gcc.target/mips/mips16-attributes-3.c: Likewise.
	* gcc.target/mips/args-3.c: Skip for -mflip-mips16.  Do not use the
	hard-float asm when __mips16 is defined.
	* gcc.target/mips/atomic-memory-1.c (main): Add a nomips16 attribute.
	* gcc.target/mips/atomic-memory-2.c (main): Likewise.
	* gcc.target/mips/fpcmp-1.c (f1, f2): Likewise.
	* gcc.target/mips/fpcmp-2.c (f1, f2): Likewise.
	* gcc.target/mips/neg-abs-1.c (f1, f2, d1, f2): Likewise.
	* gcc.target/mips/pr26765.c (foo): Likewise.
	* gcc.target/mips/gcc-have-sync-compare-and-swap-1.c: Run for all
	targets, use dg-mips-options instead of dg-options, and use -mgp32
	to force 32-bit mode.
	* gcc.target/mips/gcc-have-sync-compare-and-swap-2.c: Likewise -mgp64
	and 64-bit mode.
	* gcc.target/mips/mips.exp (is_gp32_flag): Return true for -mips32*.

Co-Authored-By: Sandra Loosemore <sandra@codesourcery.com>

From-SVN: r128460
---
 gcc/ChangeLog                                 |  31 +++
 gcc/config/mips/mips.c                        | 226 +++++++++++++-----
 gcc/config/mips/mips.h                        |   5 -
 gcc/testsuite/ChangeLog                       |  20 ++
 .../gcc.dg/gcc-have-sync-compare-and-swap.c   |   4 +
 gcc/testsuite/gcc.target/mips/args-3.c        |   3 +-
 .../gcc.target/mips/atomic-memory-1.c         |   4 +-
 .../gcc.target/mips/atomic-memory-2.c         |   4 +-
 gcc/testsuite/gcc.target/mips/fpcmp-1.c       |   6 +-
 gcc/testsuite/gcc.target/mips/fpcmp-2.c       |   6 +-
 .../mips/gcc-have-sync-compare-and-swap-1.c   |   2 +-
 .../mips/gcc-have-sync-compare-and-swap-2.c   |   4 +-
 gcc/testsuite/gcc.target/mips/mips.exp        |   1 +
 .../gcc.target/mips/mips16-attributes-2.c     |  15 ++
 .../gcc.target/mips/mips16-attributes-3.c     |   6 +
 gcc/testsuite/gcc.target/mips/neg-abs-1.c     |  10 +-
 gcc/testsuite/gcc.target/mips/pr26765.c       |   4 +-
 17 files changed, 271 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/mips/mips16-attributes-2.c
 create mode 100644 gcc/testsuite/gcc.target/mips/mips16-attributes-3.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c9facbd57bbe..cad07c673751 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,34 @@
+2007-09-13  Richard Sandiford  <richard@codesourcery.com>
+	    Sandra Loosemore <sandra@codesourcery.com>
+
+	* config/mips/mips.h (SYMBOL_FLAG_MIPS16_FUNC): Delete.
+	(SYMBOL_REF_MIPS16_FUNC_P): Delete.
+	* config/mips/mips.c (mips_attribute_table): Turn mips16 and
+	nomips16 into decl attributes.
+	(TARGET_INSERT_ATTRIBUTES): Override.
+	(TARGET_MERGE_DECL_ATTRIBUTES): Likewise.
+	(TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P): Always return true.
+	(mips_mips16_type_p, mips_nomips16_type_p): Delete in favor of...
+	(mips_mips16_decl_p, mips_nomips16_decl_p): ...these new functions.
+	(mips_comp_type_attributes): Remove mips16 and nomips16 handling.
+	(mips_use_mips16_mode_p): Reimplement as a function that takes
+	a decl and considers only decl attributes.  If the decl is nested
+	function, use its parent attributes.
+	(mips_function_ok_for_sibcall): Use mips_use_mips16_mode_p
+	instead of SYMBOL_REF_MIPS16_FUNC_P.
+	(mips_set_mips16_mode): Move call to sorry here from old
+	mips_use_mips16_mode_p.
+	(mflip_mips16_entry): New structure.
+	(mflip_mips16_htab): New variable.
+	(mflip_mips16_htab_hash, mflip_mips16_htab_eq): New functions.
+	(mflip_mips16_use_mips16_p, mips_insert_attributes): Likewise.
+	(mips_merge_decl_attributes): New function.
+	(mips_set_current_function): Reinstate call to mips_set_mips16_mode.
+	Use mips_use_mips16_mode_p.
+	(mips_output_mi_thunk): Use mips_use_mips16_mode_p instead of
+	SYMBOL_REF_MIPS16_FUNC_P.
+	(mips_encode_section_info): Don't set SYMBOL_FLAG_MIPS16_FUNC.
+
 2007-09-13  Richard Sandiford  <richard@codesourcery.com>
 
 	* c-parser.c (c_parser_struct_declaration): Check for a null return.
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 1a2cc0699db8..410f7d7a7c75 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -426,6 +426,8 @@ 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_insert_attributes (tree, tree *);
+static tree mips_merge_decl_attributes (tree, tree);
 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);
@@ -734,9 +736,13 @@ 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 },
+  /* Switch MIPS16 ASE on and off per-function.  We would really like
+     to make these type attributes, but GCC doesn't provide the hooks
+     we need to support the right conversion rules.  As declaration
+     attributes, they affect code generation but don't carry other
+     semantics.  */
+  { "mips16", 	   0, 0, true,  false, false, NULL },
+  { "nomips16",    0, 0, true,  false, false, NULL },
   { NULL,	   0, 0, false, false, false, NULL }
 };
 
@@ -1268,6 +1274,10 @@ 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_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES mips_insert_attributes
+#undef TARGET_MERGE_DECL_ATTRIBUTES
+#define TARGET_MERGE_DECL_ATTRIBUTES mips_merge_decl_attributes
 #undef TARGET_SET_CURRENT_FUNCTION
 #define TARGET_SET_CURRENT_FUNCTION mips_set_current_function
 
@@ -1352,6 +1362,10 @@ static const unsigned char mips16e_save_restore_regs[] = {
 
 #undef TARGET_ATTRIBUTE_TABLE
 #define TARGET_ATTRIBUTE_TABLE mips_attribute_table
+/* All our function attributes are related to how out-of-line copies should
+   be compiled or called.  They don't in themselves prevent inlining.  */
+#undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P
+#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P hook_bool_const_tree_true
 
 #undef TARGET_EXTRA_LIVE_ON_ENTRY
 #define TARGET_EXTRA_LIVE_ON_ENTRY mips_extra_live_on_entry
@@ -1395,15 +1409,15 @@ mips_far_type_p (const_tree type)
 /* Similar predicates for "mips16"/"nomips16" attributes.  */
 
 static bool
-mips_mips16_type_p (const_tree type)
+mips_mips16_decl_p (const_tree decl)
 {
-  return lookup_attribute ("mips16", TYPE_ATTRIBUTES (type)) != NULL;
+  return lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL;
 }
 
 static bool
-mips_nomips16_type_p (const_tree type)
+mips_nomips16_decl_p (const_tree decl)
 {
-  return lookup_attribute ("nomips16", TYPE_ATTRIBUTES (type)) != NULL;
+  return lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL;
 }
 
 /* Return 0 if the attributes for two types are incompatible, 1 if they
@@ -1423,11 +1437,6 @@ 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;
 }
 
@@ -4120,6 +4129,27 @@ mips_gen_conditional_trap (rtx *operands)
 			      operands[1]));
 }
 
+/* Return true if function DECL is a MIPS16 function.  Return the ambient
+   setting if DECL is null.  */
+
+static bool
+mips_use_mips16_mode_p (tree decl)
+{
+  if (decl)
+    {
+      /* Nested functions must use the same frame pointer as their
+	 parent and must therefore use the same ISA mode.  */
+      tree parent = decl_function_context (decl);
+      if (parent)
+	decl = parent;
+      if (mips_mips16_decl_p (decl))
+	return true;
+      if (mips_nomips16_decl_p (decl))
+	return false;
+    }
+  return mips_base_mips16;
+}
+
 /* Return true if calls to X can use R_MIPS_CALL* relocations.  */
 
 static bool
@@ -4223,7 +4253,7 @@ mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
   /* 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)))
+  if (mips_use_mips16_mode_p (decl))
     return false;
 
   /* Otherwise OK.  */
@@ -5666,6 +5696,9 @@ mips_set_mips16_mode (int mips16_p)
 	 of lw and sw instead.  */
       targetm.min_anchor_offset = 0;
       targetm.max_anchor_offset = 127;
+
+      if (flag_pic || TARGET_ABICALLS)
+	sorry ("MIPS16 PIC");
     }
   else 
     {
@@ -5703,12 +5736,130 @@ mips_set_mips16_mode (int mips16_p)
   was_mips16_p = TARGET_MIPS16;
 }
 
+/* Use a hash table to keep track of implicit mips16/nomips16 attributes
+   for -mflip_mips16.  It maps decl names onto a boolean mode setting.  */
+
+struct mflip_mips16_entry GTY (()) {
+  const char *name;
+  bool mips16_p;
+};
+static GTY ((param_is (struct mflip_mips16_entry))) htab_t mflip_mips16_htab;
+
+/* Hash table callbacks for mflip_mips16_htab.  */
+
+static hashval_t
+mflip_mips16_htab_hash (const void *entry)
+{
+  return htab_hash_string (((const struct mflip_mips16_entry *) entry)->name);
+}
+
+static int
+mflip_mips16_htab_eq (const void *entry, const void *name)
+{
+  return strcmp (((const struct mflip_mips16_entry *) entry)->name,
+		 (const char *) name) == 0;
+}
+
+/* DECL is a function that needs a default "mips16" or "nomips16" attribute
+   for -mflip-mips16.  Return true if it should use "mips16" and false if
+   it should use "nomips16".  */
+
+static bool
+mflip_mips16_use_mips16_p (tree decl)
+{
+  struct mflip_mips16_entry *entry;
+  const char *name;
+  hashval_t hash;
+  void **slot;
+
+  /* Use the opposite of the command-line setting for anonymous decls.  */
+  if (!DECL_NAME (decl))
+    return !mips_base_mips16;
+
+  if (!mflip_mips16_htab)
+    mflip_mips16_htab = htab_create_ggc (37, mflip_mips16_htab_hash,
+					 mflip_mips16_htab_eq, NULL);
+
+  name = IDENTIFIER_POINTER (DECL_NAME (decl));
+  hash = htab_hash_string (name);
+  slot = htab_find_slot_with_hash (mflip_mips16_htab, name, hash, INSERT);
+  entry = (struct mflip_mips16_entry *) *slot;
+  if (!entry)
+    {
+      mips16_flipper = !mips16_flipper;
+      entry = GGC_NEW (struct mflip_mips16_entry);
+      entry->name = name;
+      entry->mips16_p = mips16_flipper ? !mips_base_mips16 : mips_base_mips16;
+      *slot = entry;
+    }
+  return entry->mips16_p;
+}
+
+/* Implement TARGET_INSERT_ATTRIBUTES.  */
+
+static void
+mips_insert_attributes (tree decl, tree *attributes)
+{
+  const char *name;
+  bool mips16_p, nomips16_p;
+
+  /* Check for "mips16" and "nomips16" attributes.  */
+  mips16_p = lookup_attribute ("mips16", *attributes) != NULL;
+  nomips16_p = lookup_attribute ("nomips16", *attributes) != NULL;
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    {
+      if (mips16_p)
+	error ("%qs attribute only applies to functions", "mips16");
+      if (nomips16_p)
+	error ("%qs attribute only applies to functions", "nomips16");
+    }
+  else
+    {
+      mips16_p |= mips_mips16_decl_p (decl);
+      nomips16_p |= mips_nomips16_decl_p (decl);
+      if (mips16_p || nomips16_p)
+	{
+	  /* DECL cannot be simultaneously mips16 and nomips16.  */
+	  if (mips16_p && nomips16_p)
+	    error ("%qs cannot have both %<mips16%> and "
+		   "%<nomips16%> attributes",
+		   IDENTIFIER_POINTER (DECL_NAME (decl)));
+	}
+      else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
+	{
+	  /* Implement -mflip-mips16.  If DECL has neither a "nomips16" nor a
+	     "mips16" attribute, arbitrarily pick one.  We must pick the same
+	     setting for duplicate declarations of a function.  */
+	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
+	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
+	}
+    }
+}
+
+/* Implement TARGET_MERGE_DECL_ATTRIBUTES.  */
+
+static tree
+mips_merge_decl_attributes (tree olddecl, tree newdecl)
+{
+  /* The decls' "mips16" and "nomips16" attributes must match exactly.  */
+  if (mips_mips16_decl_p (olddecl) != mips_mips16_decl_p (newdecl))
+    error ("%qs redeclared with conflicting %qs attributes",
+	   IDENTIFIER_POINTER (DECL_NAME (newdecl)), "mips16");
+  if (mips_nomips16_decl_p (olddecl) != mips_nomips16_decl_p (newdecl))
+    error ("%qs redeclared with conflicting %qs attributes",
+	   IDENTIFIER_POINTER (DECL_NAME (newdecl)), "nomips16");
+
+  return merge_attributes (DECL_ATTRIBUTES (olddecl),
+			   DECL_ATTRIBUTES (newdecl));
+}
+
 /* 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 ATTRIBUTE_UNUSED)
+mips_set_current_function (tree fndecl)
 {
+  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
 }
 
 /* Implement TARGET_HANDLE_OPTION.  */
@@ -8783,7 +8934,7 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
      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)
-      || SYMBOL_REF_MIPS16_FUNC_P (fnaddr))
+      || mips_use_mips16_mode_p (function))
     {
       /* This is messy.  gas treats "la $25,foo" as part of a call
 	 sequence and may allow a global "foo" to be lazily bound.
@@ -12724,43 +12875,6 @@ mips_expand_builtin_bposge (enum mips_builtin_type builtin_type, rtx target)
 				       const1_rtx, const0_rtx);
 }
 
-/* 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.  */
 
@@ -12777,14 +12891,6 @@ mips_encode_section_info (tree decl, rtx rtl, int first)
       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;
-	}
     }
 }
 
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 7aa6aa83338d..c9d2742860fc 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -2338,11 +2338,6 @@ 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,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 35894f0de320..34af18c43b8b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,23 @@
+2007-09-13  Richard Sandiford  <richard@codesourcery.com>
+
+	* gcc.dg/gcc-have-sync-compare-and-swap.c: Skip for -mflip-mips16.
+	* gcc.target/mips/mips16-attributes-2.c: New test.
+	* gcc.target/mips/mips16-attributes-3.c: Likewise.
+	* gcc.target/mips/args-3.c: Skip for -mflip-mips16.  Do not use the
+	hard-float asm when __mips16 is defined.
+	* gcc.target/mips/atomic-memory-1.c (main): Add a nomips16 attribute.
+	* gcc.target/mips/atomic-memory-2.c (main): Likewise.
+	* gcc.target/mips/fpcmp-1.c (f1, f2): Likewise.
+	* gcc.target/mips/fpcmp-2.c (f1, f2): Likewise.
+	* gcc.target/mips/neg-abs-1.c (f1, f2, d1, f2): Likewise.
+	* gcc.target/mips/pr26765.c (foo): Likewise.
+	* gcc.target/mips/gcc-have-sync-compare-and-swap-1.c: Run for all
+	targets, use dg-mips-options instead of dg-options, and use -mgp32
+	to force 32-bit mode.
+	* gcc.target/mips/gcc-have-sync-compare-and-swap-2.c: Likewise -mgp64
+	and 64-bit mode.
+	* gcc.target/mips/mips.exp (is_gp32_flag): Return true for -mips32*.
+
 2007-09-12  Dwarakanath Rajagopal  <dwarak.rajagopal@amd.com>
 	    Michael Meissner  <michael.meissner@amd.com>
 
diff --git a/gcc/testsuite/gcc.dg/gcc-have-sync-compare-and-swap.c b/gcc/testsuite/gcc.dg/gcc-have-sync-compare-and-swap.c
index 89527f6c3612..faed818d5005 100644
--- a/gcc/testsuite/gcc.dg/gcc-have-sync-compare-and-swap.c
+++ b/gcc/testsuite/gcc.dg/gcc-have-sync-compare-and-swap.c
@@ -1,4 +1,8 @@
 /* { dg-do link } */
+/* MIPS only supports these built-in functions for non-MIPS16 mode, and
+   -mflip-mips16 will change the mode of some functions to be different
+   from the command-line setting.  */
+/* { dg-skip-if "" { mips*-*-* } { "-mflip-mips16" } { "" } } */
 
 void f1()
 {
diff --git a/gcc/testsuite/gcc.target/mips/args-3.c b/gcc/testsuite/gcc.target/mips/args-3.c
index e91816f08066..6a79ce6745ea 100644
--- a/gcc/testsuite/gcc.target/mips/args-3.c
+++ b/gcc/testsuite/gcc.target/mips/args-3.c
@@ -1,6 +1,7 @@
 /* __mips, and related defines, guarantee that certain assembly
    instructions can be used.  Check a few examples.  */
 /* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-mflip-mips16" } { "" } } */
 extern void abort (void);
 extern void exit (int);
 
@@ -11,7 +12,7 @@ int foo (float inf, int64 in64, int32 in32)
   int64 res64;
   int32 res32;
 
-#if __mips != 1 && defined (__mips_hard_float)
+#if __mips != 1 && defined (__mips_hard_float) && !defined (__mips16)
   __asm__ ("trunc.w.s %0, %1" : "=f" (res32) : "f" (inf));
   if (res32 != 11)
     abort ();
diff --git a/gcc/testsuite/gcc.target/mips/atomic-memory-1.c b/gcc/testsuite/gcc.target/mips/atomic-memory-1.c
index 1664daa3d71d..b44bd46cf7ee 100644
--- a/gcc/testsuite/gcc.target/mips/atomic-memory-1.c
+++ b/gcc/testsuite/gcc.target/mips/atomic-memory-1.c
@@ -2,7 +2,9 @@
 extern void abort (void);
 extern void exit (int);
 
-int main ()
+#define NOMIPS16 __attribute__ ((nomips16))
+
+NOMIPS16 int main ()
 {
 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
   unsigned v = 0;
diff --git a/gcc/testsuite/gcc.target/mips/atomic-memory-2.c b/gcc/testsuite/gcc.target/mips/atomic-memory-2.c
index b0492be84a03..18ec64d004ad 100644
--- a/gcc/testsuite/gcc.target/mips/atomic-memory-2.c
+++ b/gcc/testsuite/gcc.target/mips/atomic-memory-2.c
@@ -3,7 +3,9 @@
 /* { dg-final { scan-assembler "addiu" } } */
 /* { dg-final { scan-assembler-not "subu" } } */
 
-unsigned long
+#define NOMIPS16 __attribute__ ((nomips16))
+
+NOMIPS16 unsigned long
 f(unsigned long *p)
 {
     return __sync_fetch_and_sub (p, 5);
diff --git a/gcc/testsuite/gcc.target/mips/fpcmp-1.c b/gcc/testsuite/gcc.target/mips/fpcmp-1.c
index 144a6d1c186d..e3206a589a51 100644
--- a/gcc/testsuite/gcc.target/mips/fpcmp-1.c
+++ b/gcc/testsuite/gcc.target/mips/fpcmp-1.c
@@ -1,6 +1,8 @@
 /* We used to use c.lt.fmt instead of c.ule.fmt here.  */
 /* { dg-mips-options "-mhard-float -O2" } */
-int f1 (float x, float y) { return __builtin_isless (x, y); }
-int f2 (double x, double y) { return __builtin_isless (x, y); }
+#define NOMIPS16 __attribute__ ((nomips16))
+
+NOMIPS16 int f1 (float x, float y) { return __builtin_isless (x, y); }
+NOMIPS16 int f2 (double x, double y) { return __builtin_isless (x, y); }
 /* { dg-final { scan-assembler "c\\.ule\\.s" } } */
 /* { dg-final { scan-assembler "c\\.ule\\.d" } } */
diff --git a/gcc/testsuite/gcc.target/mips/fpcmp-2.c b/gcc/testsuite/gcc.target/mips/fpcmp-2.c
index 4a9bbaad7c25..9f89417668fb 100644
--- a/gcc/testsuite/gcc.target/mips/fpcmp-2.c
+++ b/gcc/testsuite/gcc.target/mips/fpcmp-2.c
@@ -1,6 +1,8 @@
 /* We used to use c.le.fmt instead of c.ult.fmt here.  */
 /* { dg-mips-options "-mhard-float -O2" } */
-int f1 (float x, float y) { return __builtin_islessequal (x, y); }
-int f2 (double x, double y) { return __builtin_islessequal (x, y); }
+#define NOMIPS16 __attribute__ ((nomips16))
+
+NOMIPS16 int f1 (float x, float y) { return __builtin_islessequal (x, y); }
+NOMIPS16 int f2 (double x, double y) { return __builtin_islessequal (x, y); }
 /* { dg-final { scan-assembler "c\\.ult\\.s" } } */
 /* { dg-final { scan-assembler "c\\.ult\\.d" } } */
diff --git a/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c b/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c
index 315aa464e6e2..b1c524bcb868 100644
--- a/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c
+++ b/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c
@@ -1,5 +1,5 @@
 /* { dg-do preprocess } */
-/* { dg-options "-mips32 -mabi=32" } */
+/* { dg-mips-options "-mips2" } */
 
 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
 #error nonono
diff --git a/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c b/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c
index f07ebe7ebbd4..25cd6732e08a 100644
--- a/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c
+++ b/gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c
@@ -1,5 +1,5 @@
-/* { dg-do preprocess { target { mips64*-*-* } } } */
-/* { dg-options "-mips64 -mabi=64" } */
+/* { dg-do preprocess } */
+/* { dg-mips-options "-mgp64" } */
 
 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
 #error nonono
diff --git a/gcc/testsuite/gcc.target/mips/mips.exp b/gcc/testsuite/gcc.target/mips/mips.exp
index c88edc0a5070..3e10eba12a3c 100644
--- a/gcc/testsuite/gcc.target/mips/mips.exp
+++ b/gcc/testsuite/gcc.target/mips/mips.exp
@@ -103,6 +103,7 @@ proc is_gp32_flag {flag} {
     switch -glob -- $flag {
 	-msmartmips -
 	-mips[12] -
+	-mips32* -
 	-march=mips32* -
 	-mgp32 { return 1 }
 	default { return 0 }
diff --git a/gcc/testsuite/gcc.target/mips/mips16-attributes-2.c b/gcc/testsuite/gcc.target/mips/mips16-attributes-2.c
new file mode 100644
index 000000000000..eeadf8129b8b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/mips16-attributes-2.c
@@ -0,0 +1,15 @@
+/* { dg-skip-if "" { *-*-* } { "-mflip-mips16" } { "" } } */
+
+void f1 (void);
+void __attribute__((mips16)) f1 (void) {} /* { dg-error "conflicting" } */
+
+void __attribute__((mips16)) f2 (void);
+void f2 (void) {} /* { dg-error "conflicting" } */
+
+void f3 (void);
+void __attribute__((nomips16)) f3 (void) {} /* { dg-error "conflicting" } */
+
+void __attribute__((nomips16)) f4 (void);
+void f4 (void) {} /* { dg-error "conflicting" } */
+
+void __attribute__((mips16, nomips16)) f5 (void) {} /* { dg-error "cannot have both" } */
diff --git a/gcc/testsuite/gcc.target/mips/mips16-attributes-3.c b/gcc/testsuite/gcc.target/mips/mips16-attributes-3.c
new file mode 100644
index 000000000000..3b4e10777a42
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/mips16-attributes-3.c
@@ -0,0 +1,6 @@
+/* We should be able to assign mips16 and nomips16 functions to a pointer.  */
+void __attribute__((mips16)) f1 (void);
+void (*ptr1) (void) = f1;
+
+void __attribute__((nomips16)) f2 (void);
+void (*ptr2) (void) = f2;
diff --git a/gcc/testsuite/gcc.target/mips/neg-abs-1.c b/gcc/testsuite/gcc.target/mips/neg-abs-1.c
index 038b8983cb74..6c1d1baae567 100644
--- a/gcc/testsuite/gcc.target/mips/neg-abs-1.c
+++ b/gcc/testsuite/gcc.target/mips/neg-abs-1.c
@@ -7,7 +7,9 @@
 /* { dg-final { scan-assembler "abs.s" } } */
 /* { dg-final { scan-assembler "abs.d" } } */
 
-float f1 (float f) { return -f; }
-float f2 (float f) { return __builtin_fabsf (f); }
-double d1 (double d) { return -d; }
-double d2 (double d) { return __builtin_fabs (d); }
+#define NOMIPS16 __attribute__ ((nomips16))
+
+NOMIPS16 float f1 (float f) { return -f; }
+NOMIPS16 float f2 (float f) { return __builtin_fabsf (f); }
+NOMIPS16 double d1 (double d) { return -d; }
+NOMIPS16 double d2 (double d) { return __builtin_fabs (d); }
diff --git a/gcc/testsuite/gcc.target/mips/pr26765.c b/gcc/testsuite/gcc.target/mips/pr26765.c
index 6c4fbc493143..cd1d9fe8badd 100644
--- a/gcc/testsuite/gcc.target/mips/pr26765.c
+++ b/gcc/testsuite/gcc.target/mips/pr26765.c
@@ -6,7 +6,9 @@
 
 __thread int *a = 0;
 
-void foo (void)
+#define NOMIPS16 __attribute__ ((nomips16))
+
+NOMIPS16 void foo (void)
 {
   extern int *b;
   b = (int *) ((*a));
-- 
GitLab