This patch generalises the code used to handle __mips16_rdhwr stubs so that it can be reused in the next patch. I also threw in a couple of #undefs for macros in surrounding code.
Tested on mips64-linux-gnu and mipsisa64-sde-elf. Applied. Thanks, Richard gcc/ * config/mips/mips.c (mips_one_only_stub): New class. (mips_need_mips16_rdhwr_p): Replace with... (mips16_rdhwr_stub): ...this new variable. (mips16_stub_call_address): New function. (mips16_rdhwr_one_only_stub): New class. (mips_expand_thread_pointer): Use mips16_stub_call_address. (mips_output_mips16_rdhwr): Delete. (mips_finish_stub): New function. (mips_code_end): Use it to handle rdhwr stubs. Index: gcc/config/mips/mips.c =================================================================== --- gcc/config/mips/mips.c 2014-02-02 15:50:25.896853693 +0000 +++ gcc/config/mips/mips.c 2014-02-02 15:56:14.313401402 +0000 @@ -275,12 +275,27 @@ #define DECLARE_MIPS_COND(X) MIPS_FP_CON enum mips_fp_condition { MIPS_FP_CONDITIONS (DECLARE_MIPS_COND) }; +#undef DECLARE_MIPS_COND /* Index X provides the string representation of MIPS_FP_COND_<X>. */ #define STRINGIFY(X) #X static const char *const mips_fp_conditions[] = { MIPS_FP_CONDITIONS (STRINGIFY) }; +#undef STRINGIFY + +/* A class used to control a comdat-style stub that we output in each + translation unit that needs it. */ +class mips_one_only_stub { +public: + virtual ~mips_one_only_stub () {} + + /* Return the name of the stub. */ + virtual const char *get_name () = 0; + + /* Output the body of the function to asm_out_file. */ + virtual void output_body () = 0; +}; /* Tuning information that is automatically derived from other sources (such as the scheduler). */ @@ -626,8 +641,8 @@ struct target_globals *mips16_globals; and returned from mips_sched_reorder2. */ static int cached_can_issue_more; -/* True if the output uses __mips16_rdhwr. */ -static bool mips_need_mips16_rdhwr_p; +/* The stub for __mips16_rdhwr, if used. */ +static mips_one_only_stub *mips16_rdhwr_stub; /* Index R is the smallest register class that contains register R. */ const enum reg_class mips_regno_to_class[FIRST_PSEUDO_REGISTER] = { @@ -1606,6 +1621,45 @@ mips16_stub_function (const char *name) SYMBOL_REF_FLAGS (x) |= (SYMBOL_FLAG_EXTERNAL | SYMBOL_FLAG_FUNCTION); return x; } + +/* Return a legitimate call address for STUB, given that STUB is a MIPS16 + support function. */ + +static rtx +mips16_stub_call_address (mips_one_only_stub *stub) +{ + rtx fn = mips16_stub_function (stub->get_name ()); + SYMBOL_REF_FLAGS (fn) |= SYMBOL_FLAG_LOCAL; + if (!call_insn_operand (fn, VOIDmode)) + fn = force_reg (Pmode, fn); + return fn; +} + +/* A stub for moving the thread pointer into TLS_GET_TP_REGNUM. */ + +class mips16_rdhwr_one_only_stub : public mips_one_only_stub +{ + virtual const char *get_name (); + virtual void output_body (); +}; + +const char * +mips16_rdhwr_one_only_stub::get_name () +{ + return "__mips16_rdhwr"; +} + +void +mips16_rdhwr_one_only_stub::output_body () +{ + fprintf (asm_out_file, + "\t.set\tpush\n" + "\t.set\tmips32r2\n" + "\t.set\tnoreorder\n" + "\trdhwr\t$3,$29\n" + "\t.set\tpop\n" + "\tj\t$31\n"); +} /* Return true if symbols of type TYPE require a GOT access. */ @@ -3070,11 +3124,9 @@ mips_expand_thread_pointer (rtx tp) if (TARGET_MIPS16) { - mips_need_mips16_rdhwr_p = true; - fn = mips16_stub_function ("__mips16_rdhwr"); - SYMBOL_REF_FLAGS (fn) |= SYMBOL_FLAG_LOCAL; - if (!call_insn_operand (fn, VOIDmode)) - fn = force_reg (Pmode, fn); + if (!mips16_rdhwr_stub) + mips16_rdhwr_stub = new mips16_rdhwr_one_only_stub (); + fn = mips16_stub_call_address (mips16_rdhwr_stub); emit_insn (PMODE_INSN (gen_tls_get_tp_mips16, (tp, fn))); } else @@ -6204,25 +6256,24 @@ mips_end_function_definition (const char fputs ("\n", asm_out_file); } } - -/* Output a definition of the __mips16_rdhwr function. */ + +/* If *STUB_PTR points to a stub, output a comdat-style definition for it, + then free *STUB_PTR. */ static void -mips_output_mips16_rdhwr (void) +mips_finish_stub (mips_one_only_stub **stub_ptr) { - const char *name; + mips_one_only_stub *stub = *stub_ptr; + if (!stub) + return; - name = "__mips16_rdhwr"; + const char *name = stub->get_name (); mips_start_unique_function (name); mips_start_function_definition (name, false); - fprintf (asm_out_file, - "\t.set\tpush\n" - "\t.set\tmips32r2\n" - "\t.set\tnoreorder\n" - "\trdhwr\t$3,$29\n" - "\t.set\tpop\n" - "\tj\t$31\n"); + stub->output_body (); mips_end_function_definition (name); + delete stub; + *stub_ptr = 0; } /* Return true if calls to X can use R_MIPS_CALL* relocations. */ @@ -8906,8 +8957,7 @@ mips_file_start (void) static void mips_code_end (void) { - if (mips_need_mips16_rdhwr_p) - mips_output_mips16_rdhwr (); + mips_finish_stub (&mips16_rdhwr_stub); } /* Make the last instruction frame-related and note that it performs