[22/61] Add -minline-intermix to ignore mips16/nomips16

Message ID 20250131171232.1018281-24-aleksandar.rakic@htecgroup.com
State New
Headers
Series Improve Mips target |

Commit Message

Aleksandar Rakic Jan. 31, 2025, 5:13 p.m. UTC
  From: Matthew Fortune <matthew.fortune@imgtec.com>

Add a CLI option and an inline_intermix function attribute to ignore ISA
differences between a caller and a callee. The format of this attribute
is __attribute__((inline_intermix(yes|no))).

gcc/
        * doc/extend.texi: Document inline_intermix.
        * config/mips/mips.cc (mips_attribute_table): Add
        inline_intermix.
        (mips_handle_inline_intermix_attr): New function.
        (mips_get_inline_intermix_attr): Likewise.
        (mips_can_inline_p): Use mips_get_inline_intermix_attr.

gcc/testsuite/
        * gcc.target/mips/mips.exp: Add -m[no-]inline-intermix.
        * gcc.target/mips/inline-intermix-1.c: New file.
        * gcc.target/mips/inline-intermix-2.c: Likewise.
        * gcc.target/mips/inline-intermix-3.c: Likewise.
        * gcc.target/mips/inline-intermix-4.c: Likewise.

Cherry-picked 02c76fc61198186af09fd9c4c0ef7352ab6511ad
and ae484b9431e5bd407e09b66392a1882b6878e4de
from https://github.com/MIPS/gcc

Signed-off-by: Matthew Fortune <matthew.fortune@imgtec.com>
Signed-off-by: Faraz Shahbazker <fshahbazker@wavecomp.com>
Signed-off-by: Aleksandar Rakic <aleksandar.rakic@htecgroup.com>
---
 gcc/config/mips/mips.cc                       | 72 ++++++++++++++++++-
 gcc/config/mips/mips.opt                      |  4 ++
 gcc/doc/extend.texi                           | 17 +++++
 gcc/doc/invoke.texi                           | 12 ++++
 .../gcc.target/mips/inline-intermix-1.c       | 13 ++++
 .../gcc.target/mips/inline-intermix-2.c       | 13 ++++
 .../gcc.target/mips/inline-intermix-3.c       | 13 ++++
 .../gcc.target/mips/inline-intermix-4.c       | 13 ++++
 gcc/testsuite/gcc.target/mips/mips.exp        |  1 +
 9 files changed, 157 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/mips/inline-intermix-1.c
 create mode 100644 gcc/testsuite/gcc.target/mips/inline-intermix-2.c
 create mode 100644 gcc/testsuite/gcc.target/mips/inline-intermix-3.c
 create mode 100644 gcc/testsuite/gcc.target/mips/inline-intermix-4.c
  

Patch

diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc
index 9808fda286c..e8ed002dfed 100644
--- a/gcc/config/mips/mips.cc
+++ b/gcc/config/mips/mips.cc
@@ -607,6 +607,7 @@  const enum reg_class mips_regno_to_class[FIRST_PSEUDO_REGISTER] = {
 };
 
 static tree mips_handle_code_readable_attr (tree *, tree, tree, int, bool *);
+static tree mips_handle_inline_intermix_attr (tree *, tree, tree, int, bool *);
 static tree mips_handle_interrupt_attr (tree *, tree, tree, int, bool *);
 static tree mips_handle_use_shadow_register_set_attr (tree *, tree, tree, int,
 						      bool *);
