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). */
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] = {
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;
+}
+\f
+/* 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");
+}
\f
/* Return true if symbols of type TYPE require a GOT access. */
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
fputs ("\n", asm_out_file);
}
}
-\f
-/* 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;
}
\f
/* Return true if calls to X can use R_MIPS_CALL* relocations. */
static void
mips_code_end (void)
{
- if (mips_need_mips16_rdhwr_p)
- mips_output_mips16_rdhwr ();
+ mips_finish_stub (&mips16_rdhwr_stub);
}
\f
/* Make the last instruction frame-related and note that it performs