This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PR rtl-optimization/20532] plus(ashift,ashift) -> mult may overflow
- From: Alexandre Oliva <aoliva at redhat dot com>
- To: Roger Sayle <roger at eyesopen dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: 24 Mar 2005 03:50:38 -0300
- Subject: Re: [PR rtl-optimization/20532] plus(ashift,ashift) -> mult may overflow
- Organization: Red Hat Global Engineering Services Compiler Team
- References: <Pine.LNX.4.44.0503222130100.9781-100000@www.eyesopen.com>
On Mar 23, 2005, Roger Sayle <roger@eyesopen.com> wrote:
> After two or three days on mainline without any reported problems,
> this patch is also OK for the 4.0 branch (after bootstrapping and
> regression testing there).
This is the backport to the 4.0 branch, involving only indentation
changes.
Index: gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
PR rtl-optimization/20532
* simplify-rtx.c (simplify_binary_operation): Protect from
overflow when adding coefficients for PLUS or MINUS. Handle
CONST_DOUBLE exact power of two as multiplier.
Index: gcc/simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.230.2.1
diff -u -p -r1.230.2.1 simplify-rtx.c
--- gcc/simplify-rtx.c 10 Mar 2005 22:21:58 -0000 1.230.2.1
+++ gcc/simplify-rtx.c 24 Mar 2005 06:11:14 -0000
@@ -1551,48 +1551,69 @@ simplify_binary_operation (enum rtx_code
if (! FLOAT_MODE_P (mode))
{
- HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
+ HOST_WIDE_INT coeff0h = 0, coeff1h = 0;
+ unsigned HOST_WIDE_INT coeff0l = 1, coeff1l = 1;
rtx lhs = op0, rhs = op1;
if (GET_CODE (lhs) == NEG)
- coeff0 = -1, lhs = XEXP (lhs, 0);
+ {
+ coeff0l = -1;
+ coeff0h = -1;
+ lhs = XEXP (lhs, 0);
+ }
else if (GET_CODE (lhs) == MULT
&& GET_CODE (XEXP (lhs, 1)) == CONST_INT)
{
- coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
+ coeff0l = INTVAL (XEXP (lhs, 1));
+ coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
+ lhs = XEXP (lhs, 0);
}
else if (GET_CODE (lhs) == ASHIFT
&& GET_CODE (XEXP (lhs, 1)) == CONST_INT
&& INTVAL (XEXP (lhs, 1)) >= 0
&& INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
{
- coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+ coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+ coeff0h = 0;
lhs = XEXP (lhs, 0);
}
if (GET_CODE (rhs) == NEG)
- coeff1 = -1, rhs = XEXP (rhs, 0);
+ {
+ coeff1l = -1;
+ coeff1h = -1;
+ rhs = XEXP (rhs, 0);
+ }
else if (GET_CODE (rhs) == MULT
&& GET_CODE (XEXP (rhs, 1)) == CONST_INT)
{
- coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
+ coeff1l = INTVAL (XEXP (rhs, 1));
+ coeff1h = INTVAL (XEXP (rhs, 1)) < 0 ? -1 : 0;
+ rhs = XEXP (rhs, 0);
}
else if (GET_CODE (rhs) == ASHIFT
&& GET_CODE (XEXP (rhs, 1)) == CONST_INT
&& INTVAL (XEXP (rhs, 1)) >= 0
&& INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
{
- coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
+ coeff1l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
+ coeff1h = 0;
rhs = XEXP (rhs, 0);
}
if (rtx_equal_p (lhs, rhs))
{
rtx orig = gen_rtx_PLUS (mode, op0, op1);
- tem = simplify_gen_binary (MULT, mode, lhs,
- GEN_INT (coeff0 + coeff1));
+ rtx coeff;
+ unsigned HOST_WIDE_INT l;
+ HOST_WIDE_INT h;
+
+ add_double (coeff0l, coeff0h, coeff1l, coeff1h, &l, &h);
+ coeff = immed_double_const (l, h, mode);
+
+ tem = simplify_gen_binary (MULT, mode, lhs, coeff);
return rtx_cost (tem, SET) <= rtx_cost (orig, SET)
- ? tem : 0;
+ ? tem : 0;
}
}
@@ -1701,46 +1722,69 @@ simplify_binary_operation (enum rtx_code
if (! FLOAT_MODE_P (mode))
{
- HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
+ HOST_WIDE_INT coeff0h = 0, negcoeff1h = -1;
+ unsigned HOST_WIDE_INT coeff0l = 1, negcoeff1l = -1;
rtx lhs = op0, rhs = op1;
if (GET_CODE (lhs) == NEG)
- coeff0 = -1, lhs = XEXP (lhs, 0);
+ {
+ coeff0l = -1;
+ coeff0h = -1;
+ lhs = XEXP (lhs, 0);
+ }
else if (GET_CODE (lhs) == MULT
&& GET_CODE (XEXP (lhs, 1)) == CONST_INT)
{
- coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
+ coeff0l = INTVAL (XEXP (lhs, 1));
+ coeff0h = INTVAL (XEXP (lhs, 1)) < 0 ? -1 : 0;
+ lhs = XEXP (lhs, 0);
}
else if (GET_CODE (lhs) == ASHIFT
&& GET_CODE (XEXP (lhs, 1)) == CONST_INT
&& INTVAL (XEXP (lhs, 1)) >= 0
&& INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
{
- coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+ coeff0l = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+ coeff0h = 0;
lhs = XEXP (lhs, 0);
}
if (GET_CODE (rhs) == NEG)
- coeff1 = - 1, rhs = XEXP (rhs, 0);
+ {
+ negcoeff1l = 1;
+ negcoeff1h = 0;
+ rhs = XEXP (rhs, 0);
+ }
else if (GET_CODE (rhs) == MULT
&& GET_CODE (XEXP (rhs, 1)) == CONST_INT)
{
- coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
+ negcoeff1l = -INTVAL (XEXP (rhs, 1));
+ negcoeff1h = INTVAL (XEXP (rhs, 1)) <= 0 ? 0 : -1;
+ rhs = XEXP (rhs, 0);
}
else if (GET_CODE (rhs) == ASHIFT
&& GET_CODE (XEXP (rhs, 1)) == CONST_INT
&& INTVAL (XEXP (rhs, 1)) >= 0
&& INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
{
- coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
+ negcoeff1l = -(((HOST_WIDE_INT) 1)
+ << INTVAL (XEXP (rhs, 1)));
+ negcoeff1h = -1;
rhs = XEXP (rhs, 0);
}
if (rtx_equal_p (lhs, rhs))
{
rtx orig = gen_rtx_MINUS (mode, op0, op1);
- tem = simplify_gen_binary (MULT, mode, lhs,
- GEN_INT (coeff0 - coeff1));
+ rtx coeff;
+ unsigned HOST_WIDE_INT l;
+ HOST_WIDE_INT h;
+
+ add_double (coeff0l, coeff0h, negcoeff1l, negcoeff1h,
+ &l, &h);
+ coeff = immed_double_const (l, h, mode);
+
+ tem = simplify_gen_binary (MULT, mode, lhs, coeff);
return rtx_cost (tem, SET) <= rtx_cost (orig, SET)
? tem : 0;
}
@@ -1827,6 +1871,17 @@ simplify_binary_operation (enum rtx_code
|| val != HOST_BITS_PER_WIDE_INT - 1))
return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
+ /* Likewise for multipliers wider than a word. */
+ else if (GET_CODE (trueop1) == CONST_DOUBLE
+ && (GET_MODE (trueop1) == VOIDmode
+ || GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_INT)
+ && GET_MODE (op0) == mode
+ && CONST_DOUBLE_LOW (trueop1) == 0
+ && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0)
+ return simplify_gen_binary (ASHIFT, mode, op0,
+ GEN_INT (val
+ + HOST_BITS_PER_WIDE_INT));
+
/* x*2 is x+x and x*(-1) is -x */
if (GET_CODE (trueop1) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_FLOAT
Index: gcc/testsuite/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
PR rtl-optimization/20532
* gcc.target/i386/badshift.c: New.
Index: gcc/testsuite/gcc.target/i386/badshift.c
===================================================================
RCS file: gcc/testsuite/gcc.target/i386/badshift.c
diff -N gcc/testsuite/gcc.target/i386/badshift.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.target/i386/badshift.c 24 Mar 2005 06:11:28 -0000
@@ -0,0 +1,28 @@
+/* PR rtl-optimization/20532 */
+
+/* { dg-do run } */
+/* { dg-options "-m32 -march=i386 -O1" } */
+
+/* We used to optimize the DImode shift-by-32 to zero because in combine
+ we turned:
+
+ (v << 31) * (v << 31)
+
+ into:
+
+ (v * (((HOST_WIDE_INT)1 << 31) + ((HOST_WIDE_INT)1 << 31)))
+
+ With a 32-bit HOST_WIDE_INT, the coefficient overflowed to zero. */
+
+unsigned long long int badshift(unsigned long long int v)
+{
+ return v << 31 << 1;
+}
+
+extern void abort ();
+
+int main() {
+ if (badshift (1) == 0)
+ abort ();
+ return 0;
+}
--
Alexandre Oliva http://www.ic.unicamp.br/~oliva/
Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org}