Redesign and clean up the relaxation mechanism.
authorNick Clifton <nickc@redhat.com>
Fri, 22 Sep 2000 17:33:55 +0000 (17:33 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 22 Sep 2000 17:33:55 +0000 (17:33 +0000)
gas/ChangeLog
gas/config/tc-m68k.c

index 8208a51e91370674000ecb186f5bd2308db2da56..08edc25333b9dd0218170036ecc793baeef42975 100644 (file)
@@ -1,3 +1,9 @@
+2000-09-22  Michael Sokolov  <msokolov@ivan.Harhan.ORG>
+
+       * config/tc-m68k.c (md_relax_table, m68k_ip, md_convert_frag_1, 
+       md_estimate_size_before_relax): Redesign and clean up the
+       relaxation mechanism.
+
 2000-09-21  Kazu Hirata  <kazu@hxi.com>
 
        * config/tc-ns32k.c: Fix formatting.
index a6eb73f7e766a69c95304a6dabae7f6c05ea4bca..ef8e53ef1160ae01161fa59134c16bb5f5acd34a 100644 (file)
@@ -133,35 +133,6 @@ static struct label_line *current_label;
 /* See flames below */
 static struct obstack robyn;
 
-#define TAB(x,y)       (((x)<<2)+(y))
-#define TABTYPE(xy)     ((xy) >> 2)
-#define BYTE           0
-#define SHORT          1
-#define LONG           2
-#define SZ_UNDEF       3
-#undef BRANCH
-/* Case `g' except when BCC68000 is applicable.  */
-#define ABRANCH                1
-/* Coprocessor branches.  */
-#define FBRANCH                2
-/* Mode 7.2 -- program counter indirect with (16-bit) displacement,
-   supported on all cpus.  Widens to 32-bit absolute.  */
-#define PCREL          3
-/* For inserting an extra jmp instruction with long offset on 68000,
-   for expanding conditional branches.  (Not bsr or bra.)  Since the
-   68000 doesn't support 32-bit displacements for conditional
-   branches, we fake it by reversing the condition and branching
-   around a jmp with an absolute long operand.  */
-#define BCC68000        4
-/* For the DBcc "instructions".  If the displacement requires 32 bits,
-   the branch-around-a-jump game is played here too.  */
-#define DBCC            5
-/* Not currently used?  */
-#define PCLEA          6
-/* Mode AINDX (apc-relative) using PC, with variable target, might fit
-   in 16 or 8 bits.  */
-#define PCINDEX                7
-
 struct m68k_incant
   {
     const char *m_operands;
@@ -433,11 +404,60 @@ static const struct m68k_cpu archs[] = {
 
 static const int n_archs = sizeof (archs) / sizeof (archs[0]);
 
-/* BCC68000 is for patching in an extra jmp instruction for long offsets
-   on the 68000.  The 68000 doesn't support long branches with branchs */
+/* This is the assembler relaxation table for m68k. m68k is a rich CISC
+   architecture and we have a lot of relaxation modes.  */
 
-/* This table desribes how you change sizes for the various types of variable
-   size expressions.  This version only supports two kinds.  */
+/* Macros used in the relaxation code.  */
+#define TAB(x,y)       (((x) << 2) + (y))
+#define TABTYPE(x)      ((x) >> 2)
+
+/* Relaxation states.  */
+#define BYTE           0
+#define SHORT          1
+#define LONG           2
+#define SZ_UNDEF       3
+
+/* Here are all the relaxation modes we support.  First we can relax ordinary
+   branches.  On 68020 and higher and on CPU32 all branch instructions take
+   three forms, so on these CPUs all branches always remain as such.  When we
+   have to expand to the LONG form on a 68000, though, we substitute an
+   absolute jump instead.  This is a direct replacement for unconditional
+   branches and a branch over a jump for conditional branches.  However, if the
+   user requires PIC and disables this with --pcrel, we can only relax between
+   BYTE and SHORT forms, punting if that isn't enough.  This gives us four
+   different relaxation modes for branches:  */
+
+#define BRANCHBWL      1       /* branch byte, word, or long */
+#define BRABSJUNC      2       /* absolute jump for LONG, unconditional */
+#define BRABSJCOND     3       /* absolute jump for LONG, conditional */
+#define BRANCHBW       4       /* branch byte or word */
+
+/* We also relax coprocessor branches and DBcc's.  All CPUs that support
+   coprocessor branches support them in word and long forms, so we have only
+   one relaxation mode for them.  DBcc's are word only on all CPUs.  We can
+   relax them to the LONG form with a branch-around sequence.  This sequence
+   can use a long branch (if available) or an absolute jump (if acceptable).
+   This gives us two relaxation modes.  If long branches are not available and
+   absolute jumps are not acceptable, we don't relax DBcc's.  */
+
+#define FBRANCH                5       /* coprocessor branch */
+#define DBCCLBR                6       /* DBcc relaxable with a long branch */
+#define DBCCABSJ       7       /* DBcc relaxable with an absolute jump */
+
+/* That's all for instruction relaxation.  However, we also relax PC-relative
+   operands.  Specifically, we have three operand relaxation modes.  On the
+   68000 PC-relative operands can only be 16-bit, but on 68020 and higher and
+   on CPU32 they may be 16-bit or 32-bit.  For the latter we relax between the
+   two.  Also PC+displacement+index operands in their simple form (with a non-
+   suppressed index without memory indirection) are supported on all CPUs, but
+   on the 68000 the displacement can be 8-bit only, whereas on 68020 and higher
+   and on CPU32 we relax it to SHORT and LONG forms as well using the extended
+   form of the PC+displacement+index operand.  Finally, some absolute operands
+   can be relaxed down to 16-bit PC-relative.  */
+
+#define PCREL1632      8       /* 16-bit or 32-bit PC-relative */
+#define PCINDEX                9       /* PC+displacement+index */
+#define ABSTOPCREL     10      /* absolute relax down to 16-bit PC-relative */
 
 /* Note that calls to frag_var need to specify the maximum expansion
    needed; this is currently 10 bytes for DBCC.  */
@@ -455,41 +475,55 @@ relax_typeS md_relax_table[] =
   {1, 1, 0, 0},                        /* that the VAX doesn't either */
   {1, 1, 0, 0},
 
-  {(127), (-128), 0, TAB (ABRANCH, SHORT)},
-  {(32767), (-32768), 2, TAB (ABRANCH, LONG)},
+  {(127), (-128), 0, TAB (BRANCHBWL, SHORT)},
+  {(32767), (-32768), 2, TAB (BRANCHBWL, LONG)},
   {0, 0, 4, 0},
   {1, 1, 0, 0},
 
-  {1, 1, 0, 0},                        /* FBRANCH doesn't come BYTE */
-  {(32767), (-32768), 2, TAB (FBRANCH, LONG)},
+  {(127), (-128), 0, TAB (BRABSJUNC, SHORT)},
+  {(32767), (-32768), 2, TAB (BRABSJUNC, LONG)},
   {0, 0, 4, 0},
   {1, 1, 0, 0},
 
-  {1, 1, 0, 0},                        /* PCREL doesn't come BYTE */
-  {(32767), (-32768), 2, TAB (PCREL, LONG)},
+  {(127), (-128), 0, TAB (BRABSJCOND, SHORT)},
+  {(32767), (-32768), 2, TAB (BRABSJCOND, LONG)},
+  {0, 0, 6, 0},
+  {1, 1, 0, 0},
+
+  {(127), (-128), 0, TAB (BRANCHBW, SHORT)},
+  {0, 0, 2, 0},
+  {1, 1, 0, 0},
+  {1, 1, 0, 0},
+
+  {1, 1, 0, 0},                        /* FBRANCH doesn't come BYTE */
+  {(32767), (-32768), 2, TAB (FBRANCH, LONG)},
   {0, 0, 4, 0},
   {1, 1, 0, 0},
 
-  {(127), (-128), 0, TAB (BCC68000, SHORT)},
-  {(32767), (-32768), 2, TAB (BCC68000, LONG)},
-  {0, 0, 6, 0},                        /* jmp long space */
+  {1, 1, 0, 0},                        /* DBCC doesn't come BYTE */
+  {(32767), (-32768), 2, TAB (DBCCLBR, LONG)},
+  {0, 0, 10, 0},
   {1, 1, 0, 0},
 
   {1, 1, 0, 0},                        /* DBCC doesn't come BYTE */
-  {(32767), (-32768), 2, TAB (DBCC, LONG)},
-  {0, 0, 10, 0},               /* bra/jmp long space */
+  {(32767), (-32768), 2, TAB (DBCCABSJ, LONG)},
+  {0, 0, 10, 0},
   {1, 1, 0, 0},
 
-  {1, 1, 0, 0},                        /* PCLEA doesn't come BYTE */
-  {32767, -32768, 2, TAB (PCLEA, LONG)},
+  {1, 1, 0, 0},                        /* PCREL1632 doesn't come BYTE */
+  {32767, -32768, 2, TAB (PCREL1632, LONG)},
   {0, 0, 6, 0},
   {1, 1, 0, 0},
 
-  /* For, e.g., jmp pcrel indexed.  */
   {125, -130, 0, TAB (PCINDEX, SHORT)},
   {32765, -32770, 2, TAB (PCINDEX, LONG)},
   {0, 0, 4, 0},
   {1, 1, 0, 0},
+
+  {1, 1, 0, 0},                        /* ABSTOPCREL doesn't come BYTE */
+  {(32767), (-32768), 2, TAB (ABSTOPCREL, LONG)},
+  {0, 0, 4, 0},
+  {1, 1, 0, 0},
 };
 
 /* These are the machine dependent pseudo-ops.  These are included so
@@ -2064,7 +2098,7 @@ m68k_ip (instring)
                            {
                              add_frag (adds (&opP->disp),
                                        offs (&opP->disp),
-                                       TAB (PCLEA, SZ_UNDEF));
+                                       TAB (PCREL1632, SZ_UNDEF));
                              break;
                            }
                        }
@@ -2372,15 +2406,13 @@ m68k_ip (instring)
                         cannot be relaxed.  */
                      && opP->disp.pic_reloc == pic_none
 #endif
-                     && S_GET_SEGMENT (adds (&opP->disp)) == now_seg
-                     && relaxable_symbol (adds (&opP->disp))
                      && !flag_long_jumps
                      && !strchr ("~%&$?", s[0]))
                    {
                      tmpreg = 0x3A;    /* 7.2 */
                      add_frag (adds (&opP->disp),
                                offs (&opP->disp),
-                               TAB (PCREL, SZ_UNDEF));
+                               TAB (ABSTOPCREL, SZ_UNDEF));
                      break;
                    }
                  /* Fall through into long */
