fold-mem-offsets, v2: Fix powerpc64le-linux profiledbootstrap [PR111601]
Checks
Commit Message
On Tue, Nov 28, 2023 at 02:19:36PM +0200, Manolis Tsamis wrote:
> > So, like this (so far untested)?
> >
> > Note, the earlier posted patch passed bootstrap/regtest on
> > {powerpc64le,x86_64,i686}-linux.
Testing revealed this fails miserably, artificial uses don't really
have DF_REF_INSN, so I'm now retrying with this which first punts
on non-regular uses (hoping non-regular uses are always the same
between -g and -g0) and only continuing on DEBUG_INSNs for the regular
uses.
2023-11-28 Jakub Jelinek <jakub@redhat.com>
PR bootstrap/111601
* fold-mem-offsets.cc (get_uses): Ignore DEBUG_INSN uses. Otherwise,
punt if use is in a different basic block from INSN or appears before
INSN in the same basic block. Formatting fixes.
(get_single_def_in_bb): Formatting fixes.
(fold_offsets_1, pass_fold_mem_offsets::execute): Comment formatting
fixes.
* g++.dg/opt/pr111601.C: New test.
Jakub
@@ -154,7 +154,7 @@ static int stats_fold_count;
The definition is desired for REG used in INSN.
Return the definition insn or NULL if there's no definition with
the desired criteria. */
-static rtx_insn*
+static rtx_insn *
get_single_def_in_bb (rtx_insn *insn, rtx reg)
{
df_ref use;
@@ -205,11 +205,10 @@ get_single_def_in_bb (rtx_insn *insn, rt
/* Get all uses of REG which is set in INSN. Return the use list or NULL if a
use is missing / irregular. If SUCCESS is not NULL then set it to false if
there are missing / irregular uses and true otherwise. */
-static struct df_link*
+static df_link *
get_uses (rtx_insn *insn, rtx reg, bool *success)
{
df_ref def;
- struct df_link *ref_chain, *ref_link;
if (success)
*success = false;
@@ -221,18 +220,30 @@ get_uses (rtx_insn *insn, rtx reg, bool
if (!def)
return NULL;
- ref_chain = DF_REF_CHAIN (def);
+ df_link *ref_chain = DF_REF_CHAIN (def);
+ int insn_luid = DF_INSN_LUID (insn);
+ basic_block insn_bb = BLOCK_FOR_INSN (insn);
- for (ref_link = ref_chain; ref_link; ref_link = ref_link->next)
+ for (df_link *ref_link = ref_chain; ref_link; ref_link = ref_link->next)
{
/* Problem getting a use for this instruction. */
if (ref_link->ref == NULL)
return NULL;
if (DF_REF_CLASS (ref_link->ref) != DF_REF_REGULAR)
return NULL;
+
+ rtx_insn *use = DF_REF_INSN (ref_link->ref);
+ if (DEBUG_INSN_P (use))
+ continue;
+
/* We do not handle REG_EQUIV/REG_EQ notes for now. */
if (DF_REF_FLAGS (ref_link->ref) & DF_REF_IN_NOTE)
return NULL;
+ if (BLOCK_FOR_INSN (use) != insn_bb)
+ return NULL;
+ /* Punt if use appears before def in the basic block. See PR111601. */
+ if (DF_INSN_LUID (use) < insn_luid)
+ return NULL;
}
if (success)
@@ -255,8 +266,7 @@ fold_offsets (rtx_insn *insn, rtx reg, b
If DO_RECURSION is true and ANALYZE is false then offset that would result
from folding is computed and is returned through the pointer OFFSET_OUT.
- The instructions that can be folded are recorded in FOLDABLE_INSNS.
-*/
+ The instructions that can be folded are recorded in FOLDABLE_INSNS. */
static bool
fold_offsets_1 (rtx_insn *insn, bool analyze, bool do_recursion,
HOST_WIDE_INT *offset_out, bitmap foldable_insns)
@@ -846,8 +856,8 @@ pass_fold_mem_offsets::execute (function
FOR_ALL_BB_FN (bb, fn)
{
/* There is a conflict between this pass and RISCV's shorten-memrefs
- pass. For now disable folding if optimizing for size because
- otherwise this cancels the effects of shorten-memrefs. */
+ pass. For now disable folding if optimizing for size because
+ otherwise this cancels the effects of shorten-memrefs. */
if (optimize_bb_for_size_p (bb))
continue;
@@ -0,0 +1,86 @@
+// PR bootstrap/111601
+// { dg-do run { target c++11 } }
+// { dg-options "-O2 -fno-exceptions -fno-rtti -fprofile-generate" }
+// { dg-require-profiling "-fprofile-generate" }
+// { dg-final { cleanup-coverage-files } }
+
+struct tree_base
+{
+ int code:16;
+};
+struct saved_scope
+{
+ void *pad[14];
+ int x_processing_template_decl;
+};
+struct saved_scope *scope_chain;
+struct z_candidate
+{
+ tree_base *fn;
+ void *pad[11];
+ z_candidate *next;
+ int viable;
+ int flags;
+};
+
+__attribute__((noipa)) struct z_candidate *
+splice_viable (struct z_candidate *cands, bool strict_p, bool *any_viable_p)
+{
+ struct z_candidate *viable;
+ struct z_candidate **last_viable;
+ struct z_candidate **cand;
+ bool found_strictly_viable = false;
+ if (scope_chain->x_processing_template_decl)
+ strict_p = true;
+ viable = (z_candidate *) 0;
+ last_viable = &viable;
+ *any_viable_p = false;
+ cand = &cands;
+ while (*cand)
+ {
+ struct z_candidate *c = *cand;
+ if (!strict_p && (c->viable == 1 || ((int) (c->fn)->code) == 273))
+ {
+ strict_p = true;
+ if (viable && !found_strictly_viable)
+ {
+ *any_viable_p = false;
+ *last_viable = cands;
+ cands = viable;
+ viable = (z_candidate *) 0;
+ last_viable = &viable;
+ }
+ }
+ if (strict_p ? c->viable == 1 : c->viable)
+ {
+ *last_viable = c;
+ *cand = c->next;
+ c->next = (z_candidate *) 0;
+ last_viable = &c->next;
+ *any_viable_p = true;
+ if (c->viable == 1)
+ found_strictly_viable = true;
+ }
+ else
+ cand = &c->next;
+ }
+ return viable ? viable : cands;
+}
+
+int
+main ()
+{
+ saved_scope s{};
+ scope_chain = &s;
+ z_candidate z[4] = {};
+ z[0].next = &z[1];
+ z[1].viable = 1;
+ z[1].next = &z[2];
+ z[2].viable = 1;
+ z[2].next = &z[3];
+ bool b;
+ z_candidate *c = splice_viable (&z[0], true, &b);
+ if (c != &z[1] || z[1].next != &z[2] || z[2].next)
+ __builtin_abort ();
+ return 0;
+}