]> oss.titaniummirror.com Git - msp430-binutils.git/blobdiff - gas/config/tc-ppc.c
Merge commit 'upstream/2.20'
[msp430-binutils.git] / gas / config / tc-ppc.c
index f8405fcc331413d6e4a1e2a1d2ade538ce06e191..493bfe5546bd2a2b02663957955acd7ddfee0214 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
    Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GAS, the GNU Assembler.
@@ -178,6 +178,10 @@ const char ppc_symbol_chars[] = "%[";
 
 /* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
 int ppc_cie_data_alignment;
+
+/* The type of processor we are assembling for.  This is one or more
+   of the PPC_OPCODE flags defined in opcode/ppc.h.  */
+ppc_cpu_t ppc_cpu = 0;
 \f
 /* The target specific pseudo-ops which we support.  */
 
@@ -354,9 +358,42 @@ static const struct pd_reg pre_defined_registers[] =
   { "f.3", 3 },
   { "f.30", 30 },
   { "f.31", 31 },
+
+  { "f.32", 32 },    /* Extended floating point scalar registers (ISA 2.06).  */
+  { "f.33", 33 },
+  { "f.34", 34 },
+  { "f.35", 35 },
+  { "f.36", 36 },
+  { "f.37", 37 },
+  { "f.38", 38 },
+  { "f.39", 39 },
   { "f.4", 4 },
+  { "f.40", 40 },
+  { "f.41", 41 },
+  { "f.42", 42 },
+  { "f.43", 43 },
+  { "f.44", 44 },
+  { "f.45", 45 },
+  { "f.46", 46 },
+  { "f.47", 47 },
+  { "f.48", 48 },
+  { "f.49", 49 },
   { "f.5", 5 },
+  { "f.50", 50 },
+  { "f.51", 51 },
+  { "f.52", 52 },
+  { "f.53", 53 },
+  { "f.54", 54 },
+  { "f.55", 55 },
+  { "f.56", 56 },
+  { "f.57", 57 },
+  { "f.58", 58 },
+  { "f.59", 59 },
   { "f.6", 6 },
+  { "f.60", 60 },
+  { "f.61", 61 },
+  { "f.62", 62 },
+  { "f.63", 63 },
   { "f.7", 7 },
   { "f.8", 8 },
   { "f.9", 9 },
@@ -387,15 +424,66 @@ static const struct pd_reg pre_defined_registers[] =
   { "f3", 3 },
   { "f30", 30 },
   { "f31", 31 },
+
+  { "f32", 32 },    /* Extended floating point scalar registers (ISA 2.06).  */
+  { "f33", 33 },
+  { "f34", 34 },
+  { "f35", 35 },
+  { "f36", 36 },
+  { "f37", 37 },
+  { "f38", 38 },
+  { "f39", 39 },
   { "f4", 4 },
+  { "f40", 40 },
+  { "f41", 41 },
+  { "f42", 42 },
+  { "f43", 43 },
+  { "f44", 44 },
+  { "f45", 45 },
+  { "f46", 46 },
+  { "f47", 47 },
+  { "f48", 48 },
+  { "f49", 49 },
   { "f5", 5 },
+  { "f50", 50 },
+  { "f51", 51 },
+  { "f52", 52 },
+  { "f53", 53 },
+  { "f54", 54 },
+  { "f55", 55 },
+  { "f56", 56 },
+  { "f57", 57 },
+  { "f58", 58 },
+  { "f59", 59 },
   { "f6", 6 },
+  { "f60", 60 },
+  { "f61", 61 },
+  { "f62", 62 },
+  { "f63", 63 },
   { "f7", 7 },
   { "f8", 8 },
   { "f9", 9 },
 
   { "fpscr", 0 },
 
+  /* Quantization registers used with pair single instructions.  */
+  { "gqr.0", 0 },
+  { "gqr.1", 1 },
+  { "gqr.2", 2 },
+  { "gqr.3", 3 },
+  { "gqr.4", 4 },
+  { "gqr.5", 5 },
+  { "gqr.6", 6 },
+  { "gqr.7", 7 },
+  { "gqr0", 0 },
+  { "gqr1", 1 },
+  { "gqr2", 2 },
+  { "gqr3", 3 },
+  { "gqr4", 4 },
+  { "gqr5", 5 },
+  { "gqr6", 6 },
+  { "gqr7", 7 },
+
   { "lr", 8 },     /* Link Register */
 
   { "pmr", 0 },
@@ -479,7 +567,7 @@ static const struct pd_reg pre_defined_registers[] =
   { "srr0", 26 }, /* Machine Status Save/Restore Register 0 */
   { "srr1", 27 }, /* Machine Status Save/Restore Register 1 */
 
-  { "v.0", 0 },     /* Vector registers */
+  { "v.0", 0 },     /* Vector (Altivec/VMX) registers */
   { "v.1", 1 },
   { "v.10", 10 },
   { "v.11", 11 },
@@ -545,6 +633,136 @@ static const struct pd_reg pre_defined_registers[] =
   { "v8", 8 },
   { "v9", 9 },
 
+  { "vs.0", 0 },     /* Vector Scalar (VSX) registers (ISA 2.06).  */
+  { "vs.1", 1 },
+  { "vs.10", 10 },
+  { "vs.11", 11 },
+  { "vs.12", 12 },
+  { "vs.13", 13 },
+  { "vs.14", 14 },
+  { "vs.15", 15 },
+  { "vs.16", 16 },
+  { "vs.17", 17 },
+  { "vs.18", 18 },
+  { "vs.19", 19 },
+  { "vs.2", 2 },
+  { "vs.20", 20 },
+  { "vs.21", 21 },
+  { "vs.22", 22 },
+  { "vs.23", 23 },
+  { "vs.24", 24 },
+  { "vs.25", 25 },
+  { "vs.26", 26 },
+  { "vs.27", 27 },
+  { "vs.28", 28 },
+  { "vs.29", 29 },
+  { "vs.3", 3 },
+  { "vs.30", 30 },
+  { "vs.31", 31 },
+  { "vs.32", 32 },
+  { "vs.33", 33 },
+  { "vs.34", 34 },
+  { "vs.35", 35 },
+  { "vs.36", 36 },
+  { "vs.37", 37 },
+  { "vs.38", 38 },
+  { "vs.39", 39 },
+  { "vs.4", 4 },
+  { "vs.40", 40 },
+  { "vs.41", 41 },
+  { "vs.42", 42 },
+  { "vs.43", 43 },
+  { "vs.44", 44 },
+  { "vs.45", 45 },
+  { "vs.46", 46 },
+  { "vs.47", 47 },
+  { "vs.48", 48 },
+  { "vs.49", 49 },
+  { "vs.5", 5 },
+  { "vs.50", 50 },
+  { "vs.51", 51 },
+  { "vs.52", 52 },
+  { "vs.53", 53 },
+  { "vs.54", 54 },
+  { "vs.55", 55 },
+  { "vs.56", 56 },
+  { "vs.57", 57 },
+  { "vs.58", 58 },
+  { "vs.59", 59 },
+  { "vs.6", 6 },
+  { "vs.60", 60 },
+  { "vs.61", 61 },
+  { "vs.62", 62 },
+  { "vs.63", 63 },
+  { "vs.7", 7 },
+  { "vs.8", 8 },
+  { "vs.9", 9 },
+
+  { "vs0", 0 },
+  { "vs1", 1 },
+  { "vs10", 10 },
+  { "vs11", 11 },
+  { "vs12", 12 },
+  { "vs13", 13 },
+  { "vs14", 14 },
+  { "vs15", 15 },
+  { "vs16", 16 },
+  { "vs17", 17 },
+  { "vs18", 18 },
+  { "vs19", 19 },
+  { "vs2", 2 },
+  { "vs20", 20 },
+  { "vs21", 21 },
+  { "vs22", 22 },
+  { "vs23", 23 },
+  { "vs24", 24 },
+  { "vs25", 25 },
+  { "vs26", 26 },
+  { "vs27", 27 },
+  { "vs28", 28 },
+  { "vs29", 29 },
+  { "vs3", 3 },
+  { "vs30", 30 },
+  { "vs31", 31 },
+  { "vs32", 32 },
+  { "vs33", 33 },
+  { "vs34", 34 },
+  { "vs35", 35 },
+  { "vs36", 36 },
+  { "vs37", 37 },
+  { "vs38", 38 },
+  { "vs39", 39 },
+  { "vs4", 4 },
+  { "vs40", 40 },
+  { "vs41", 41 },
+  { "vs42", 42 },
+  { "vs43", 43 },
+  { "vs44", 44 },
+  { "vs45", 45 },
+  { "vs46", 46 },
+  { "vs47", 47 },
+  { "vs48", 48 },
+  { "vs49", 49 },
+  { "vs5", 5 },
+  { "vs50", 50 },
+  { "vs51", 51 },
+  { "vs52", 52 },
+  { "vs53", 53 },
+  { "vs54", 54 },
+  { "vs55", 55 },
+  { "vs56", 56 },
+  { "vs57", 57 },
+  { "vs58", 58 },
+  { "vs59", 59 },
+  { "vs6", 6 },
+  { "vs60", 60 },
+  { "vs61", 61 },
+  { "vs62", 62 },
+  { "vs63", 63 },
+  { "vs7", 7 },
+  { "vs8", 8 },
+  { "vs9", 9 },
+
   { "xer", 1 },
 
 };
