From 6e7a355c164ab9adb03365f83f864b8e2c201c23 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Tue, 19 Oct 2004 00:45:01 +0200 Subject: [PATCH] re PR middle-end/18045 (signed integer remainder for power of 2 broken) 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 | 6 ++++++ gcc/expmed.c | 34 ++++++++++++++++++++++------------ gcc/testsuite/ChangeLog | 4 ++++ gcc/testsuite/gcc.dg/smod-1.c | 25 +++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/smod-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1cf128f204d..02a42e4cdbf 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2004-10-18 Eric Botcazou + + 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 * c-parse.in (reservedwords): Add OBJC_TYPE_QUAL as alternative. diff --git a/gcc/expmed.c b/gcc/expmed.c index 98981b8f247..2601361f60e 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -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) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 929a9cde67e..0254a749d12 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-10-18 Eric Botcazou + + * gcc.dg/smod-1.c: New test. + 2004-10-18 Ziemowit Laski * 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 index 00000000000..18c43ee5df4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/smod-1.c @@ -0,0 +1,25 @@ +/* PR middle-end/18045 */ +/* Contributed by Eric Botcazou */ + +/* { dg-do run } */ +/* { dg-options "-std=c99" } */ +/* { dg-options "-std=c99 -mtune=i486" { target i?86-*-* x86_64-*-* } } */ + +#include + +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; +}