Allow QImode subregs of AND results in HImode and SImode (and DImode
on 64-bit targets).  Also allow memory operands for the BT base operand
to increase combine opportunities and enable better insn propagation.

The BT insn is slow when using a memory base with a variable bit index,
but the register allocator can reload a memory operand into a register to
satisfy BT pattern constraints.

The patch improves code generation for the included testcase from:

mask_get_flag:
        movl    %esi, %ecx
        movl    $1, %eax
        salq    %cl, %rax
        testq   %rdi, %rax
        setne   %al
        ret
to:

mask_get_flag:
        xorl    %eax, %eax
        btq     %rsi, %rdi
        setc    %al
        ret

gcc/ChangeLog:

    * config/i386/i386.md (*bt<SWI48:mode>_mask): Use
    int248_register_operand for operand 1 predicate.
    (*jcc_bt<mode>_mask): Use nonimmediate_operand for operand 1 predicate.
    (*jcc_bt<SWI48:mode>_mask_1): Use nonimmediate_operand for operand 1
    predicate and int248_register_operand for operand 2 predicate.
    (BT followed by CMOV splitter): Use nonimmediate_operand
    for operand 1 predicate.
    (*bt<mode>_setcqi): Ditto.
    (*bt<mode>_setncqi): Ditto.
    (*bt<mode>_setnc<mode>): Ditto.
    (*bt<mode>_setncqi_2): Ditto.
    (*bt<mode>_setc<mode>_mask): Use nonimmediate_operand for operand 1
    predicate and int248_register_operand for operand 2 predicate.

gcc/testsuite/ChangeLog:

    * gcc.target/i386/bt-8.c: New test.

Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.

Uros.
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index e514809453d..b0990294b9a 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -19573,8 +19573,8 @@ (define_insn_and_split "*bt<SWI48:mode>_mask"
             (match_operand:SWI48 0 "nonimmediate_operand" "r,m")
             (const_int 1)
            (subreg:QI
-             (and:SWI248
-               (match_operand:SWI248 1 "register_operand")
+             (and
+               (match_operand 1 "int248_register_operand")
                (match_operand 2 "const_int_operand")) 0))))]
   "TARGET_USE_BT
    && (INTVAL (operands[2]) & (GET_MODE_BITSIZE (<SWI48:MODE>mode)-1))
@@ -19629,7 +19629,7 @@ (define_insn_and_split "*jcc_bt<mode>_mask"
   [(set (pc)
        (if_then_else (match_operator 0 "bt_comparison_operator"
                        [(zero_extract:SWI48
-                          (match_operand:SWI48 1 "register_operand")
+                          (match_operand:SWI48 1 "nonimmediate_operand")
                           (const_int 1)
                           (and:QI
                             (match_operand:QI 2 "register_operand")
@@ -19665,11 +19665,11 @@ (define_insn_and_split "*jcc_bt<SWI48:mode>_mask_1"
   [(set (pc)
        (if_then_else (match_operator 0 "bt_comparison_operator"
                        [(zero_extract:SWI48
-                          (match_operand:SWI48 1 "register_operand")
+                          (match_operand:SWI48 1 "nonimmediate_operand")
                           (const_int 1)
                           (subreg:QI
-                            (and:SWI248
-                              (match_operand:SWI248 2 "register_operand")
+                            (and
+                              (match_operand 2 "int248_register_operand")
                               (match_operand 3 "const_int_operand")) 0))
                         (const_int 0)])
                      (label_ref (match_operand 4))
@@ -19704,7 +19704,7 @@ (define_split
        (if_then_else:SWI248
         (match_operator 5 "bt_comparison_operator"
          [(zero_extract:SWI48
-           (match_operand:SWI48 1 "register_operand")
+           (match_operand:SWI48 1 "nonimmediate_operand")
            (const_int 1)
            (match_operand:QI 2 "register_operand"))
           (const_int 0)])
@@ -19730,7 +19730,7 @@ (define_split
 (define_insn_and_split "*bt<mode>_setcqi"
   [(set (subreg:SWI48 (match_operand:QI 0 "register_operand") 0)
         (zero_extract:SWI48
-         (match_operand:SWI48 1 "register_operand")
+         (match_operand:SWI48 1 "nonimmediate_operand")
          (const_int 1)
          (match_operand:QI 2 "register_operand")))
    (clobber (reg:CC FLAGS_REG))]
@@ -19750,7 +19750,7 @@ (define_insn_and_split "*bt<mode>_setncqi"
        (and:QI
         (not:QI
          (subreg:QI
-          (lshiftrt:SWI48 (match_operand:SWI48 1 "register_operand")
+          (lshiftrt:SWI48 (match_operand:SWI48 1 "nonimmediate_operand")
                           (match_operand:QI 2 "register_operand")) 0))
         (const_int 1)))
    (clobber (reg:CC FLAGS_REG))]
@@ -19768,7 +19768,7 @@ (define_insn_and_split "*bt<mode>_setnc<mode>"
   [(set (match_operand:SWI48 0 "register_operand")
        (and:SWI48
         (not:SWI48
-         (lshiftrt:SWI48 (match_operand:SWI48 1 "register_operand")
+         (lshiftrt:SWI48 (match_operand:SWI48 1 "nonimmediate_operand")
                          (match_operand:QI 2 "register_operand")))
         (const_int 1)))
    (clobber (reg:CC FLAGS_REG))]
@@ -19789,7 +19789,7 @@ (define_insn_and_split "*bt<mode>_setncqi_2"
   [(set (match_operand:QI 0 "register_operand")
        (eq:QI
          (zero_extract:SWI48
-           (match_operand:SWI48 1 "register_operand")
+           (match_operand:SWI48 1 "nonimmediate_operand")
            (const_int 1)
            (match_operand:QI 2 "register_operand"))
          (const_int 0)))
@@ -19808,11 +19808,11 @@ (define_insn_and_split "*bt<mode>_setncqi_2"
 (define_insn_and_split "*bt<mode>_setc<mode>_mask"
   [(set (match_operand:SWI48 0 "register_operand")
        (zero_extract:SWI48
-         (match_operand:SWI48 1 "register_operand")
+         (match_operand:SWI48 1 "nonimmediate_operand")
          (const_int 1)
          (subreg:QI
-           (and:SWI48
-             (match_operand:SWI48 2 "register_operand")
+           (and
+             (match_operand 2 "int248_register_operand")
              (match_operand 3 "const_int_operand")) 0)))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_USE_BT
diff --git a/gcc/testsuite/gcc.target/i386/bt-8.c 
b/gcc/testsuite/gcc.target/i386/bt-8.c
new file mode 100644
index 00000000000..3cd75c850b4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/bt-8.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=core2" } */
+
+_Bool mask_get_flag(long mask, int offset)
+{
+  return mask & 1ul << (offset % (__SIZEOF_LONG__ * __CHAR_BIT__));
+}
+
+/* { dg-final { scan-assembler "bt\[lq\]\[ \t\]" } } */
+/* { dg-final { scan-assembler-not "sal\[lq\]\[ \t\]" } } */

Reply via email to