* config/tc-ppc.c (ppc_insert_operand): Truncate sign bits in
authorAlan Modra <amodra@gmail.com>
Sat, 26 May 2007 14:49:39 +0000 (14:49 +0000)
committerAlan Modra <amodra@gmail.com>
Sat, 26 May 2007 14:49:39 +0000 (14:49 +0000)
top 32 bits of 64 bit value if so doing results in passing
range check.  Rewrite sign extension fudges similarly.  Enable
fudges for powerpc64 too.  Report user value if range check
fails rather than fudged value.  Negate PPC_OPERAND_NEGATIVE
range rather than value, also to report user value on failure.

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

index 8b471d5dc2111f163055de4b9d5a104da6ecb106..95dfaa44deaa7ba00ee0e750d6686b4c0fc72dd1 100644 (file)
@@ -1,3 +1,12 @@
+2007-05-26  Alan Modra  <amodra@bigpond.net.au>
+
+       * config/tc-ppc.c (ppc_insert_operand): Truncate sign bits in
+       top 32 bits of 64 bit value if so doing results in passing
+       range check.  Rewrite sign extension fudges similarly.  Enable
+       fudges for powerpc64 too.  Report user value if range check
+       fails rather than fudged value.  Negate PPC_OPERAND_NEGATIVE
+       range rather than value, also to report user value on failure.
+
 2007-03-25  Paul Brook  <paul@codesourcery.com>
 
        * config/tc-arm.c (T2_SUBS_PC_LR): Define.
index 96f165c2b43a5c585614d10e61a75cbe54ad4550..b07306e677d0284b2d66a3425fef5dd252d8fe2a 100644 (file)
@@ -86,9 +86,6 @@ static bfd_boolean reg_names_p = TARGET_REG_NAMES_P;
 
 static bfd_boolean register_name PARAMS ((expressionS *));
 static void ppc_set_cpu PARAMS ((void));
-static unsigned long ppc_insert_operand
-  PARAMS ((unsigned long insn, const struct powerpc_operand *operand,
-          offsetT val, char *file, unsigned int line));
 static void ppc_macro PARAMS ((char *str, const struct powerpc_macro *macro));
 static void ppc_byte PARAMS ((int));
 
@@ -1507,15 +1504,13 @@ ppc_cleanup ()
 /* Insert an operand value into an instruction.  */
 
 static unsigned long
-ppc_insert_operand (insn, operand, val, file, line)
-     unsigned long insn;
-     const struct powerpc_operand *operand;
-     offsetT val;
-     char *file;
-     unsigned int line;
+ppc_insert_operand (unsigned long insn,
+                   const struct powerpc_operand *operand,
+                   offsetT val,
+                   char *file,
+                   unsigned int line)
 {
   long min, max, right;
-  offsetT test;
 
   max = operand->bitm;
   right = max & -max;
@@ -1526,35 +1521,44 @@ ppc_insert_operand (insn, operand, val, file, line)
       if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0)
        max = (max >> 1) & -right;
       min = ~max & -right;
-
-      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)
-           {
-             val -= 0x80000000;
-             val -= 0x80000000;
-           }
-       }
     }
 
   if ((operand->flags & PPC_OPERAND_PLUS1) != 0)
     max++;
 
   if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0)
-    test = - val;
-  else
-    test = val;
-
-  if ((min <= max && (test < (offsetT) min || test > (offsetT) max))
-      || (test & (right - 1)) != 0)
-    as_bad_value_out_of_range (_("operand"),
-                              test, (offsetT) min, (offsetT) max, file, line);
+    {
+      long tmp = min;
+      min = -max;
+      max = -tmp;
+    }
+
+  if (min <= 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 - 0x80000000 - 0x80000000) & (right - 1)) == 0)
+       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 + 0x80000000 + 0x80000000) & (right - 1)) == 0)
+       val = val + 0x80000000 + 0x80000000;
+
+      else if (val < min
+              || val > max
+              || (val & (right - 1)) != 0)
+       as_bad_value_out_of_range (_("operand"), val, min, max, file, line);
+    }
 
   if (operand->insert)
     {