MIPS16/GAS: Factor out duplicate symbol value conversion code
authorMaciej W. Rozycki <macro@imgtec.com>
Thu, 27 Apr 2017 01:25:33 +0000 (02:25 +0100)
committerMaciej W. Rozycki <macro@imgtec.com>
Thu, 27 Apr 2017 11:21:58 +0000 (12:21 +0100)
Factor out and consolidate duplicate section-relative to PC-relative
symbol value conversion in `mips16_extended_frag' and `md_convert_frag'
used for MIPS16 relaxation, observing that the final calculation in the
latter function implies `stretch == 0'.  Sanitize the formatting of code
moved.

gas/
* config/tc-mips.c (mips16_pcrel_val): New function, factored
out from...
(mips16_extended_frag): ... here.
(md_convert_frag): Use `mips16_pcrel_val' rather than repeated
code in MIPS16 relaxation, with `stretch' hardcoded to 0.

gas/ChangeLog
gas/config/tc-mips.c

index a980370bcee379f3129bbe1a870df5f6d0ae7a55..d5849c0849e5ae895e0df78debde09fc711d34c3 100644 (file)
@@ -1,3 +1,11 @@
+2017-04-27  Maciej W. Rozycki  <macro@imgtec.com>
+
+       * config/tc-mips.c (mips16_pcrel_val): New function, factored
+       out from...
+       (mips16_extended_frag): ... here.
+       (md_convert_frag): Use `mips16_pcrel_val' rather than repeated
+       code in MIPS16 relaxation, with `stretch' hardcoded to 0.
+
 2017-04-27  Maciej W. Rozycki  <macro@imgtec.com>
 
        * config/tc-mips.c (RELAX_MIPS16_LONG_BRANCH): Rename to...
index a18dbccd43c9a52df52929d81626e825c4cb8ba2..fbf67a139ede356365f63164e65c9b43b966e30c 100644 (file)
@@ -17179,7 +17179,82 @@ pic_need_relax (symbolS *sym)
          /* A global or weak symbol is treated as external.  */
          && (!S_IS_WEAK (sym) && !S_IS_EXTERNAL (sym)));
 }
+\f
+/* Given a MIPS16 variant frag FRAGP and PC-relative operand PCREL_OP
+   convert a section-relative value VAL to the equivalent PC-relative
+   value.  */
+
+static offsetT
+mips16_pcrel_val (fragS *fragp, const struct mips_pcrel_operand *pcrel_op,
+                 offsetT val, long stretch)
+{
+  fragS *sym_frag;
+  addressT addr;
+
+  gas_assert (pcrel_op->root.root.type == OP_PCREL);
+
+  sym_frag = symbol_get_frag (fragp->fr_symbol);
+
+  /* If the relax_marker of the symbol fragment differs from the
+     relax_marker of this fragment, we have not yet adjusted the
+     symbol fragment fr_address.  We want to add in STRETCH in
+     order to get a better estimate of the address.  This
+     particularly matters because of the shift bits.  */
+  if (stretch != 0 && sym_frag->relax_marker != fragp->relax_marker)
+    {
+      fragS *f;
+
+      /* Adjust stretch for any alignment frag.  Note that if have
+        been expanding the earlier code, the symbol may be
+        defined in what appears to be an earlier frag.  FIXME:
+        This doesn't handle the fr_subtype field, which specifies
+        a maximum number of bytes to skip when doing an
+        alignment.  */
+      for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next)
+       {
+         if (f->fr_type == rs_align || f->fr_type == rs_align_code)
+           {
+             if (stretch < 0)
+               stretch = -(-stretch & ~((1 << (int) f->fr_offset) - 1));
+             else
+               stretch &= ~((1 << (int) f->fr_offset) - 1);
+             if (stretch == 0)
+               break;
+           }
+       }
+      if (f != NULL)
+       val += stretch;
+    }
+
+  addr = fragp->fr_address + fragp->fr_fix;
+
+  /* The base address rules are complicated.  The base address of
+     a branch is the following instruction.  The base address of a
+     PC relative load or add is the instruction itself, but if it
+     is in a delay slot (in which case it can not be extended) use
+     the address of the instruction whose delay slot it is in.  */
+  if (pcrel_op->include_isa_bit)
+    {
+      addr += 2;
+
+      /* If we are currently assuming that this frag should be
+        extended, then the current address is two bytes higher.  */
+      if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
+       addr += 2;
+
+      /* Ignore the low bit in the target, since it will be set
+        for a text label.  */
+      val &= -2;
+    }
+  else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
+    addr -= 4;
+  else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
+    addr -= 2;
 
+  val -= addr & -(1 << pcrel_op->align_log2);
+
+  return val;
+}
 
 /* Given a mips16 variant frag FRAGP, return non-zero if it needs an
    extended opcode.  SEC is the section the frag is in.  */
@@ -17187,11 +17262,10 @@ pic_need_relax (symbolS *sym)
 static int
 mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
 {
-  int type;
   const struct mips_int_operand *operand;
   offsetT val;
   segT symsec;
-  fragS *sym_frag;
+  int type;
 
   if (RELAX_MIPS16_USER_SMALL (fragp->fr_subtype))
     return 0;
@@ -17207,80 +17281,18 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch)
          : !bfd_is_abs_section (symsec)))
     return 1;
 
-  sym_frag = symbol_get_frag (fragp->fr_symbol);
   val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
 
   if (operand->root.type == OP_PCREL)
     {
       const struct mips_pcrel_operand *pcrel_op;
-      addressT addr;
       offsetT maxtiny;
 
       if (RELAX_MIPS16_ALWAYS_EXTENDED (fragp->fr_subtype))
        return 1;
 
       pcrel_op = (const struct mips_pcrel_operand *) operand;
-
-      /* If the relax_marker of the symbol fragment differs from the
-        relax_marker of this fragment, we have not yet adjusted the
-        symbol fragment fr_address.  We want to add in STRETCH in
-        order to get a better estimate of the address.  This
-        particularly matters because of the shift bits.  */
-      if (stretch != 0
-         && sym_frag->relax_marker != fragp->relax_marker)
-       {
-         fragS *f;
-
-         /* Adjust stretch for any alignment frag.  Note that if have
-             been expanding the earlier code, the symbol may be
-             defined in what appears to be an earlier frag.  FIXME:
-             This doesn't handle the fr_subtype field, which specifies
-             a maximum number of bytes to skip when doing an
-             alignment.  */
-         for (f = fragp; f != NULL && f != sym_frag; f = f->fr_next)
-           {
-             if (f->fr_type == rs_align || f->fr_type == rs_align_code)
-               {
-                 if (stretch < 0)
-                   stretch = - ((- stretch)
-                                & ~ ((1 << (int) f->fr_offset) - 1));
-                 else
-                   stretch &= ~ ((1 << (int) f->fr_offset) - 1);
-                 if (stretch == 0)
-                   break;
-               }
-           }
-         if (f != NULL)
-           val += stretch;
-       }
-
-      addr = fragp->fr_address + fragp->fr_fix;
-
-      /* The base address rules are complicated.  The base address of
-         a branch is the following instruction.  The base address of a
-         PC relative load or add is the instruction itself, but if it
-         is in a delay slot (in which case it can not be extended) use
-         the address of the instruction whose delay slot it is in.  */
-      if (pcrel_op->include_isa_bit)
-       {
-         addr += 2;
-
-         /* If we are currently assuming that this frag should be
-            extended, then, the current address is two bytes
-            higher.  */
-         if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype))
-           addr += 2;
-
-         /* Ignore the low bit in the target, since it will be set
-             for a text label.  */
-         val &= -2;
-       }
-      else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
-       addr -= 4;
-      else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
-       addr -= 2;
-
-      val -= addr & -(1 << pcrel_op->align_log2);
+      val = mips16_pcrel_val (fragp, pcrel_op, val, stretch);
 
       /* If any of the shifted bits are set, we must use an extended
          opcode.  If the address depends on the size of this
@@ -18377,39 +18389,21 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp)
       if (operand->root.type == OP_PCREL)
        {
          const struct mips_pcrel_operand *pcrel_op;
-         addressT addr;
 
          pcrel_op = (const struct mips_pcrel_operand *) operand;
-         addr = fragp->fr_address + fragp->fr_fix;
 
-         /* The rules for the base address of a PC relative reloc are
-             complicated; see mips16_extended_frag.  */
-         if (pcrel_op->include_isa_bit)
+         if (pcrel_op->include_isa_bit && !need_reloc)
            {
-             if (!need_reloc)
-               {
-                 if (!ELF_ST_IS_MIPS16 (S_GET_OTHER (fragp->fr_symbol)))
-                   as_bad_where (fragp->fr_file, fragp->fr_line,
-                                 _("branch to a symbol in another ISA mode"));
-                 else if ((fragp->fr_offset & 0x1) != 0)
-                   as_bad_where (fragp->fr_file, fragp->fr_line,
-                                 _("branch to misaligned address (0x%lx)"),
-                                 (long) val);
-               }
-             addr += 2;
-             if (ext)
-               addr += 2;
-             /* Ignore the low bit in the target, since it will be
-                 set for a text label.  */
-             val &= -2;
+             if (!ELF_ST_IS_MIPS16 (S_GET_OTHER (fragp->fr_symbol)))
+               as_bad_where (fragp->fr_file, fragp->fr_line,
+                             _("branch to a symbol in another ISA mode"));
+             else if ((fragp->fr_offset & 0x1) != 0)
+               as_bad_where (fragp->fr_file, fragp->fr_line,
+                             _("branch to misaligned address (0x%lx)"),
+                             (long) val);
            }
-         else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
-           addr -= 4;
-         else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
-           addr -= 2;
 
-         addr &= -(1 << pcrel_op->align_log2);
-         val -= addr;
+         val = mips16_pcrel_val (fragp, pcrel_op, val, 0);
 
          /* Make sure the section winds up with the alignment we have
              assumed.  */