@@ -666,6 +884,8 @@ ppc_parse_name (const char *name, expressionS *expr)
   if (! cr_operand)
     return 0;
 
+  if (*name == '%')
+    ++name;
   val = reg_name_search (cr_names, sizeof cr_names / sizeof cr_names[0],
                         name);
   if (val < 0)
@@ -679,10 +899,6 @@ ppc_parse_name (const char *name, expressionS *expr)
 \f
 /* Local variables.  */
 
-/* The type of processor we are assembling for.  This is one or more
-   of the PPC_OPCODE flags defined in opcode/ppc.h.  */
-static unsigned long ppc_cpu = 0;
-
 /* Whether to target xcoff64/elf64.  */
 static unsigned int ppc_obj64 = BFD_DEFAULT_TARGET_SIZE == 64;
 
@@ -799,131 +1015,11 @@ const struct option md_longopts[] = {
 };
 const size_t md_longopts_size = sizeof (md_longopts);
 
-
-/* Handle -m options that set cpu type, and .machine arg.  */
-
-static int
-parse_cpu (const char *arg)
-{
-  /* -mpwrx and -mpwr2 mean to assemble for the IBM POWER/2
-     (RIOS2).  */
-  if (strcmp (arg, "pwrx") == 0 || strcmp (arg, "pwr2") == 0)
-    ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_32;
-  /* -mpwr means to assemble for the IBM POWER (RIOS1).  */
-  else if (strcmp (arg, "pwr") == 0)
-    ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_32;
-  /* -m601 means to assemble for the PowerPC 601, which includes
-     instructions that are holdovers from the Power.  */
-  else if (strcmp (arg, "601") == 0)
-    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-              | PPC_OPCODE_601 | PPC_OPCODE_32);
-  /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the
-     PowerPC 603/604.  */
-  else if (strcmp (arg, "ppc") == 0
-          || strcmp (arg, "ppc32") == 0
-          || strcmp (arg, "603") == 0
-          || strcmp (arg, "604") == 0)
-    ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
-  /* -m403 and -m405 mean to assemble for the PowerPC 403/405.  */
-  else if (strcmp (arg, "403") == 0
-          || strcmp (arg, "405") == 0)
-    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-              | PPC_OPCODE_403 | PPC_OPCODE_32);
-  else if (strcmp (arg, "440") == 0)
-    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32
-              | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI);
-  else if (strcmp (arg, "7400") == 0
-          || strcmp (arg, "7410") == 0
-          || strcmp (arg, "7450") == 0
-          || strcmp (arg, "7455") == 0)
-    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-              | PPC_OPCODE_ALTIVEC | PPC_OPCODE_32);
-  else if (strcmp (arg, "e300") == 0)
-    ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32
-              | PPC_OPCODE_E300);
-  else if (strcmp (arg, "altivec") == 0)
-    {
-      if (ppc_cpu == 0)
-       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ALTIVEC;
-      else
-       ppc_cpu |= PPC_OPCODE_ALTIVEC;
-    }
-  else if (strcmp (arg, "e500") == 0 || strcmp (arg, "e500x2") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE
-                | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
-                | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
-                | PPC_OPCODE_RFMCI);
-    }
-  else if (strcmp (arg, "spe") == 0)
-    {
-      if (ppc_cpu == 0)
-       ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_SPE | PPC_OPCODE_EFS;
-      else
-       ppc_cpu |= PPC_OPCODE_SPE;
-    }
-  /* -mppc64 and -m620 mean to assemble for the 64-bit PowerPC
-     620.  */
-  else if (strcmp (arg, "ppc64") == 0 || strcmp (arg, "620") == 0)
-    {
-      ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
-    }
-  else if (strcmp (arg, "ppc64bridge") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                | PPC_OPCODE_64_BRIDGE | PPC_OPCODE_64);
-    }
-  /* -mbooke/-mbooke32 mean enable 32-bit BookE support.  */
-  else if (strcmp (arg, "booke") == 0 || strcmp (arg, "booke32") == 0)
-    {
-      ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32;
-    }
-  /* -mbooke64 means enable 64-bit BookE support.  */
-  else if (strcmp (arg, "booke64") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE
-                | PPC_OPCODE_BOOKE64 | PPC_OPCODE_64);
-    }
-  else if (strcmp (arg, "power4") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                | PPC_OPCODE_64 | PPC_OPCODE_POWER4);
-    }
-  else if (strcmp (arg, "power5") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                | PPC_OPCODE_64 | PPC_OPCODE_POWER4
-                | PPC_OPCODE_POWER5);
-    }
-  else if (strcmp (arg, "power6") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                | PPC_OPCODE_64 | PPC_OPCODE_POWER4
-                | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6);
-    }
-  else if (strcmp (arg, "cell") == 0)
-    {
-      ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
-                | PPC_OPCODE_64 | PPC_OPCODE_POWER4
-                | PPC_OPCODE_CELL);
-    }
-  /* -mcom means assemble for the common intersection between Power
-     and PowerPC.  At present, we just allow the union, rather
-     than the intersection.  */
-  else if (strcmp (arg, "com") == 0)
-    ppc_cpu = PPC_OPCODE_COMMON | PPC_OPCODE_32;
-  /* -many means to assemble for any architecture (PWR/PWRX/PPC).  */
-  else if (strcmp (arg, "any") == 0)
-    ppc_cpu |= PPC_OPCODE_ANY;
-  else
-    return 0;
-
-  return 1;
-}
-
 int
 md_parse_option (int c, char *arg)
 {
+  ppc_cpu_t new_cpu;
+
   switch (c)
     {
     case 'u':
@@ -986,8 +1082,8 @@ md_parse_option (int c, char *arg)
       break;
 
     case 'm':
-      if (parse_cpu (arg))
-       ;
+      if ((new_cpu = ppc_parse_cpu (ppc_cpu, arg)) != 0)
+       ppc_cpu = new_cpu;
 
       else if (strcmp (arg, "regnames") == 0)
        reg_names_p = TRUE;
@@ -1088,25 +1184,32 @@ PowerPC options:\n\
 -m601                  generate code for PowerPC 601\n\
 -mppc, -mppc32, -m603, -m604\n\
                        generate code for PowerPC 603/604\n\
--m403, -m405           generate code for PowerPC 403/405\n\
+-m403                  generate code for PowerPC 403\n\
+-m405                  generate code for PowerPC 405\n\
 -m440                  generate code for PowerPC 440\n\
+-m464                  generate code for PowerPC 464\n\
+-m476                  generate code for PowerPC 476\n\
 -m7400, -m7410, -m7450, -m7455\n\
-                       generate code For PowerPC 7400/7410/7450/7455\n"));
+                       generate code for PowerPC 7400/7410/7450/7455\n\
+-m750cl                        generate code for PowerPC 750cl\n"));
   fprintf (stream, _("\
 -mppc64, -m620         generate code for PowerPC 620/625/630\n\
 -mppc64bridge          generate code for PowerPC 64, including bridge insns\n\
--mbooke64              generate code for 64-bit PowerPC BookE\n\
--mbooke, mbooke32      generate code for 32-bit PowerPC BookE\n\
+-mbooke                        generate code for 32-bit PowerPC BookE\n\
+-ma2                   generate code for A2 architecture\n\
 -mpower4               generate code for Power4 architecture\n\
 -mpower5               generate code for Power5 architecture\n\
 -mpower6               generate code for Power6 architecture\n\
+-mpower7               generate code for Power7 architecture\n\
 -mcell                 generate code for Cell Broadband Engine architecture\n\
 -mcom                  generate code Power/PowerPC common instructions\n\
 -many                  generate code for any architecture (PWR/PWRX/PPC)\n"));
   fprintf (stream, _("\
 -maltivec              generate code for AltiVec\n\
+-mvsx                  generate code for Vector-Scalar (VSX) instructions\n\
 -me300                 generate code for PowerPC e300 family\n\
 -me500, -me500x2       generate code for Motorola e500 core complex\n\
+-me500mc,               generate code for Freescale e500mc core complex\n\
 -mspe                  generate code for Motorola SPE instructions\n\
 -mregnames             Allow symbolic names for registers\n\
 -mno-regnames          Do not allow symbolic names for registers\n"));
@@ -1275,6 +1378,55 @@ ppc_setup_opcodes (void)
          const unsigned char *o;
          unsigned long omask = op->mask;
 
+         if (op != powerpc_opcodes)
+           {
+             /* The major opcodes had better be sorted.  Code in the
+                disassembler assumes the insns are sorted according to
+                major opcode.  */
+             if (PPC_OP (op[0].opcode) < PPC_OP (op[-1].opcode))
+               {
+                 as_bad (_("major opcode is not sorted for %s"),
+                         op->name);
+                 bad_insn = TRUE;
+               }
+
+             /* Warn if the table isn't more strictly ordered.
+                Unfortunately it doesn't seem possible to order the
+                table on much more than the major opcode, which makes
+                it difficult to implement a binary search in the
+                disassembler.  The problem is that we have multiple
+                ways to disassemble instructions, and we usually want
+                to choose a more specific form (with more bits set in
+                the opcode) than a more general form.  eg. all of the
+                following are equivalent:
+                bne label      # opcode = 0x40820000, mask = 0xff830003
+                bf  2,label    # opcode = 0x40800000, mask = 0xff800003
+                bc  4,2,label  # opcode = 0x40000000, mask = 0xfc000003
+
+                There are also cases where the table needs to be out
+                of order to disassemble the correct instruction for
+                processor variants.  */
+             else if (0)
+               {
+                 unsigned long t1 = op[0].opcode;
+                 unsigned long t2 = op[-1].opcode;
+
+                 if (((t1 ^ t2) & 0xfc0007ff) == 0
+                     && (t1 & 0xfc0006df) == 0x7c000286)
+                   {
+                     /* spr field is split.  */
+                     t1 = ((t1 & ~0x1ff800)
+                           | ((t1 & 0xf800) << 5) | ((t1 & 0x1f0000) >> 5));
+                     t2 = ((t2 & ~0x1ff800)
+                           | ((t2 & 0xf800) << 5) | ((t2 & 0x1f0000) >> 5));
+                   }
+                 if (t1 < t2)
+                   as_warn (_("%s (%08lx %08lx) after %s (%08lx %08lx)"),
+                            op[0].name, op[0].opcode, op[0].mask,
+                            op[-1].name, op[-1].opcode, op[-1].mask);
+               }
+           }
+
          /* The mask had better not trim off opcode bits.  */
          if ((op->opcode & omask) != op->opcode)
            {
@@ -1313,23 +1465,7 @@ ppc_setup_opcodes (void)
              || ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64))
                  == (ppc_cpu & (PPC_OPCODE_32 | PPC_OPCODE_64)))
              || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0)
