merge from gcc
[external/binutils.git] / gas / config / tc-v850.c
index 1828396..e0ac162 100644 (file)
@@ -1,12 +1,12 @@
 /* tc-v850.c -- Assembler code for the NEC V850
-   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-   Free Software Foundation, Inc.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+   2006, 2007, 2009  Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -19,7 +19,6 @@
    the Free 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"
@@ -478,16 +477,16 @@ v850_longcode (int type)
   if (! v850_relax)
     {
       if (type == 1)
-       as_warn (".longcall pseudo-op seen when not relaxing");
+       as_warn (_(".longcall pseudo-op seen when not relaxing"));
       else
-       as_warn (".longjump pseudo-op seen when not relaxing");
+       as_warn (_(".longjump pseudo-op seen when not relaxing"));
     }
 
   expression (&ex);
 
   if (ex.X_op != O_symbol || ex.X_add_number != 0)
     {
-      as_bad ("bad .longcall format");
+      as_bad (_("bad .longcall format"));
       ignore_rest_of_line ();
 
       return;
@@ -1179,39 +1178,7 @@ md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 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;
-
-  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, FALSE);
 }
 
 /* Very gross.  */
@@ -1221,13 +1188,29 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
                 asection *sec,
                 fragS *fragP)
 {
+  /* This code performs some nasty type punning between the
+     fr_opcode field of the frag structure (a char *) and the
+     fx_r_type field of the fix structure (a bfd_reloc_code_real_type)
+     On a 64bit host this causes problems because these two fields
+     are not the same size, but since we know that we are only
+     ever storing small integers in the fields, it is safe to use
+     a union to convert between them.  */
+  union u
+  {
+    bfd_reloc_code_real_type fx_r_type;
+    char * fr_opcode;
+  }
+  opcode_converter;
   subseg_change (sec, 0);
 
+  opcode_converter.fr_opcode = fragP->fr_opcode;
+      
   /* In range conditional or unconditional branch.  */
   if (fragP->fr_subtype == 0 || fragP->fr_subtype == 2)
     {
       fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
-              fragP->fr_offset, 1, BFD_RELOC_UNUSED + (int)fragP->fr_opcode);
+              fragP->fr_offset, 1,
+              BFD_RELOC_UNUSED + opcode_converter.fx_r_type);
       fragP->fr_fix += 2;
     }
   /* Out of range conditional branch.  Emit a branch around a jump.  */
@@ -1249,8 +1232,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
         target.  */
       md_number_to_chars ((char *) buffer + 2, 0x00000780, 4);
       fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
-              fragP->fr_offset, 1, BFD_RELOC_UNUSED +
-              (int) fragP->fr_opcode + 1);
+              fragP->fr_offset, 1,
+              BFD_RELOC_UNUSED + opcode_converter.fx_r_type + 1);
       fragP->fr_fix += 6;
     }
   /* Out of range unconditional branch.  Emit a jump.  */
@@ -1258,8 +1241,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
     {
       md_number_to_chars (fragP->fr_fix + fragP->fr_literal, 0x00000780, 4);
       fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
-              fragP->fr_offset, 1, BFD_RELOC_UNUSED +
-              (int) fragP->fr_opcode + 1);
+              fragP->fr_offset, 1,
+              BFD_RELOC_UNUSED + opcode_converter.fx_r_type + 1);
       fragP->fr_fix += 4;
     }
   else
@@ -1522,9 +1505,9 @@ v850_insert_operand (unsigned long insn,
          else
            {
              if (file == (char *) NULL)
-               as_warn (message);
+               as_warn ("%s", message);
              else
-               as_warn_where (file, line, message);
+               as_warn_where (file, line, "%s", message);
            }
        }
     }
@@ -1553,7 +1536,24 @@ v850_insert_operand (unsigned long insn,
                min = 0;
            }
 
