* read.c (convert_to_bignum): New function, split out from...
authorRichard Sandiford <rdsandiford@googlemail.com>
Wed, 19 Jan 2005 11:53:53 +0000 (11:53 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Wed, 19 Jan 2005 11:53:53 +0000 (11:53 +0000)
(emit_expr): ...here.  Handle the case where X_add_number is
positive and the input value is negative.
(output_big_sleb128): Fix setting of continuation bit.  Check whether
the final byte needs to be sign-extended.  Fix size-shrinking loop.
(emit_leb128_expr): When generating a signed leb128, see whether the
sign of an O_constant's X_add_number matches the sign of the input
value.  Use a bignum if not.

gas/ChangeLog
gas/read.c
gas/testsuite/ChangeLog
gas/testsuite/gas/all/gas.exp
gas/testsuite/gas/all/quad.d [new file with mode: 0644]
gas/testsuite/gas/all/quad.s [new file with mode: 0644]
gas/testsuite/gas/all/sleb128.d [new file with mode: 0644]
gas/testsuite/gas/all/sleb128.s [new file with mode: 0644]

index c0f8ca4..a833acd 100644 (file)
@@ -1,3 +1,14 @@
+2005-01-19  Richard Sandiford  <rsandifo@redhat.com>
+
+       * read.c (convert_to_bignum): New function, split out from...
+       (emit_expr): ...here.  Handle the case where X_add_number is
+       positive and the input value is negative.
+       (output_big_sleb128): Fix setting of continuation bit.  Check whether
+       the final byte needs to be sign-extended.  Fix size-shrinking loop.
+       (emit_leb128_expr): When generating a signed leb128, see whether the
+       sign of an O_constant's X_add_number matches the sign of the input
+       value.  Use a bignum if not.
+
 2005-01-17  Andrew Stubbs  <andrew.stubbs@st.com>
 
        * tc-sh.c (md_begin,md_parse_option): Change arch_sh1_up to
index e6cee54..e04e00c 100644 (file)
@@ -1,6 +1,7 @@
 /* read.c - read a source file -
    Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
 
 This file is part of GAS, the GNU Assembler.
 
@@ -1082,6 +1083,29 @@ read_a_source_file (char *name)
 #endif
 }
 
+/* Convert O_constant expression EXP into the equivalent O_big representation.
+   Take the sign of the number from X_unsigned rather than X_add_number.  */
+
+static void
+convert_to_bignum (expressionS *exp)
+{
+  valueT value;
+  unsigned int i;
+
+  value = exp->X_add_number;
+  for (i = 0; i < sizeof (exp->X_add_number) / CHARS_PER_LITTLENUM; i++)
+    {
+      generic_bignum[i] = value & LITTLENUM_MASK;
+      value >>= LITTLENUM_NUMBER_OF_BITS;
+    }
+  /* Add a sequence of sign bits if the top bit of X_add_number is not
+     the sign of the original value.  */
+  if ((exp->X_add_number < 0) != !exp->X_unsigned)
+    generic_bignum[i++] = exp->X_unsigned ? 0 : LITTLENUM_MASK;
+  exp->X_op = O_big;
+  exp->X_add_number = i;
+}
+
 /* For most MRI pseudo-ops, the line actually ends at the first
    nonquoted space.  This function looks for that point, stuffs a null
    in, and sets *STOPCP to the character that used to be there, and
@@ -3541,22 +3565,9 @@ emit_expr (expressionS *exp, unsigned int nbytes)
      pass to md_number_to_chars, handle it as a bignum.  */
   if (op == O_constant && nbytes > sizeof (valueT))
     {
-      valueT val;
-      int gencnt;
-
-      if (!exp->X_unsigned && exp->X_add_number < 0)
-       extra_digit = (valueT) -1;
-      val = (valueT) exp->X_add_number;
-      gencnt = 0;
-      do
-       {
-         generic_bignum[gencnt] = val & LITTLENUM_MASK;
-         val >>= LITTLENUM_NUMBER_OF_BITS;
-         ++gencnt;
-       }
-      while (val != 0);
-      op = exp->X_op = O_big;
-      exp->X_add_number = gencnt;
+      extra_digit = exp->X_unsigned ? 0 : -1;
+      convert_to_bignum (exp);
+      op = O_big;
     }
 
   if (op == O_constant)
@@ -4276,36 +4287,48 @@ output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size)
   unsigned byte;
 
   /* Strip leading sign extensions off the bignum.  */
