From 584892a6d567210d0f242cd5eca32ee46e91872c Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Fri, 23 Jan 2004 13:00:18 +0000 Subject: [PATCH] * config/tc-mips.c (RELAX_ENCODE): Remove WARN argument. (RELAX_FIRST, RELAX_SECOND): Turn into 8-bit quantities. (RELAX_USE_SECOND): Bump to 0x10000. (RELAX_SECOND_LONGER, RELAX_NOMACRO, RELAX_DELAY_SLOT): New flags. (mips_macro_warning): New variable. (md_assemble): Wrap macro expansion in macro_start() and macro_end(). (s_cpload, s_cpsetup, s_cprestore, s_cpreturn): Likewise. (relax_close_frag): Set mips_macro_warning.first_frag. Adjust use of RELAX_ENCODE. (append_insn): Update mips_macro_warning.sizes. (macro_start, macro_warning, macro_end): New functions. (macro_build): Don't emit warnings here. (macro_build_lui, md_estimate_size_before_relax): ...or here. (md_convert_frag): Check for cases where one macro alternative needs a warning and the other doesn't. Emit a warning if the longer sequence was chosen. --- gas/ChangeLog | 19 +++++ gas/config/tc-mips.c | 191 +++++++++++++++++++++++++++++++------------ 2 files changed, 157 insertions(+), 53 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 6c8716d431..1c0b33ea1f 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,22 @@ +2004-01-23 Richard Sandiford + + * config/tc-mips.c (RELAX_ENCODE): Remove WARN argument. + (RELAX_FIRST, RELAX_SECOND): Turn into 8-bit quantities. + (RELAX_USE_SECOND): Bump to 0x10000. + (RELAX_SECOND_LONGER, RELAX_NOMACRO, RELAX_DELAY_SLOT): New flags. + (mips_macro_warning): New variable. + (md_assemble): Wrap macro expansion in macro_start() and macro_end(). + (s_cpload, s_cpsetup, s_cprestore, s_cpreturn): Likewise. + (relax_close_frag): Set mips_macro_warning.first_frag. Adjust use + of RELAX_ENCODE. + (append_insn): Update mips_macro_warning.sizes. + (macro_start, macro_warning, macro_end): New functions. + (macro_build): Don't emit warnings here. + (macro_build_lui, md_estimate_size_before_relax): ...or here. + (md_convert_frag): Check for cases where one macro alternative + needs a warning and the other doesn't. Emit a warning if the + longer sequence was chosen. + 2004-01-23 Richard Sandiford * config/tc-mips.h (tc_frag_data_type, TC_FRAG_TYPE): Remove. diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index e6e9b8cff9..7ac580b225 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -629,14 +629,27 @@ static int mips_relax_branch; absolute one. In SVR4 PIC, the first sequence will be for global symbols and the second will be for local symbols. - The frag's "subtype" is RELAX_ENCODE (FIRST, SECOND, WARN), where - FIRST and SECOND are the lengths of the two sequences in bytes - and WARN is true if ".set nomacro" was in effect when the macro - was expanded. These fields can be extracted using RELAX_FIRST(), - RELAX_SECOND() and RELAX_WARN(). + The frag's "subtype" is RELAX_ENCODE (FIRST, SECOND), where FIRST and + SECOND are the lengths of the two sequences in bytes. These fields + can be extracted using RELAX_FIRST() and RELAX_SECOND(). In addition, + the subtype has the following flags: - In addition, the RELAX_USE_SECOND flag is set if it has been decided - that we should use the second sequence instead of the first. + RELAX_USE_SECOND + Set if it has been decided that we should use the second + sequence instead of the first. + + RELAX_SECOND_LONGER + Set in the first variant frag if the macro's second implementation + is longer than its first. This refers to the macro as a whole, + not an individual relaxation. + + RELAX_NOMACRO + Set in the first variant frag if the macro appeared in a .set nomacro + block and if one alternative requires a warning but the other does not. + + RELAX_DELAY_SLOT + Like RELAX_NOMACRO, but indicates that the macro appears in a branch + delay slot. The frag's "opcode" points to the first fixup for relaxable code. @@ -650,13 +663,14 @@ static int mips_relax_branch; The code and fixups for the unwanted alternative are discarded by md_convert_frag. */ -#define RELAX_ENCODE(FIRST, SECOND, WARN) \ - (((FIRST) << 8) | ((SECOND) << 1) | ((WARN) != 0)) +#define RELAX_ENCODE(FIRST, SECOND) (((FIRST) << 8) | (SECOND)) -#define RELAX_FIRST(X) (((X) >> 8) & 0x7f) -#define RELAX_SECOND(X) (((X) >> 1) & 0x7f) -#define RELAX_WARN(X) ((X) & 1) -#define RELAX_USE_SECOND 0x8000 +#define RELAX_FIRST(X) (((X) >> 8) & 0xff) +#define RELAX_SECOND(X) ((X) & 0xff) +#define RELAX_USE_SECOND 0x10000 +#define RELAX_SECOND_LONGER 0x20000 +#define RELAX_NOMACRO 0x40000 +#define RELAX_DELAY_SLOT 0x80000 /* Branch without likely bit. If label is out of range, we turn: @@ -810,6 +824,21 @@ static struct { symbolS *symbol; } mips_relax; +/* Global variables used to decide whether a macro needs a warning. */ +static struct { + /* True if the macro is in a branch delay slot. */ + bfd_boolean delay_slot_p; + + /* For relaxable macros, sizes[0] is the length of the first alternative + in bytes and sizes[1] is the length of the second alternative. + For non-relaxable macros, both elements give the length of the + macro in bytes. */ + unsigned int sizes[2]; + + /* The first variant frag for this macro. */ + fragS *first_frag; +} mips_macro_warning; + /* Prototypes for static functions. */ #define internalError() \ @@ -823,6 +852,8 @@ static void mips_no_prev_insn (int); static void mips16_macro_build (int *, expressionS *, const char *, const char *, va_list); static void load_register (int *, int, expressionS *, int); +static void macro_start (void); +static void macro_end (void); static void macro (struct mips_cl_insn * ip); static void mips16_macro (struct mips_cl_insn * ip); #ifdef LOSING_COMPILER @@ -1340,10 +1371,12 @@ md_assemble (char *str) if (insn.insn_mo->pinfo == INSN_MACRO) { + macro_start (); if (mips_opts.mips16) mips16_macro (&insn); else macro (&insn); + macro_end (); } else { @@ -1518,10 +1551,9 @@ mips16_mark_labels (void) static void relax_close_frag (void) { + mips_macro_warning.first_frag = frag_now; frag_var (rs_machine_dependent, 0, 0, - RELAX_ENCODE (mips_relax.sizes[0], - mips_relax.sizes[1], - mips_opts.warn_about_macros), + RELAX_ENCODE (mips_relax.sizes[0], mips_relax.sizes[1]), mips_relax.symbol, 0, (char *) mips_relax.first_fixup); memset (&mips_relax.sizes, 0, sizeof (mips_relax.sizes)); @@ -2025,6 +2057,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, mips_relax.sizes[mips_relax.sequence - 1] += 4; } + if (mips_relax.sequence != 2) + mips_macro_warning.sizes[0] += 4; + if (mips_relax.sequence != 1) + mips_macro_warning.sizes[1] += 4; + f = frag_more (4); } @@ -2851,6 +2888,71 @@ mips_emit_delays (bfd_boolean insns) mips_no_prev_insn (insns); } +/* Set up global variables for the start of a new macro. */ + +static void +macro_start (void) +{ + memset (&mips_macro_warning.sizes, 0, sizeof (mips_macro_warning.sizes)); + mips_macro_warning.delay_slot_p = (mips_opts.noreorder + && (prev_insn.insn_mo->pinfo + & (INSN_UNCOND_BRANCH_DELAY + | INSN_COND_BRANCH_DELAY + | INSN_COND_BRANCH_LIKELY)) != 0); +} + +/* Given that a macro is longer than 4 bytes, return the appropriate warning + for it. Return null if no warning is needed. SUBTYPE is a bitmask of + RELAX_DELAY_SLOT and RELAX_NOMACRO. */ + +static const char * +macro_warning (relax_substateT subtype) +{ + if (subtype & RELAX_DELAY_SLOT) + return _("Macro instruction expanded into multiple instructions" + " in a branch delay slot"); + else if (subtype & RELAX_NOMACRO) + return _("Macro instruction expanded into multiple instructions"); + else + return 0; +} + +/* Finish up a macro. Emit warnings as appropriate. */ + +static void +macro_end (void) +{ + if (mips_macro_warning.sizes[0] > 4 || mips_macro_warning.sizes[1] > 4) + { + relax_substateT subtype; + + /* Set up the relaxation warning flags. */ + subtype = 0; + if (mips_macro_warning.sizes[1] > mips_macro_warning.sizes[0]) + subtype |= RELAX_SECOND_LONGER; + if (mips_opts.warn_about_macros) + subtype |= RELAX_NOMACRO; + if (mips_macro_warning.delay_slot_p) + subtype |= RELAX_DELAY_SLOT; + + if (mips_macro_warning.sizes[0] > 4 && mips_macro_warning.sizes[1] > 4) + { + /* Either the macro has a single implementation or both + implementations are longer than 4 bytes. Emit the + warning now. */ + const char *msg = macro_warning (subtype); + if (msg != 0) + as_warn (msg); + } + else + { + /* One implementation might need a warning but the other + definitely doesn't. */ + mips_macro_warning.first_frag->fr_subtype |= subtype; + } + } +} + /* Build an instruction created by a macro expansion. This is passed a pointer to the count of instructions created so far, an expression, the name of the instruction to build, an operand format @@ -2866,28 +2968,6 @@ macro_build (char *place ATTRIBUTE_UNUSED, int *counter, va_start (args, fmt); - if (mips_relax.sequence != 2) - { - if (*counter == 1) - { - /* If the macro is about to expand into a second instruction, - and it is in a delay slot, print a warning. */ - if (mips_opts.noreorder - && (prev_prev_insn.insn_mo->pinfo - & (INSN_UNCOND_BRANCH_DELAY - | INSN_COND_BRANCH_DELAY - | INSN_COND_BRANCH_LIKELY)) != 0) - as_warn (_("Macro instruction expanded into multiple instructions in a branch delay slot")); - - /* If the macro is about to expand into a second instruction, - print a warning if needed. We need to pass ip as a parameter - to generate a better warning message here... */ - else if (mips_opts.warn_about_macros) - as_warn (_("Macro instruction expanded into multiple instructions")); - } - ++*counter; - } - if (mips_opts.mips16) { mips16_macro_build (counter, ep, name, fmt, args); @@ -3253,7 +3333,7 @@ macro_build_jalr (int icnt, expressionS *ep) * Generate a "lui" instruction. */ static void -macro_build_lui (char *place ATTRIBUTE_UNUSED, int *counter, +macro_build_lui (char *place ATTRIBUTE_UNUSED, int *counter ATTRIBUTE_UNUSED, expressionS *ep, int regnum) { expressionS high_expr; @@ -3266,15 +3346,6 @@ macro_build_lui (char *place ATTRIBUTE_UNUSED, int *counter, assert (! mips_opts.mips16); high_expr = *ep; - if (mips_relax.sequence != 2) - { - /* If the macro is about to expand into a second instruction, - print a warning if needed. We need to pass ip as a parameter - to generate a better warning message here... */ - if (mips_opts.warn_about_macros && *counter == 1) - as_warn (_("Macro instruction expanded into multiple instructions")); - ++*counter; - } if (high_expr.X_op == O_constant) { @@ -12230,12 +12301,14 @@ s_cpload (int ignore ATTRIBUTE_UNUSED) /* In ELF, this symbol is implicitly an STT_OBJECT symbol. */ symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT; + macro_start (); macro_build_lui (NULL, &icnt, &ex, mips_gp_register); macro_build (NULL, &icnt, &ex, "addiu", "t,r,j", mips_gp_register, mips_gp_register, BFD_RELOC_LO16); macro_build (NULL, &icnt, NULL, "addu", "d,v,t", mips_gp_register, mips_gp_register, tc_get_register (0)); + macro_end (); demand_empty_rest_of_line (); } @@ -12303,6 +12376,7 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED) SKIP_WHITESPACE (); expression (&ex_sym); + macro_start (); if (mips_cpreturn_register == -1) { ex_off.X_op = O_constant; @@ -12338,6 +12412,7 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED) macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t", mips_gp_register, mips_gp_register, reg1); + macro_end (); demand_empty_rest_of_line (); } @@ -12383,8 +12458,10 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED) ex.X_op_symbol = NULL; ex.X_add_number = mips_cprestore_offset; + macro_start (); macro_build_ldst_constoffset (NULL, &icnt, &ex, ADDRESS_STORE_INSN, mips_gp_register, SP, HAVE_64BIT_ADDRESSES); + macro_end (); demand_empty_rest_of_line (); } @@ -12410,6 +12487,7 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED) return; } + macro_start (); if (mips_cpreturn_register == -1) { ex.X_op = O_constant; @@ -12423,6 +12501,7 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED) else macro_build (NULL, &icnt, NULL, "daddu", "d,v,t", mips_gp_register, mips_cpreturn_register, 0); + macro_end (); demand_empty_rest_of_line (); } @@ -12545,9 +12624,11 @@ s_cpadd (int ignore ATTRIBUTE_UNUSED) } /* Add $gp to the register named as an argument. */ + macro_start (); reg = tc_get_register (0); macro_build (NULL, &icnt, NULL, ADDRESS_ADD_INSN, "d,v,t", reg, reg, mips_gp_register); + macro_end (); demand_empty_rest_of_line (); } @@ -13155,11 +13236,6 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype) if (change) { fragp->fr_subtype |= RELAX_USE_SECOND; - /* FIXME: This really needs as_warn_where. */ - if (RELAX_WARN (fragp->fr_subtype)) - as_warn (_("AT used after \".set noat\" or macro used after " - "\".set nomacro\"")); - return -RELAX_FIRST (fragp->fr_subtype); } else @@ -13680,6 +13756,15 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) second = RELAX_SECOND (fragp->fr_subtype); fixp = (fixS *) fragp->fr_opcode; + /* Possibly emit a warning if we've chosen the longer option. */ + if (((fragp->fr_subtype & RELAX_USE_SECOND) != 0) + == ((fragp->fr_subtype & RELAX_SECOND_LONGER) != 0)) + { + const char *msg = macro_warning (fragp->fr_subtype); + if (msg != 0) + as_warn_where (fragp->fr_file, fragp->fr_line, msg); + } + /* Go through all the fixups for the first sequence. Disable them (by marking them as done) if we're going to use the second sequence instead. */