@@ -2512,9 +2544,9 @@ m68k_ip (instring)
              break;
            case 'L':
            long_branch:
-             if (!HAVE_LONG_BRANCH(current_architecture))
-               as_warn (_("Can't use long branches on 68000/68010/5200"));
-             the_ins.opcode[the_ins.numo - 1] |= 0xff;
+             if (! HAVE_LONG_BRANCH (current_architecture))
+               as_warn (_("Can't use long branches on 68000/68010/5200"));     
+             the_ins.opcode[0] |= 0xff;
              add_fix ('l', &opP->disp, 1, 0);
              addword (0);
              addword (0);
@@ -2529,37 +2561,66 @@ m68k_ip (instring)
              if (opP->disp.pic_reloc != pic_none)
                goto long_branch;
 #endif
-
              /* This could either be a symbol, or an absolute
-                address.  No matter, the frag hacking will finger it
-                out.  Not quite: it can't switch from BRANCH to
-                BCC68000 for the case where opnd is absolute (it
-                needs to use the 68000 hack since no conditional abs
-                jumps).  */
-             if (( !HAVE_LONG_BRANCH(current_architecture)
-                  || (0 == adds (&opP->disp)))
-                 && (the_ins.opcode[0] >= 0x6200)
-                 && (the_ins.opcode[0] <= 0x6f00))
+                address.  If it's an absolute address, turn it into
+                an absolute jump right here and keep it out of the
+                relaxer.  */
+             if (adds (&opP->disp) == 0)
+               {
+                 if (the_ins.opcode[0] == 0x6000)      /* jbra */
+                   the_ins.opcode[0] = 0x4EF1;
+                 else if (the_ins.opcode[0] == 0x6100) /* jbsr */
+                   the_ins.opcode[0] = 0x4EB1;
+                 else                                  /* jCC */
+                   {
+                     the_ins.opcode[0] ^= 0x0100;
+                     the_ins.opcode[0] |= 0x0006;
+                     addword (0x4EF1);
+                   }
+                 add_fix ('l', &opP->disp, 0, 0);
+                 addword (0);
+                 addword (0);
+                 break;
+               }
+
+             /* Now we know it's going into the relaxer.  Now figure
+                out which mode.  We try in this order of preference:
+                long branch, absolute jump, byte/word branches only.  */
+             if (HAVE_LONG_BRANCH (current_architecture))
                add_frag (adds (&opP->disp), offs (&opP->disp),
-                         TAB (BCC68000, SZ_UNDEF));
+                         TAB (BRANCHBWL, SZ_UNDEF));
+             else if (! flag_keep_pcrel)
+               {
+                 if ((the_ins.opcode[0] == 0x6000)
+                     || (the_ins.opcode[0] == 0x6100))
+                   add_frag (adds (&opP->disp), offs (&opP->disp),
+                             TAB (BRABSJUNC, SZ_UNDEF));
+                 else
+                   add_frag (adds (&opP->disp), offs (&opP->disp),
+                             TAB (BRABSJCOND, SZ_UNDEF));
+               }
              else
                add_frag (adds (&opP->disp), offs (&opP->disp),
-                         TAB (ABRANCH, SZ_UNDEF));
+                         TAB (BRANCHBW, SZ_UNDEF));
              break;
            case 'w':
              if (isvar (&opP->disp))
                {
-#if 1
-                 /* check for DBcc instruction */
-                 if ((the_ins.opcode[0] & 0xf0f8) == 0x50c8)
+                 /* Check for DBcc instructions.  We can relax them,
+                    but only if we have long branches and/or absolute
+                    jumps.  */
+                 if (((the_ins.opcode[0] & 0xf0f8) == 0x50c8)
+                     && (HAVE_LONG_BRANCH (current_architecture)
+                         || (! flag_keep_pcrel)))
                    {
-                     /* size varies if patch */
-                     /* needed for long form */
-                     add_frag (adds (&opP->disp), offs (&opP->disp),
-                               TAB (DBCC, SZ_UNDEF));
+                     if (HAVE_LONG_BRANCH (current_architecture))
+                       add_frag (adds (&opP->disp), offs (&opP->disp),
+                                 TAB (DBCCLBR, SZ_UNDEF));
+                     else
+                       add_frag (adds (&opP->disp), offs (&opP->disp),
+                                 TAB (DBCCABSJ, SZ_UNDEF));
                      break;
                    }
-#endif
                  add_fix ('w', &opP->disp, 1, 0);
                }
              addword (0);
