include/opcode/
[deliverable/binutils-gdb.git] / gas / config / tc-ppc.c
index c7ad970672443ee9547c5ed92bb0af278080dfc0..be745abbf65aa56b2e9fecbd6a7bc0ffe4993fb9 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,
 /* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
    Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005 Free Software Foundation, Inc.
+   2004, 2005, 2006, 2007 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GAS, the GNU Assembler.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GAS, the GNU Assembler.
@@ -20,7 +20,6 @@
    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
    02110-1301, USA.  */
 
    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
    02110-1301, USA.  */
 
-#include <stdio.h>
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
@@ -183,11 +182,9 @@ const char EXP_CHARS[] = "eE";
    as in 0d1.0.  */
 const char FLT_CHARS[] = "dD";
 
    as in 0d1.0.  */
 const char FLT_CHARS[] = "dD";
 
-/* '+' and '-' can be used as postfix predicate predictors for conditional
-   branches.  So they need to be accepted as symbol characters.
-   Also, anything that can start an operand needs to be mentioned here,
+/* Anything that can start an operand needs to be mentioned here,
    to stop the input scrubber eating whitespace.  */
    to stop the input scrubber eating whitespace.  */
-const char ppc_symbol_chars[] = "+-%[";
+const char ppc_symbol_chars[] = "%[";
 
 /* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
 int ppc_cie_data_alignment;
 
 /* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
 int ppc_cie_data_alignment;
@@ -917,6 +914,18 @@ parse_cpu (const char *arg)
                 | PPC_OPCODE_64 | PPC_OPCODE_POWER4
                 | PPC_OPCODE_POWER5);
     }
                 | 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.  */
   /* -mcom means assemble for the common intersection between Power
      and PowerPC.  At present, we just allow the union, rather
      than the intersection.  */
@@ -1112,6 +1121,8 @@ PowerPC options:\n\
 -mbooke, mbooke32      generate code for 32-bit PowerPC BookE\n\
 -mpower4               generate code for Power4 architecture\n\
 -mpower5               generate code for Power5 architecture\n\
 -mbooke, mbooke32      generate code for 32-bit PowerPC BookE\n\
 -mpower4               generate code for Power4 architecture\n\
 -mpower5               generate code for Power5 architecture\n\
+-mpower6               generate code for Power6 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, _("\
 -mcom                  generate code Power/PowerPC common instructions\n\
 -many                  generate code for any architecture (PWR/PWRX/PPC)\n"));
   fprintf (stream, _("\
@@ -1237,7 +1248,8 @@ ppc_setup_opcodes (void)
   const struct powerpc_opcode *op_end;
   const struct powerpc_macro *macro;
   const struct powerpc_macro *macro_end;
   const struct powerpc_opcode *op_end;
   const struct powerpc_macro *macro;
   const struct powerpc_macro *macro_end;
-  bfd_boolean dup_insn = FALSE;
+  unsigned int i;
+  bfd_boolean bad_insn = FALSE;
 
   if (ppc_hash != NULL)
     hash_die (ppc_hash);
 
   if (ppc_hash != NULL)
     hash_die (ppc_hash);
@@ -1247,10 +1259,60 @@ ppc_setup_opcodes (void)
   /* Insert the opcodes into a hash table.  */
   ppc_hash = hash_new ();
 
   /* Insert the opcodes into a hash table.  */
   ppc_hash = hash_new ();
 
+  /* Check operand masks.  Code here and in the disassembler assumes
+     all the 1's in the mask are contiguous.  */
+  for (i = 0; i < num_powerpc_operands; ++i)
+    {
+      unsigned long mask = powerpc_operands[i].bitm;
+      unsigned long right_bit;
+
+      right_bit = mask & -mask;
+      mask += right_bit;
+      right_bit = mask & -mask;
+      if (mask != right_bit)
+       {
+         as_bad (_("powerpc_operands[%d].bitm invalid"), i);
+         bad_insn = TRUE;
+       }
+    }
+
   op_end = powerpc_opcodes + powerpc_num_opcodes;
   for (op = powerpc_opcodes; op < op_end; op++)
     {
   op_end = powerpc_opcodes + powerpc_num_opcodes;
   for (op = powerpc_opcodes; op < op_end; op++)
     {
-      know ((op->opcode & op->mask) == op->opcode);
+      const unsigned char *o;
+      unsigned long omask = op->mask;
+
+      /* The mask had better not trim off opcode bits.  */
+      if ((op->opcode & omask) != op->opcode)
+       {
+         as_bad (_("mask trims opcode bits for %s"),
+                 op->name);
+         bad_insn = TRUE;
+       }
+
+      /* The operands must not overlap the opcode or each other.  */
+      for (o = op->operands; *o; ++o)
+       if (*o >= num_powerpc_operands)
+         {
+           as_bad (_("operand index error for %s"),
+                   op->name);
+           bad_insn = TRUE;
+         }
+       else
+         {
+           const struct powerpc_operand *operand = &powerpc_operands[*o];
+           if (operand->shift >= 0)
+             {
+               unsigned long mask = operand->bitm << operand->shift;
+               if (omask & mask)
+                 {
+                   as_bad (_("operand %d overlap in %s"),
+                           (int) (o - op->operands), op->name);
+                   bad_insn = TRUE;
+                 }
+               omask |= mask;
+             }
+         }
 
       if ((op->flags & ppc_cpu & ~(PPC_OPCODE_32 | PPC_OPCODE_64)) != 0
          && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0
 
       if ((op->flags & ppc_cpu & ~(PPC_OPCODE_32 | PPC_OPCODE_64)) != 0
          && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0
@@ -1270,7 +1332,10 @@ ppc_setup_opcodes (void)
                  == (ppc_cpu & PPC_OPCODE_POWER4)))
          && ((op->flags & PPC_OPCODE_POWER5) == 0
              || ((op->flags & PPC_OPCODE_POWER5)
                  == (ppc_cpu & PPC_OPCODE_POWER4)))
          && ((op->flags & PPC_OPCODE_POWER5) == 0
              || ((op->flags & PPC_OPCODE_POWER5)
-                 == (ppc_cpu & PPC_OPCODE_POWER5))))
+                 == (ppc_cpu & PPC_OPCODE_POWER5)))
+         && ((op->flags & PPC_OPCODE_POWER6) == 0
+             || ((op->flags & PPC_OPCODE_POWER6)
+                 == (ppc_cpu & PPC_OPCODE_POWER6))))
        {
          const char *retval;
 
        {
          const char *retval;
 
@@ -1282,9 +1347,9 @@ ppc_setup_opcodes (void)
                  && (op->flags & PPC_OPCODE_POWER) != 0)
                continue;
 
                  && (op->flags & PPC_OPCODE_POWER) != 0)
                continue;
 