-         /* Certain instructions (eg: extsw) do not exist in the
-            32-bit BookE instruction set, but they do exist in the
-            64-bit BookE instruction set, and other PPC instruction
-            sets.  Check to see if the opcode has the BOOKE64 flag set.
-            If it does make sure that the target CPU is not the BookE32.  */
-         && ((op->flags & PPC_OPCODE_BOOKE64) == 0
-             || (ppc_cpu & PPC_OPCODE_BOOKE64) == PPC_OPCODE_BOOKE64
-             || (ppc_cpu & PPC_OPCODE_BOOKE) == 0)
-         && ((op->flags & (PPC_OPCODE_POWER4 | PPC_OPCODE_NOPOWER4)) == 0
-             || ((op->flags & PPC_OPCODE_POWER4)
-                 == (ppc_cpu & PPC_OPCODE_POWER4)))
-         && ((op->flags & PPC_OPCODE_POWER5) == 0
-             || ((op->flags & PPC_OPCODE_POWER5)
-                 == (ppc_cpu & PPC_OPCODE_POWER5)))
-         && ((op->flags & PPC_OPCODE_POWER6) == 0
-             || ((op->flags & PPC_OPCODE_POWER6)
-                 == (ppc_cpu & PPC_OPCODE_POWER6))))
+         && !(ppc_cpu & op->deprecated))
        {
          const char *retval;
 
@@ -1488,6 +1624,7 @@ static unsigned long
 ppc_insert_operand (unsigned long insn,
                    const struct powerpc_operand *operand,
                    offsetT val,
+                   ppc_cpu_t ppc_cpu,
                    char *file,
                    unsigned int line)
 {
@@ -1548,7 +1685,7 @@ ppc_insert_operand (unsigned long insn,
       errmsg = NULL;
       insn = (*operand->insert) (insn, (long) val, ppc_cpu, &errmsg);
       if (errmsg != (const char *) NULL)
-       as_bad_where (file, line, errmsg);
+       as_bad_where (file, line, "%s", errmsg);
     }
   else
     insn |= ((long) val & operand->bitm) << operand->shift;
@@ -1693,13 +1830,38 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p)
       {
        int reloc = ptr->reloc;
 
-       if (!ppc_obj64)
-         if (exp_p->X_add_number != 0
-             && (reloc == (int) BFD_RELOC_16_GOTOFF
-                 || reloc == (int) BFD_RELOC_LO16_GOTOFF
-                 || reloc == (int) BFD_RELOC_HI16_GOTOFF
-                 || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
-           as_warn (_("identifier+constant@got means identifier@got+constant"));
+       if (!ppc_obj64 && exp_p->X_add_number != 0)
+         {
+           switch (reloc)
+             {
+             case BFD_RELOC_16_GOTOFF:
+             case BFD_RELOC_LO16_GOTOFF:
+             case BFD_RELOC_HI16_GOTOFF:
+             case BFD_RELOC_HI16_S_GOTOFF:
+               as_warn (_("identifier+constant@got means "
+                          "identifier@got+constant"));
+               break;
+
+             case BFD_RELOC_PPC_GOT_TLSGD16:
+             case BFD_RELOC_PPC_GOT_TLSGD16_LO:
+             case BFD_RELOC_PPC_GOT_TLSGD16_HI:
+             case BFD_RELOC_PPC_GOT_TLSGD16_HA:
+             case BFD_RELOC_PPC_GOT_TLSLD16:
+             case BFD_RELOC_PPC_GOT_TLSLD16_LO:
+             case BFD_RELOC_PPC_GOT_TLSLD16_HI:
+             case BFD_RELOC_PPC_GOT_TLSLD16_HA:
+             case BFD_RELOC_PPC_GOT_DTPREL16:
+             case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+             case BFD_RELOC_PPC_GOT_DTPREL16_HI:
+             case BFD_RELOC_PPC_GOT_DTPREL16_HA:
+             case BFD_RELOC_PPC_GOT_TPREL16:
+             case BFD_RELOC_PPC_GOT_TPREL16_LO:
+             case BFD_RELOC_PPC_GOT_TPREL16_HI:
+             case BFD_RELOC_PPC_GOT_TPREL16_HA:
+               as_bad (_("symbol+offset not supported for got tls"));
+               break;
+             }
+         }
 
        /* Now check for identifier@suffix+constant.  */
        if (*str == '-' || *str == '+')
@@ -2279,7 +2441,7 @@ md_assemble (char *str)
        {
          insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg);
          if (errmsg != (const char *) NULL)
-           as_bad (errmsg);
+           as_bad ("%s", errmsg);
          continue;
        }
 
@@ -2292,7 +2454,7 @@ md_assemble (char *str)
            {
              insn = (*operand->insert) (insn, 0L, ppc_cpu, &errmsg);
              if (errmsg != (const char *) NULL)
-               as_bad (errmsg);
+               as_bad ("%s", errmsg);
            }
          if ((operand->flags & PPC_OPERAND_NEXT) != 0)
            next_opindex = *opindex_ptr + 1;
@@ -2367,7 +2529,7 @@ md_assemble (char *str)
                 explain.  */
              if (ex.X_op == O_symbol)
                {
-                 assert (ex.X_add_symbol != NULL);
+                 gas_assert (ex.X_add_symbol != NULL);
                  if (symbol_get_bfdsym (ex.X_add_symbol)->section
                      != tocdata_section)
                    {
@@ -2418,12 +2580,19 @@ md_assemble (char *str)
       else
 #endif         /* TE_PE */
        {
-         if (! register_name (&ex))
+         if ((reg_names_p && (operand->flags & PPC_OPERAND_CR) != 0)
+             || !register_name (&ex))
            {
+             char save_lex = lex_type['%'];
+
              if ((operand->flags & PPC_OPERAND_CR) != 0)
-               cr_operand = TRUE;
+               {
+                 cr_operand = TRUE;
+                 lex_type['%'] |= LEX_BEGIN_NAME;
+               }
              expression (&ex);
              cr_operand = FALSE;
+             lex_type['%'] = save_lex;
            }
        }
 
@@ -2437,7 +2606,7 @@ md_assemble (char *str)
       else if (ex.X_op == O_register)
        {
          insn = ppc_insert_operand (insn, operand, ex.X_add_number,
-                                    (char *) NULL, 0);
+                                    ppc_cpu, (char *) NULL, 0);
        }
       else if (ex.X_op == O_constant)
        {
@@ -2506,124 +2675,171 @@ md_assemble (char *str)
              }
 #endif /* OBJ_ELF */
          insn = ppc_insert_operand (insn, operand, ex.X_add_number,
-                                    (char *) NULL, 0);
+                                    ppc_cpu, (char *) NULL, 0);
        }
 #ifdef OBJ_ELF
-      else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
+      else
        {
-         /* Some TLS tweaks.  */
-         switch (reloc)
+         if (ex.X_op == O_symbol && str[0] == '(')
            {
-           default:
-             break;
-           case BFD_RELOC_PPC_TLS:
-             insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
-                                        (char *) NULL, 0);
-             break;
-         /* We'll only use the 32 (or 64) bit form of these relocations
-            in constants.  Instructions get the 16 bit form.  */
-           case BFD_RELOC_PPC_DTPREL:
-             reloc = BFD_RELOC_PPC_DTPREL16;
-             break;
-           case BFD_RELOC_PPC_TPREL:
-             reloc = BFD_RELOC_PPC_TPREL16;
-             break;
-           }
+             const char *sym_name = S_GET_NAME (ex.X_add_symbol);
+             if (sym_name[0] == '.')
+               ++sym_name;
 
-         /* For the absolute forms of branches, convert the PC
-            relative form back into the absolute.  */
-         if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
-           {
-             switch (reloc)
+             if (strcasecmp (sym_name, "__tls_get_addr") == 0)
                {
-               case BFD_RELOC_PPC_B26:
-                 reloc = BFD_RELOC_PPC_BA26;
-                 break;
-               case BFD_RELOC_PPC_B16:
-                 reloc = BFD_RELOC_PPC_BA16;
-                 break;
-               case BFD_RELOC_PPC_B16_BRTAKEN:
-                 reloc = BFD_RELOC_PPC_BA16_BRTAKEN;
-                 break;
-               case BFD_RELOC_PPC_B16_BRNTAKEN:
-                 reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;
-                 break;
-               default:
-                 break;
+                 expressionS tls_exp;
+
+                 hold = input_line_pointer;
+                 input_line_pointer = str + 1;
+                 expression (&tls_exp);
+                 if (tls_exp.X_op == O_symbol)
+                   {
+                     reloc = BFD_RELOC_UNUSED;
+                     if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0)
+                       {
+                         reloc = BFD_RELOC_PPC_TLSGD;
+                         input_line_pointer += 7;
+                       }
+                     else if (strncasecmp (input_line_pointer, "@tlsld)", 7) == 0)
+                       {
+                         reloc = BFD_RELOC_PPC_TLSLD;
+                         input_line_pointer += 7;
+                       }
+                     if (reloc != BFD_RELOC_UNUSED)
+                       {
+                         SKIP_WHITESPACE ();
+                         str = input_line_pointer;
+
+                         if (fc >= MAX_INSN_FIXUPS)
+                           as_fatal (_("too many fixups"));
+                         fixups[fc].exp = tls_exp;
+                         fixups[fc].opindex = *opindex_ptr;
+                         fixups[fc].reloc = reloc;
+                         ++fc;
+                       }
+                   }
+                 input_line_pointer = hold;
                }
            }
 
-         if (ppc_obj64
-             && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
+         if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
            {
+             /* Some TLS tweaks.  */
              switch (reloc)
                {
-               case BFD_RELOC_16:
-                 reloc = BFD_RELOC_PPC64_ADDR16_DS;
-                 break;
-               case BFD_RELOC_LO16:
-                 reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
-                 break;
-               case BFD_RELOC_16_GOTOFF:
-                 reloc = BFD_RELOC_PPC64_GOT16_DS;
-                 break;
-               case BFD_RELOC_LO16_GOTOFF:
-                 reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
-                 break;
-               case BFD_RELOC_LO16_PLTOFF:
-                 reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
-                 break;
-               case BFD_RELOC_16_BASEREL:
-                 reloc = BFD_RELOC_PPC64_SECTOFF_DS;
-                 break;
-               case BFD_RELOC_LO16_BASEREL:
-                 reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
-                 break;
-               case BFD_RELOC_PPC_TOC16:
-                 reloc = BFD_RELOC_PPC64_TOC16_DS;
-                 break;
-               case BFD_RELOC_PPC64_TOC16_LO:
-                 reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
-                 break;
-               case BFD_RELOC_PPC64_PLTGOT16:
-                 reloc = BFD_RELOC_PPC64_PLTGOT16_DS;
-                 break;
-               case BFD_RELOC_PPC64_PLTGOT16_LO:
-                 reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
-                 break;
-               case BFD_RELOC_PPC_DTPREL16:
-                 reloc = BFD_RELOC_PPC64_DTPREL16_DS;
-                 break;
-               case BFD_RELOC_PPC_DTPREL16_LO:
-                 reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
-                 break;
-               case BFD_RELOC_PPC_TPREL16:
-                 reloc = BFD_RELOC_PPC64_TPREL16_DS;
+               default:
                  break;
-               case BFD_RELOC_PPC_TPREL16_LO:
-                 reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
+
+               case BFD_RELOC_PPC_TLS:
+                 insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
+                                            ppc_cpu, (char *) NULL, 0);
                  break;
-               case BFD_RELOC_PPC_GOT_DTPREL16:
-               case BFD_RELOC_PPC_GOT_DTPREL16_LO:
-               case BFD_RELOC_PPC_GOT_TPREL16:
-               case BFD_RELOC_PPC_GOT_TPREL16_LO:
+
+                 /* We'll only use the 32 (or 64) bit form of these relocations
+                    in constants.  Instructions get the 16 bit form.  */
+               case BFD_RELOC_PPC_DTPREL:
+                 reloc = BFD_RELOC_PPC_DTPREL16;
                  break;
-               default:
-                 as_bad (_("unsupported relocation for DS offset field"));
+               case BFD_RELOC_PPC_TPREL:
+                 reloc = BFD_RELOC_PPC_TPREL16;
                  break;
                }
+
+             /* For the absolute forms of branches, convert the PC
+                relative form back into the absolute.  */
+             if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
+               {
+                 switch (reloc)
+                   {
+                   case BFD_RELOC_PPC_B26:
+                     reloc = BFD_RELOC_PPC_BA26;
+                     break;
+                   case BFD_RELOC_PPC_B16:
+                     reloc = BFD_RELOC_PPC_BA16;
+                     break;
+                   case BFD_RELOC_PPC_B16_BRTAKEN:
+                     reloc = BFD_RELOC_PPC_BA16_BRTAKEN;
+                     break;
+                   case BFD_RELOC_PPC_B16_BRNTAKEN:
+                     reloc = BFD_RELOC_PPC_BA16_BRNTAKEN;
+                     break;
+                   default:
+                     break;
+                   }
+               }
+
+             if (ppc_obj64
+                 && (operand->flags & (PPC_OPERAND_DS | PPC_OPERAND_DQ)) != 0)
+               {
+                 switch (reloc)
+                   {
+                   case BFD_RELOC_16:
+                     reloc = BFD_RELOC_PPC64_ADDR16_DS;
+                     break;
+                   case BFD_RELOC_LO16:
+                     reloc = BFD_RELOC_PPC64_ADDR16_LO_DS;
+                     break;
+                   case BFD_RELOC_16_GOTOFF:
+                     reloc = BFD_RELOC_PPC64_GOT16_DS;
+                     break;
+                   case BFD_RELOC_LO16_GOTOFF:
+                     reloc = BFD_RELOC_PPC64_GOT16_LO_DS;
+                     break;
+                   case BFD_RELOC_LO16_PLTOFF:
+                     reloc = BFD_RELOC_PPC64_PLT16_LO_DS;
+                     break;
+                   case BFD_RELOC_16_BASEREL:
+                     reloc = BFD_RELOC_PPC64_SECTOFF_DS;
+                     break;
+                   case BFD_RELOC_LO16_BASEREL:
+                     reloc = BFD_RELOC_PPC64_SECTOFF_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_TOC16:
+                     reloc = BFD_RELOC_PPC64_TOC16_DS;
+                     break;
+                   case BFD_RELOC_PPC64_TOC16_LO:
+                     reloc = BFD_RELOC_PPC64_TOC16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC64_PLTGOT16:
+                     reloc = BFD_RELOC_PPC64_PLTGOT16_DS;
+                     break;
+                   case BFD_RELOC_PPC64_PLTGOT16_LO:
+                     reloc = BFD_RELOC_PPC64_PLTGOT16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_DTPREL16:
+                     reloc = BFD_RELOC_PPC64_DTPREL16_DS;
+                     break;
+                   case BFD_RELOC_PPC_DTPREL16_LO:
+                     reloc = BFD_RELOC_PPC64_DTPREL16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_TPREL16:
+                     reloc = BFD_RELOC_PPC64_TPREL16_DS;
+                     break;
+                   case BFD_RELOC_PPC_TPREL16_LO:
+                     reloc = BFD_RELOC_PPC64_TPREL16_LO_DS;
+                     break;
+                   case BFD_RELOC_PPC_GOT_DTPREL16:
+                   case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+                   case BFD_RELOC_PPC_GOT_TPREL16:
+                   case BFD_RELOC_PPC_GOT_TPREL16_LO:
+                     break;
+                   default:
+                     as_bad (_("unsupported relocation for DS offset field"));
+                     break;
+                   }
+               }
            }
 
          /* We need to generate a fixup for this expression.  */
          if (fc >= MAX_INSN_FIXUPS)
            as_fatal (_("too many fixups"));
          fixups[fc].exp = ex;
-         fixups[fc].opindex = 0;
+         fixups[fc].opindex = *opindex_ptr;
          fixups[fc].reloc = reloc;
          ++fc;
        }