@@ -2570,23 +2631,16 @@ m68k_ip (instring)
              addword (0);
              break;
            case 'c':           /* Var size Coprocesssor branches */
-             if (subs (&opP->disp))
+             if (subs (&opP->disp) || (adds (&opP->disp) == 0))
                {
-                 add_fix ('l', &opP->disp, 1, 0);
-                 add_frag ((symbolS *) 0, (offsetT) 0, TAB (FBRANCH, LONG));
-               }
-             else if (adds (&opP->disp))
-               add_frag (adds (&opP->disp), offs (&opP->disp),
-                         TAB (FBRANCH, SZ_UNDEF));
-             else
-               {
-                 /* add_frag ((symbolS *) 0, offs (&opP->disp),
-                              TAB(FBRANCH,SHORT)); */
                  the_ins.opcode[the_ins.numo - 1] |= 0x40;
                  add_fix ('l', &opP->disp, 1, 0);
                  addword (0);
                  addword (0);
                }
+             else
+               add_frag (adds (&opP->disp), offs (&opP->disp),
+                         TAB (FBRANCH, SZ_UNDEF));
              break;
            default:
              abort ();
@@ -4275,7 +4329,6 @@ md_convert_frag_1 (fragP)
      register fragS *fragP;
 {
   long disp;
-  long ext = 0;
   fixS *fixP;
 
   /* Address in object code of the displacement.  */
@@ -4298,76 +4351,59 @@ md_convert_frag_1 (fragP)
 
   switch (fragP->fr_subtype)
     {
-    case TAB (BCC68000, BYTE):
-    case TAB (ABRANCH, BYTE):
+    case TAB (BRANCHBWL, BYTE):
+    case TAB (BRABSJUNC, BYTE):
+    case TAB (BRABSJCOND, BYTE):
+    case TAB (BRANCHBW, BYTE):
       know (issbyte (disp));
       if (disp == 0)
        as_bad (_("short branch with zero offset: use :w"));
-      fragP->fr_opcode[1] = disp;
-      ext = 0;
-      break;
-    case TAB (DBCC, SHORT):
-      know (issword (disp));
-      ext = 2;
+      fixP = fix_new (fragP, fragP->fr_fix - 1, 1, fragP->fr_symbol,
+                     fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
+      fixP->fx_pcrel_adjust = -1;
       break;
-    case TAB (BCC68000, SHORT):
-    case TAB (ABRANCH, SHORT):
-      know (issword (disp));
+    case TAB (BRANCHBWL, SHORT):
+    case TAB (BRABSJUNC, SHORT):
+    case TAB (BRABSJCOND, SHORT):
+    case TAB (BRANCHBW, SHORT):
       fragP->fr_opcode[1] = 0x00;
-      ext = 2;
+      fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
+              1, BFD_RELOC_16_PCREL);
+      fragP->fr_fix += 2;
+      break;
+    case TAB (BRANCHBWL, LONG):
+      fragP->fr_opcode[1] = (char) 0xFF;
+      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
+              1, BFD_RELOC_32_PCREL);
+      fragP->fr_fix += 4;
       break;
-    case TAB (ABRANCH, LONG):
-      if (!HAVE_LONG_BRANCH (current_architecture))
+    case TAB (BRABSJUNC, LONG):
+      if (fragP->fr_opcode[0] == 0x61)         /* jbsr */
        {
-         if (flag_keep_pcrel)
-           as_bad (_("long branch not supported"));
-
-         if (fragP->fr_opcode[0] == 0x61)
-           /* BSR */
-           {
-             fragP->fr_opcode[0] = 0x4E;
-             fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */
-
-             fix_new (fragP,
-                      fragP->fr_fix,
-                      4,
-                      fragP->fr_symbol,
-                      fragP->fr_offset,
-                      0,
-                      NO_RELOC);
-
-             fragP->fr_fix += 4;
-             ext = 0;
-           }
-         /* BRA */
-         else if (fragP->fr_opcode[0] == 0x60)
-           {
-             fragP->fr_opcode[0] = 0x4E;
-             fragP->fr_opcode[1] = (char) 0xF9; /* JMP  with ABSL LONG offset */
-             fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-                      fragP->fr_offset, 0, NO_RELOC);
-             fragP->fr_fix += 4;
-             ext = 0;
-           }
-         else
-           {
-             /* This should never happen, because if it's a conditional
-                branch and we are on a 68000, BCC68000 should have been
-                picked instead of ABRANCH.  */
-             abort ();
-           }
+         fragP->fr_opcode[0] = 0x4E;
+         fragP->fr_opcode[1] = (char) 0xB9; /* JSR with ABSL LONG operand */
+         fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
+                  0, BFD_RELOC_32);
+         fragP->fr_fix += 4;
+       }
+      else if (fragP->fr_opcode[0] == 0x60)    /* jbra */
+       {
+         fragP->fr_opcode[0] = 0x4E;
+         fragP->fr_opcode[1] = (char) 0xF9; /* JMP with ABSL LONG operand */
+         fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
+                  0, BFD_RELOC_32);
+         fragP->fr_fix += 4;
        }
       else
        {
-         fragP->fr_opcode[1] = (char) 0xff;
-         ext = 4;
+         /* This cannot happen, because jbsr and jbra are the only two
+            unconditional branches.  */
+         abort ();
        }
       break;
