}
// See the comment above the declaration.
+clobber_info *
+clobber_group::prev_clobber (insn_info *insn) const
+{
+ auto &tree = const_cast<clobber_tree &> (m_clobber_tree);
+ int comparison = lookup_clobber (tree, insn);
+ if (comparison <= 0)
+ return dyn_cast<clobber_info *> (tree.root ()->prev_def ());
+ return tree.root ();
+}
+
+// See the comment above the declaration.
+clobber_info *
+clobber_group::next_clobber (insn_info *insn) const
+{
+ auto &tree = const_cast<clobber_tree &> (m_clobber_tree);
+ int comparison = lookup_clobber (tree, insn);
+ if (comparison >= 0)
+ return dyn_cast<clobber_info *> (tree.root ()->next_def ());
+ return tree.root ();
+}
+
+// See the comment above the declaration.
void
clobber_group::print (pretty_printer *pp) const
{
pp_indentation (pp) -= 4;
}
+// See the comment above the declaration.
+def_info *
+def_lookup::prev_def (insn_info *insn) const
+{
+ if (mux && comparison == 0)
+ if (auto *node = mux.dyn_cast<def_node *> ())
+ if (auto *group = dyn_cast<clobber_group *> (node))
+ if (clobber_info *clobber = group->prev_clobber (insn))
+ return clobber;
+
+ return last_def_of_prev_group ();
+}
+
+// See the comment above the declaration.
+def_info *
+def_lookup::next_def (insn_info *insn) const
+{
+ if (mux && comparison == 0)
+ if (auto *node = mux.dyn_cast<def_node *> ())
+ if (auto *group = dyn_cast<clobber_group *> (node))
+ if (clobber_info *clobber = group->next_clobber (insn))
+ return clobber;
+
+ return first_def_of_next_group ();
+}
+
// Return a clobber_group for CLOBBER, creating one if CLOBBER doesn't
// already belong to a group.
clobber_group *
input->m_is_temp = true;
phi->m_is_temp = true;
phi->make_degenerate (input);
- if (def_info *prev = dl.prev_def ())
+ if (def_info *prev = dl.prev_def (phi_insn))
phi->set_prev_def (prev);
- if (def_info *next = dl.next_def ())
+ if (def_info *next = dl.next_def (phi_insn))
phi->set_next_def (next);
}
clobber_info *first_clobber () const;
clobber_info *last_clobber () const { return m_last_clobber; }
+ // Return the last clobber before INSN in the group, or null if none.
+ clobber_info *prev_clobber (insn_info *insn) const;
+
+ // Return the next clobber after INSN in the group, or null if none.
+ clobber_info *next_clobber (insn_info *insn) const;
+
// Return true if this group has been replaced by new clobber_groups.
bool has_been_superceded () const { return !m_last_clobber; }
//
// Otherwise, return the last definition that occurs before P,
// or null if none.
- def_info *prev_def () const;
+ def_info *last_def_of_prev_group () const;
// If we found a clobber_group that spans P, return the definition
// that follows the end of the group, or null if none.
//
// Otherwise, return the first definition that occurs after P,
// or null if none.
- def_info *next_def () const;
+ def_info *first_def_of_next_group () const;
// If we found a set_info at P, return that set_info, otherwise return null.
set_info *matching_set () const;
// If we found a set_info at P, return that set_info, otherwise return
// prev_def ().
- def_info *matching_or_prev_def () const;
+ def_info *matching_set_or_last_def_of_prev_group () const;
// If we found a set_info at P, return that set_info, otherwise return
// next_def ().
- def_info *matching_or_next_def () const;
+ def_info *matching_set_or_first_def_of_next_group () const;
+
+ // P is the location of INSN. Return the last definition (of any kind)
+ // that occurs before INSN, or null if none.
+ def_info *prev_def (insn_info *insn) const;
+
+ // P is the location of INSN. Return the next definition (of any kind)
+ // that occurs after INSN, or null if none.
+ def_info *next_def (insn_info *insn) const;
def_mux mux;
int comparison;
}
inline def_info *
-def_lookup::prev_def () const
+def_lookup::last_def_of_prev_group () const
{
if (!mux)
return nullptr;
}
inline def_info *
-def_lookup::next_def () const
+def_lookup::first_def_of_next_group () const
{
if (!mux)
return nullptr;
}
inline def_info *
-def_lookup::matching_or_prev_def () const
+def_lookup::matching_set_or_last_def_of_prev_group () const
{
if (set_info *set = matching_set ())
return set;
- return prev_def ();
+ return last_def_of_prev_group ();
}
inline def_info *
-def_lookup::matching_or_next_def () const
+def_lookup::matching_set_or_first_def_of_next_group () const
{
if (set_info *set = matching_set ())
return set;
- return next_def ();
+ return first_def_of_next_group ();
}
inline insn_note::insn_note (insn_note_kind kind)
resource_info resource = full_register (regno);
def_lookup dl = crtl->ssa->find_def (resource, insn);
- def_info *prev = dl.prev_def ();
+ def_info *prev = dl.last_def_of_prev_group ();
ebb_info *ebb = insn->ebb ();
if (!prev || prev->ebb () != ebb)
{
}
// Stop the instruction moving beyond the next relevant definition of REGNO.
- def_info *next = first_def_ignoring (dl.matching_or_next_def (),
- ignore_clobbers::YES, ignore);
+ def_info *next = dl.matching_set_or_first_def_of_next_group ();
+ next = first_def_ignoring (next, ignore_clobbers::YES, ignore);
if (next)
move_range = move_earlier_than (move_range, next->insn ());
--- /dev/null
+// PR rtl-optimization/104869
+// { dg-do run }
+// { dg-options "-O2 -fvisibility=hidden -std=c++11" }
+// { dg-require-visibility "" }
+
+struct QBasicAtomicInteger {
+ [[gnu::noipa]] int loadRelaxed() { return 1; }
+};
+struct RefCount {
+ bool deref() {
+ int count = atomic.loadRelaxed();
+ if (count)
+ return false;
+ return deref();
+ }
+ QBasicAtomicInteger atomic;
+};
+struct QArrayData {
+ RefCount ref;
+};
+struct QString {
+ ~QString();
+ QArrayData d;
+};
+int ok;
+QString::~QString() { d.ref.deref(); }
+struct Label {
+ bool isValid() { return generator; }
+ int *generator;
+ int index;
+};
+struct ControlFlow;
+struct Codegen {
+ [[gnu::noipa]] bool visit();
+ ControlFlow *controlFlow;
+};
+struct ControlFlow {
+ enum UnwindType { EE };
+ struct UnwindTarget {
+ Label linkLabel;
+ };
+ ControlFlow *parent;
+ UnwindType unwindTarget_type;
+ UnwindTarget unwindTarget() {
+ QString label;
+ ControlFlow *flow = this;
+ while (flow) {
+ Label l = getUnwindTarget(unwindTarget_type, label);
+ if (l.isValid())
+ return {l};
+ flow = flow->parent;
+ }
+ return UnwindTarget();
+ }
+ [[gnu::noipa]] Label getUnwindTarget(UnwindType, QString &) {
+ Label l = { &ok, 0 };
+ return l;
+ }
+};
+[[gnu::noipa]] void foo(int) {
+ ok = 1;
+}
+[[gnu::noipa]] bool Codegen::visit() {
+ if (!controlFlow)
+ return false;
+ ControlFlow::UnwindTarget target = controlFlow->unwindTarget();
+ if (target.linkLabel.isValid())
+ foo(2);
+ return false;
+}
+int
+main() {
+ ControlFlow cf = { nullptr, ControlFlow::UnwindType::EE };
+ Codegen c = { &cf };
+ c.visit();
+ if (!ok)
+ __builtin_abort ();
+}