diff --git a/gcc/rtl-ssa/accesses.cc b/gcc/rtl-ssa/accesses.cc index 47f2aea05db..dcf2335056b 100644 --- a/gcc/rtl-ssa/accesses.cc +++ b/gcc/rtl-ssa/accesses.cc @@ -393,6 +393,28 @@ set_node::print (pretty_printer *pp) const pp_access (pp, first_def ()); } +// See the comment above the declaration. +clobber_info * +clobber_group::prev_clobber (insn_info *insn) const +{ + auto &tree = const_cast (m_clobber_tree); + int comparison = lookup_clobber (tree, insn); + if (comparison <= 0) + return dyn_cast (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 (m_clobber_tree); + int comparison = lookup_clobber (tree, insn); + if (comparison >= 0) + return dyn_cast (tree.root ()->next_def ()); + return tree.root (); +} + // See the comment above the declaration. void clobber_group::print (pretty_printer *pp) const @@ -415,6 +437,32 @@ 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 ()) + if (auto *group = dyn_cast (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 ()) + if (auto *group = dyn_cast (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 * @@ -1299,9 +1347,9 @@ function_info::make_use_available (use_info *use, bb_info *bb, 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); } diff --git a/gcc/rtl-ssa/accesses.h b/gcc/rtl-ssa/accesses.h index 9b5d3eec56e..85c8b2cfdf3 100644 --- a/gcc/rtl-ssa/accesses.h +++ b/gcc/rtl-ssa/accesses.h @@ -909,6 +909,12 @@ public: 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; } @@ -993,25 +999,33 @@ public: // // 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; diff --git a/gcc/rtl-ssa/member-fns.inl b/gcc/rtl-ssa/member-fns.inl index efc4e8ce113..eea20b9c4c0 100644 --- a/gcc/rtl-ssa/member-fns.inl +++ b/gcc/rtl-ssa/member-fns.inl @@ -401,7 +401,7 @@ def_mux::set () const } inline def_info * -def_lookup::prev_def () const +def_lookup::last_def_of_prev_group () const { if (!mux) return nullptr; @@ -413,7 +413,7 @@ def_lookup::prev_def () const } inline def_info * -def_lookup::next_def () const +def_lookup::first_def_of_next_group () const { if (!mux) return nullptr; @@ -433,19 +433,19 @@ def_lookup::matching_set () const } 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) diff --git a/gcc/rtl-ssa/movement.h b/gcc/rtl-ssa/movement.h index d36926e5b01..98a0ac3a5b9 100644 --- a/gcc/rtl-ssa/movement.h +++ b/gcc/rtl-ssa/movement.h @@ -103,7 +103,7 @@ restrict_movement_for_dead_range (insn_range_info &move_range, 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) { @@ -143,8 +143,8 @@ restrict_movement_for_dead_range (insn_range_info &move_range, } // 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 ()); diff --git a/gcc/testsuite/g++.dg/pr104869.C b/gcc/testsuite/g++.dg/pr104869.C new file mode 100644 index 00000000000..9a6ef88adbd --- /dev/null +++ b/gcc/testsuite/g++.dg/pr104869.C @@ -0,0 +1,78 @@ +// 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 (); +}