-    case TAB (BCC68000, LONG):
-      /* only Bcc 68000 instructions can come here */
-      /* change bcc into b!cc/jmp absl long */
-      if (flag_keep_pcrel)
-       as_bad (_("long branch not supported"));
+    case TAB (BRABSJCOND, LONG):
+      /* Only Bcc 68000 instructions can come here.  */
+      /* Change bcc into b!cc/jmp absl long.  */
 
       fragP->fr_opcode[0] ^= 0x01;     /* invert bcc */
       fragP->fr_opcode[1] = 0x6;/* branch offset = 6 */
@@ -4379,125 +4415,120 @@ md_convert_frag_1 (fragP)
       *buffer_address++ = (char) 0xf9;
       fragP->fr_fix += 2;      /* account for jmp instruction */
       fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-              fragP->fr_offset, 0, NO_RELOC);
+              fragP->fr_offset, 0, BFD_RELOC_32);
       fragP->fr_fix += 4;
-      ext = 0;
       break;
-    case TAB (DBCC, LONG):
-      /* only DBcc 68000 instructions can come here */
+    case TAB (FBRANCH, SHORT):
+      know ((fragP->fr_opcode[1] & 0x40) == 0);
+      fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
+              1, BFD_RELOC_16_PCREL);
+      fragP->fr_fix += 2;
+      break;
+    case TAB (FBRANCH, LONG):
+      fragP->fr_opcode[1] |= 0x40;     /* Turn on LONG bit */
+      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
+              1, BFD_RELOC_32_PCREL);
+      fragP->fr_fix += 4;
+      break;
+    case TAB (DBCCLBR, SHORT):
+    case TAB (DBCCABSJ, SHORT):
+      fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
+              1, BFD_RELOC_16_PCREL);
+      fragP->fr_fix += 2;
+      break;
+    case TAB (DBCCLBR, LONG):
+      /* only DBcc instructions can come here */
       /* Change dbcc into dbcc/bral.  */