-             as_bad (_("Internal assembler error for instruction %s"),
+             as_bad (_("duplicate instruction %s"),
                      op->name);
                      op->name);
-             dup_insn = TRUE;
+             bad_insn = TRUE;
            }
        }
     }
            }
        }
     }
@@ -1306,13 +1371,13 @@ ppc_setup_opcodes (void)
          retval = hash_insert (ppc_macro_hash, macro->name, (PTR) macro);
          if (retval != (const char *) NULL)
            {
          retval = hash_insert (ppc_macro_hash, macro->name, (PTR) macro);
          if (retval != (const char *) NULL)
            {
-             as_bad (_("Internal assembler error for macro %s"), macro->name);
-             dup_insn = TRUE;
+             as_bad (_("duplicate macro %s"), macro->name);
+             bad_insn = TRUE;
            }
        }
     }
 
            }
        }
     }
 
-  if (dup_insn)
+  if (bad_insn)
     abort ();
 }
 
     abort ();
 }
 
@@ -1433,49 +1498,52 @@ ppc_insert_operand (insn, operand, val, file, line)
      char *file;
      unsigned int line;
 {
      char *file;
      unsigned int line;
 {
-  if (operand->bits != 32)
+  long min, max, right;
+  offsetT test;
+  
+  max = operand->bitm;
+  right = max & -max;
+  min = 0;
+
+  if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
     {
     {
-      long min, max;
-      offsetT test;
+      if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0)
+       max >>= 1;
+      min = ~(max | ((max & -max) - 1)) ;
 
 
-      if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+      if (!ppc_obj64)
        {
        {
-         if ((operand->flags & PPC_OPERAND_SIGNOPT) != 0)
-           max = (1 << operand->bits) - 1;
-         else
-           max = (1 << (operand->bits - 1)) - 1;
-         min = - (1 << (operand->bits - 1));
-
-         if (!ppc_obj64)
+         /* Some people write 32 bit hex constants with the sign
+            extension done by hand.  This shouldn't really be
+            valid, but, to permit this code to assemble on a 64
+            bit host, we sign extend the 32 bit value.  */
+         if (val > 0
+             && (val & (offsetT) 0x80000000) != 0
+             && (val & (offsetT) 0xffffffff) == val)
            {
            {
-             /* Some people write 32 bit hex constants with the sign
-                extension done by hand.  This shouldn't really be
-                valid, but, to permit this code to assemble on a 64
-                bit host, we sign extend the 32 bit value.  */
-             if (val > 0
-                 && (val & (offsetT) 0x80000000) != 0
-                 && (val & (offsetT) 0xffffffff) == val)
-               {
-                 val -= 0x80000000;
-                 val -= 0x80000000;
-               }
+             val -= 0x80000000;
+             val -= 0x80000000;
            }
        }
            }
        }
-      else
-       {
-         max = (1 << operand->bits) - 1;
-         min = 0;
-       }
-
-      if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0)
-       test = - val;
-      else
-       test = val;
+    }
 
 
-      if (test < (offsetT) min || test > (offsetT) max)
-       as_bad_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line);
+  if ((operand->flags & PPC_OPERAND_PLUS1) != 0)
+    {
+      max++;
+      min++;
     }
 
     }
 
