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\]" } } */