-      if (! HAVE_LONG_BRANCH (current_architecture) && flag_keep_pcrel)
-       as_bad (_("long branch not supported"));
 
       /* JF: these used to be fr_opcode[2-7], but that's wrong */
       *buffer_address++ = 0x00;        /* branch offset = 4 */
       *buffer_address++ = 0x04;
       *buffer_address++ = 0x60;        /* put in bra pc+6 */
       *buffer_address++ = 0x06;
-      if (HAVE_LONG_BRANCH (current_architecture))
-       {
-         *buffer_address++ = 0x60;     /* Put in bral (0x60ff).  */
-         *buffer_address++ = (char) 0xff;
-       }
-      else
-       {
-         *buffer_address++ = 0x4e;     /* Put in jmp long (0x4ef9).  */
-         *buffer_address++ = (char) 0xf9;
-       }
+      *buffer_address++ = 0x60;     /* Put in bral (0x60ff).  */
+      *buffer_address++ = (char) 0xff;
 
       fragP->fr_fix += 6;      /* account for bra/jmp instructions */
-      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-              fragP->fr_offset, HAVE_LONG_BRANCH (current_architecture),
-              NO_RELOC);
+      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 1,
+              BFD_RELOC_32_PCREL);
       fragP->fr_fix += 4;
-      ext = 0;
-      break;
-    case TAB (FBRANCH, SHORT):
-      know ((fragP->fr_opcode[1] & 0x40) == 0);
-      ext = 2;
       break;
-    case TAB (FBRANCH, LONG):
-      fragP->fr_opcode[1] |= 0x40;     /* Turn on LONG bit */
-      ext = 4;
-      break;
-    case TAB (PCREL, SHORT):
-      ext = 2;
-      break;
-    case TAB (PCREL, LONG):
-      /* The thing to do here is force it to ABSOLUTE LONG, since
-       PCREL is really trying to shorten an ABSOLUTE address anyway */
-      /* JF FOO This code has not been tested */
-      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
-              0, NO_RELOC);
-      if ((fragP->fr_opcode[1] & 0x3F) != 0x3A)
-       as_bad (_("Internal error (long PC-relative operand) for insn 0x%04x at 0x%lx"),
-               (unsigned) fragP->fr_opcode[0],
-               (unsigned long) fragP->fr_address);
-      fragP->fr_opcode[1] &= ~0x3F;
-      fragP->fr_opcode[1] |= 0x39;     /* Mode 7.1 */
+    case TAB (DBCCABSJ, LONG):
+      /* only DBcc instructions can come here */
+      /* Change dbcc into dbcc/jmp.  */
+
+      /* JF: these used to be fr_opcode[2-7], but that's wrong */
+      *buffer_address++ = 0x00;        /* branch offset = 4 */
+      *buffer_address++ = 0x04;
+      *buffer_address++ = 0x60;        /* put in bra pc+6 */
+      *buffer_address++ = 0x06;
+      *buffer_address++ = 0x4e;     /* Put in jmp long (0x4ef9).  */
+      *buffer_address++ = (char) 0xf9;
+
+      fragP->fr_fix += 6;      /* account for bra/jmp instructions */
+      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 0,
+              BFD_RELOC_32);
       fragP->fr_fix += 4;
-      ext = 0;
       break;
-    case TAB (PCLEA, SHORT):
-      fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
-              fragP->fr_offset, 1, NO_RELOC);
+    case TAB (PCREL1632, SHORT):
       fragP->fr_opcode[1] &= ~0x3F;
       fragP->fr_opcode[1] |= 0x3A; /* 072 - mode 7.2 */
