On Wed, Nov 13, 2013 at 06:38:00PM +0100, Uros Bizjak wrote:
> > --- 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.

But x86_64_immediate_operand will.

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

No, because mode_signbit_p tests if the constant is equal to the
sign bit, while we need to test whether the sign bit is set.
For & 0x80000000 it is the same thing, but for & 0x80000001 it is not.

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

Even if mode_signbit_p did something different, that would pessimize:
long long
foo (long long a)
{
  long long b = a & 0xfffffffff0000000LL;
  if (b > 0)
    bar ();
  return b;
}
because then we can use *anddi_2 just fine:
#(insn 7 25 8 2 (parallel [
#            (set (reg:CCNO 17 flags)
#                (compare:CCNO (and:DI (reg/v:DI 3 bx [orig:87 b ] [87])
#                        (const_int -268435456 [0xfffffffff0000000]))
#                    (const_int 0 [0])))
#            (set (reg/v:DI 3 bx [orig:87 b ] [87])
#                (and:DI (reg/v:DI 3 bx [orig:87 b ] [87])
#                    (const_int -268435456 [0xfffffffff0000000])))
#        ]) pr59101-3.c:7 392 {*anddi_2}
#     (nil))
        andq    $-268435456, %rbx       # 7     *anddi_2/2      [length = 7]
#(jump_insn 8 7 9 2 (set (pc)
#        (if_then_else (le (reg:CCNO 17 flags)
#                (const_int 0 [0]))
#            (label_ref 12)
#            (pc))) pr59101-3.c:7 607 {*jcc_1}
#     (expr_list:REG_DEAD (reg:CCNO 17 flags)
#        (int_list:REG_BR_PROB 3666 (nil)))
# -> 12)
        jle     .L2     # 8     *jcc_1  [length = 2]

as we aren't using the first alternative (andl), but another one.

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

So what about this version?  If x86_64_zext_immediate_operand
returns true for non-CONST_INT (CONST_DOUBLE won't happen for DImode
operand with 64-bit HWI), it might be SYMBOL_REF/LABEL_REF etc. and
it is IMHO better to just assume it might have bit 31 set.

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

        PR target/59101
        * config/i386/i386.md (*anddi_2): Only allow CCZmode if
        operands[2] is x86_64_zext_immediate_operand that might
        have bit 31 set.

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

--- gcc/config/i386/i386.md.jj  2013-11-13 18:32:48.586808734 +0100
+++ gcc/config/i386/i386.md     2013-11-13 19:07:05.648122323 +0100
@@ -7978,7 +7978,20 @@ (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,
+                        /* If we are going to emit andl instead of andq,
+                           and the operands[2] constant might have the
+                           SImode sign bit set, make sure the sign flag isn't
+                           tested, because the instruction will set the sign
+                           flag based on bit 31 rather than bit 63.
+                           If it isn't CONST_INT, conservatively assume
+                           it might have bit 31 set.  */
+                        (x86_64_zext_immediate_operand (operands[2], VOIDmode)
+                         && (!CONST_INT_P (operands[2])
+                             || (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 
18:49:04.922736108 +0100
+++ gcc/testsuite/gcc.c-torture/execute/pr59101.c       2013-11-13 
18:49:04.922736108 +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;
+}


        Jakub

Reply via email to