gcc/gcc12-pr106590.patch

160 lines
3.8 KiB
Diff

2022-08-15 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/106590
* ifcvt.cc (check_for_cc_cmp_clobbers): New function.
(noce_convert_multiple_sets_1): If SEQ sets or clobbers any regs
mentioned in cc_cmp or rev_cc_cmp, don't consider seq2 for any
further conditional moves.
* gcc.dg/torture/pr106590.c: New test.
--- gcc/ifcvt.cc
+++ gcc/ifcvt.cc
@@ -3369,6 +3369,20 @@ noce_convert_multiple_sets (struct noce_if_info *if_info)
return TRUE;
}
+/* Helper function for noce_convert_multiple_sets_1. If store to
+ DEST can affect P[0] or P[1], clear P[0]. Called via note_stores. */
+
+static void
+check_for_cc_cmp_clobbers (rtx dest, const_rtx, void *p0)
+{
+ rtx *p = (rtx *) p0;
+ if (p[0] == NULL_RTX)
+ return;
+ if (reg_overlap_mentioned_p (dest, p[0])
+ || (p[1] && reg_overlap_mentioned_p (dest, p[1])))
+ p[0] = NULL_RTX;
+}
+
/* This goes through all relevant insns of IF_INFO->then_bb and tries to
create conditional moves. In case a simple move sufficis the insn
should be listed in NEED_NO_CMOV. The rewired-src cases should be
@@ -3519,7 +3533,7 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info,
as min/max and emit an insn, accordingly. */
unsigned cost1 = 0, cost2 = 0;
- rtx_insn *seq, *seq1, *seq2;
+ rtx_insn *seq, *seq1, *seq2 = NULL;
rtx temp_dest = NULL_RTX, temp_dest1 = NULL_RTX, temp_dest2 = NULL_RTX;
bool read_comparison = false;
@@ -3531,9 +3545,10 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info,
as well. This allows the backend to emit a cmov directly without
creating an additional compare for each. If successful, costing
is easier and this sequence is usually preferred. */
- seq2 = try_emit_cmove_seq (if_info, temp, cond,
- new_val, old_val, need_cmov,
- &cost2, &temp_dest2, cc_cmp, rev_cc_cmp);
+ if (cc_cmp)
+ seq2 = try_emit_cmove_seq (if_info, temp, cond,
+ new_val, old_val, need_cmov,
+ &cost2, &temp_dest2, cc_cmp, rev_cc_cmp);
/* The backend might have created a sequence that uses the
condition. Check this. */
@@ -3588,6 +3603,24 @@ noce_convert_multiple_sets_1 (struct noce_if_info *if_info,
return FALSE;
}
+ if (cc_cmp)
+ {
+ /* Check if SEQ can clobber registers mentioned in
+ cc_cmp and/or rev_cc_cmp. If yes, we need to use
+ only seq1 from that point on. */
+ rtx cc_cmp_pair[2] = { cc_cmp, rev_cc_cmp };
+ for (walk = seq; walk; walk = NEXT_INSN (walk))
+ {
+ note_stores (walk, check_for_cc_cmp_clobbers, cc_cmp_pair);
+ if (cc_cmp_pair[0] == NULL_RTX)
+ {
+ cc_cmp = NULL_RTX;
+ rev_cc_cmp = NULL_RTX;
+ break;
+ }
+ }
+ }
+
/* End the sub sequence and emit to the main sequence. */
emit_insn (seq);
--- gcc/testsuite/gcc.dg/torture/pr106590.c
+++ gcc/testsuite/gcc.dg/torture/pr106590.c
@@ -0,0 +1,75 @@
+/* PR rtl-optimization/106590 } */
+/* { dg-do run } */
+/* { dg-additional-options "-mtune=skylake" { target { i?86-*-* x86_64-*-* } } } */
+
+typedef struct A { short a; } A;
+typedef A *B;
+typedef struct C { int c, d; } C;
+typedef C *D;
+
+B
+foo (void)
+{
+ static A r = { .a = 1 };
+ return &r;
+}
+
+D
+bar (void)
+{
+ static C r = { .c = 1, .d = 23 };
+ return &r;
+}
+
+static inline int __attribute__((always_inline))
+baz (short a)
+{
+ int e = 1, f;
+ short g;
+ D h;
+
+ switch (a)
+ {
+ case 1:
+ f = 23;
+ g = 1;
+ break;
+ case 2:
+ f = 20;
+ g = 2;
+ break;
+ }
+
+ h = bar ();
+
+ if (h->d != f || h->c != g)
+ __builtin_abort ();
+ return e;
+}
+
+int
+qux (void)
+{
+ B i = foo ();
+ int e = 1;
+
+ switch (i->a)
+ {
+ case 1:
+ case 2:
+ e = baz (i->a);
+ break;
+ case 3:
+ e = 0;
+ break;
+ }
+
+ return e;
+}
+
+int
+main ()
+{
+ qux ();
+ return 0;
+}