-      ext = 2;
+      fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
+              fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_fix += 2;
       break;
-    case TAB (PCLEA, LONG):
-      fixP = fix_new (fragP, (int) (fragP->fr_fix) + 2, 4, fragP->fr_symbol,
-                     fragP->fr_offset, 1, NO_RELOC);
-      fixP->fx_pcrel_adjust = 2;
+    case TAB (PCREL1632, LONG):
       /* Already set to mode 7.3; this indicates: PC indirect with
         suppressed index, 32-bit displacement.  */
       *buffer_address++ = 0x01;
       *buffer_address++ = 0x70;
       fragP->fr_fix += 2;
-      ext = 4;
+      fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
+                     fragP->fr_offset, 1, BFD_RELOC_32_PCREL);
+      fixP->fx_pcrel_adjust = 2;
+      fragP->fr_fix += 4;
       break;
-
     case TAB (PCINDEX, BYTE):
-      disp += 2;
-      if (!issbyte (disp))
-       {
-         as_bad (_("displacement doesn't fit in one byte"));
-         disp = 0;
-       }
       assert (fragP->fr_fix >= 2);
       buffer_address[-2] &= ~1;
-      buffer_address[-1] = disp;
-      ext = 0;
+      fixP = fix_new (fragP, fragP->fr_fix - 1, 1, fragP->fr_symbol,
+                     fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
+      fixP->fx_pcrel_adjust = 1;
       break;
     case TAB (PCINDEX, SHORT):
-      disp += 2;
-      assert (issword (disp));
       assert (fragP->fr_fix >= 2);
       buffer_address[-2] |= 0x1;
       buffer_address[-1] = 0x20;
       fixP = fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
-                     fragP->fr_offset, (fragP->fr_opcode[1] & 077) == 073,
-                     NO_RELOC);
+                     fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
       fixP->fx_pcrel_adjust = 2;
-      ext = 2;
+      fragP->fr_fix += 2;
       break;
     case TAB (PCINDEX, LONG):
-      disp += 2;
-      fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
-                     fragP->fr_offset, (fragP->fr_opcode[1] & 077) == 073,
-                     NO_RELOC);
-      fixP->fx_pcrel_adjust = 2;
       assert (fragP->fr_fix >= 2);
       buffer_address[-2] |= 0x1;
       buffer_address[-1] = 0x30;
-      ext = 4;
+      fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
+                     fragP->fr_offset, 1, BFD_RELOC_32_PCREL);
+      fixP->fx_pcrel_adjust = 2;
+      fragP->fr_fix += 4;
+      break;
+    case TAB (ABSTOPCREL, SHORT):
+      fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
+              1, BFD_RELOC_16_PCREL);
+      fragP->fr_fix += 2;
+      break;
+    case TAB (ABSTOPCREL, LONG):
+      /* The thing to do here is force it to ABSOLUTE LONG, since
+        ABSTOPCREL is really trying to shorten an ABSOLUTE address anyway */
+      if ((fragP->fr_opcode[1] & 0x3F) != 0x3A)
+       abort ();
+      fragP->fr_opcode[1] &= ~0x3F;
+      fragP->fr_opcode[1] |= 0x39;     /* Mode 7.1 */
+      fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
+              0, BFD_RELOC_32);
+      fragP->fr_fix += 4;
       break;
-    }
-
-  if (ext)
-    {
-      md_number_to_chars (buffer_address, (long) disp, (int) ext);
-      fragP->fr_fix += ext;
     }
 }
 
@@ -4537,218 +4568,125 @@ md_estimate_size_before_relax (fragP, segment)
 
   old_fix = fragP->fr_fix;
 
