* config/tc-mips.c (RELAX_ENCODE): Remove WARN argument.
authorRichard Sandiford <rdsandiford@googlemail.com>
Fri, 23 Jan 2004 13:00:18 +0000 (13:00 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Fri, 23 Jan 2004 13:00:18 +0000 (13:00 +0000)
(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
gas/config/tc-mips.c

index 6c8716d..1c0b33e 100644 (file)
@@ -1,5 +1,24 @@
 2004-01-23  Richard Sandiford  <rsandifo@redhat.com>
 
+       * 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  <rsandifo@redhat.com>
+
        * config/tc-mips.h (tc_frag_data_type, TC_FRAG_TYPE): Remove.
        * config/tc-mips.c (RELAX_ENCODE): Take three arguments: the size of
        the first sequence, the size of the second sequence, and a flag
index e6e9b8c..7ac580b 100644 (file)
@@ -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;
 \f
+/* 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;
+\f
 /* 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.  */