return m_outgoing[bb->index];
}
+// Return the bitmap vector of all exports AND their dependencies from BB
+// in TMPBIT. Calculate if necessary. Return TMPBIT.
+
+bitmap
+gori_map::exports_and_deps (basic_block bb, bitmap tmpbit)
+{
+ if (bb->index >= (signed int)m_outgoing.length () || !m_outgoing[bb->index])
+ calculate_gori (bb);
+ bitmap_copy (tmpbit, m_outgoing[bb->index]);
+ if (!bitmap_empty_p (tmpbit))
+ {
+ tree name;
+ FOR_EACH_GORI_EXPORT_NAME (this, bb, name)
+ {
+ bitmap dep = get_def_chain (name);
+ if (dep)
+ bitmap_ior_into (tmpbit, dep);
+ }
+ }
+ return tmpbit;
+}
+
// Return the bitmap vector of all imports to BB. Calculate if necessary.
bitmap
bool is_export_p (tree name, basic_block bb = NULL);
bool is_import_p (tree name, basic_block bb);
bitmap exports (basic_block bb);
+ bitmap exports_and_deps (basic_block bb, bitmap tmpbit);
bitmap imports (basic_block bb);
void set_range_invariant (tree name, bool invariant = true);
bool gori_name_on_edge (vrange &r, tree name, edge e, range_query *q = NULL);
// For each name that is an import into BB's exports..
-#define FOR_EACH_GORI_IMPORT_NAME(gorimap, bb, name) \
+#define FOR_EACH_GORI_IMPORT_NAME(gorimap, bb, name) \
for (gori_export_iterator iter ((gorimap)->imports ((bb))); \
((name) = iter.get_name ()); \
iter.next ())
((name) = iter.get_name ()); \
iter.next ())
+// For each name and all their dependencies possibly exported from block BB.
+#define FOR_EACH_GORI_EXPORT_AND_DEP_NAME(gorimap, bb, name, bm) \
+ for (gori_export_iterator iter ((gorimap)->exports_and_deps ((bb),(bm))); \
+ ((name) = iter.get_name ()); \
+ iter.next ())
+
// Used to assist with iterating over the GORI export list in various ways
class gori_export_iterator {
public:
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp1" } */
+[[gnu::noipa]] void
+bar (int a, int b)
+{
+ if (a < 0)
+ __builtin_abort ();
+}
+
+[[gnu::noipa]] void
+foo (int n, bool p)
+{
+ for (int i = n; i-- > 0;)
+ {
+ const int x = 1 << i;
+ if (x <= 0)
+ __builtin_unreachable ();
+ if (p)
+ bar (i, x);
+ }
+}
+
+int
+main ()
+{
+ foo (4, true);
+}
+/* { dg-final { scan-tree-dump "__builtin_unreachable" "vrp1" } } */
+
class remove_unreachable {
public:
remove_unreachable (range_query &r, bool all) : m_ranger (r), final_p (all)
- { m_list.create (30); }
- ~remove_unreachable () { m_list.release (); }
+ { m_list.create (30); m_tmp = BITMAP_ALLOC (NULL); }
+ ~remove_unreachable () { BITMAP_FREE (m_tmp); m_list.release (); }
void handle_early (gimple *s, edge e);
void maybe_register (gimple *s);
bool remove ();
bool remove_and_update_globals ();
+ bool fully_replaceable (tree name, basic_block bb);
vec<std::pair<int, int> > m_list;
range_query &m_ranger;
bool final_p;
+ bitmap m_tmp;
};
// Check if block BB has a __builtin_unreachable () call on one arm, and
// goto <bb 3>; [0.00%]
// Any additional use of _1 or _2 in this block invalidates early replacement.
-static bool
-fully_replaceable (tree name, basic_block bb)
+bool
+remove_unreachable::fully_replaceable (tree name, basic_block bb)
{
use_operand_p use_p;
imm_use_iterator iter;
gcc_checking_assert (gimple_outgoing_range_stmt_p (e->src) == s);
gcc_checking_assert (!final_p);
- // Check if every export use is dominated by this branch.
+ // Check if every export and its dependencies are dominated by this branch.
+ // Dependencies are required as it needs to dominate potential
+ // recalculations. See PR 123300.
tree name;
- FOR_EACH_GORI_EXPORT_NAME (m_ranger.gori_ssa (), e->src, name)
+ FOR_EACH_GORI_EXPORT_AND_DEP_NAME (m_ranger.gori_ssa (), e->src, name, m_tmp)
{
if (!fully_replaceable (name, e->src))
return;