-  /* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */
+  /* Handle SZ_UNDEF first, it can be changed to BYTE or SHORT.  */
   switch (fragP->fr_subtype)
     {
-
-    case TAB (ABRANCH, SZ_UNDEF):
+    case TAB (BRANCHBWL, SZ_UNDEF):
+    case TAB (BRABSJUNC, SZ_UNDEF):
       {
-       if ((fragP->fr_symbol != NULL)  /* Not absolute */
-           && S_GET_SEGMENT (fragP->fr_symbol) == segment
+       if (S_GET_SEGMENT (fragP->fr_symbol) == segment
            && relaxable_symbol (fragP->fr_symbol))
          {
            fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE);
-           break;
          }
-       else if ((fragP->fr_symbol != NULL)
-                && (flag_short_refs || flag_keep_pcrel))
-         {                     /* Symbol is undefined and we want short ref */
-           fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
-                    fragP->fr_offset, 1, NO_RELOC);
-           fragP->fr_fix += 2;
-           frag_wane (fragP);
-           break;
-         }
-       else if ((fragP->fr_symbol == 0) || !HAVE_LONG_BRANCH(current_architecture))
+       else if (flag_short_refs)
          {
-           /* On 68000, or for absolute value, switch to abs long */
-           /* FIXME, we should check abs val, pick short or long */
-           if (fragP->fr_opcode[0] == 0x61)
-             {
-               fragP->fr_opcode[0] = 0x4E;
-               fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */
-               fix_new (fragP, fragP->fr_fix, 4,
-                        fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
-               fragP->fr_fix += 4;
-               frag_wane (fragP);
-             }
-           else if (fragP->fr_opcode[0] == 0x60)
-             {
-               fragP->fr_opcode[0] = 0x4E;
-               fragP->fr_opcode[1] = (char) 0xF9; /* JMP  with ABSL LONG offset */
-               fix_new (fragP, fragP->fr_fix, 4,
-                        fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
-               fragP->fr_fix += 4;
-               frag_wane (fragP);
-             }
-           else
-             {
-               /* This should never happen, because if it's a conditional
-                  branch and we are on a 68000, BCC68000 should have been
-                  picked instead of ABRANCH.  */
-               abort ();
-             }
+           /* Symbol is undefined and we want short ref.  */
+           fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
+           fragP->fr_var += 2;
          }
        else
-         {                     /* Symbol is still undefined.  Make it simple */
-           fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
-                    fragP->fr_offset, 1, NO_RELOC);
-           fragP->fr_fix += 4;
-           fragP->fr_opcode[1] = (char) 0xff;
-           frag_wane (fragP);
-           break;
+         {
+           /* Symbol is still undefined.  Make it LONG.  */
+           fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), LONG);
+           fragP->fr_var += 4;
          }
-
        break;
-      }                                /* case TAB(ABRANCH,SZ_UNDEF) */
+      }
 
-    case TAB (FBRANCH, SZ_UNDEF):
+    case TAB (BRABSJCOND, SZ_UNDEF):
       {
-       if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
-            && relaxable_symbol (fragP->fr_symbol))
-           || flag_short_refs)
+       if (S_GET_SEGMENT (fragP->fr_symbol) == segment
+           && relaxable_symbol (fragP->fr_symbol))
          {
-           fragP->fr_subtype = TAB (FBRANCH, SHORT);
+           fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE);
+         }
+       else if (flag_short_refs)
+         {
+           /* Symbol is undefined and we want short ref.  */
+           fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
            fragP->fr_var += 2;
          }
        else
          {
-           fix_new (fragP, (int) fragP->fr_fix, 4, fragP->fr_symbol,
-                    fragP->fr_offset, 1, NO_RELOC);
-           fragP->fr_fix += 4;
-           fragP->fr_opcode[1] |= 0x40; /* Turn on LONG bit */
-           frag_wane (fragP);
+           /* Symbol is still undefined.  Make it LONG.  */
+           fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), LONG);
+           fragP->fr_var += 6;
          }
        break;
-      }                                /* TAB(FBRANCH,SZ_UNDEF) */
+      }
 
-    case TAB (PCREL, SZ_UNDEF):
+    case TAB (BRANCHBW, SZ_UNDEF):
       {
-       if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
-            && relaxable_symbol (fragP->fr_symbol))
-           || flag_short_refs)
+       if (S_GET_SEGMENT (fragP->fr_symbol) == segment
+           && relaxable_symbol (fragP->fr_symbol))
          {
-           fragP->fr_subtype = TAB (PCREL, SHORT);
-           fragP->fr_var += 2;
+           fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE);
          }
        else
          {
-           fragP->fr_subtype = TAB (PCREL, LONG);
-           fragP->fr_var += 4;
+           /* Symbol is undefined and we don't have long branches.  */
+           fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
+           fragP->fr_var += 2;
          }
        break;
-      }                                /* TAB(PCREL,SZ_UNDEF) */
+      }
 
-    case TAB (BCC68000, SZ_UNDEF):
+    case TAB (FBRANCH, SZ_UNDEF):
       {
-       if ((fragP->fr_symbol != NULL)
-           && S_GET_SEGMENT (fragP->fr_symbol) == segment
-           && relaxable_symbol (fragP->fr_symbol))
-         {
-           fragP->fr_subtype = TAB (BCC68000, BYTE);
-           break;
-         }
-       /* only Bcc 68000 instructions can come here */
-       if ((fragP->fr_symbol != NULL) && (flag_short_refs || flag_keep_pcrel))
+       if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
+            && relaxable_symbol (fragP->fr_symbol))
+           || flag_short_refs)
          {
-           /* the user wants short refs, so emit one */
-           fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
-                    fragP->fr_offset, 1, NO_RELOC);
-           fragP->fr_fix += 2;
+           fragP->fr_subtype = TAB (FBRANCH, SHORT);
+           fragP->fr_var += 2;
          }
        else
          {
-           /* change bcc into b!cc/jmp absl long */
-           fragP->fr_opcode[0] ^= 0x01;        /* invert bcc */
-           fragP->fr_opcode[1] = 0x06; /* branch offset = 6 */
-           /* JF: these were fr_opcode[2,3] */
-           buffer_address[0] = 0x4e;   /* put in jmp long (0x4ef9) */
-           buffer_address[1] = (char) 0xf9;
-           fragP->fr_fix += 2; /* account for jmp instruction */
-           fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-                    fragP->fr_offset, 0, NO_RELOC);
-           fragP->fr_fix += 4;
+           fragP->fr_subtype = TAB (FBRANCH, LONG);
+           fragP->fr_var += 4;
          }
