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/
* 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 <[email protected]>
Signed-off-by: Faraz Shahbazker <[email protected]>
Signed-off-by: Aleksandar Rakic <[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 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
--
2.34.1