diff mbox

Fix *anddi_2 (PR target/59101)

Message ID 20131113170358.GS27813@tucnak.zalov.cz
State New
Headers show

Commit Message

Jakub Jelinek Nov. 13, 2013, 5:03 p.m. UTC
Hi!

If *anddi_2 is used with 64-bit integer constant that matches
"Z" constraint, but has bit 31 set, we emit it as andl instead,
but that is wrong unless just ZF is tested in the flags, because
SF might be different (if operands[1] has bit 31 set, then SF
from andl will be set, but for the 64-bit operation it would be clear).
If constant doesn't have bit 31 set (nor any other higher bits), then
SF will be 0 both when using andl or when using andq, so it is fine
to keep using andl in that case.

At -O2 VRP will optimize
  _3 = ~a_2(D);
  _4 = (long long int) _3;
  _5 = _4 & 4102790424;
  if (_5 > 0)
into:
  _3 = ~a_2(D);
  _4 = (long long int) _3;
  _5 = _4 & 4102790424;
  if (_5 != 0)
but at -O1, -Og (or -O2 -fno-tree-vrp) it will not and then we can end
up with wrong-code.

Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok
for trunk/4.8?

2013-11-13  Jakub Jelinek  <jakub@redhat.com>

	PR target/59101
	* config/i386/i386.md (*anddi_2): Only allow CCZmode if
	operands[2] is positive 64-bit constant that is negative in
	SImode.

	* gcc.c-torture/execute/pr59101.c: New test.


	Jakub

Comments

Uros Bizjak Nov. 13, 2013, 5:38 p.m. UTC | #1
On Wed, Nov 13, 2013 at 6:03 PM, Jakub Jelinek <jakub@redhat.com> wrote:

> If *anddi_2 is used with 64-bit integer constant that matches
> "Z" constraint, but has bit 31 set, we emit it as andl instead,
> but that is wrong unless just ZF is tested in the flags, because
> SF might be different (if operands[1] has bit 31 set, then SF
> from andl will be set, but for the 64-bit operation it would be clear).
> If constant doesn't have bit 31 set (nor any other higher bits), then
> SF will be 0 both when using andl or when using andq, so it is fine
> to keep using andl in that case.
>
> At -O2 VRP will optimize
>   _3 = ~a_2(D);
>   _4 = (long long int) _3;
>   _5 = _4 & 4102790424;
>   if (_5 > 0)
> into:
>   _3 = ~a_2(D);
>   _4 = (long long int) _3;
>   _5 = _4 & 4102790424;
>   if (_5 != 0)
> but at -O1, -Og (or -O2 -fno-tree-vrp) it will not and then we can end
> up with wrong-code.
>
> Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok
> for trunk/4.8?
>
> 2013-11-13  Jakub Jelinek  <jakub@redhat.com>
>
>         PR target/59101
>         * config/i386/i386.md (*anddi_2): Only allow CCZmode if
>         operands[2] is positive 64-bit constant that is negative in
>         SImode.
>
>         * gcc.c-torture/execute/pr59101.c: New test.
>
> --- gcc/config/i386/i386.md.jj  2013-11-12 11:31:31.000000000 +0100
> +++ gcc/config/i386/i386.md     2013-11-13 10:14:10.981609589 +0100
> @@ -7978,7 +7978,12 @@ (define_insn "*anddi_2"
>          (const_int 0)))
>     (set (match_operand:DI 0 "nonimmediate_operand" "=r,r,rm")
>         (and:DI (match_dup 1) (match_dup 2)))]
> -  "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)
> +  "TARGET_64BIT
> +   && ix86_match_ccmode (insn, CONST_INT_P (operands[2])
> +                              && INTVAL (operands[2]) > 0
> +                              && (INTVAL (operands[2])
> +                                  & (HOST_WIDE_INT_1 << 31)) != 0
> +                              ? CCZmode : CCNOmode)

"Z" constraint, a.k.a x86_64_zext_immediate_operand won't allow
constants with high bits set.

It looks to me, we can use mode_signbit_p here, and simplify the expression to

ix86_match_ccmode (insn, mode_signbit_p (SImode, operands[2])
                                        ? CCZmode : CCNOmode)

Please also add comment, this issue is quite non-obvious.

Uros.
diff mbox

Patch

--- gcc/config/i386/i386.md.jj	2013-11-12 11:31:31.000000000 +0100
+++ gcc/config/i386/i386.md	2013-11-13 10:14:10.981609589 +0100
@@ -7978,7 +7978,12 @@  (define_insn "*anddi_2"
 	 (const_int 0)))
    (set (match_operand:DI 0 "nonimmediate_operand" "=r,r,rm")
 	(and:DI (match_dup 1) (match_dup 2)))]
-  "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)
+  "TARGET_64BIT
+   && ix86_match_ccmode (insn, CONST_INT_P (operands[2])
+			       && INTVAL (operands[2]) > 0
+			       && (INTVAL (operands[2])
+				   & (HOST_WIDE_INT_1 << 31)) != 0
+			       ? CCZmode : CCNOmode)
    && ix86_binary_operator_ok (AND, DImode, operands)"
   "@
    and{l}\t{%k2, %k0|%k0, %k2}
--- gcc/testsuite/gcc.c-torture/execute/pr59101.c.jj	2013-11-13 10:22:08.489154035 +0100
+++ gcc/testsuite/gcc.c-torture/execute/pr59101.c	2013-11-13 10:23:01.734870201 +0100
@@ -0,0 +1,15 @@ 
+/* PR target/59101 */
+
+__attribute__((noinline, noclone)) int
+foo (int a)
+{
+  return (~a & 4102790424LL) > 0 | 6;
+}
+
+int
+main ()
+{
+  if (foo (0) != 7)
+    __builtin_abort ();
+  return 0;
+}