-       frag_wane (fragP);
        break;
-      }                                /* case TAB(BCC68000,SZ_UNDEF) */
+      }
 
-    case TAB (DBCC, SZ_UNDEF):
+    case TAB (DBCCLBR, SZ_UNDEF):
+    case TAB (DBCCABSJ, SZ_UNDEF):
       {
-       if (fragP->fr_symbol != NULL
-           && S_GET_SEGMENT (fragP->fr_symbol) == segment
-           && relaxable_symbol (fragP->fr_symbol))
+       if (S_GET_SEGMENT (fragP->fr_symbol) == segment
+           && relaxable_symbol (fragP->fr_symbol)
+           || flag_short_refs)
          {
-           fragP->fr_subtype = TAB (DBCC, SHORT);
+           fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
            fragP->fr_var += 2;
-           break;
-         }
-       /* only DBcc 68000 instructions can come here */
-
-       if (fragP->fr_symbol != NULL
-           && (flag_short_refs
-               || (! HAVE_LONG_BRANCH (current_architecture)
-                   && flag_keep_pcrel)))
-         {
-           /* the user wants short refs, so emit one */
-           fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
-                    fragP->fr_offset, 1, NO_RELOC);
-           fragP->fr_fix += 2;
          }
        else
          {
-           /* Change dbcc into dbcc/bral.  */
-           /* JF: these used to be fr_opcode[2-4], which is wrong.  */
-           buffer_address[0] = 0x00;   /* branch offset = 4 */
-           buffer_address[1] = 0x04;
-           buffer_address[2] = 0x60;   /* put in bra pc + ...  */
-           /* JF: these were fr_opcode[5-7] */
-           buffer_address[3] = 0x06;   /* Plus 6 */
-           if (HAVE_LONG_BRANCH (current_architecture))
-             {
-               buffer_address[4] = 0x60;       /* Put in bral (0x60ff).  */
-               buffer_address[5] = (char) 0xff;
-             }
-           else
-             {
-               buffer_address[4] = 0x4e;       /* Put in jmp long (0x4ef9).  */
-               buffer_address[5] = (char) 0xf9;
-             }
-           fragP->fr_fix += 6; /* account for bra/jmp instruction */
-           fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-                    fragP->fr_offset, HAVE_LONG_BRANCH (current_architecture),
-                    NO_RELOC);
-           fragP->fr_fix += 4;
+           fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), LONG);
+           fragP->fr_var += 10;
          }
-
-       frag_wane (fragP);
        break;
-      }                                /* case TAB(DBCC,SZ_UNDEF) */
+      }
 
-    case TAB (PCLEA, SZ_UNDEF):
+    case TAB (PCREL1632, SZ_UNDEF):
       {
        if (((S_GET_SEGMENT (fragP->fr_symbol)) == segment
             && relaxable_symbol (fragP->fr_symbol))
-           || flag_short_refs
-           || cpu_of_arch (current_architecture) < m68020
-           || cpu_of_arch (current_architecture) == mcf5200)
+           || flag_short_refs)
          {
-           fragP->fr_subtype = TAB (PCLEA, SHORT);
+           fragP->fr_subtype = TAB (PCREL1632, SHORT);
            fragP->fr_var += 2;
          }
        else
          {
-           fragP->fr_subtype = TAB (PCLEA, LONG);
+           fragP->fr_subtype = TAB (PCREL1632, LONG);
            fragP->fr_var += 6;
          }
        break;
-      }                                /* TAB(PCLEA,SZ_UNDEF) */
-
+      }
+      
     case TAB (PCINDEX, SZ_UNDEF):
       if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
-          && relaxable_symbol (fragP->fr_symbol))
-         || cpu_of_arch (current_architecture) < m68020
-         || cpu_of_arch (current_architecture) == mcf5200)
+          && relaxable_symbol (fragP->fr_symbol)))
        {
          fragP->fr_subtype = TAB (PCINDEX, BYTE);
        }
@@ -4759,15 +4697,33 @@ md_estimate_size_before_relax (fragP, segment)
        }
       break;
 
+    case TAB (ABSTOPCREL, SZ_UNDEF):
+      {
+       if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
+            && relaxable_symbol (fragP->fr_symbol)))
+         {
+           fragP->fr_subtype = TAB (ABSTOPCREL, SHORT);
+           fragP->fr_var += 2;
+         }
+       else
+         {
+           fragP->fr_subtype = TAB (ABSTOPCREL, LONG);
+           fragP->fr_var += 4;
+         }
+       break;
+      }
+
     default:
       break;
     }
 
-  /* now that SZ_UNDEF are taken care of, check others */
+  /* Now that SZ_UNDEF are taken care of, check others.  */
   switch (fragP->fr_subtype)
     {
-    case TAB (BCC68000, BYTE):
-    case TAB (ABRANCH, BYTE):
+    case TAB (BRANCHBWL, BYTE):
+    case TAB (BRABSJUNC, BYTE):
+    case TAB (BRABSJCOND, BYTE):
+    case TAB (BRANCHBW, BYTE):
       /* We can't do a short jump to the next instruction, so in that
         case we force word mode.  At this point S_GET_VALUE should
         return the offset of the symbol within its frag.  If the