-  while (size > 0 && bignum[size - 1] == (LITTLENUM_TYPE) -1)
+  while (size > 1
+        && bignum[size - 1] == LITTLENUM_MASK
+        && bignum[size - 2] > LITTLENUM_MASK / 2)
     size--;
 
   do
     {
-      if (loaded < 7 && size > 0)
-       {
-         val |= (*bignum << loaded);
-         loaded += 8 * CHARS_PER_LITTLENUM;
-         size--;
-         bignum++;
-       }
-
-      byte = val & 0x7f;
-      loaded -= 7;
-      val >>= 7;
+      /* OR in the next part of the littlenum.  */
+      val |= (*bignum << loaded);
+      loaded += LITTLENUM_NUMBER_OF_BITS;
+      size--;
+      bignum++;
 
-      if (size == 0)
+      /* Add bytes until there are less than 7 bits left in VAL
+        or until every non-sign bit has been written.  */
+      do
        {
-         if ((val == 0 && (byte & 0x40) == 0)
-             || (~(val | ~(((valueT) 1 << loaded) - 1)) == 0
-                 && (byte & 0x40) != 0))
+         byte = val & 0x7f;
+         loaded -= 7;
+         val >>= 7;
+         if (size > 0
+             || val != ((byte & 0x40) == 0 ? 0 : ((valueT) 1 << loaded) - 1))
            byte |= 0x80;
+
+         if (orig)
+           *p = byte;
+         p++;
        }
+      while ((byte & 0x80) != 0 && loaded >= 7);
+    }
+  while (size > 0);
 
+  /* Mop up any left-over bits (of which there will be less than 7).  */
+  if ((byte & 0x80) != 0)
+    {
+      /* Sign-extend VAL.  */
+      if (val & (1 << (loaded - 1)))
+       val |= ~0 << loaded;
       if (orig)
-       *p = byte;
+       *p = val & 0x7f;
       p++;
     }
-  while (byte & 0x80);
 
   return p - orig;
 }
@@ -4384,6 +4407,16 @@ emit_leb128_expr (expressionS *exp, int sign)
       as_warn (_("register value used as expression"));
       op = O_constant;
     }
+  else if (op == O_constant
+          && sign
+          && (exp->X_add_number < 0) != !exp->X_unsigned)
+    {
+      /* We're outputting a signed leb128 and the sign of X_add_number
+        doesn't reflect the sign of the original value.  Convert EXP
+        to a correctly-extended bignum instead.  */
+      convert_to_bignum (exp);
+      op = O_big;
+    }
 
   /* Let check_eh_frame know that data is being emitted.  nbytes == -1 is
      a signal that this is leb128 data.  It shouldn't optimize this away.  */
index e1eab3b..e070cf3 100644 (file)
@@ -1,3 +1,9 @@
+2005-01-19  Richard Sandiford  <rsandifo@redhat.com>
+
+       * gas/all/sleb128.[sd]: New test.
+       * gas/all/quad.[sd]: New test.
+       * gas/all/gas.exp: Run them.
+
 2005-01-17  Andrew Stubbs  <andrew.stubbs@st.com>
 
        * gas/sh/arch/arch.exp: Correct the email address.
index 966c112..6f196fa 100644 (file)
@@ -195,6 +195,9 @@ if {   [istarget "i*86-*-*pe*"] \
   gas_test "fastcall.s" ""   "" "fastcall labels"
 }
 
+run_dump_test sleb128
+run_dump_test quad
+
 load_lib gas-dg.exp
 dg-init
 dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/err-*.s $srcdir/$subdir/warn-*.s]] "" ""