+  if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0)
+    test = - val;
+  else
+    test = val;
+
+  if (test < (offsetT) min
+      || test > (offsetT) max
+      || (test & (right - 1)) != 0)
+    as_bad_value_out_of_range (_("operand"),
+                              test, (offsetT) min, (offsetT) max, file, line);
+
   if (operand->insert)
     {
       const char *errmsg;
   if (operand->insert)
     {
       const char *errmsg;
@@ -1486,8 +1554,7 @@ ppc_insert_operand (insn, operand, val, file, line)
        as_bad_where (file, line, errmsg);
     }
   else
        as_bad_where (file, line, errmsg);
     }
   else
-    insn |= (((long) val & ((1 << operand->bits) - 1))
-            << operand->shift);
+    insn |= ((long) val & operand->bitm) << operand->shift;
 
   return insn;
 }
 
   return insn;
 }
@@ -1931,7 +1998,7 @@ ppc_frob_file_before_adjust ()
       dotname = xmalloc (len + 1);
       dotname[0] = '.';
       memcpy (dotname + 1, name, len);
       dotname = xmalloc (len + 1);
       dotname[0] = '.';
       memcpy (dotname + 1, name, len);
-      dotsym = symbol_find (dotname);
+      dotsym = symbol_find_noref (dotname, 1);
       free (dotname);
       if (dotsym != NULL && (symbol_used_p (dotsym)
                             || symbol_used_in_reloc_p (dotsym)))
       free (dotname);
       if (dotsym != NULL && (symbol_used_p (dotsym)
                             || symbol_used_in_reloc_p (dotsym)))
@@ -4416,6 +4483,7 @@ ppc_pe_comm (lcomm)
     {
       S_SET_VALUE (symbolP, (valueT) temp);
       S_SET_EXTERNAL (symbolP);
     {
       S_SET_VALUE (symbolP, (valueT) temp);
       S_SET_EXTERNAL (symbolP);
+      S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
     }
 
   demand_empty_rest_of_line ();
     }
 
   demand_empty_rest_of_line ();
@@ -4840,6 +4908,10 @@ ppc_frob_label (sym)
                     &symbol_rootP, &symbol_lastP);
       symbol_get_tc (ppc_current_csect)->within = sym;
     }
                     &symbol_rootP, &symbol_lastP);
       symbol_get_tc (ppc_current_csect)->within = sym;
     }
+
+#ifdef OBJ_ELF
+  dwarf2_emit_label (sym);
+#endif
 }
 
 /* This variable is set by ppc_frob_symbol if any absolute symbols are
 }
 
 /* This variable is set by ppc_frob_symbol if any absolute symbols are
@@ -5251,13 +5323,15 @@ md_number_to_chars (buf, val, n)
 /* Align a section (I don't know why this is machine dependent).  */
 
 valueT
 /* Align a section (I don't know why this is machine dependent).  */
 
 valueT
-md_section_align (seg, addr)
-     asection *seg;
-     valueT addr;
+md_section_align (asection *seg ATTRIBUTE_UNUSED, valueT addr)
 {
 {
+#ifdef OBJ_ELF
+  return addr;
+#else
   int align = bfd_get_section_alignment (stdoutput, seg);
 
   return ((addr + (1 << align) - 1) & (-1 << align));
   int align = bfd_get_section_alignment (stdoutput, seg);
 
   return ((addr + (1 << align) - 1) & (-1 << align));
+#endif
 }
 
 /* We don't have any form of relaxing.  */
 }
 
 /* We don't have any form of relaxing.  */
@@ -5505,6 +5579,47 @@ ppc_fix_adjustable (fix)
 }
 #endif
 
 }
 #endif
 
