This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR middle-end/18045


Hello,

This is the miscompilation of the Ada front-end on i486-linux, namely 
ada/uintp.adb:UI_From_Dint.  The problem is that the recently added 
expand_smod_pow2 cannot handle modes whose size is greater than that of 
HOST_WIDE_INT on targets where branches are cheap.  The testcase demonstrates 
the problem with DImode and HOST_WIDE_INT=32-bit long.

Bootstrapped/regtested on i486-mandrake-linux-gnu, approved offline by Roger, 
applied to mainline.


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 ?Eric Botcazou ?<ebotcazou@libertysurf.fr>

	* gcc.dg/smod-1.c: New test.


-- 
Eric Botcazou
Index: expmed.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expmed.c,v
retrieving revision 1.198
diff -u -p -r1.198 expmed.c
--- expmed.c	7 Oct 2004 05:56:51 -0000	1.198
+++ expmed.c	18 Oct 2004 12:07:30 -0000
@@ -3193,7 +3193,7 @@ expand_mult_highpart (enum machine_mode 
 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
       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
 				   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
 
 	      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
      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
 
   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)
/* 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;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]