diff --git a/gas/testsuite/gas/all/quad.d b/gas/testsuite/gas/all/quad.d
new file mode 100644 (file)
index 0000000..c3a758d
--- /dev/null
@@ -0,0 +1,12 @@
+#objdump : -s -j .data
+#name : .quad tests
+
+.*: .*
+
+Contents of section .data:
+ 0000 (00000000 76543210 00000000 80000000|10325476 00000000 00000080 00000000) .*
+ 0010 (00000000 87654321 00000000 ffffffff|21436587 00000000 ffffffff 00000000) .*
+ 0020 (ffffffff 89abcdf0 ffffffff 80000000|f0cdab89 ffffffff 00000080 ffffffff) .*
+ 0030 (ffffffff 789abcdf ffffffff 00000001|dfbc9a78 ffffffff 01000000 ffffffff) .*
+ 0040 (01234567 89abcdef fedcba98 76543211|efcdab89 67452301 11325476 98badcfe) .*
+#pass
diff --git a/gas/testsuite/gas/all/quad.s b/gas/testsuite/gas/all/quad.s
new file mode 100644 (file)
index 0000000..af250cd
--- /dev/null
@@ -0,0 +1,12 @@
+       .data
+       .quad   0x76543210
+       .quad   0x80000000
+       .quad   0x87654321
+       .quad   0xffffffff
+       .quad   -0x76543210
+       .quad   -0x80000000
+       .quad   -0x87654321
+       .quad   -0xffffffff
+
+       .quad   0x123456789abcdef
+       .quad   -0x123456789abcdef
diff --git a/gas/testsuite/gas/all/sleb128.d b/gas/testsuite/gas/all/sleb128.d
new file mode 100644 (file)
index 0000000..eaff63d
--- /dev/null
@@ -0,0 +1,57 @@
+#objdump : -s -j .data
+#name : .sleb128 tests
+
+.*: .*
+
+Contents of section .data:
+#
+# 0x76543210   :           000_0111 0110_010 1_0100_00 11_0010_0 001_0000
+# 0x80000000   :           000_1000 0000_000 0_0000_00 00_0000_0 000_0000
+# 0x87654321   :           000_1000 0111_011 0_0101_01 00_0011_0 010_0001
+# 0xffffffff   :           ..................................... 111_1111
+#
+ 0000 90e4d0b2 07808080 8008a186 95bb08ff .*
+#
+# 0xffffffff   :           000_1111 1111_111 1_1111_11 11_1111_1 ........
+# -0x76543210  :           111_1000 1001_101 0_1011_11 00_1101_1 111_0000
+# -0x80000000  :           111_1000 0000_000 0_0000_00 00_0000_0 000_0000
+# -0x87654321  :           ........................... 11_1100_1 101_1111
+#
+ 0010 ffffff0f f09bafcd 78808080 8078dff9 .*
+#
+# -0x87654321  :           111_0111 1000_100 1_1010_10 ..................
+# -0xffffffff  :           111_0000 0000_000 0_0000_00 00_0000_0 000_0001
+#    789abcdef :           111_1000 1001_101 0_1011_11 00_1101_1 110_1111
+# 0x123456     :           ........ 0010_001 1_0100_01 01_0110_0
+#
+ 0020 eac47781 80808070 ef9bafcd f8acd191 .*
+#
+# 0x123456     :           000_0001 ............................
+#    789abcdef :           000_0111 0110_010 1_0100_00 11_0010_0 001_0001
+# -0x123456    :           111_1110 1101_110 0_1011_10 01_1001_1
+#    fffffffff :           000_0000 0000_000 0_0000_00 00_0000_0 000_0001
+# -0x7ff       :                             ......... 00_0000_0
+#
+ 0030 0191e4d0 b287d3ae ee7e8180 80808080 .*
+#
+# -0x7ff       :                             1_1000_00 .........
+#    000000000 :           000_0000 0000_000 0_0000_00 00_0000_0 000_0000
+# -0x800       :                             1_1000_00 00_0000_0
+#    fffffffff :           000_0000 0000_000 0_0000_00 00_0000_0 000_0001
+# -0x7ffffff   : .................. 0000_000 0_0000_00 00_0000_0
+#
+ 0040 60808080 80808060 81808080 80808080 .*
+#
+# -0x7ffffff   : 11_1111_1 000_0000 ............................
+#    000000000 :           000_0000 0000_000 0_0000_00 00_0000_0 000_0000
+# -0x8000000   : 11_1111_1 000_0000 0000_000 0_0000_00 00_0000_0
+# -0x100000000 :           ........ 0000_000 0_0000_00 00_0000_0 000_0000
+#
+ 0050 807f8080 80808080 8080807f 80808080 .*
+#
+# -0x100000000 :           111_0000 .....................................
+#    000000000 :           000_0000 0000_000 0_0000_00 00_0000_0 000_0000
+# -0x1000      :                             1_0000_00 00_0000_0
+#
+ 0060 70808080 80808040 00000000 00000000 .*
+#pass
diff --git a/gas/testsuite/gas/all/sleb128.s b/gas/testsuite/gas/all/sleb128.s
new file mode 100644 (file)
index 0000000..e8997ca
--- /dev/null
@@ -0,0 +1,22 @@
+       .data
+       .sleb128        0x76543210
+       .sleb128        0x80000000
+       .sleb128        0x87654321
+       .sleb128        0xffffffff
+       .sleb128        -0x76543210
+       .sleb128        -0x80000000
+       .sleb128        -0x87654321
+       .sleb128        -0xffffffff
+
+       .sleb128        0x123456789abcdef
+       .sleb128        -0x123456789abcdef
+
+       .sleb128        -0x7fffffffffff
+       .sleb128        -0x800000000000
+       .sleb128        -0x7fffffffffffffff
+       .sleb128        -0x8000000000000000
+
+       .sleb128        -0x100000000
+       .sleb128        -0x1000000000000
+
+       .fill           32