+/* Implement HANDLE_ALIGN.  This writes the NOP pattern into an
+   rs_align_code frag.  */
+
+void
+ppc_handle_align (struct frag *fragP)
+{
+  valueT count = (fragP->fr_next->fr_address
+                 - (fragP->fr_address + fragP->fr_fix));
+
+  if (count != 0 && (count & 3) == 0)
+    {
+      char *dest = fragP->fr_literal + fragP->fr_fix;
+
+      fragP->fr_var = 4;
+      md_number_to_chars (dest, 0x60000000, 4);
+
+      if ((ppc_cpu & PPC_OPCODE_POWER6) != 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.  */
+         if (count > 4)
+           {
+             struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4);
+
+             memcpy (group_nop, fragP, SIZEOF_STRUCT_FRAG);
+             group_nop->fr_address = group_nop->fr_next->fr_address - 4;
+             group_nop->fr_fix = 0;
+             group_nop->fr_offset = 1;
+             group_nop->fr_type = rs_fill;
+             fragP->fr_next = group_nop;
+             dest = group_nop->fr_literal;
+           }
+
+         md_number_to_chars (dest, 0x60210000, 4);
+       }
+    }
+}
+
 /* Apply a fixup to the object code.  This is called for all the
    fixups we generated by the call to fix_new_exp, above.  In the call
    above we used a reloc code which was the largest legal reloc code
 /* Apply a fixup to the object code.  This is called for all the
    fixups we generated by the call to fix_new_exp, above.  In the call
    above we used a reloc code which was the largest legal reloc code
@@ -5575,7 +5690,7 @@ md_apply_fix (fixP, valP, seg)
         csect.  Other usages, such as `.long sym', generate relocs.  This
         is the documented behaviour of non-TOC symbols.  */
       if ((operand->flags & PPC_OPERAND_PARENS) != 0
         csect.  Other usages, such as `.long sym', generate relocs.  This
         is the documented behaviour of non-TOC symbols.  */
       if ((operand->flags & PPC_OPERAND_PARENS) != 0
-         && operand->bits == 16
+         && (operand->bitm & 0xfff0) == 0xfff0
          && operand->shift == 0
          && (operand->insert == NULL || ppc_obj64)
          && fixP->fx_addsy != NULL
          && operand->shift == 0
          && (operand->insert == NULL || ppc_obj64)
          && fixP->fx_addsy != NULL
@@ -5613,11 +5728,11 @@ md_apply_fix (fixP, valP, seg)
         We are only prepared to turn a few of the operands into
         relocs.  */
       if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
         We are only prepared to turn a few of the operands into
         relocs.  */
       if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
-         && operand->bits == 26
+         && operand->bitm == 0x3fffffc
          && operand->shift == 0)
        fixP->fx_r_type = BFD_RELOC_PPC_B26;
       else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
          && operand->shift == 0)
        fixP->fx_r_type = BFD_RELOC_PPC_B26;
       else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
-         && operand->bits == 16
+         && operand->bitm == 0xfffc
          && operand->shift == 0)
        {
          fixP->fx_r_type = BFD_RELOC_PPC_B16;
          && operand->shift == 0)
        {
          fixP->fx_r_type = BFD_RELOC_PPC_B16;
@@ -5628,11 +5743,11 @@ md_apply_fix (fixP, valP, seg)
 #endif
        }
       else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
 #endif
        }
       else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
-              && operand->bits == 26
+              && operand->bitm == 0x3fffffc
               && operand->shift == 0)
        fixP->fx_r_type = BFD_RELOC_PPC_BA26;
       else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
               && operand->shift == 0)
        fixP->fx_r_type = BFD_RELOC_PPC_BA26;
       else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
-              && operand->bits == 16
+              && operand->bitm == 0xfffc
               && operand->shift == 0)
        {
          fixP->fx_r_type = BFD_RELOC_PPC_BA16;
               && operand->shift == 0)
        {
          fixP->fx_r_type = BFD_RELOC_PPC_BA16;
@@ -5644,7 +5759,7 @@ md_apply_fix (fixP, valP, seg)
        }
 #if defined (OBJ_XCOFF) || defined (OBJ_ELF)
       else if ((operand->flags & PPC_OPERAND_PARENS) != 0
        }
 #if defined (OBJ_XCOFF) || defined (OBJ_ELF)
       else if ((operand->flags & PPC_OPERAND_PARENS) != 0
-              && operand->bits == 16
+              && (operand->bitm & 0xfff0) == 0xfff0
               && operand->shift == 0)
        {
          if (ppc_is_toc_sym (fixP->fx_addsy))
               && operand->shift == 0)
        {
          if (ppc_is_toc_sym (fixP->fx_addsy))
@@ -6073,7 +6188,7 @@ ppc_cfi_frame_initial_instructions ()
 }
 
 int
 }
 
 int
-tc_ppc_regname_to_dw2regnum (const char *regname)
+tc_ppc_regname_to_dw2regnum (char *regname)
 {
   unsigned int regnum = -1;
   unsigned int i;
 {
   unsigned int regnum = -1;
   unsigned int i;
This page took 0.03853 seconds and 4 git commands to generate.