* config/mips/mips-protos.h (mips_push_asm_switch): New function.
(mips_pop_asm_switch): Likewise.
* config/mips/mips.c (set_noreorder, set_nomacro, set_noat): Replace
with...
(mips_noreorder, mips_nomacro, mips_noat): ...these new variables.
(mips_push_asm_switch_1, mips_pop_asm_switch_1): New functions.
(mips_push_asm_switch, mips_pop_asm_switch): Likewise.
(mips_print_operand_punctuation): Use them. Check mips_noreorder
instead of set_noreorder.
(mips_output_function_prologue): Use the new functions.
(mips_output_function_epilogue): Likewise.
(mips_need_noat_wrapper_p): New function, split out from...
(mips_final_prescan_insn, mips_final_postscan_insn): ...here.
Use mips_push_asm_switch and mips_pop_asm_switch.
* config/mips/mips.h (FUNCTION_PROFILER): Use mips_push_asm_switch
and mips_pop_asm_switch.
(ASM_OUTPUT_REG_POP): Likewise.
(DBR_OUTPUT_SEQEND): Remove boilerplate comment.
Use mips_pop_asm_switch.
(mips_asm_switch): New structure.
(set_noreorder, set_nomacro): Replace with...
(mips_noreorder, mips_nomacro, mips_noat): ...these new variables.
* config/mips/mips.md (fix_truncdfsi2_macro): Use mips_nomacro
instead of set_nomacro.
(fix_truncsfsi2_macro): Likewise.
(cprestore): Likewise.
(hazard): Use mips_noreorder instead of set_noreorder.
* config/mips/sdemtk.h (FUNCTION_PROFILER): As for mips.h.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@150803
138bc75d-0d04-0410-961f-
82ee72b054a4
+2009-08-16 Richard Sandiford <rdsandiford@googlemail.com>
+
+ * config/mips/mips-protos.h (mips_push_asm_switch): New function.
+ (mips_pop_asm_switch): Likewise.
+ * config/mips/mips.c (set_noreorder, set_nomacro, set_noat): Replace
+ with...
+ (mips_noreorder, mips_nomacro, mips_noat): ...these new variables.
+ (mips_push_asm_switch_1, mips_pop_asm_switch_1): New functions.
+ (mips_push_asm_switch, mips_pop_asm_switch): Likewise.
+ (mips_print_operand_punctuation): Use them. Check mips_noreorder
+ instead of set_noreorder.
+ (mips_output_function_prologue): Use the new functions.
+ (mips_output_function_epilogue): Likewise.
+ (mips_need_noat_wrapper_p): New function, split out from...
+ (mips_final_prescan_insn, mips_final_postscan_insn): ...here.
+ Use mips_push_asm_switch and mips_pop_asm_switch.
+ * config/mips/mips.h (FUNCTION_PROFILER): Use mips_push_asm_switch
+ and mips_pop_asm_switch.
+ (ASM_OUTPUT_REG_POP): Likewise.
+ (DBR_OUTPUT_SEQEND): Remove boilerplate comment.
+ Use mips_pop_asm_switch.
+ (mips_asm_switch): New structure.
+ (set_noreorder, set_nomacro): Replace with...
+ (mips_noreorder, mips_nomacro, mips_noat): ...these new variables.
+ * config/mips/mips.md (fix_truncdfsi2_macro): Use mips_nomacro
+ instead of set_nomacro.
+ (fix_truncsfsi2_macro): Likewise.
+ (cprestore): Likewise.
+ (hazard): Use mips_noreorder instead of set_noreorder.
+ * config/mips/sdemtk.h (FUNCTION_PROFILER): As for mips.h.
+
2009-08-16 Uros Bizjak <ubizjak@gmail.com>
* config/alpha/alpha.c (alpha_and_function): Handle NULL_RTX returned
extern void mips_order_regs_for_local_alloc (void);
extern HOST_WIDE_INT mips_debugger_offset (rtx, HOST_WIDE_INT);
+extern void mips_push_asm_switch (struct mips_asm_switch *);
+extern void mips_pop_asm_switch (struct mips_asm_switch *);
extern void mips_print_operand (FILE *, rtx, int);
extern void mips_print_operand_address (FILE *, rtx);
extern void mips_output_external (FILE *, tree, const char *);
int mips_dwarf_regno[FIRST_PSEUDO_REGISTER];
/* The nesting depth of the PRINT_OPERAND '%(', '%<' and '%[' constructs. */
-int set_noreorder;
-int set_nomacro;
-static int set_noat;
+struct mips_asm_switch mips_noreorder = { "reorder", 0 };
+struct mips_asm_switch mips_nomacro = { "macro", 0 };
+struct mips_asm_switch mips_noat = { "at", 0 };
/* True if we're writing out a branch-likely instruction rather than a
normal branch. */
fputc (')', file);
}
+/* Start a new block with the given asm switch enabled. If we need
+ to print a directive, emit PREFIX before it and SUFFIX after it. */
+
+static void
+mips_push_asm_switch_1 (struct mips_asm_switch *asm_switch,
+ const char *prefix, const char *suffix)
+{
+ if (asm_switch->nesting_level == 0)
+ fprintf (asm_out_file, "%s.set\tno%s%s", prefix, asm_switch->name, suffix);
+ asm_switch->nesting_level++;
+}
+
+/* Likewise, but end a block. */
+
+static void
+mips_pop_asm_switch_1 (struct mips_asm_switch *asm_switch,
+ const char *prefix, const char *suffix)
+{
+ gcc_assert (asm_switch->nesting_level);
+ asm_switch->nesting_level--;
+ if (asm_switch->nesting_level == 0)
+ fprintf (asm_out_file, "%s.set\t%s%s", prefix, asm_switch->name, suffix);
+}
+
+/* Wrappers around mips_push_asm_switch_1 and mips_pop_asm_switch_1
+ that either print a complete line or print nothing. */
+
+void
+mips_push_asm_switch (struct mips_asm_switch *asm_switch)
+{
+ mips_push_asm_switch_1 (asm_switch, "\t", "\n");
+}
+
+void
+mips_pop_asm_switch (struct mips_asm_switch *asm_switch)
+{
+ mips_pop_asm_switch_1 (asm_switch, "\t", "\n");
+}
+
/* Print the text for PRINT_OPERAND punctation character CH to FILE.
The punctuation characters are:
switch (ch)
{
case '(':
- if (set_noreorder++ == 0)
- fputs (".set\tnoreorder\n\t", file);
+ mips_push_asm_switch_1 (&mips_noreorder, "", "\n\t");
break;
case ')':
- gcc_assert (set_noreorder > 0);
- if (--set_noreorder == 0)
- fputs ("\n\t.set\treorder", file);
+ mips_pop_asm_switch_1 (&mips_noreorder, "\n\t", "");
break;
case '[':
- if (set_noat++ == 0)
- fputs (".set\tnoat\n\t", file);
+ mips_push_asm_switch_1 (&mips_noat, "", "\n\t");
break;
case ']':
- gcc_assert (set_noat > 0);
- if (--set_noat == 0)
- fputs ("\n\t.set\tat", file);
+ mips_pop_asm_switch_1 (&mips_noat, "\n\t", "");
break;
case '<':
- if (set_nomacro++ == 0)
- fputs (".set\tnomacro\n\t", file);
+ mips_push_asm_switch_1 (&mips_nomacro, "", "\n\t");
break;
case '>':
- gcc_assert (set_nomacro > 0);
- if (--set_nomacro == 0)
- fputs ("\n\t.set\tmacro", file);
+ mips_pop_asm_switch_1 (&mips_nomacro, "\n\t", "");
break;
case '*':
break;
case '#':
- if (set_noreorder != 0)
+ if (mips_noreorder.nesting_level > 0)
fputs ("\n\tnop", file);
break;
/* Print an extra newline so that the delayed insn is separated
from the following ones. This looks neater and is consistent
with non-nop delayed sequences. */
- if (set_noreorder != 0 && final_sequence == 0)
+ if (mips_noreorder.nesting_level > 0 && final_sequence == 0)
fputs ("\n\tnop\n", file);
break;
output_asm_insn ("sll\t$2,16", 0);
output_asm_insn ("addu\t$2,$3", 0);
}
- /* .cpload must be in a .set noreorder but not a .set nomacro block. */
- else if (!cfun->machine->all_noreorder_p)
- output_asm_insn ("%(.cpload\t%^%)", 0);
else
- output_asm_insn ("%(.cpload\t%^\n\t%<", 0);
+ {
+ /* .cpload must be in a .set noreorder but not a
+ .set nomacro block. */
+ mips_push_asm_switch (&mips_noreorder);
+ output_asm_insn (".cpload\t%^", 0);
+ if (!cfun->machine->all_noreorder_p)
+ mips_pop_asm_switch (&mips_noreorder);
+ else
+ mips_push_asm_switch (&mips_nomacro);
+ }
}
else if (cfun->machine->all_noreorder_p)
- output_asm_insn ("%(%<", 0);
+ {
+ mips_push_asm_switch (&mips_noreorder);
+ mips_push_asm_switch (&mips_nomacro);
+ }
/* Tell the assembler which register we're using as the global
pointer. This is needed for thunks, since they can use either
if (cfun->machine->all_noreorder_p)
{
- /* Avoid using %>%) since it adds excess whitespace. */
- output_asm_insn (".set\tmacro", 0);
- output_asm_insn (".set\treorder", 0);
- set_noreorder = set_nomacro = 0;
+ mips_pop_asm_switch (&mips_nomacro);
+ mips_pop_asm_switch (&mips_noreorder);
}
/* Get the function name the same way that toplev.c does before calling
return REG_P (*x) && REGNO (*x) == AT_REGNUM;
}
+/* Return true if INSN needs to be wrapped in ".set noat".
+ INSN has NOPERANDS operands, stored in OPVEC. */
-/* Implement FINAL_PRESCAN_INSN. */
-
-void
-mips_final_prescan_insn (rtx insn, rtx *opvec, int noperands)
+static bool
+mips_need_noat_wrapper_p (rtx insn, rtx *opvec, int noperands)
{
int i;
- /* We need to emit ".set noat" before an instruction that accesses
- $1 (AT). */
if (recog_memoized (insn) >= 0)
for (i = 0; i < noperands; i++)
if (for_each_rtx (&opvec[i], mips_at_reg_p, NULL))
- if (set_noat++ == 0)
- fprintf (asm_out_file, "\t.set\tnoat\n");
+ return true;
+ return false;
+}
+
+/* Implement FINAL_PRESCAN_INSN. */
+
+void
+mips_final_prescan_insn (rtx insn, rtx *opvec, int noperands)
+{
+ if (mips_need_noat_wrapper_p (insn, opvec, noperands))
+ mips_push_asm_switch (&mips_noat);
}
/* Implement TARGET_ASM_FINAL_POSTSCAN_INSN. */
static void
-mips_final_postscan_insn (FILE *file, rtx insn, rtx *opvec, int noperands)
+mips_final_postscan_insn (FILE *file ATTRIBUTE_UNUSED, rtx insn,
+ rtx *opvec, int noperands)
{
- int i;
-
- /* Close any ".set noat" block opened by mips_final_prescan_insn. */
- if (recog_memoized (insn) >= 0)
- for (i = 0; i < noperands; i++)
- if (for_each_rtx (&opvec[i], mips_at_reg_p, NULL))
- if (--set_noat == 0)
- fprintf (file, "\t.set\tat\n");
+ if (mips_need_noat_wrapper_p (insn, opvec, noperands))
+ mips_pop_asm_switch (&mips_noat);
}
\f
/* Initialize the GCC target structure. */
else \
fprintf (FILE, "\tla\t%s,_mcount\n", reg_names[GP_REG_FIRST + 3]); \
} \
- fprintf (FILE, "\t.set\tnoat\n"); \
+ mips_push_asm_switch (&mips_noat); \
fprintf (FILE, "\tmove\t%s,%s\t\t# save current return address\n", \
reg_names[GP_REG_FIRST + 1], reg_names[GP_REG_FIRST + 31]); \
/* _mcount treats $2 as the static chain register. */ \
fprintf (FILE, "\tjalr\t%s\n", reg_names[GP_REG_FIRST + 3]); \
else \
fprintf (FILE, "\tjal\t_mcount\n"); \
- fprintf (FILE, "\t.set\tat\n"); \
+ mips_pop_asm_switch (&mips_noat); \
/* _mcount treats $2 as the static chain register. */ \
if (cfun->static_chain_decl != NULL) \
fprintf (FILE, "\tmove\t%s,%s\n", reg_names[STATIC_CHAIN_REGNUM], \
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) mips_print_operand_punct[CODE]
#define PRINT_OPERAND_ADDRESS mips_print_operand_address
-/* A C statement, to be executed after all slot-filler instructions
- have been output. If necessary, call `dbr_sequence_length' to
- determine the number of slots filled in a sequence (zero if not
- currently outputting a sequence), to decide how many no-ops to
- output, or whatever.
-
- Don't define this macro if it has nothing to do, but it is
- helpful in reading assembly output if the extent of the delay
- sequence is made explicit (e.g. with white space).
-
- Note that output routines for instructions with delay slots must
- be prepared to deal with not being output as part of a sequence
- (i.e. when the scheduling pass is not run, or when no slot
- fillers could be found.) The variable `final_sequence' is null
- when not processing a sequence, otherwise it contains the
- `sequence' rtx being output. */
-
#define DBR_OUTPUT_SEQEND(STREAM) \
do \
{ \
- if (set_nomacro > 0 && --set_nomacro == 0) \
- fputs ("\t.set\tmacro\n", STREAM); \
- \
- if (set_noreorder > 0 && --set_noreorder == 0) \
- fputs ("\t.set\treorder\n", STREAM); \
- \
+ /* Undo the effect of '%*'. */ \
+ mips_pop_asm_switch (&mips_nomacro); \
+ mips_pop_asm_switch (&mips_noreorder); \
+ /* Emit a blank line after the delay slot for emphasis. */ \
fputs ("\n", STREAM); \
} \
while (0)
#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \
do \
{ \
- if (! set_noreorder) \
- fprintf (STREAM, "\t.set\tnoreorder\n"); \
- \
+ mips_push_asm_switch (&mips_noreorder); \
fprintf (STREAM, "\t%s\t%s,0(%s)\n\t%s\t%s,%s,8\n", \
TARGET_64BIT ? "ld" : "lw", \
reg_names[REGNO], \
TARGET_64BIT ? "daddu" : "addu", \
reg_names[STACK_POINTER_REGNUM], \
reg_names[STACK_POINTER_REGNUM]); \
- \
- if (! set_noreorder) \
- fprintf (STREAM, "\t.set\treorder\n"); \
+ mips_pop_asm_switch (&mips_noreorder); \
} \
while (0)
#define MIPS_SYNC_EXCHANGE_12_NONZERO_OP "\tor\t%@,%@,%4\n"
#ifndef USED_FOR_TARGET
+/* Information about ".set noFOO; ...; .set FOO" blocks. */
+struct mips_asm_switch {
+ /* The FOO in the description above. */
+ const char *name;
+
+ /* The current block nesting level, or 0 if we aren't in a block. */
+ int nesting_level;
+};
+
extern const enum reg_class mips_regno_to_class[];
extern bool mips_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];
extern bool mips_print_operand_punct[256];
extern const char *current_function_file; /* filename current function is in */
extern int num_source_filenames; /* current .file # */
-extern int set_noreorder; /* # of nested .set noreorder's */
-extern int set_nomacro; /* # of nested .set nomacro's */
+extern struct mips_asm_switch mips_noreorder;
+extern struct mips_asm_switch mips_nomacro;
+extern struct mips_asm_switch mips_noat;
extern int mips_dbx_regno[];
extern int mips_dwarf_regno[];
extern bool mips_split_p[];
(clobber (match_scratch:DF 2 "=d"))]
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !ISA_HAS_TRUNC_W"
{
- if (set_nomacro)
+ if (mips_nomacro.nesting_level > 0)
return ".set\tmacro\;trunc.w.d %0,%1,%2\;.set\tnomacro";
else
return "trunc.w.d %0,%1,%2";
(clobber (match_scratch:SF 2 "=d"))]
"TARGET_HARD_FLOAT && !ISA_HAS_TRUNC_W"
{
- if (set_nomacro)
+ if (mips_nomacro.nesting_level > 0)
return ".set\tmacro\;trunc.w.s %0,%1,%2\;.set\tnomacro";
else
return "trunc.w.s %0,%1,%2";
UNSPEC_CPRESTORE)]
""
{
- if (set_nomacro && which_alternative == 1)
+ if (mips_nomacro.nesting_level > 0 && which_alternative == 1)
return ".set\tmacro\;.cprestore\t%0\;.set\tnomacro";
else
return ".cprestore\t%0";
[(const_int 1)]
""
{
- if (set_noreorder)
+ if (mips_noreorder.nesting_level > 0)
return "nop";
else
return "#nop";
#undef FUNCTION_PROFILER
#define FUNCTION_PROFILER(FILE, LABELNO) \
{ \
- fprintf (FILE, "\t.set\tnoat\n"); \
+ mips_push_asm_switch (&mips_noat); \
/* _mcount treats $2 as the static chain register. */ \
if (cfun->static_chain_decl != NULL) \
fprintf (FILE, "\tmove\t%s,%s\n", reg_names[2], \
reg_names[GP_REG_FIRST + (TARGET_MIPS16 ? 3 : 1)], \
reg_names[GP_REG_FIRST + 31]); \
fprintf (FILE, "\tjal\t_mcount\n"); \
- fprintf (FILE, "\t.set\tat\n"); \
+ mips_pop_asm_switch (&mips_noat); \
/* _mcount treats $2 as the static chain register. */ \
if (cfun->static_chain_decl != NULL) \
fprintf (FILE, "\tmove\t%s,%s\n", reg_names[STATIC_CHAIN_REGNUM], \