expmed.c (store_bit_field): Make the SUBREG code adjust bitnum.
authorRichard Sandiford <rsandifo@redhat.com>
Sun, 6 Feb 2005 15:39:07 +0000 (15:39 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Sun, 6 Feb 2005 15:39:07 +0000 (15:39 +0000)
* expmed.c (store_bit_field): Make the SUBREG code adjust bitnum.
Set bitpos and offset later in the function.  Do nothing if the
target is a register and if the bitfield lies completely outside
that register.
(extract_bit_field): Make the same SUBREG, bitpos and offset changes
here.  Return an uninitialised register if the source value is stored
in a register and the bitfield lies completely outside that register.

From-SVN: r94677

gcc/ChangeLog
gcc/expmed.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/compile/20050206-1.c [new file with mode: 0644]

index b1a5558fc36395f3f031a1214c1b6a1108c0caa8..e02434e999df063381702a1a6fa559e5f31b3151 100644 (file)
@@ -1,3 +1,13 @@
+2005-02-06  Richard Sandiford  <rsandifo@redhat.com>
+
+       * expmed.c (store_bit_field): Make the SUBREG code adjust bitnum.
+       Set bitpos and offset later in the function.  Do nothing if the
+       target is a register and if the bitfield lies completely outside
+       that register.
+       (extract_bit_field): Make the same SUBREG, bitpos and offset changes
+       here.  Return an uninitialised register if the source value is stored
+       in a register and the bitfield lies completely outside that register.
+
 2005-02-06  Steven Bosscher  <stevenb@suse.de>
 
        * df.c (df_insn_refs_record): Use XEXP to get the operand of a USE,
index 87a219d2605fa1a9b5f9e608b6a17e4f2abe8ccd..1a1bdf74b048836756dbd6399fecee9734e2a494 100644 (file)
@@ -337,8 +337,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 {
   unsigned int unit
     = (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
-  unsigned HOST_WIDE_INT offset = bitnum / unit;
-  unsigned HOST_WIDE_INT bitpos = bitnum % unit;
+  unsigned HOST_WIDE_INT offset, bitpos;
   rtx op0 = str_rtx;
   int byte_offset;
   rtx orig_value;
@@ -352,12 +351,16 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
         meaningful at a much higher level; when structures are copied
         between memory and regs, the higher-numbered regs
         always get higher addresses.  */
-      offset += (SUBREG_BYTE (op0) / UNITS_PER_WORD);
-      /* We used to adjust BITPOS here, but now we do the whole adjustment
-        right after the loop.  */
+      bitnum += SUBREG_BYTE (op0) * BITS_PER_UNIT;
       op0 = SUBREG_REG (op0);
     }
 
+  /* No action is needed if the target is a register and if the field
+     lies completely outside that register.  This can occur if the source
+     code contains an out-of-bounds access to a small array.  */
+  if (REG_P (op0) && bitnum >= GET_MODE_BITSIZE (GET_MODE (op0)))
+    return value;
+
   /* Use vec_set patterns for inserting parts of vectors whenever
      available.  */
   if (VECTOR_MODE_P (GET_MODE (op0))
@@ -419,6 +422,8 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      done with a simple store.  For targets that support fast unaligned
      memory, any naturally sized, unit aligned field can be done directly.  */
 
+  offset = bitnum / unit;
+  bitpos = bitnum % unit;
   byte_offset = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
                 + (offset * UNITS_PER_WORD);
 
@@ -1064,8 +1069,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 {
   unsigned int unit
     = (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
-  unsigned HOST_WIDE_INT offset = bitnum / unit;
-  unsigned HOST_WIDE_INT bitpos = bitnum % unit;
+  unsigned HOST_WIDE_INT offset, bitpos;
   rtx op0 = str_rtx;
   rtx spec_target = target;
   rtx spec_target_subreg = 0;
@@ -1080,15 +1084,16 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
   while (GET_CODE (op0) == SUBREG)
     {
-      bitpos += SUBREG_BYTE (op0) * BITS_PER_UNIT;
-      if (bitpos > unit)
-       {
-         offset += (bitpos / unit);
-         bitpos %= unit;
-       }
+      bitnum += SUBREG_BYTE (op0) * BITS_PER_UNIT;
       op0 = SUBREG_REG (op0);
     }
 
+  /* If we have an out-of-bounds access to a register, just return an
+     uninitialised register of the required mode.  This can occur if the
+     source code contains an out-of-bounds access to a small array.  */
+  if (REG_P (op0) && bitnum >= GET_MODE_BITSIZE (GET_MODE (op0)))
+    return gen_reg_rtx (tmode);
+
   if (REG_P (op0)
       && mode == GET_MODE (op0)
       && bitnum == 0
@@ -1188,6 +1193,8 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      can also be extracted with a SUBREG.  For this, we need the
      byte offset of the value in op0.  */
 
+  bitpos = bitnum % unit;
+  offset = bitnum / unit;
   byte_offset = bitpos / BITS_PER_UNIT + offset * UNITS_PER_WORD;
 
   /* If OP0 is a register, BITPOS must count within a word.
index 608b077b2337b75595cb4b18fedb17fcc7409072..2dfc38fff8c2f5fc1c9cb24c821d76eb3b0526b5 100644 (file)
@@ -1,3 +1,7 @@
+2005-02-06  Richard Sandiford  <rsandifo@redhat.com>
+
+       * gcc.c-torture/compile/20050206-1.c: New test.
+
 2005-02-03  Andrew Pinski  <pinskia@physics.uc.edu>
 
        PR tree-opt/19768
diff --git a/gcc/testsuite/gcc.c-torture/compile/20050206-1.c b/gcc/testsuite/gcc.c-torture/compile/20050206-1.c
new file mode 100644 (file)
index 0000000..5ea49a6
--- /dev/null
@@ -0,0 +1,8 @@
+unsigned short foo (void)
+{
+  unsigned short u[1] = { 1 };
+  u[0] = 0;
+  u[1] = 1;
+  u[2] = 2;
+  return u[0] + u[1] + u[2];
+}