aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/config/i386/i386.md86
-rw-r--r--gcc/testsuite/gcc.target/i386/pr95535-1.c54
-rw-r--r--gcc/testsuite/gcc.target/i386/pr95535-2.c54
3 files changed, 194 insertions, 0 deletions
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 459cf62..a8592a9 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -13985,6 +13985,50 @@
(set_attr "prefix_rep" "1")
(set_attr "mode" "<MODE>")])
+(define_insn_and_split "*ctzsi2_zext"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI
+ (subreg:DI
+ (ctz:SI
+ (match_operand:SI 1 "nonimmediate_operand" "rm")) 0)
+ (const_int 63)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_BMI && TARGET_64BIT"
+ "tzcnt{l}\t{%1, %k0|%k0, %1}"
+ "&& TARGET_AVOID_FALSE_DEP_FOR_BMI && epilogue_completed
+ && optimize_function_for_speed_p (cfun)
+ && !reg_mentioned_p (operands[0], operands[1])"
+ [(parallel
+ [(set (match_dup 0)
+ (and:DI (subreg:DI (ctz:SI (match_dup 1)) 0) (const_int 63)))
+ (unspec [(match_dup 0)] UNSPEC_INSN_FALSE_DEP)
+ (clobber (reg:CC FLAGS_REG))])]
+ "ix86_expand_clear (operands[0]);"
+ [(set_attr "type" "alu1")
+ (set_attr "prefix_0f" "1")
+ (set_attr "prefix_rep" "1")
+ (set_attr "mode" "SI")])
+
+; False dependency happens when destination is only updated by tzcnt,
+; lzcnt or popcnt. There is no false dependency when destination is
+; also used in source.
+(define_insn "*ctzsi2_zext_falsedep"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI
+ (subreg:DI
+ (ctz:SI
+ (match_operand:SI 1 "nonimmediate_operand" "rm")) 0)
+ (const_int 63)))
+ (unspec [(match_operand:DI 2 "register_operand" "0")]
+ UNSPEC_INSN_FALSE_DEP)
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_BMI && TARGET_64BIT"
+ "tzcnt{l}\t{%1, %k0|%k0, %1}"
+ [(set_attr "type" "alu1")
+ (set_attr "prefix_0f" "1")
+ (set_attr "prefix_rep" "1")
+ (set_attr "mode" "SI")])
+
(define_insn "bsr_rex64"
[(set (match_operand:DI 0 "register_operand" "=r")
(minus:DI (const_int 63)
@@ -14077,6 +14121,48 @@
(set_attr "type" "bitmanip")
(set_attr "mode" "<MODE>")])
+(define_insn_and_split "*clzsi2_lzcnt_zext"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI
+ (subreg:DI
+ (clz:SI
+ (match_operand:SI 1 "nonimmediate_operand" "rm")) 0)
+ (const_int 63)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_LZCNT && TARGET_64BIT"
+ "lzcnt{l}\t{%1, %k0|%k0, %1}"
+ "&& TARGET_AVOID_FALSE_DEP_FOR_BMI && epilogue_completed
+ && optimize_function_for_speed_p (cfun)
+ && !reg_mentioned_p (operands[0], operands[1])"
+ [(parallel
+ [(set (match_dup 0)
+ (and:DI (subreg:DI (clz:SI (match_dup 1)) 0) (const_int 63)))
+ (unspec [(match_dup 0)] UNSPEC_INSN_FALSE_DEP)
+ (clobber (reg:CC FLAGS_REG))])]
+ "ix86_expand_clear (operands[0]);"
+ [(set_attr "prefix_rep" "1")
+ (set_attr "type" "bitmanip")
+ (set_attr "mode" "SI")])
+
+; False dependency happens when destination is only updated by tzcnt,
+; lzcnt or popcnt. There is no false dependency when destination is
+; also used in source.
+(define_insn "*clzsi2_lzcnt_zext_falsedep"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI
+ (subreg:DI
+ (clz:SI
+ (match_operand:SWI48 1 "nonimmediate_operand" "rm")) 0)
+ (const_int 63)))
+ (unspec [(match_operand:DI 2 "register_operand" "0")]
+ UNSPEC_INSN_FALSE_DEP)
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_LZCNT"
+ "lzcnt{l}\t{%1, %k0|%k0, %1}"
+ [(set_attr "prefix_rep" "1")
+ (set_attr "type" "bitmanip")
+ (set_attr "mode" "SI")])
+
(define_int_iterator LT_ZCNT
[(UNSPEC_TZCNT "TARGET_BMI")
(UNSPEC_LZCNT "TARGET_LZCNT")])
diff --git a/gcc/testsuite/gcc.target/i386/pr95535-1.c b/gcc/testsuite/gcc.target/i386/pr95535-1.c
new file mode 100644
index 0000000..df847ff
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr95535-1.c
@@ -0,0 +1,54 @@
+/* PR target/95535 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-O2 -mbmi" } */
+/* { dg-final { scan-assembler-not "cltq" } } */
+
+unsigned int foo (void);
+
+unsigned long
+f1 (unsigned int x)
+{
+ return __builtin_ctz (x);
+}
+
+unsigned long
+f2 (unsigned int x)
+{
+ return (unsigned) __builtin_ctz (x);
+}
+
+unsigned long
+f3 (unsigned int x)
+{
+ return __builtin_ctz (x) & 63ULL;
+}
+
+unsigned long
+f4 (unsigned int x)
+{
+ return __builtin_ctz (x) & 1023ULL;
+}
+
+unsigned long
+f5 (void)
+{
+ return __builtin_ctz (foo ());
+}
+
+unsigned long
+f6 (void)
+{
+ return (unsigned) __builtin_ctz (foo ());
+}
+
+unsigned long
+f7 (void)
+{
+ return __builtin_ctz (foo ()) & 63ULL;
+}
+
+unsigned long
+f8 (void)
+{
+ return __builtin_ctz (foo ()) & 1023ULL;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr95535-2.c b/gcc/testsuite/gcc.target/i386/pr95535-2.c
new file mode 100644
index 0000000..670ef16
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr95535-2.c
@@ -0,0 +1,54 @@
+/* PR target/95535 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-O2 -mlzcnt" } */
+/* { dg-final { scan-assembler-not "cltq" } } */
+
+unsigned int foo (void);
+
+unsigned long
+f1 (unsigned int x)
+{
+ return __builtin_clz (x);
+}
+
+unsigned long
+f2 (unsigned int x)
+{
+ return (unsigned) __builtin_clz (x);
+}
+
+unsigned long
+f3 (unsigned int x)
+{
+ return __builtin_clz (x) & 63ULL;
+}
+
+unsigned long
+f4 (unsigned int x)
+{
+ return __builtin_clz (x) & 1023ULL;
+}
+
+unsigned long
+f5 (void)
+{
+ return __builtin_clz (foo ());
+}
+
+unsigned long
+f6 (void)
+{
+ return (unsigned) __builtin_clz (foo ());
+}
+
+unsigned long
+f7 (void)
+{
+ return __builtin_clz (foo ()) & 63ULL;
+}
+
+unsigned long
+f8 (void)
+{
+ return __builtin_clz (foo ()) & 1023ULL;
+}