@@ -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);
}
@@ -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.
@@ -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
@@ -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
new file mode 100644
@@ -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();
+}
+
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-options "-mips16 -mabi=32" } */
+
+__attribute__((nomips16, always_inline, inline_intermix))
+inline int foo()
+{
+ return 1;
+}
+
+int bar()
+{
+ return foo();
+}
+
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-options "-mips16 -mabi=32 -minline-intermix" } */
+
+__attribute__((nomips16, always_inline))
+inline int foo()
+{
+ return 1;
+}
+
+int bar()
+{
+ return foo();
+}
+
new file mode 100644
@@ -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();
+}
+
@@ -285,6 +285,7 @@ foreach option {
fix-r10000
fix-vr4130
gpopt
+ inline-intermix
local-sdata
long-calls
lxc1-sxc1