diff mbox

[i386] : Fix PR46091, missed optimization: x86 bt/btc/bts instructions

Message ID CAFULd4azJ6bjnSmB6ncX3CsugFhWh_dqFrCd1H+7nqHscaYu1w@mail.gmail.com
State New
Headers show

Commit Message

Uros Bizjak Aug. 14, 2017, 4:56 p.m. UTC
Hello!

Attached patch implements generation of btr, bts and btc instructions.
These insns are generated for operations with registers and exact log2
immediates, where bitpos <= 63 and >= 31. Immediates with bits >= 31
are out of range for x86 andq/orq/xorq instructions, so we save a
movabsq constant load.

2017-08-14  Uros Bizjak  <ubizjak@gmail.com>

    PR target/46091
    * config/i386/i386.md (*anddi_1_btr): New insn_and_split pattern.
    (*iordi_1_bts): Ditto.
    (*xordi_1_btc): Ditto.

testsuite/ChangeLog:

2017-08-14  Uros Bizjak  <ubizjak@gmail.com>

    PR target/46091
    * gcc.target/i386/pr46091-1.c: New test.
    * gcc.target/i386/pr46091-2.c: Ditto.
    * gcc.target/i386/pr46091-3.c: Ditto.

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

Committed to mainline.

Uros.
diff mbox

Patch

Index: config/i386/i386.md
===================================================================
--- config/i386/i386.md	(revision 251086)
+++ config/i386/i386.md	(working copy)
@@ -8267,6 +8267,27 @@ 
        (const_string "*")))
    (set_attr "mode" "SI,DI,DI,SI")])
 
+(define_insn_and_split "*anddi_1_btr"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(and:DI
+	 (match_operand:DI 1 "register_operand" "%0")
+	 (match_operand:DI 2 "const_int_operand" "n")))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT && TARGET_USE_BT
+   && IN_RANGE (exact_log2 (~INTVAL (operands[2])), 31, 63)"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (zero_extract:DI (match_dup 0)
+				    (const_int 1)
+				    (match_dup 3))
+		   (const_int 0))
+	      (clobber (reg:CC FLAGS_REG))])]
+  "operands[3] = GEN_INT (exact_log2 (~INTVAL (operands[2])));"
+  [(set_attr "type" "alu1")
+   (set_attr "prefix_0f" "1")
+   (set_attr "znver1_decode" "double")
+   (set_attr "mode" "DI")])
+
 ;; Turn *anddi_1 into *andsi_1_zext if possible.
 (define_split
   [(set (match_operand:DI 0 "register_operand")
@@ -8791,6 +8812,50 @@ 
   [(set_attr "type" "alu")
    (set_attr "mode" "<MODE>")])
 
+(define_insn_and_split "*iordi_1_bts"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(ior:DI
+	 (match_operand:DI 1 "register_operand" "%0")
+	 (match_operand:DI 2 "const_int_operand" "n")))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT && TARGET_USE_BT
+   && IN_RANGE (exact_log2 (INTVAL (operands[2])), 31, 63)"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (zero_extract:DI (match_dup 0)
+				    (const_int 1)
+				    (match_dup 3))
+		   (const_int 1))
+	      (clobber (reg:CC FLAGS_REG))])]
+  "operands[3] = GEN_INT (exact_log2 (INTVAL (operands[2])));"
+  [(set_attr "type" "alu1")
+   (set_attr "prefix_0f" "1")
+   (set_attr "znver1_decode" "double")
+   (set_attr "mode" "DI")])
+
+(define_insn_and_split "*xordi_1_btc"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(xor:DI
+	 (match_operand:DI 1 "register_operand" "%0")
+	 (match_operand:DI 2 "const_int_operand" "n")))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT && TARGET_USE_BT
+   && IN_RANGE (exact_log2 (INTVAL (operands[2])), 31, 63)"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (zero_extract:DI (match_dup 0)
+				    (const_int 1)
+				    (match_dup 3))
+		   (not:DI (zero_extract:DI (match_dup 0)
+					    (const_int 1)
+					    (match_dup 3))))
+	      (clobber (reg:CC FLAGS_REG))])]
+  "operands[3] = GEN_INT (exact_log2 (INTVAL (operands[2])));"
+  [(set_attr "type" "alu1")
+   (set_attr "prefix_0f" "1")
+   (set_attr "znver1_decode" "double")
+   (set_attr "mode" "DI")])
+
 ;; See comment for addsi_1_zext why we do use nonimmediate_operand
 (define_insn "*<code>si_1_zext"
   [(set (match_operand:DI 0 "register_operand" "=r")
Index: testsuite/gcc.target/i386/pr46091-1.c
===================================================================
--- testsuite/gcc.target/i386/pr46091-1.c	(nonexistent)
+++ testsuite/gcc.target/i386/pr46091-1.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2" } */
+
+unsigned long long test (unsigned long long a)
+{
+  return a & ~(1ull << 55);
+}
+
+/* { dg-final { scan-assembler "btr" } } */
Index: testsuite/gcc.target/i386/pr46091-2.c
===================================================================
--- testsuite/gcc.target/i386/pr46091-2.c	(nonexistent)
+++ testsuite/gcc.target/i386/pr46091-2.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2" } */
+
+unsigned long long test (unsigned long long a)
+{
+  return a | (1ull << 55);
+}
+
+/* { dg-final { scan-assembler "bts" } } */
Index: testsuite/gcc.target/i386/pr46091-3.c
===================================================================
--- testsuite/gcc.target/i386/pr46091-3.c	(nonexistent)
+++ testsuite/gcc.target/i386/pr46091-3.c	(working copy)
@@ -0,0 +1,9 @@ 
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2" } */
+
+unsigned long long test (unsigned long long a)
+{
+  return a ^ (1ull << 55);
+}
+
+/* { dg-final { scan-assembler "btc" } } */