-#endif /* OBJ_ELF */
-
+#else /* OBJ_ELF */
       else
        {
          /* We need to generate a fixup for this expression.  */
@@ -2634,11 +2850,20 @@ md_assemble (char *str)
          fixups[fc].reloc = BFD_RELOC_UNUSED;
          ++fc;
        }
+#endif /* OBJ_ELF */
 
       if (need_paren)
        {
          endc = ')';
          need_paren = 0;
+         /* If expecting more operands, then we want to see "),".  */
+         if (*str == endc && opindex_ptr[1] != 0)
+           {
+             do
+               ++str;
+             while (ISSPACE (*str));
+             endc = ',';
+           }
        }
       else if ((operand->flags & PPC_OPERAND_PARENS) != 0)
        {
@@ -2669,10 +2894,7 @@ md_assemble (char *str)
 
 #ifdef OBJ_ELF
   /* Do we need/want a APUinfo section? */
-  if (ppc_cpu & (PPC_OPCODE_SPE
-              | PPC_OPCODE_ISEL | PPC_OPCODE_EFS
-              | PPC_OPCODE_BRLOCK | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
-              | PPC_OPCODE_RFMCI))
+  if ((ppc_cpu & PPC_OPCODE_E500MC) != 0)
     {
       /* These are all version "1".  */
       if (opcode->flags & PPC_OPCODE_SPE)
@@ -2713,9 +2935,6 @@ md_assemble (char *str)
      md_apply_fix.  */
   for (i = 0; i < fc; i++)
     {
-      const struct powerpc_operand *operand;
-
-      operand = &powerpc_operands[fixups[i].opindex];
       if (fixups[i].reloc != BFD_RELOC_UNUSED)
        {
          reloc_howto_type *reloc_howto;
@@ -2762,13 +2981,18 @@ md_assemble (char *str)
            }
        }
       else
-       fix_new_exp (frag_now,
-                    f - frag_now->fr_literal,
-                    4,
-                    &fixups[i].exp,
-                    (operand->flags & PPC_OPERAND_RELATIVE) != 0,
-                    ((bfd_reloc_code_real_type)
-                     (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
+       {
+         const struct powerpc_operand *operand;
+
+         operand = &powerpc_operands[fixups[i].opindex];
+         fix_new_exp (frag_now,
+                      f - frag_now->fr_literal,
+                      4,
+                      &fixups[i].exp,
+                      (operand->flags & PPC_OPERAND_RELATIVE) != 0,
+                      ((bfd_reloc_code_real_type)
+                       (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
+       }
     }
 }
 
@@ -2853,7 +3077,7 @@ ppc_macro (char *str, const struct powerpc_macro *macro)
 #ifdef OBJ_ELF
 /* For ELF, add support for SHF_EXCLUDE and SHT_ORDERED.  */
 
-int
+bfd_vma
 ppc_section_letter (int letter, char **ptr_msg)
 {
   if (letter == 'e')
@@ -2863,7 +3087,7 @@ ppc_section_letter (int letter, char **ptr_msg)
   return -1;
 }
 
-int
+bfd_vma
 ppc_section_word (char *str, size_t len)
 {
   if (len == 7 && strncmp (str, "exclude", 7) == 0)
@@ -2882,7 +3106,7 @@ ppc_section_type (char *str, size_t len)
 }
 
 int
-ppc_section_flags (int flags, int attr, int type)
+ppc_section_flags (flagword flags, bfd_vma attr, int type)
 {
   if (type == SHT_ORDERED)
     flags |= SEC_ALLOC | SEC_LOAD | SEC_SORT_ENTRIES;
@@ -3116,7 +3340,7 @@ ppc_csect (int ignore ATTRIBUTE_UNUSED)
   if (S_GET_NAME (sym)[0] == '\0')
     {
       /* An unnamed csect is assumed to be [PR].  */
-      symbol_get_tc (sym)->class = XMC_PR;
+      symbol_get_tc (sym)->symbol_class = XMC_PR;
     }
 
   align = 2;
@@ -3152,7 +3376,7 @@ ppc_change_csect (symbolS *sym, offsetT align)
         data section.  */
       after_toc = 0;
       is_code = 0;
-      switch (symbol_get_tc (sym)->class)
+      switch (symbol_get_tc (sym)->symbol_class)
        {
        case XMC_PR:
        case XMC_RO:
@@ -3542,8 +3766,8 @@ ppc_function (int ignore ATTRIBUTE_UNUSED)
       symbol_set_value_expression (ext_sym, &exp);
     }
 
-  if (symbol_get_tc (ext_sym)->class == -1)
-    symbol_get_tc (ext_sym)->class = XMC_PR;
+  if (symbol_get_tc (ext_sym)->symbol_class == -1)
+    symbol_get_tc (ext_sym)->symbol_class = XMC_PR;
   symbol_get_tc (ext_sym)->output = 1;
 
   if (*input_line_pointer == ',')
@@ -3976,7 +4200,7 @@ ppc_tc (int ignore ATTRIBUTE_UNUSED)
        symbolS *label;
 
        label = symbol_get_tc (ppc_current_csect)->within;
-       if (symbol_get_tc (label)->class != XMC_TC0)
+       if (symbol_get_tc (label)->symbol_class != XMC_TC0)
          {
            as_bad (_(".tc with no label"));
            ignore_rest_of_line ();
@@ -3996,7 +4220,7 @@ ppc_tc (int ignore ATTRIBUTE_UNUSED)
     S_SET_SEGMENT (sym, now_seg);
     symbol_set_frag (sym, frag_now);
     S_SET_VALUE (sym, (valueT) frag_now_fix ());
-    symbol_get_tc (sym)->class = XMC_TC;
+    symbol_get_tc (sym)->symbol_class = XMC_TC;
     symbol_get_tc (sym)->output = 1;
 
     ppc_frob_label (sym);
@@ -4008,6 +4232,7 @@ ppc_tc (int ignore ATTRIBUTE_UNUSED)
 
   /* Skip the TOC symbol name.  */
   while (is_part_of_name (*input_line_pointer)
+        || *input_line_pointer == ' '
         || *input_line_pointer == '['
         || *input_line_pointer == ']'
         || *input_line_pointer == '{'
@@ -4036,7 +4261,7 @@ ppc_machine (int ignore ATTRIBUTE_UNUSED)
 {
   char *cpu_string;
 #define MAX_HISTORY 100
-  static unsigned long *cpu_history;
+  static ppc_cpu_t *cpu_history;
   static int curr_hist;
 
   SKIP_WHITESPACE ();
@@ -4057,7 +4282,8 @@ ppc_machine (int ignore ATTRIBUTE_UNUSED)
 
   if (cpu_string != NULL)
     {
-      unsigned long old_cpu = ppc_cpu;
+      ppc_cpu_t old_cpu = ppc_cpu;
+      ppc_cpu_t new_cpu;
       char *p;
 
       for (p = cpu_string; *p != 0; p++)
@@ -4080,8 +4306,8 @@ ppc_machine (int ignore ATTRIBUTE_UNUSED)
          else
            ppc_cpu = cpu_history[--curr_hist];
        }
-      else if (parse_cpu (cpu_string))
-       ;
+      else if ((new_cpu = ppc_parse_cpu (ppc_cpu, cpu_string)) != 0)
+       ppc_cpu = new_cpu;
       else
        as_bad (_("invalid machine `%s'"), cpu_string);
 
@@ -4098,7 +4324,7 @@ static int
 ppc_is_toc_sym (symbolS *sym)
 {
 #ifdef OBJ_XCOFF
-  return symbol_get_tc (sym)->class == XMC_TC;
+  return symbol_get_tc (sym)->symbol_class == XMC_TC;
 #endif
 #ifdef OBJ_ELF
   const char *sname = segment_name (S_GET_SEGMENT (sym));
@@ -4748,7 +4974,7 @@ ppc_symbol_new_hook (symbolS *sym)
   tc = symbol_get_tc (sym);
   tc->next = NULL;
   tc->output = 0;
-  tc->class = -1;
+  tc->symbol_class = -1;
   tc->real_name = NULL;
   tc->subseg = 0;
   tc->align = 0;
@@ -4771,55 +4997,55 @@ ppc_symbol_new_hook (symbolS *sym)
     {
     case 'B':
       if (strcmp (s, "BS]") == 0)
-       tc->class = XMC_BS;
+       tc->symbol_class = XMC_BS;
       break;
     case 'D':
       if (strcmp (s, "DB]") == 0)
-       tc->class = XMC_DB;
+       tc->symbol_class = XMC_DB;
       else if (strcmp (s, "DS]") == 0)
-       tc->class = XMC_DS;
+       tc->symbol_class = XMC_DS;
       break;
     case 'G':
       if (strcmp (s, "GL]") == 0)
-       tc->class = XMC_GL;
+       tc->symbol_class = XMC_GL;
       break;
     case 'P':
       if (strcmp (s, "PR]") == 0)
-       tc->class = XMC_PR;
+       tc->symbol_class = XMC_PR;
       break;
     case 'R':
       if (strcmp (s, "RO]") == 0)
-       tc->class = XMC_RO;
+       tc->symbol_class = XMC_RO;
       else if (strcmp (s, "RW]") == 0)
-       tc->class = XMC_RW;
+       tc->symbol_class = XMC_RW;
       break;
     case 'S':
       if (strcmp (s, "SV]") == 0)
-       tc->class = XMC_SV;
+       tc->symbol_class = XMC_SV;
       break;
     case 'T':
       if (strcmp (s, "TC]") == 0)
-       tc->class = XMC_TC;
+       tc->symbol_class = XMC_TC;
       else if (strcmp (s, "TI]") == 0)
-       tc->class = XMC_TI;
+       tc->symbol_class = XMC_TI;
       else if (strcmp (s, "TB]") == 0)
-       tc->class = XMC_TB;
+       tc->symbol_class = XMC_TB;
       else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0)
-       tc->class = XMC_TC0;
+       tc->symbol_class = XMC_TC0;
       break;
     case 'U':
       if (strcmp (s, "UA]") == 0)
-       tc->class = XMC_UA;
+       tc->symbol_class = XMC_UA;
       else if (strcmp (s, "UC]") == 0)
-       tc->class = XMC_UC;
+       tc->symbol_class = XMC_UC;
       break;
     case 'X':
       if (strcmp (s, "XO]") == 0)
-       tc->class = XMC_XO;
+       tc->symbol_class = XMC_XO;
       break;
     }
 
-  if (tc->class == -1)
+  if (tc->symbol_class == -1)
     as_bad (_("Unrecognized symbol suffix"));
 }
 
@@ -4832,8 +5058,8 @@ ppc_frob_label (symbolS *sym)
 {
   if (ppc_current_csect != (symbolS *) NULL)
     {
-      if (symbol_get_tc (sym)->class == -1)
-       symbol_get_tc (sym)->class = symbol_get_tc (ppc_current_csect)->class;
+      if (symbol_get_tc (sym)->symbol_class == -1)
+       symbol_get_tc (sym)->symbol_class = symbol_get_tc (ppc_current_csect)->symbol_class;
 
       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
       symbol_append (sym, symbol_get_tc (ppc_current_csect)->within,
@@ -4946,6 +5172,7 @@ ppc_frob_symbol (symbolS *sym)
     S_SET_STORAGE_CLASS (sym, C_HIDEXT);
 
   if (S_GET_STORAGE_CLASS (sym) == C_EXT
+      || S_GET_STORAGE_CLASS (sym) == C_AIX_WEAKEXT
       || S_GET_STORAGE_CLASS (sym) == C_HIDEXT)
     {
       int i;
@@ -4955,7 +5182,7 @@ ppc_frob_symbol (symbolS *sym)
       i = S_GET_NUMBER_AUXILIARY (sym);
       S_SET_NUMBER_AUXILIARY (sym, i + 1);
       a = &coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].u.auxent;
-      if (symbol_get_tc (sym)->class == XMC_TC0)
+      if (symbol_get_tc (sym)->symbol_class == XMC_TC0)
        {
          /* This is the TOC table.  */
          know (strcmp (S_GET_NAME (sym), "TOC") == 0);
@@ -4984,9 +5211,9 @@ ppc_frob_symbol (symbolS *sym)
          a->x_csect.x_scnlen.l = symbol_get_frag (sym)->fr_offset;
          a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_CM;
          if (S_IS_EXTERNAL (sym))
-           symbol_get_tc (sym)->class = XMC_RW;
+           symbol_get_tc (sym)->symbol_class = XMC_RW;
          else
-           symbol_get_tc (sym)->class = XMC_BS;
+           symbol_get_tc (sym)->symbol_class = XMC_BS;
        }
       else if (S_GET_SEGMENT (sym) == absolute_section)
        {
@@ -4994,8 +5221,8 @@ ppc_frob_symbol (symbolS *sym)
             ppc_adjust_symtab.  */
          ppc_saw_abs = TRUE;
          a->x_csect.x_smtyp = XTY_LD;
-         if (symbol_get_tc (sym)->class == -1)
-           symbol_get_tc (sym)->class = XMC_XO;
+         if (symbol_get_tc (sym)->symbol_class == -1)
+           symbol_get_tc (sym)->symbol_class = XMC_XO;
        }
       else if (! S_IS_DEFINED (sym))
        {
@@ -5003,17 +5230,17 @@ ppc_frob_symbol (symbolS *sym)
          a->x_csect.x_scnlen.l = 0;
          a->x_csect.x_smtyp = XTY_ER;
        }
-      else if (symbol_get_tc (sym)->class == XMC_TC)
+      else if (symbol_get_tc (sym)->symbol_class == XMC_TC)
        {
          symbolS *next;
 
          /* This is a TOC definition.  x_scnlen is the size of the
             TOC entry.  */
          next = symbol_next (sym);
-         while (symbol_get_tc (next)->class == XMC_TC0)
+         while (symbol_get_tc (next)->symbol_class == XMC_TC0)
            next = symbol_next (next);
          if (next == (symbolS *) NULL
-             || symbol_get_tc (next)->class != XMC_TC)
+             || symbol_get_tc (next)->symbol_class != XMC_TC)
            {
              if (ppc_after_toc_frag == (fragS *) NULL)
                a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput,
@@ -5073,10 +5300,10 @@ ppc_frob_symbol (symbolS *sym)
 
       a->x_csect.x_parmhash = 0;
       a->x_csect.x_snhash = 0;
-      if (symbol_get_tc (sym)->class == -1)
+      if (symbol_get_tc (sym)->symbol_class == -1)
        a->x_csect.x_smclas = XMC_PR;
       else
-       a->x_csect.x_smclas = symbol_get_tc (sym)->class;
+       a->x_csect.x_smclas = symbol_get_tc (sym)->symbol_class;
       a->x_csect.x_stab = 0;
       a->x_csect.x_snstab = 0;
 
@@ -5178,58 +5405,10 @@ ppc_frob_section (asection *sec)
 
 #endif /* OBJ_XCOFF */
 \f
-/* Turn a string in input_line_pointer into a floating point constant
-   of type TYPE, and store the appropriate bytes in *LITP.  The number
-   of LITTLENUMS emitted is stored in *SIZEP.  An error message is
-   returned, or NULL on OK.  */
-
 char *
 md_atof (int type, char *litp, int *sizep)
 {
-  int prec;
-  LITTLENUM_TYPE words[4];
-  char *t;
-  int i;
-
-  switch (type)
-    {
-    case 'f':
-      prec = 2;
-      break;
-
-    case 'd':
-      prec = 4;
-      break;
-
-    default:
-      *sizep = 0;
-      return _("bad call to md_atof");
-    }
-
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-
-  *sizep = prec * 2;
-
-  if (target_big_endian)
-    {
-      for (i = 0; i < prec; i++)
-       {
-         md_number_to_chars (litp, (valueT) words[i], 2);
-         litp += 2;
-       }
-    }
-  else
-    {
-      for (i = prec - 1; i >= 0; i--)
-       {
-         md_number_to_chars (litp, (valueT) words[i], 2);
-         litp += 2;
-       }
-    }
-
-  return NULL;
+  return ieee_md_atof (type, litp, sizep, target_big_endian);
 }
 
 /* Write a value out to the object file, using the appropriate
@@ -5329,9 +5508,9 @@ ppc_fix_adjustable (fixS *fix)
        {
          TC_SYMFIELD_TYPE *sy_tc = symbol_get_tc (sy);
 
-         if (sy_tc->class == XMC_TC0)
+         if (sy_tc->symbol_class == XMC_TC0)
            continue;
-         if (sy_tc->class != XMC_TC)
+         if (sy_tc->symbol_class != XMC_TC)
            break;
          if (val == resolve_symbol_value (sy))
            {
@@ -5348,8 +5527,8 @@ ppc_fix_adjustable (fixS *fix)
   /* Possibly adjust the reloc to be against the csect.  */
   tc = symbol_get_tc (fix->fx_addsy);
   if (tc->subseg == 0
-      && tc->class != XMC_TC0
-      && tc->class != XMC_TC
+      && tc->symbol_class != XMC_TC0
+      && tc->symbol_class != XMC_TC
       && symseg != bss_section
       /* Don't adjust if this is a reloc in the toc section.  */
       && (symseg != data_section
@@ -5510,13 +5689,14 @@ ppc_handle_align (struct frag *fragP)
       fragP->fr_var = 4;
       md_number_to_chars (dest, 0x60000000, 4);
 
-      if ((ppc_cpu & PPC_OPCODE_POWER6) != 0)
+      if ((ppc_cpu & PPC_OPCODE_POWER6) != 0
+         || (ppc_cpu & PPC_OPCODE_POWER7) != 0)
        {
-         /* For power6, we want the last nop to be a group terminating
-            one, "ori 1,1,0".  Do this by inserting an rs_fill frag
-            immediately after this one, with its address set to the last
-            nop location.  This will automatically reduce the number of
-            nops in the current frag by one.  */
+         /* For power6 and power7, we want the last nop to be a group
+            terminating one.  Do this by inserting an rs_fill frag immediately
+            after this one, with its address set to the last nop location.
+            This will automatically reduce the number of nops in the current
+            frag by one.  */
          if (count > 4)
            {
              struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4);
@@ -5530,7 +5710,12 @@ ppc_handle_align (struct frag *fragP)
              dest = group_nop->fr_literal;
            }
 
-         md_number_to_chars (dest, 0x60210000, 4);
+         if ((ppc_cpu & PPC_OPCODE_POWER7) != 0)
+           /* power7 group terminating nop: "ori 2,2,0".  */
+           md_number_to_chars (dest, 0x60420000, 4);
+         else
+           /* power6 group terminating nop: "ori 1,1,0".  */
+           md_number_to_chars (dest, 0x60210000, 4);
        }
     }
 }
@@ -5565,18 +5750,19 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
      going to use the symbol value.  That means that if the reloc is
      fully resolved we want to use *valP since bfd_install_relocation is
      not being used.
-     However, if the reloc is not fully resolved we do not want to use
-     *valP, and must use fx_offset instead.  However, if the reloc
-     is PC relative, we do want to use *valP since it includes the
-     result of md_pcrel_from.  This is confusing.  */
+     However, if the reloc is not fully resolved we do not want to
+     use *valP, and must use fx_offset instead.  If the relocation
+     is PC-relative, we then need to re-apply md_pcrel_from_section
+     to this new relocation value.  */
   if (fixP->fx_addsy == (symbolS *) NULL)
     fixP->fx_done = 1;
 
-  else if (fixP->fx_pcrel)
-    ;
-
   else
-    value = fixP->fx_offset;
+    {
+      value = fixP->fx_offset;
+      if (fixP->fx_pcrel)
+       value -= md_pcrel_from_section (fixP, seg);
+    }
 #endif
 
   if (fixP->fx_subsy != (symbolS *) NULL)
@@ -5607,8 +5793,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          && (operand->insert == NULL || ppc_obj64)
          && fixP->fx_addsy != NULL
          && symbol_get_tc (fixP->fx_addsy)->subseg != 0
-         && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC
-         && symbol_get_tc (fixP->fx_addsy)->class != XMC_TC0
+         && symbol_get_tc (fixP->fx_addsy)->symbol_class != XMC_TC
+         && symbol_get_tc (fixP->fx_addsy)->symbol_class != XMC_TC0
          && S_GET_SEGMENT (fixP->fx_addsy) != bss_section)
        {
          value = fixP->fx_offset;
@@ -5624,6 +5810,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       else
        insn = bfd_getl32 ((unsigned char *) where);
       insn = ppc_insert_operand (insn, operand, (offsetT) value,
+                                fixP->tc_fix_data.ppc_cpu,
                                 fixP->fx_file, fixP->fx_line);
       if (target_big_endian)
        bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
@@ -5634,7 +5821,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
        /* Nothing else to do here.  */
        return;
 
-      assert (fixP->fx_addsy != NULL);
+      gas_assert (fixP->fx_addsy != NULL);
 
       /* Determine a BFD reloc value based on the operand information.
         We are only prepared to turn a few of the operands into
@@ -5908,6 +6095,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          break;
 
        case BFD_RELOC_PPC_TLS:
+       case BFD_RELOC_PPC_TLSGD:
+       case BFD_RELOC_PPC_TLSLD:
          break;
 
        case BFD_RELOC_PPC_DTPMOD:
@@ -6057,10 +6246,11 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 #ifdef TE_PE
       fixP->fx_addnumber = 0;
 #else
-      /* We want to use the offset within the data segment of the
-        symbol, not the actual VMA of the symbol.  */
+      /* We want to use the offset within the toc, not the actual VMA
+        of the symbol.  */
       fixP->fx_addnumber =
-       - bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixP->fx_addsy));
+       - bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixP->fx_addsy))
+       - S_GET_VALUE (ppc_toc_csect);
 #endif
     }
 #endif