@@ -627,6 +628,8 @@  TARGET_GNU_ATTRIBUTES (mips_attribute_table, {
   { "nomips16",    0, 0, true,  false, false, false, NULL, NULL },
   { "micromips",   0, 0, true,  false, false, false, NULL, NULL },
   { "nomicromips", 0, 0, true,  false, false, false, NULL, NULL },
+  { "inline_intermix", 0, 1, true,  false, false, false,
+    mips_handle_inline_intermix_attr, NULL },
   { "nocompression", 0, 0, true,  false, false, false, NULL, NULL },
   { "code_readable", 0, 1, true,  false, false, false,
     mips_handle_code_readable_attr, NULL },
@@ -770,6 +773,7 @@  static const struct attr_desc mips_func_opt_list_strings[] = {
   {"hot",		 0,	     FOL_ARG_NONE, 1 << FOLC_COLD },
   {"cold",		 0,	     FOL_ARG_NONE, 1 << FOLC_HOT },
   {"code_readable",	 0,	     FOL_ARG_STRING, 0 },
+  {"inline_intermix",	 0,	     FOL_ARG_STRING, 0 },
   {"alias",		 0,	     FOL_ARG_STRING, 0 },
   {"aligned",		 0,	     FOL_ARG_SINGLE_NUM, 0},
   {"alloc_size",	 0,	     FOL_ARG_NUM_ONE_OR_TWO, 0},
@@ -1917,6 +1921,71 @@  mips_use_debug_exception_return_p (tree type)
 			   TYPE_ATTRIBUTES (type)) != NULL;
 }
 
+/* Verify the arguments to an inline_intermix attribute.  */
+
+static tree
+mips_handle_inline_intermix_attr (tree *node ATTRIBUTE_UNUSED, tree name,
+				  tree args, int flags ATTRIBUTE_UNUSED,
+				  bool *no_add_attrs)
+{
+  if (!is_attribute_p ("inline_intermix", name) || args == NULL)
+    return NULL_TREE;
+
+  if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
+    {
+      warning (OPT_Wattributes,
+	       "%qE attribute requires a string argument", name);
+      *no_add_attrs = true;
+    }
+  else if (strcmp (TREE_STRING_POINTER (TREE_VALUE (args)), "no") != 0
+	   && strcmp (TREE_STRING_POINTER (TREE_VALUE (args)), "yes") != 0)
+    {
+      warning (OPT_Wattributes,
+	       "argument to %qE attribute is neither no nor yes", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Determine the inline_intermix setting for a function if it has one.
+   When inline_intermix is used without an argument it is the same as
+   inline_intermix=yes.  */
+
+static bool
+mips_get_inline_intermix_attr (tree decl)
+{
+  tree attr;
+
+  if (decl == NULL)
+    return TARGET_INLINE_INTERMIX;
+
+  attr = lookup_attribute ("inline_intermix", DECL_ATTRIBUTES (decl));
+
+  if (attr != NULL)
+    {
+      if (TREE_VALUE (attr) != NULL_TREE)
+	{
+	  const char * str;
+
+	  str = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)));
+	  if (strcmp (str, "no") == 0)
+	    return false;
+	  else if (strcmp (str, "yes") == 0)
+	    return true;
+
+	  /* mips_handle_inline_intermix_attr will have verified the
+	     arguments are correct before adding the attribute.  */
+	  gcc_unreachable ();
+	}
+
+      /* No argument is the same as inline_intermix=true like the
+	 command line option -minline-intermix.  */
+      return true;
+    }
+
+  return TARGET_INLINE_INTERMIX;
+}
 
 /* Verify the arguments to a code_readable attribute.  */
 
@@ -2294,7 +2363,8 @@  mips_merge_decl_attributes (tree olddecl, tree newdecl)
 static bool
 mips_can_inline_p (tree caller, tree callee)
 {
-  if (mips_get_compress_mode (callee) != mips_get_compress_mode (caller))
+  if (mips_get_compress_mode (callee) != mips_get_compress_mode (caller)
+      && !mips_get_inline_intermix_attr (callee))
     return false;
   return default_target_can_inline_p (caller, callee);
 }
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index c5a3addbc55..222fdbfaf96 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -565,3 +565,7 @@  Target Undocumented Var(TARGET_USE_SAVE_RESTORE) Init(-1)
 
 muse-copyw-ucopyw
 Target Undocumented Var(TARGET_USE_COPYW_UCOPYW) Init(-1)
+
+minline-intermix
+Target Var(TARGET_INLINE_INTERMIX)
+Allow inlining even if the compression flags differ between caller and callee.
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index c566474074d..76ebdf97a98 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -6005,6 +6005,23 @@  This function attribute instructs the compiler to generate a hazard barrier
 return that clears all execution and instruction hazards while returning,
 instead of generating a normal return instruction.
 
+@item inline_intermix
+@cindex @code{inline_intermix} function attribute, MIPS
+On MIPS targets, you can use the @code{inline_intermix} attribute to override
+the default inlining rule that prevents functions with different ISAs being
+inlined.  This can be helpful when the ISA selection is made for performance
+or code density reasons instead of fundamental dependency on a specific ISA.
+The attribute takes a single optional argument:
+
+@table @samp
+@item no
+The function must not be inlined into a function with a different ISA.
+@item yes
+The function can be inlined into a function with a different ISA.
+@end table
+
+If there is no argument supplied, the default of @code{"yes"} applies.
+
 @item code_readable
 @cindex @code{code_readable} function attribute, MIPS
 For MIPS targets that support PC-relative addressing modes, this attribute
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index d607f8e430c..3560a7920a7 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1125,6 +1125,7 @@  Objective-C and Objective-C++ Dialects}.
 -mips16  -mno-mips16  -mflip-mips16
 -minterlink-compressed  -mno-interlink-compressed
 -minterlink-mips16  -mno-interlink-mips16
