]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
i386: Relax predicates in BT splitters
authorUros Bizjak <ubizjak@gmail.com>
Mon, 4 May 2026 15:15:02 +0000 (17:15 +0200)
committerUros Bizjak <ubizjak@gmail.com>
Mon, 4 May 2026 15:26:17 +0000 (17:26 +0200)
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.

gcc/config/i386/i386.md
gcc/testsuite/gcc.target/i386/bt-8.c [new file with mode: 0644]

index e514809453d67a7924dfa50344ff39466df532ac..b0990294b9a81acd8b2d0ad94133d4faae472f4d 100644 (file)
             (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))
   [(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")
   [(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))
        (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)])
 (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))]
        (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))]
   [(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))]
   [(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)))
 (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 (file)
index 0000000..3cd75c8
--- /dev/null
@@ -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\]" } } */