]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR middle-end/18045 (signed integer remainder for power of 2 broken)
authorEric Botcazou <ebotcazou@libertysurf.fr>
Mon, 18 Oct 2004 22:45:01 +0000 (00:45 +0200)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 18 Oct 2004 22:45:01 +0000 (22:45 +0000)
PR middle-end/18045
* expmed.c (expand_smod_pow2): Handle modes whose size
is greater than that of HOST_WIDE_INT.

From-SVN: r89253

gcc/ChangeLog
gcc/expmed.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/smod-1.c [new file with mode: 0644]

index 1cf128f204dd6226e878513eb9f3c36c67c3442f..02a42e4cdbfc251e853f8a5d10e7cba6d6c3cb9e 100644 (file)
@@ -1,3 +1,9 @@
+2004-10-18  Eric Botcazou  <ebotcazou@libertysurf.fr>
+
+       PR middle-end/18045
+       * expmed.c (expand_smod_pow2): Handle modes whose size
+       is greater than that of HOST_WIDE_INT.
+
 2004-10-18  Ziemowit Laski  <zlaski@apple.com>
 
        * c-parse.in (reservedwords): Add OBJC_TYPE_QUAL as alternative.
index 98981b8f24739e9c4cd4a801b2b1ce349bdcd653..2601361f60ea8a456c08a88b7ce454d188a98375 100644 (file)
@@ -3193,7 +3193,7 @@ expand_mult_highpart (enum machine_mode mode, rtx op0,
 static rtx
 expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
-  unsigned HOST_WIDE_INT mask;
+  unsigned HOST_WIDE_INT masklow, maskhigh;
   rtx result, temp, shift, label;
   int logd;
 
@@ -3209,14 +3209,14 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
       if (signmask)
        {
          signmask = force_reg (mode, signmask);
-         mask = ((HOST_WIDE_INT) 1 << logd) - 1;
+         masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
          shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
 
          /* Use the rtx_cost of a LSHIFTRT instruction to determine
             which instruction sequence to use.  If logical right shifts
             are expensive the use 2 XORs, 2 SUBs and an AND, otherwise
             use a LSHIFTRT, 1 ADD, 1 SUB and an AND.  */
-            
+
          temp = gen_rtx_LSHIFTRT (mode, result, shift);
          if (lshr_optab->handlers[mode].insn_code == CODE_FOR_nothing
              || rtx_cost (temp, SET) > COSTS_N_INSNS (2))
@@ -3225,7 +3225,7 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
              temp = expand_binop (mode, sub_optab, temp, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
-             temp = expand_binop (mode, and_optab, temp, GEN_INT (mask),
+             temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
              temp = expand_binop (mode, xor_optab, temp, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
@@ -3240,7 +3240,7 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 
              temp = expand_binop (mode, add_optab, op0, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
-             temp = expand_binop (mode, and_optab, temp, GEN_INT (mask),
+             temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
              temp = expand_binop (mode, sub_optab, temp, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
@@ -3254,11 +3254,19 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
      can avoid an explicit compare operation in the following comparison
      against zero.  */
 
-  mask = (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1)
-        | (((HOST_WIDE_INT) 1 << logd) - 1);
+  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
+  if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+    {
+      masklow |= (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1);
+      maskhigh = -1;
+    }
+  else
+    maskhigh = (HOST_WIDE_INT) -1
+                << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
 
-  temp = expand_binop (mode, and_optab, op0, GEN_INT (mask), result,
-                      1, OPTAB_LIB_WIDEN);
+  temp = expand_binop (mode, and_optab, op0,
+                      immed_double_const (masklow, maskhigh, mode),
+                      result, 1, OPTAB_LIB_WIDEN);
   if (temp != result)
     emit_move_insn (result, temp);
 
@@ -3267,9 +3275,11 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 
   temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
                       0, OPTAB_LIB_WIDEN);
-  mask = (HOST_WIDE_INT) -1 << logd;
-  temp = expand_binop (mode, ior_optab, temp, GEN_INT (mask), result,
-                      1, OPTAB_LIB_WIDEN);
+  masklow = (HOST_WIDE_INT) -1 << logd;
+  maskhigh = -1;
+  temp = expand_binop (mode, ior_optab, temp,
+                      immed_double_const (masklow, maskhigh, mode),
+                      result, 1, OPTAB_LIB_WIDEN);
   temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
                       0, OPTAB_LIB_WIDEN);
   if (temp != result)
index 929a9cde67e58bb1405f5190fc7b45f68c12e17b..0254a749d12803dcebb2dc2b2261b97185a87294 100644 (file)
@@ -1,3 +1,7 @@
+2004-10-18  Eric Botcazou  <ebotcazou@libertysurf.fr>
+
+       * gcc.dg/smod-1.c: New test.
+
 2004-10-18  Ziemowit Laski  <zlaski@apple.com>
 
        * objc.dg/method-14.m: New test.
diff --git a/gcc/testsuite/gcc.dg/smod-1.c b/gcc/testsuite/gcc.dg/smod-1.c
new file mode 100644 (file)
index 0000000..18c43ee
--- /dev/null
@@ -0,0 +1,25 @@
+/* PR middle-end/18045 */
+/* Contributed by Eric Botcazou <ebotcazou@libertysurf.fr> */
+
+/* { dg-do run } */
+/* { dg-options "-std=c99" } */
+/* { dg-options "-std=c99 -mtune=i486" { target i?86-*-* x86_64-*-* } } */
+
+#include <limits.h>
+
+extern void abort(void);
+
+long long smod16(long long x)
+{
+  return x % 16;
+}
+
+int main(void)
+{
+#if LLONG_MAX > 2147483647L
+  if (smod16 (0xFFFFFFFF) != 0xF)
+    abort ();
+#endif
+
+  return 0;
+}