-         if (val < (offsetT) min || val > (offsetT) max)
+         /* Some people write constants with the sign extension done by
+            hand but only up to 32 bits.  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 to 64 bits if so doing makes the
+            value valid.  */
+         if (val > max
+             && (offsetT) (val - 0x80000000 - 0x80000000) >= min
+             && (offsetT) (val - 0x80000000 - 0x80000000) <= max)
+           val = val - 0x80000000 - 0x80000000;
+
+         /* Similarly, people write expressions like ~(1<<15), and expect
+            this to be OK for a 32-bit unsigned value.  */
+         else if (val < min
+                  && (offsetT) (val + 0x80000000 + 0x80000000) >= min
+                  && (offsetT) (val + 0x80000000 + 0x80000000) <= max)
+           val = val + 0x80000000 + 0x80000000;
+
+         else if (val < (offsetT) min || val > (offsetT) max)
            {
              char buf [128];
 
@@ -2036,6 +2036,20 @@ md_assemble (char *str)
 
   if (relaxable && fc > 0)
     {
+      /* On a 64-bit host the size of an 'int' is not the same
+        as the size of a pointer, so we need a union to convert
+        the opindex field of the fr_cgen structure into a char *
+        so that it can be stored in the frag.  We do not have
+        to worry about loosing accuracy as we are not going to
+        be even close to the 32bit limit of the int.  */
+      union
+      {
+       int opindex;
+       char * ptr;
+      }
+      opindex_converter;
+
+      opindex_converter.opindex = fixups[0].opindex;
       insn_size = 2;
       fc = 0;
 
@@ -2044,7 +2058,7 @@ md_assemble (char *str)
          f = frag_var (rs_machine_dependent, 4, 2, 2,
                        fixups[0].exp.X_add_symbol,
                        fixups[0].exp.X_add_number,
-                       (char *) fixups[0].opindex);
+                       opindex_converter.ptr);
          md_number_to_chars (f, insn, insn_size);
          md_number_to_chars (f + 2, 0, 2);
        }
@@ -2053,7 +2067,7 @@ md_assemble (char *str)
          f = frag_var (rs_machine_dependent, 6, 4, 0,
                        fixups[0].exp.X_add_symbol,
                        fixups[0].exp.X_add_number,
-                       (char *) fixups[0].opindex);
+                       opindex_converter.ptr);
          md_number_to_chars (f, insn, insn_size);
          md_number_to_chars (f + 2, 0, 4);
        }
@@ -2087,7 +2101,7 @@ md_assemble (char *str)
      BFD_RELOC_UNUSED plus the operand index.  This lets us easily
      handle fixups for any operand type, although that is admittedly
      not a very exciting feature.  We pick a BFD reloc type in
-     md_apply_fix3.  */
+     md_apply_fix.  */
   for (i = 0; i < fc; i++)
     {
       const struct v850_operand *operand;
@@ -2240,7 +2254,7 @@ v850_pcrel_from_section (fixS *fixp, segT section)
 }
 
 void
-md_apply_fix3 (fixS *fixP, valueT *valueP, segT seg ATTRIBUTE_UNUSED)
+md_apply_fix (fixS *fixP, valueT *valueP, segT seg ATTRIBUTE_UNUSED)
 {
   valueT value = * valueP;
   char *where;
@@ -2321,8 +2335,10 @@ md_apply_fix3 (fixS *fixP, valueT *valueP, segT seg ATTRIBUTE_UNUSED)
       /* We still have to insert the value into memory!  */
       where = fixP->fx_frag->fr_literal + fixP->fx_where;
 
-      if (fixP->tc_fix_data != NULL)
+      if (fixP->tc_fix_data != NULL
+         && ((struct v850_operand *) fixP->tc_fix_data)->insert != NULL)
        {
+         const char * message = NULL;
          struct v850_operand * operand = (struct v850_operand *) fixP->tc_fix_data;
          unsigned long insn;
 
@@ -2339,8 +2355,8 @@ md_apply_fix3 (fixS *fixP, valueT *valueP, segT seg ATTRIBUTE_UNUSED)
 
          /* Use the operand's insertion procedure, if present, in order to
             make sure that the value is correctly stored in the insn.  */
-         insn = v850_insert_operand (insn, operand, (offsetT) value,
-                                     fixP->fx_file, fixP->fx_line, NULL);
+         insn = operand->insert (insn, (offsetT) value, & message);
+         /* Ignore message even if it is set.  */
 
          bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
        }