From: Matthew Fortune <[email protected]>

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/ChangeLog:

        * config/mips/mips.cc (mips_attribute_table): Add
        inline_intermix.
        (mips_func_opt_list_strings): 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.
        * config/mips/mips.opt (-minline-intermix): New option.
        * doc/extend.texi: Document inline_intermix.
        * doc/invoke.texi (gccoptlist): Add and document
        -m(no-)inline-intermix.

gcc/testsuite/ChangeLog:

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

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

Signed-off-by: Matthew Fortune <[email protected]>
Signed-off-by: Faraz Shahbazker <[email protected]>
Signed-off-by: Aleksandar Rakic <[email protected]>
Signed-off-by: Eldar Osmanovic <[email protected]>
---
 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

diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc
index ea4c6fd7690..c35cb76b61b 100644
--- a/gcc/config/mips/mips.cc
+++ b/gcc/config/mips/mips.cc
@@ -606,6 +606,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 *);
@@ -626,6 +627,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 },
@@ -769,6 +772,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},
@@ -1904,6 +1908,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.  */
 
@@ -2281,7 +2350,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 c3e7c159475..d2967aecd38 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -549,3 +549,7 @@ munique-sections=FILE   Use to specify sections that should 
be made unique.
 mfunc-opt-list=
 Target RejectNegative Joined Var(mips_func_opt_list_file) Init(0) Defer
 mfunc-opt-list=FILE    Use to specify per function optimizations.
+
+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 4761b07973a..384184060fd 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7857,6 +7857,23 @@ It 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
 @atindex @code{code_readable}, MIPS
 This attribute applies to functions.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 0289d5c5fce..72799339365 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1224,6 +1224,7 @@ Objective-C and Objective-C++ Dialects}.
 -mips32r6  -mips64  -mips64r2  -mips64r3  -mips64r5  -mips64r6
 -mips16  -mmips16e2  -mflip-mips16
 -minterlink-compressed  -minterlink-mips16
+-minline-intermix -mno-inline-intermix
 -mabi=@var{abi}  -mabicalls  -mshared  -mplt  -mxgot
 -mgp32  -mgp64  -mfp32  -mfpxx  -mfp64  -mhard-float  -msoft-float
 -mno-float  -msingle-float  -mdouble-float  -modd-spreg
@@ -29134,6 +29135,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 a0361de7429..8a5a1fa3134 100644
--- a/gcc/testsuite/gcc.target/mips/mips.exp
+++ b/gcc/testsuite/gcc.target/mips/mips.exp
@@ -286,6 +286,7 @@ foreach option {
     fix-r10000
     fix-vr4130
     gpopt
+    inline-intermix
     local-sdata
     long-calls
     lxc1-sxc1
-- 
2.43.0

Reply via email to