This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR middle-end/18045
- From: Eric Botcazou <ebotcazou at libertysurf dot fr>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 19 Oct 2004 00:40:10 +0200
- Subject: [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;
}