]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
i386: Fix up TARGET_AVOID_FALSE_DEP_FOR_BMI APX NF splitters [PR124892]
authorJakub Jelinek <jakub@redhat.com>
Thu, 16 Apr 2026 08:03:21 +0000 (10:03 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 16 Apr 2026 08:03:21 +0000 (10:03 +0200)
The following testcase is miscompiled because the 3
TARGET_AVOID_FALSE_DEP_FOR_BMI APX NF splitters use ix86_expand_clear.
All other uses of ix86_expand_clear are on either splitters where we know
something clobbers flags register or sets it at the end of pattern (so
clearly flags register is not live across the pattern) or in
define_peephole2 where we explicitly check peep2_regno_dead_p (?, FLAGS_REG).
Now, ix86_expand_clear handles right the QI/HImode cases by setting SImode
instead and based on TARGET_USE_MOV0 and/or optimize_insn_for_size_p
decides whether to use xor reg, reg form or mov $0, reg.
Now, for these 3 APX NF splitters there is actually no flags clobber nor set
in the pattern and because it is a splitter, we don't know if flags register
is live across it (likely yes, otherwise why the APX NF pattern would be
used) or not.  So, we can't use ix86_expand_clear which could clobber flags.
As the splitters are only SWI48, we don't have to worry about QI/HImode
clearing and so IMHO just want to always use the mov $0, reg form by hand.
If flags actually isn't live across it, we have
;; Attempt to always use XOR for zeroing registers (including FP modes).
(define_peephole2
  [(set (match_operand 0 "general_reg_operand")
        (match_operand 1 "const0_operand"))]
  "GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
   && (! TARGET_USE_MOV0 || optimize_insn_for_size_p ())
   && peep2_regno_dead_p (0, FLAGS_REG)"
  [(parallel [(set (match_dup 0) (const_int 0))
              (clobber (reg:CC FLAGS_REG))])]
  "operands[0] = gen_lowpart (word_mode, operands[0]);")
peephole2 which would turn the mov $0, reg back to xor reg, reg.

2026-04-16  Jakub Jelinek  <jakub@redhat.com>

PR target/124892
* config/i386/i386.md (clz<mode>2_lzcnt_nf,
<lt_zcnt>_<mode>_nf, popcount<mode>2_nf): Emit explicit
set of (match_dup 0) to (const_int 0) without flags clobber instead of
using ix86_expand_clear.

* gcc.target/i386/apx-pr124892.c: New test.

Reviewed-by: Hongtao Liu <crazylht@gmail.com>
gcc/config/i386/i386.md
gcc/testsuite/gcc.target/i386/apx-pr124892.c [new file with mode: 0644]

index c05161fc8bcfdc3aa20c2a73c360b65906746abd..648b9b1b9518b0f9e2df7f43fde686952ea1e2ee 100644 (file)
   "&& 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) (const_int 0))
+   (parallel
     [(set (match_dup 0)
          (clz:SWI48 (match_dup 1)))
      (unspec [(match_dup 0)] UNSPEC_INSN_FALSE_DEP)])]
-  "ix86_expand_clear (operands[0]);"
+  ""
   [(set_attr "prefix_rep" "1")
    (set_attr "type" "bitmanip")
    (set_attr "mode" "<MODE>")])
   "&& 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) (const_int 0))
+   (parallel
     [(set (match_dup 0)
          (unspec:SWI48 [(match_dup 1)] LT_ZCNT))
      (unspec [(match_dup 0)] UNSPEC_INSN_FALSE_DEP)])]
-  "ix86_expand_clear (operands[0]);"
+  ""
   [(set_attr "type" "<lt_zcnt_type>")
    (set_attr "prefix_0f" "1")
    (set_attr "prefix_rep" "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) (const_int 0))
+   (parallel
     [(set (match_dup 0)
          (popcount:SWI48 (match_dup 1)))
      (unspec [(match_dup 0)] UNSPEC_INSN_FALSE_DEP)])]
-  "ix86_expand_clear (operands[0]);"
+  ""
   [(set_attr "prefix_rep" "1")
    (set_attr "type" "bitmanip")
    (set_attr "mode" "<MODE>")])
diff --git a/gcc/testsuite/gcc.target/i386/apx-pr124892.c b/gcc/testsuite/gcc.target/i386/apx-pr124892.c
new file mode 100644 (file)
index 0000000..d941d9e
--- /dev/null
@@ -0,0 +1,20 @@
+/* PR target/124892 */
+/* { dg-do run { target { apxf && { lzcnt && { ! ia32 } } } } } */
+/* { dg-options "-O2 -frename-registers" } */
+
+[[gnu::noipa, gnu::target ("apxf"), gnu::target ("lzcnt")]] char
+foo (unsigned u)
+{
+  return __builtin_stdc_bit_ceil (u);
+}
+
+int
+main ()
+{
+  if (!__builtin_cpu_supports ("apxf"))
+    return 0;
+  if (!__builtin_cpu_supports ("lzcnt"))
+    return 0;
+  if (foo (7) != 8)
+    __builtin_abort ();
+}