===================================================================
@@ -1530,6 +1530,8 @@ mips16_local_function_p (const_rtx x)
return (GET_CODE (x) == SYMBOL_REF
&& SYMBOL_REF_LOCAL_P (x)
&& !SYMBOL_REF_EXTERNAL_P (x)
+ && !SYMBOL_REF_WEAK (x)
+ && !DECL_ONE_ONLY (SYMBOL_REF_DECL (x))
&& mips_use_mips16_mode_p (SYMBOL_REF_DECL (x)));
}
@@ -6063,7 +6065,8 @@ mips16_local_alias (rtx func)
__fn_local_* is based on the __fn_stub_* names that we've
traditionally used for the non-MIPS16 stub. */
func_name = targetm.strip_name_encoding (XSTR (func, 0));
- local_name = ACONCAT (("__fn_local_", func_name, NULL));
+ local_name = ACONCAT ((LOCAL_LABEL_PREFIX, "__fn_local_", func_name,
+ NULL));
local = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (local_name));
SYMBOL_REF_FLAGS (local) = SYMBOL_REF_FLAGS (func) | SYMBOL_FLAG_LOCAL;
@@ -6190,20 +6193,15 @@ mips_output_args_xfer (int fp_code, char
into the general registers and then jumps to the MIPS16 code. */
static void
-mips16_build_function_stub (void)
+mips16_build_function_stub (rtx symbol, const char *fnname,
+ rtx alias)
{
- const char *fnname, *alias_name, *separator;
+ const char *separator;
char *secname, *stubname;
tree stubdecl;
unsigned int f;
- rtx symbol, alias;
-
- /* Create the name of the stub, and its unique section. */
- symbol = XEXP (DECL_RTL (current_function_decl), 0);
- alias = mips16_local_alias (symbol);
- fnname = targetm.strip_name_encoding (XSTR (symbol, 0));
- alias_name = targetm.strip_name_encoding (XSTR (alias, 0));
+ /* Create the name of the unique section for the stub. */
secname = ACONCAT ((".mips16.fn.", fnname, NULL));
stubname = ACONCAT (("__fn_stub_", fnname, NULL));
@@ -6215,6 +6213,12 @@ mips16_build_function_stub (void)
DECL_RESULT (stubdecl) = build_decl (BUILTINS_LOCATION,
RESULT_DECL, NULL_TREE, void_type_node);
+ /* If the original function should occur only once in the final
+ binary (e.g. it's in a COMDAT group), the same should be true of
+ the stub. */
+ if (DECL_ONE_ONLY (current_function_decl))
+ make_decl_one_only (stubdecl, DECL_ASSEMBLER_NAME (current_function_decl));
+
/* Output a comment. */
fprintf (asm_out_file, "\t# Stub function for %s (",
current_function_name ());
@@ -6265,6 +6269,25 @@ mips16_build_function_stub (void)
mips_end_function_definition (stubname);
+ switch_to_section (function_section (current_function_decl));
+}
+
+static void
+mips16_build_function_stub_and_local_alias (bool need_stub)
+{
+ const char *fnname, *alias_name;
+ rtx symbol, alias;
+
+ /* Determine the name of the alias. */
+ symbol = XEXP (DECL_RTL (current_function_decl), 0);
+ alias = mips16_local_alias (symbol);
+ fnname = targetm.strip_name_encoding (XSTR (symbol, 0));
+ alias_name = targetm.strip_name_encoding (XSTR (alias, 0));
+
+ /* Build the stub, if necessary. */
+ if (need_stub)
+ mips16_build_function_stub (symbol, fnname, alias);
+
/* If the linker needs to create a dynamic symbol for the target
function, it will associate the symbol with the stub (which,
unlike the target function, follows the proper calling conventions).
@@ -6273,8 +6296,6 @@ mips16_build_function_stub (void)
this symbol can also be used for indirect MIPS16 references from
within this file. */
ASM_OUTPUT_DEF (asm_out_file, alias_name, fnname);
-
- switch_to_section (function_section (current_function_decl));
}
/* The current function is a MIPS16 function that returns a value in an FPR.
@@ -6388,8 +6409,11 @@ mips16_build_call_stub (rtx retval, rtx
bool lazy_p;
/* If this is a locally-defined and locally-binding function,
- avoid the stub by calling the local alias directly. */
- if (mips16_local_function_p (fn))
+ avoid the stub by calling the local alias directly.
+ Functions that return floating-point values but do not take
+ floating-point arguments do not have a local alias, so we
+ cannot take this short-cut in that case. */
+ if (fp_code && mips16_local_function_p (fn))
{
*fn_ptr = mips16_local_alias (fn);
return NULL_RTX;
@@ -6445,7 +6469,7 @@ mips16_build_call_stub (rtx retval, rtx
{
const char *separator;
char *secname, *stubname;
- tree stubid, stubdecl;
+ tree stubid, stubdecl, targetdecl;
unsigned int f;
/* If the function does not return in FPRs, the special stub
@@ -6470,6 +6494,14 @@ mips16_build_call_stub (rtx retval, rtx
RESULT_DECL, NULL_TREE,
void_type_node);
+ targetdecl = SYMBOL_REF_DECL (fn);
+
+ /* If the called function should occur only once in the final binary
+ (e.g. it's in a COMDAT group), the same should be true of the
+ stub. */
+ if (targetdecl && DECL_ONE_ONLY (targetdecl))
+ make_decl_one_only (stubdecl, DECL_ASSEMBLER_NAME (targetdecl));
+
/* Output a comment. */
fprintf (asm_out_file, "\t# Stub function to call %s%s (",
(fp_ret_p
@@ -10201,10 +10233,15 @@ mips_output_function_prologue (FILE *fil
/* In MIPS16 mode, we may need to generate a non-MIPS16 stub to handle
floating-point arguments. */
- if (TARGET_MIPS16
- && TARGET_HARD_FLOAT_ABI
- && crtl->args.info.fp_code != 0)
- mips16_build_function_stub ();
+ if (TARGET_MIPS16 && TARGET_HARD_FLOAT_ABI)
+ {
+ bool fp_args = crtl->args.info.fp_code != 0;
+ rtx return_rtx = crtl->return_rtx;
+ bool fp_ret= (return_rtx
+ && mips_return_mode_in_fpr_p (GET_MODE (return_rtx)));
+ if (fp_args || fp_ret)
+ mips16_build_function_stub_and_local_alias (fp_args);
+ }
/* Get the function name the same way that toplev.c does before calling
assemble_start_function. This is needed so that the name used here
===================================================================
@@ -266,6 +266,7 @@ foreach option {
synci
relax-pic-calls
mcount-ra-address
+ interlink-mips16
} {
lappend mips_option_groups $option "-m(no-|)$option"
}
===================================================================
@@ -0,0 +1,12 @@
+/* { dg-do link { target fpic } } */
+/* { dg-options "(-mips16) -fpic -minterlink-mips16" } */
+MIPS16 static double
+fn1(void) { return 0.0; }
+MIPS16 static double
+fn2(double d) { return 0.0; }
+MIPS16 void
+main(void) {
+ volatile double d;
+ d = fn1();
+ d = fn2(0.0);
+}