+-minline-intermix -mno-inline-intermix
 -mabi=@var{abi}  -mabicalls  -mno-abicalls
 -mshared  -mno-shared  -mplt  -mno-plt  -mxgot  -mno-xgot
 -mgp32  -mgp64  -mfp32  -mfpxx  -mfp64  -mhard-float  -msoft-float
@@ -28363,6 +28364,17 @@  Aliases of @option{-minterlink-compressed} and
 @option{-mno-interlink-compressed}.  These options predate the microMIPS ASE
 and are retained for backwards compatibility.
 
+@opindex minline-intermix
+@opindex mno-inline-intermix
+@item -minline-intermix
+@itemx -mno-inline-intermix
+Enable inlining of functions which have opposing mips16/nomips16 attributes.
+This is useful when using the mips16 attribute to balance code size and
+performance so that a function will be compressed when not inlined or
+vice-versa.  When using this option it is necessary to protect functions
+that cannot be compiled as MIPS16 with a noinline attribute to ensure
+they are not inlined into a MIPS16 function.
+
 @opindex mabi
 @item -mabi=32
 @itemx -mabi=o64
diff --git a/gcc/testsuite/gcc.target/mips/inline-intermix-1.c b/gcc/testsuite/gcc.target/mips/inline-intermix-1.c
new file mode 100644
index 00000000000..f4e0c7ffa1f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/inline-intermix-1.c
@@ -0,0 +1,13 @@ 
+/* { dg-options "-mips16 -mabi=32" } */
+
+__attribute__((nomips16, always_inline))
+inline int foo() /* { dg-error "target specific option mismatch" } */
+{
+  return 1;
+}
+
+int bar()
+{
+  return foo();
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/inline-intermix-2.c b/gcc/testsuite/gcc.target/mips/inline-intermix-2.c
new file mode 100644
index 00000000000..c0b0102941d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/inline-intermix-2.c
@@ -0,0 +1,13 @@ 
+/* { dg-options "-mips16 -mabi=32" } */
+
+__attribute__((nomips16, always_inline, inline_intermix))
+inline int foo()
+{
+  return 1;
+}
+
+int bar()
+{
+  return foo();
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/inline-intermix-3.c b/gcc/testsuite/gcc.target/mips/inline-intermix-3.c
new file mode 100644
index 00000000000..bc947315fb8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/inline-intermix-3.c
@@ -0,0 +1,13 @@ 
+/* { dg-options "-mips16 -mabi=32 -minline-intermix" } */
+
+__attribute__((nomips16, always_inline))
+inline int foo()
+{
+  return 1;
+}
+
+int bar()
+{
+  return foo();
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/inline-intermix-4.c b/gcc/testsuite/gcc.target/mips/inline-intermix-4.c
new file mode 100644
index 00000000000..8c58284b477
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/inline-intermix-4.c
@@ -0,0 +1,13 @@ 
+/* { dg-options "-mips16 -mabi=32 -minline-intermix" } */
+
+__attribute__((nomips16, always_inline, inline_intermix("no")))
+inline int foo() /* { dg-error "target specific option mismatch" } */
+{
+  return 1;
+}
+
+int bar()
+{
+  return foo();
+}
+
diff --git a/gcc/testsuite/gcc.target/mips/mips.exp b/gcc/testsuite/gcc.target/mips/mips.exp
index 3907fe2a778..dade793b306 100644
--- a/gcc/testsuite/gcc.target/mips/mips.exp
+++ b/gcc/testsuite/gcc.target/mips/mips.exp
@@ -285,6 +285,7 @@  foreach option {
     fix-r10000
     fix-vr4130
     gpopt
+    inline-intermix
     local-sdata
     long-calls
     lxc1-sxc1