From 8632f8c65de6e9f301c2e729eb14b43427031665 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 23 Nov 2021 16:36:01 +0100 Subject: Remove duplicated param valud in modref tree Modref tree template stores its own copy of param_moderf_max_bases, *_max_refs and *_max_accesses values. This was done before we had per-function limits and even back then it was bit dubious, so this patch removes it. gcc/ChangeLog: * ipa-modref-tree.h (struct modref_tree): Remove max_bases, max_refs and max_accesses. (modref_tree::modref_tree): Remove parametr. (modref_tree::insert_base): Add max_bases parameter. (modref_tree::insert): Add max_bases, max_refs, max_accesses parameters. (modref_tree::insert): New member function. (modref_tree::merge): Add max_bases, max_refs, max_accesses parameters. (modref_tree::insert): New member function. * ipa-modref-tree.c (test_insert_search_collapse): Update. (test_merge): Update. * ipa-modref.c (dump_records): Don't dump max_refs and max_bases. (dump_lto_records): Likewise. (modref_summary::finalize): Fix whitespace. (get_modref_function_summary): Likewise. (modref_access_analysis::record_access): Update. (modref_access_analysis::record_access_lto): Update. (modref_access_analysis::process_fnspec): Update. (analyze_function): Update. (modref_summaries::duplicate): Update. (modref_summaries_lto::duplicate): Update. (write_modref_records): Update. (read_modref_records): Update. (read_section): Update. (propagate_unknown_call): Update. (modref_propagate_in_scc): Update. (ipa_merge_modref_summary_after_inlining): Update. --- gcc/ipa-modref-tree.c | 52 +++++++++---------- gcc/ipa-modref-tree.h | 76 ++++++++++++++++++++-------- gcc/ipa-modref.c | 136 +++++++++++++++++++++----------------------------- 3 files changed, 137 insertions(+), 127 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-modref-tree.c b/gcc/ipa-modref-tree.c index e23d88d..0671fa7 100644 --- a/gcc/ipa-modref-tree.c +++ b/gcc/ipa-modref-tree.c @@ -874,11 +874,11 @@ test_insert_search_collapse () modref_ref_node *ref_node; modref_access_node a = unspecified_modref_access_node; - modref_tree *t = new modref_tree(1, 2, 2); + modref_tree *t = new modref_tree(); ASSERT_FALSE (t->every_base); /* Insert into an empty tree. */ - t->insert (1, 2, a, false); + t->insert (1, 2, 2, 1, 2, a, false); ASSERT_NE (t->bases, NULL); ASSERT_EQ (t->bases->length (), 1); ASSERT_FALSE (t->every_base); @@ -896,7 +896,7 @@ test_insert_search_collapse () ASSERT_EQ (ref_node->ref, 2); /* Insert when base exists but ref does not. */ - t->insert (1, 3, a, false); + t->insert (1, 2, 2, 1, 3, a, false); ASSERT_NE (t->bases, NULL); ASSERT_EQ (t->bases->length (), 1); ASSERT_EQ (t->search (1), base_node); @@ -909,7 +909,7 @@ test_insert_search_collapse () /* Insert when base and ref exist, but access is not dominated by nor dominates other accesses. */ - t->insert (1, 2, a, false); + t->insert (1, 2, 2, 1, 2, a, false); ASSERT_EQ (t->bases->length (), 1); ASSERT_EQ (t->search (1), base_node); @@ -917,12 +917,12 @@ test_insert_search_collapse () ASSERT_NE (ref_node, NULL); /* Insert when base and ref exist and access is dominated. */ - t->insert (1, 2, a, false); + t->insert (1, 2, 2, 1, 2, a, false); ASSERT_EQ (t->search (1), base_node); ASSERT_EQ (base_node->search (2), ref_node); /* Insert ref to trigger ref list collapse for base 1. */ - t->insert (1, 4, a, false); + t->insert (1, 2, 2, 1, 4, a, false); ASSERT_EQ (t->search (1), base_node); ASSERT_EQ (base_node->refs, NULL); ASSERT_EQ (base_node->search (2), NULL); @@ -930,7 +930,7 @@ test_insert_search_collapse () ASSERT_TRUE (base_node->every_ref); /* Further inserts to collapsed ref list are ignored. */ - t->insert (1, 5, a, false); + t->insert (1, 2, 2, 1, 5, a, false); ASSERT_EQ (t->search (1), base_node); ASSERT_EQ (base_node->refs, NULL); ASSERT_EQ (base_node->search (2), NULL); @@ -938,13 +938,13 @@ test_insert_search_collapse () ASSERT_TRUE (base_node->every_ref); /* Insert base to trigger base list collapse. */ - t->insert (5, 0, a, false); + t->insert (1, 2, 2, 5, 0, a, false); ASSERT_TRUE (t->every_base); ASSERT_EQ (t->bases, NULL); ASSERT_EQ (t->search (1), NULL); /* Further inserts to collapsed base list are ignored. */ - t->insert (7, 8, a, false); + t->insert (1, 2, 2, 7, 8, a, false); ASSERT_TRUE (t->every_base); ASSERT_EQ (t->bases, NULL); ASSERT_EQ (t->search (1), NULL); @@ -959,23 +959,23 @@ test_merge () modref_base_node *base_node; modref_access_node a = unspecified_modref_access_node; - t1 = new modref_tree(3, 4, 1); - t1->insert (1, 1, a, false); - t1->insert (1, 2, a, false); - t1->insert (1, 3, a, false); - t1->insert (2, 1, a, false); - t1->insert (3, 1, a, false); - - t2 = new modref_tree(10, 10, 10); - t2->insert (1, 2, a, false); - t2->insert (1, 3, a, false); - t2->insert (1, 4, a, false); - t2->insert (3, 2, a, false); - t2->insert (3, 3, a, false); - t2->insert (3, 4, a, false); - t2->insert (3, 5, a, false); - - t1->merge (t2, NULL, NULL, false); + t1 = new modref_tree(); + t1->insert (3, 4, 1, 1, 1, a, false); + t1->insert (3, 4, 1, 1, 2, a, false); + t1->insert (3, 4, 1, 1, 3, a, false); + t1->insert (3, 4, 1, 2, 1, a, false); + t1->insert (3, 4, 1, 3, 1, a, false); + + t2 = new modref_tree(); + t2->insert (10, 10, 10, 1, 2, a, false); + t2->insert (10, 10, 10, 1, 3, a, false); + t2->insert (10, 10, 10, 1, 4, a, false); + t2->insert (10, 10, 10, 3, 2, a, false); + t2->insert (10, 10, 10, 3, 3, a, false); + t2->insert (10, 10, 10, 3, 4, a, false); + t2->insert (10, 10, 10, 3, 5, a, false); + + t1->merge (3, 4, 1, t2, NULL, NULL, false); ASSERT_FALSE (t1->every_base); ASSERT_NE (t1->bases, NULL); diff --git a/gcc/ipa-modref-tree.h b/gcc/ipa-modref-tree.h index 6796e6e..35190c2 100644 --- a/gcc/ipa-modref-tree.h +++ b/gcc/ipa-modref-tree.h @@ -304,16 +304,10 @@ template struct GTY((user)) modref_tree { vec *, va_gc> *bases; - size_t max_bases; - size_t max_refs; - size_t max_accesses; bool every_base; - modref_tree (size_t max_bases, size_t max_refs, size_t max_accesses): + modref_tree (): bases (NULL), - max_bases (max_bases), - max_refs (max_refs), - max_accesses (max_accesses), every_base (false) {} /* Insert BASE; collapse tree if there are more than MAX_REFS. @@ -321,7 +315,9 @@ struct GTY((user)) modref_tree something changed. If table gets full, try to insert REF instead. */ - modref_base_node *insert_base (T base, T ref, bool *changed = NULL) + modref_base_node *insert_base (T base, T ref, + unsigned int max_bases, + bool *changed = NULL) { modref_base_node *base_node; @@ -367,7 +363,10 @@ struct GTY((user)) modref_tree /* Insert memory access to the tree. Return true if something changed. */ - bool insert (T base, T ref, modref_access_node a, + bool insert (unsigned int max_bases, + unsigned int max_refs, + unsigned int max_accesses, + T base, T ref, modref_access_node a, bool record_adjustments) { if (every_base) @@ -412,7 +411,8 @@ struct GTY((user)) modref_tree return true; } - modref_base_node *base_node = insert_base (base, ref, &changed); + modref_base_node *base_node + = insert_base (base, ref, max_bases, &changed); base = base_node->base; /* If table got full we may end up with useless base. */ if (!base && !ref && !a.useful_p ()) @@ -431,8 +431,8 @@ struct GTY((user)) modref_tree return true; } - modref_ref_node *ref_node = base_node->insert_ref (ref, max_refs, - &changed); + modref_ref_node *ref_node + = base_node->insert_ref (ref, max_refs, &changed); ref = ref_node->ref; if (ref_node->every_access) @@ -458,6 +458,18 @@ struct GTY((user)) modref_tree return changed; } + /* Insert memory access to the tree. + Return true if something changed. */ + bool insert (tree fndecl, + T base, T ref, const modref_access_node &a, + bool record_adjustments) + { + return insert (opt_for_fn (fndecl, param_modref_max_bases), + opt_for_fn (fndecl, param_modref_max_refs), + opt_for_fn (fndecl, param_modref_max_accesses), + base, ref, a, record_adjustments); + } + /* Remove tree branches that are not useful (i.e. they will always pass). */ void cleanup () @@ -506,7 +518,10 @@ struct GTY((user)) modref_tree PARM_MAP, if non-NULL, maps parm indexes of callee to caller. Similar CHAIN_MAP, if non-NULL, maps static chain of callee to caller. Return true if something has changed. */ - bool merge (modref_tree *other, vec *parm_map, + bool merge (unsigned int max_bases, + unsigned int max_refs, + unsigned int max_accesses, + modref_tree *other, vec *parm_map, modref_parm_map *static_chain_map, bool record_accesses) { @@ -530,7 +545,7 @@ struct GTY((user)) modref_tree if (other == this) { release = true; - other = modref_tree::create_ggc (max_bases, max_refs, max_accesses); + other = modref_tree::create_ggc (); other->copy_from (this); } @@ -538,7 +553,8 @@ struct GTY((user)) modref_tree { if (base_node->every_ref) { - my_base_node = insert_base (base_node->base, 0, &changed); + my_base_node = insert_base (base_node->base, 0, + max_bases, &changed); if (my_base_node && !my_base_node->every_ref) { my_base_node->collapse (); @@ -551,7 +567,8 @@ struct GTY((user)) modref_tree { if (ref_node->every_access) { - changed |= insert (base_node->base, + changed |= insert (max_bases, max_refs, max_accesses, + base_node->base, ref_node->ref, unspecified_modref_access_node, record_accesses); @@ -578,8 +595,9 @@ struct GTY((user)) modref_tree a.parm_index = m.parm_index; } } - changed |= insert (base_node->base, ref_node->ref, a, - record_accesses); + changed |= insert (max_bases, max_refs, max_accesses, + base_node->base, ref_node->ref, + a, record_accesses); } } } @@ -588,10 +606,25 @@ struct GTY((user)) modref_tree return changed; } + /* Merge OTHER into the tree. + PARM_MAP, if non-NULL, maps parm indexes of callee to caller. + Similar CHAIN_MAP, if non-NULL, maps static chain of callee to caller. + Return true if something has changed. */ + bool merge (tree fndecl, + modref_tree *other, vec *parm_map, + modref_parm_map *static_chain_map, + bool record_accesses) + { + return merge (opt_for_fn (fndecl, param_modref_max_bases), + opt_for_fn (fndecl, param_modref_max_refs), + opt_for_fn (fndecl, param_modref_max_accesses), + other, parm_map, static_chain_map, record_accesses); + } + /* Copy OTHER to THIS. */ void copy_from (modref_tree *other) { - merge (other, NULL, NULL, false); + merge (INT_MAX, INT_MAX, INT_MAX, other, NULL, NULL, false); } /* Search BASE in tree; return NULL if failed. */ @@ -633,11 +666,10 @@ struct GTY((user)) modref_tree /* Return ggc allocated instance. We explicitly call destructors via ggc_delete and do not want finalizers to be registered and called at the garbage collection time. */ - static modref_tree *create_ggc (size_t max_bases, size_t max_refs, - size_t max_accesses) + static modref_tree *create_ggc () { return new (ggc_alloc_no_dtor> ()) - modref_tree (max_bases, max_refs, max_accesses); + modref_tree (); } /* Remove all records and mark tree to alias with everything. */ diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 4f93231..79d7d77 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -423,8 +423,6 @@ modref_summary_lto::useful_p (int ecf_flags, bool check_flags) static void dump_records (modref_records *tt, FILE *out) { - fprintf (out, " Limits: %i bases, %i refs\n", - (int)tt->max_bases, (int)tt->max_refs); if (tt->every_base) { fprintf (out, " Every base\n"); @@ -466,8 +464,6 @@ dump_records (modref_records *tt, FILE *out) static void dump_lto_records (modref_records_lto *tt, FILE *out) { - fprintf (out, " Limits: %i bases, %i refs\n", - (int)tt->max_bases, (int)tt->max_refs); if (tt->every_base) { fprintf (out, " Every base\n"); @@ -693,7 +689,7 @@ modref_summary::finalize (tree fun) try_dse = true; size_t i, j, k; int num_tests = 0, max_tests - = opt_for_fn (fun, param_modref_max_tests); + = opt_for_fn (fun, param_modref_max_tests); modref_base_node *base_node; modref_ref_node *ref_node; modref_access_node *access_node; @@ -768,7 +764,7 @@ get_modref_function_summary (gcall *call, bool *interposed) modref_summary *r = get_modref_function_summary (node); if (interposed && r) *interposed = r->calls_interposable - || !node->binds_to_current_def_p (); + || !node->binds_to_current_def_p (); return r; } @@ -996,7 +992,7 @@ modref_access_analysis::record_access (modref_records *tt, base_set, ref_set); a.dump (dump_file); } - tt->insert (base_set, ref_set, a, false); + tt->insert (current_function_decl, base_set, ref_set, a, false); } /* IPA version of record_access_tree. */ @@ -1062,7 +1058,7 @@ modref_access_analysis::record_access_lto (modref_records_lto *tt, ao_ref *ref, a.dump (dump_file); } - tt->insert (base_type, ref_type, a, false); + tt->insert (current_function_decl, base_type, ref_type, a, false); } /* Returns true if and only if we should store the access to EXPR. @@ -1277,12 +1273,15 @@ modref_access_analysis::merge_call_side_effects } /* Merge in loads. */ - changed |= m_summary->loads->merge (callee_summary->loads, &parm_map, - &chain_map, record_adjustments); + changed |= m_summary->loads->merge (current_function_decl, + callee_summary->loads, + &parm_map, &chain_map, + record_adjustments); /* Merge in stores. */ if (!ignore_stores_p (current_function_decl, flags)) { - changed |= m_summary->stores->merge (callee_summary->stores, + changed |= m_summary->stores->merge (current_function_decl, + callee_summary->stores, &parm_map, &chain_map, record_adjustments); if (!m_summary->writes_errno @@ -1395,9 +1394,10 @@ modref_access_analysis::process_fnspec (gcall *call) if (a.parm_index == MODREF_LOCAL_MEMORY_PARM) continue; if (m_summary) - m_summary->loads->insert (0, 0, a, false); + m_summary->loads->insert (current_function_decl, 0, 0, a, false); if (m_summary_lto) - m_summary_lto->loads->insert (0, 0, a, false); + m_summary_lto->loads->insert (current_function_decl, 0, 0, a, + false); } } if (ignore_stores_p (current_function_decl, flags)) @@ -1426,9 +1426,10 @@ modref_access_analysis::process_fnspec (gcall *call) if (a.parm_index == MODREF_LOCAL_MEMORY_PARM) continue; if (m_summary) - m_summary->stores->insert (0, 0, a, false); + m_summary->stores->insert (current_function_decl, 0, 0, a, false); if (m_summary_lto) - m_summary_lto->stores->insert (0, 0, a, false); + m_summary_lto->stores->insert (current_function_decl, + 0, 0, a, false); } if (fnspec.errno_maybe_written_p () && flag_errno_math) { @@ -3024,13 +3025,9 @@ analyze_function (function *f, bool ipa) if (nolto) { gcc_assert (!summary->loads); - summary->loads = modref_records::create_ggc (param_modref_max_bases, - param_modref_max_refs, - param_modref_max_accesses); + summary->loads = modref_records::create_ggc (); gcc_assert (!summary->stores); - summary->stores = modref_records::create_ggc (param_modref_max_bases, - param_modref_max_refs, - param_modref_max_accesses); + summary->stores = modref_records::create_ggc (); summary->writes_errno = false; summary->side_effects = false; summary->nondeterministic = false; @@ -3039,15 +3036,9 @@ analyze_function (function *f, bool ipa) if (lto) { gcc_assert (!summary_lto->loads); - summary_lto->loads = modref_records_lto::create_ggc - (param_modref_max_bases, - param_modref_max_refs, - param_modref_max_accesses); + summary_lto->loads = modref_records_lto::create_ggc (); gcc_assert (!summary_lto->stores); - summary_lto->stores = modref_records_lto::create_ggc - (param_modref_max_bases, - param_modref_max_refs, - param_modref_max_accesses); + summary_lto->stores = modref_records_lto::create_ggc (); summary_lto->writes_errno = false; summary_lto->side_effects = false; summary_lto->nondeterministic = false; @@ -3287,15 +3278,9 @@ modref_summaries::duplicate (cgraph_node *, cgraph_node *dst, optimization_summaries->remove (dst); return; } - dst_data->stores = modref_records::create_ggc - (src_data->stores->max_bases, - src_data->stores->max_refs, - src_data->stores->max_accesses); + dst_data->stores = modref_records::create_ggc (); dst_data->stores->copy_from (src_data->stores); - dst_data->loads = modref_records::create_ggc - (src_data->loads->max_bases, - src_data->loads->max_refs, - src_data->loads->max_accesses); + dst_data->loads = modref_records::create_ggc (); dst_data->loads->copy_from (src_data->loads); dst_data->kills.reserve_exact (src_data->kills.length ()); dst_data->kills.splice (src_data->kills); @@ -3319,15 +3304,9 @@ modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *, /* Be sure that no further cloning happens after ipa-modref. If it does we will need to update signatures for possible param changes. */ gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated); - dst_data->stores = modref_records_lto::create_ggc - (src_data->stores->max_bases, - src_data->stores->max_refs, - src_data->stores->max_accesses); + dst_data->stores = modref_records_lto::create_ggc (); dst_data->stores->copy_from (src_data->stores); - dst_data->loads = modref_records_lto::create_ggc - (src_data->loads->max_bases, - src_data->loads->max_refs, - src_data->loads->max_accesses); + dst_data->loads = modref_records_lto::create_ggc (); dst_data->loads->copy_from (src_data->loads); dst_data->kills.reserve_exact (src_data->kills.length ()); dst_data->kills.splice (src_data->kills); @@ -3379,10 +3358,6 @@ class pass_modref : public gimple_opt_pass static void write_modref_records (modref_records_lto *tt, struct output_block *ob) { - streamer_write_uhwi (ob, tt->max_bases); - streamer_write_uhwi (ob, tt->max_refs); - streamer_write_uhwi (ob, tt->max_accesses); - streamer_write_uhwi (ob, tt->every_base); streamer_write_uhwi (ob, vec_safe_length (tt->bases)); for (auto base_node : tt->bases) @@ -3410,20 +3385,19 @@ write_modref_records (modref_records_lto *tt, struct output_block *ob) LTO streaming is expected or not. */ static void -read_modref_records (lto_input_block *ib, struct data_in *data_in, +read_modref_records (tree decl, + lto_input_block *ib, struct data_in *data_in, modref_records **nolto_ret, modref_records_lto **lto_ret) { - size_t max_bases = streamer_read_uhwi (ib); - size_t max_refs = streamer_read_uhwi (ib); - size_t max_accesses = streamer_read_uhwi (ib); + size_t max_bases = opt_for_fn (decl, param_modref_max_bases); + size_t max_refs = opt_for_fn (decl, param_modref_max_refs); + size_t max_accesses = opt_for_fn (decl, param_modref_max_accesses); if (lto_ret) - *lto_ret = modref_records_lto::create_ggc (max_bases, max_refs, - max_accesses); + *lto_ret = modref_records_lto::create_ggc (); if (nolto_ret) - *nolto_ret = modref_records::create_ggc (max_bases, max_refs, - max_accesses); + *nolto_ret = modref_records::create_ggc (); gcc_checking_assert (lto_ret || nolto_ret); size_t every_base = streamer_read_uhwi (ib); @@ -3461,9 +3435,9 @@ read_modref_records (lto_input_block *ib, struct data_in *data_in, if (nolto_ret) nolto_base_node = (*nolto_ret)->insert_base (base_tree ? get_alias_set (base_tree) - : 0, 0); + : 0, 0, INT_MAX); if (lto_ret) - lto_base_node = (*lto_ret)->insert_base (base_tree, 0); + lto_base_node = (*lto_ret)->insert_base (base_tree, 0, max_bases); size_t every_ref = streamer_read_uhwi (ib); size_t nref = streamer_read_uhwi (ib); @@ -3743,10 +3717,10 @@ read_section (struct lto_file_decl_data *file_data, const char *data, if (modref_sum_lto) modref_sum_lto->static_chain_flags = flags; - read_modref_records (&ib, data_in, + read_modref_records (node->decl, &ib, data_in, modref_sum ? &modref_sum->loads : NULL, modref_sum_lto ? &modref_sum_lto->loads : NULL); - read_modref_records (&ib, data_in, + read_modref_records (node->decl, &ib, data_in, modref_sum ? &modref_sum->stores : NULL, modref_sum_lto ? &modref_sum_lto->stores : NULL); int j = streamer_read_uhwi (&ib); @@ -4425,10 +4399,12 @@ propagate_unknown_call (cgraph_node *node, } if (cur_summary) changed |= cur_summary->loads->insert - (0, 0, get_access_for_fnspec (e, fnspec, i, map), false); + (node->decl, 0, 0, + get_access_for_fnspec (e, fnspec, i, map), false); if (cur_summary_lto) changed |= cur_summary_lto->loads->insert - (0, 0, get_access_for_fnspec (e, fnspec, i, map), false); + (node->decl, 0, 0, + get_access_for_fnspec (e, fnspec, i, map), false); } } if (ignore_stores_p (node->decl, ecf_flags)) @@ -4455,10 +4431,12 @@ propagate_unknown_call (cgraph_node *node, } if (cur_summary) changed |= cur_summary->stores->insert - (0, 0, get_access_for_fnspec (e, fnspec, i, map), false); + (node->decl, 0, 0, + get_access_for_fnspec (e, fnspec, i, map), false); if (cur_summary_lto) changed |= cur_summary_lto->stores->insert - (0, 0, get_access_for_fnspec (e, fnspec, i, map), false); + (node->decl, 0, 0, + get_access_for_fnspec (e, fnspec, i, map), false); } } if (fnspec.errno_maybe_written_p () && flag_errno_math) @@ -4703,13 +4681,13 @@ modref_propagate_in_scc (cgraph_node *component_node) if (callee_summary) { changed |= cur_summary->loads->merge - (callee_summary->loads, &parm_map, - &chain_map, !first); + (node->decl, callee_summary->loads, + &parm_map, &chain_map, !first); if (!ignore_stores) { changed |= cur_summary->stores->merge - (callee_summary->stores, &parm_map, - &chain_map, !first); + (node->decl, callee_summary->stores, + &parm_map, &chain_map, !first); if (!cur_summary->writes_errno && callee_summary->writes_errno) { @@ -4721,13 +4699,13 @@ modref_propagate_in_scc (cgraph_node *component_node) if (callee_summary_lto) { changed |= cur_summary_lto->loads->merge - (callee_summary_lto->loads, &parm_map, - &chain_map, !first); + (node->decl, callee_summary_lto->loads, + &parm_map, &chain_map, !first); if (!ignore_stores) { changed |= cur_summary_lto->stores->merge - (callee_summary_lto->stores, &parm_map, - &chain_map, !first); + (node->decl, callee_summary_lto->stores, + &parm_map, &chain_map, !first); if (!cur_summary_lto->writes_errno && callee_summary_lto->writes_errno) { @@ -5114,20 +5092,20 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) if (!ignore_stores) { if (to_info && callee_info) - to_info->stores->merge (callee_info->stores, &parm_map, + to_info->stores->merge (to->decl, callee_info->stores, &parm_map, &chain_map, false); if (to_info_lto && callee_info_lto) - to_info_lto->stores->merge (callee_info_lto->stores, &parm_map, - &chain_map, false); + to_info_lto->stores->merge (to->decl, callee_info_lto->stores, + &parm_map, &chain_map, false); } if (!(flags & (ECF_CONST | ECF_NOVOPS))) { if (to_info && callee_info) - to_info->loads->merge (callee_info->loads, &parm_map, + to_info->loads->merge (to->decl, callee_info->loads, &parm_map, &chain_map, false); if (to_info_lto && callee_info_lto) - to_info_lto->loads->merge (callee_info_lto->loads, &parm_map, - &chain_map, false); + to_info_lto->loads->merge (to->decl, callee_info_lto->loads, + &parm_map, &chain_map, false); } } -- cgit v1.1 From 721d8b9e26bf8205c1f2125c2626919a408cdbe4 Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Tue, 23 Nov 2021 17:51:38 +0100 Subject: Fortran: fix scalarization for intrinsic LEN_TRIM with present KIND argument gcc/fortran/ChangeLog: PR fortran/87711 PR fortran/87851 * trans-array.c (arg_evaluated_for_scalarization): Add LEN_TRIM to list of intrinsics for which an optional KIND argument needs to be removed before scalarization. gcc/testsuite/ChangeLog: PR fortran/87711 PR fortran/87851 * gfortran.dg/len_trim.f90: New test. --- gcc/fortran/trans-array.c | 1 + gcc/testsuite/gfortran.dg/len_trim.f90 | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/len_trim.f90 (limited to 'gcc') diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 2090adf..238b1b7 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -11499,6 +11499,7 @@ arg_evaluated_for_scalarization (gfc_intrinsic_sym *function, switch (function->id) { case GFC_ISYM_INDEX: + case GFC_ISYM_LEN_TRIM: if (strcmp ("kind", gfc_dummy_arg_get_name (*dummy_arg)) == 0) return false; /* Fallthrough. */ diff --git a/gcc/testsuite/gfortran.dg/len_trim.f90 b/gcc/testsuite/gfortran.dg/len_trim.f90 new file mode 100644 index 0000000..2252b81 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/len_trim.f90 @@ -0,0 +1,27 @@ +! { dg-do compile } +! { dg-options "-O -Wall -Wconversion-extra -fdump-tree-original" } +! { dg-final { scan-tree-dump-not "_gfortran_stop_numeric" "original" } } +! PR fortran/87711 - ICE in gfc_trans_transfer +! PR fortran/87851 - return type for len_trim + +program main + implicit none + character(3), parameter :: a(1) = 'aa' + character(3) :: b = "bb" + character(3) :: c(1) = 'cc' + integer(4), parameter :: l4(1) = len_trim (a, kind=4) + integer(8), parameter :: l8(1) = len_trim (a, kind=8) + integer :: kk(1) = len_trim (a) + integer(4) :: mm(1) = len_trim (a, kind=4) + integer(8) :: nn(1) = len_trim (a, kind=8) + kk = len_trim (a) + mm = len_trim (a, kind=4) + nn = len_trim (a, kind=8) + kk = len_trim ([b]) + mm = len_trim ([b],kind=4) + nn = len_trim ([b],kind=8) + kk = len_trim (c) + mm = len_trim (c, kind=4) + nn = len_trim (c, kind=8) + if (any (l4 /= 2_4) .or. any (l8 /= 2_8)) stop 1 +end program main -- cgit v1.1 From e6a6569ce28958ae768acc1c2f6cc38643b55438 Mon Sep 17 00:00:00 2001 From: Bill Schmidt Date: Tue, 23 Nov 2021 12:54:50 -0600 Subject: rs6000: Fix test_mffsl.c effective target check Paul Clarke pointed out to me that I had wrongly used a compile-time check instead of a run-time check in this executable test. This patch fixes that. I also fixed a typo in a string that caught my eye. 2021-11-23 Bill Schmidt gcc/testsuite/ * gcc.target/powerpc/test_mffsl.c: Change effective target to a run-time check. Fix a typo in a debug print statement. --- gcc/testsuite/gcc.target/powerpc/test_mffsl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/powerpc/test_mffsl.c b/gcc/testsuite/gcc.target/powerpc/test_mffsl.c index 28c2b91..f1f960c 100644 --- a/gcc/testsuite/gcc.target/powerpc/test_mffsl.c +++ b/gcc/testsuite/gcc.target/powerpc/test_mffsl.c @@ -1,6 +1,6 @@ /* { dg-do run { target { powerpc*-*-* } } } */ /* { dg-options "-O2 -std=c99 -mcpu=power9" } */ -/* { dg-require-effective-target powerpc_p9vector_ok } */ +/* { dg-require-effective-target p9vector_hw } */ #ifdef DEBUG #include @@ -28,7 +28,7 @@ int main () if (mffs_val.ll != mffsl_val.ll) { #ifdef DEBUG - printf("ERROR, __builtin_mffsl() returned 0x%llx, not the expecected value 0x%llx\n", + printf("ERROR, __builtin_mffsl() returned 0x%llx, not the expected value 0x%llx\n", mffsl_val.ll, mffs_val.ll); #else abort(); -- cgit v1.1 From c2c534f6faa6a77f163bf22382250d2df423606e Mon Sep 17 00:00:00 2001 From: Bill Schmidt Date: Tue, 23 Nov 2021 10:15:00 -0600 Subject: rs6000: Add [power6-64] stanza to new builtin support 2021-11-23 Bill Schmidt gcc/ * config/rs6000/rs6000-builtin-new.def: Add power6-64 stanza. Move CMPB to power6-64 stanza. * config/rs6000/rs6000-call.c (rs6000_invalid_new_builtin): Handle ENB_P6_64 case. (rs6000_new_builtin_is_supported): Likewise. (rs6000_expand_new_builtin): Likewise. Clean up formatting. (rs6000_init_builtins): Handle ENB_P6_64 case. * config/rs6000/rs6000-gen-builtins.c (bif_stanza): Add BSTZ_P6_64. (stanza_map): Add entry mapping power6-64 to BSTZ_P6_64. (enable_string): Add "ENB_P6_64". (write_decls): Add ENB_P6_64 to bif_enable enum. --- gcc/config/rs6000/rs6000-builtin-new.def | 9 ++++-- gcc/config/rs6000/rs6000-call.c | 49 ++++++++++++++++++-------------- gcc/config/rs6000/rs6000-gen-builtins.c | 4 +++ 3 files changed, 37 insertions(+), 25 deletions(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/rs6000-builtin-new.def b/gcc/config/rs6000/rs6000-builtin-new.def index 1dd8f6b..58dfce1 100644 --- a/gcc/config/rs6000/rs6000-builtin-new.def +++ b/gcc/config/rs6000/rs6000-builtin-new.def @@ -266,13 +266,16 @@ ; Power6 builtins (ISA 2.05). [power6] - const signed long __builtin_p6_cmpb (signed long, signed long); - CMPB cmpbdi3 {} - const signed int __builtin_p6_cmpb_32 (signed int, signed int); CMPB_32 cmpbsi3 {} +; Power6 builtins requiring 64-bit GPRs (even with 32-bit addressing). +[power6-64] + const signed long __builtin_p6_cmpb (signed long, signed long); + CMPB cmpbdi3 {} + + ; AltiVec builtins. [altivec] const vsc __builtin_altivec_abs_v16qi (vsc); diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c index 83e1abb..310bf13 100644 --- a/gcc/config/rs6000/rs6000-call.c +++ b/gcc/config/rs6000/rs6000-call.c @@ -11919,6 +11919,10 @@ rs6000_invalid_new_builtin (enum rs6000_gen_builtins fncode) case ENB_P6: error ("%qs requires the %qs option", name, "-mcpu=power6"); break; + case ENB_P6_64: + error ("%qs requires the %qs option and either the %qs or %qs option", + name, "-mcpu=power6", "-m64", "-mpowerpc64"); + break; case ENB_ALTIVEC: error ("%qs requires the %qs option", name, "-maltivec"); break; @@ -13346,6 +13350,8 @@ rs6000_new_builtin_is_supported (enum rs6000_gen_builtins fncode) return TARGET_POPCNTB; case ENB_P6: return TARGET_CMPB; + case ENB_P6_64: + return TARGET_CMPB && TARGET_POWERPC64; case ENB_P7: return TARGET_POPCNTD; case ENB_P7_64: @@ -15695,29 +15701,26 @@ rs6000_expand_new_builtin (tree exp, rtx target, bif_enable e = bifaddr->enable; if (!(e == ENB_ALWAYS - || (e == ENB_P5 && TARGET_POPCNTB) - || (e == ENB_P6 && TARGET_CMPB) - || (e == ENB_ALTIVEC && TARGET_ALTIVEC) - || (e == ENB_CELL && TARGET_ALTIVEC - && rs6000_cpu == PROCESSOR_CELL) - || (e == ENB_VSX && TARGET_VSX) - || (e == ENB_P7 && TARGET_POPCNTD) - || (e == ENB_P7_64 && TARGET_POPCNTD - && TARGET_POWERPC64) - || (e == ENB_P8 && TARGET_DIRECT_MOVE) - || (e == ENB_P8V && TARGET_P8_VECTOR) - || (e == ENB_P9 && TARGET_MODULO) - || (e == ENB_P9_64 && TARGET_MODULO - && TARGET_POWERPC64) - || (e == ENB_P9V && TARGET_P9_VECTOR) + || (e == ENB_P5 && TARGET_POPCNTB) + || (e == ENB_P6 && TARGET_CMPB) + || (e == ENB_P6_64 && TARGET_CMPB && TARGET_POWERPC64) + || (e == ENB_ALTIVEC && TARGET_ALTIVEC) + || (e == ENB_CELL && TARGET_ALTIVEC && rs6000_cpu == PROCESSOR_CELL) + || (e == ENB_VSX && TARGET_VSX) + || (e == ENB_P7 && TARGET_POPCNTD) + || (e == ENB_P7_64 && TARGET_POPCNTD && TARGET_POWERPC64) + || (e == ENB_P8 && TARGET_DIRECT_MOVE) + || (e == ENB_P8V && TARGET_P8_VECTOR) + || (e == ENB_P9 && TARGET_MODULO) + || (e == ENB_P9_64 && TARGET_MODULO && TARGET_POWERPC64) + || (e == ENB_P9V && TARGET_P9_VECTOR) || (e == ENB_IEEE128_HW && TARGET_FLOAT128_HW) - || (e == ENB_DFP && TARGET_DFP) - || (e == ENB_CRYPTO && TARGET_CRYPTO) - || (e == ENB_HTM && TARGET_HTM) - || (e == ENB_P10 && TARGET_POWER10) - || (e == ENB_P10_64 && TARGET_POWER10 - && TARGET_POWERPC64) - || (e == ENB_MMA && TARGET_MMA))) + || (e == ENB_DFP && TARGET_DFP) + || (e == ENB_CRYPTO && TARGET_CRYPTO) + || (e == ENB_HTM && TARGET_HTM) + || (e == ENB_P10 && TARGET_POWER10) + || (e == ENB_P10_64 && TARGET_POWER10 && TARGET_POWERPC64) + || (e == ENB_MMA && TARGET_MMA))) { rs6000_invalid_new_builtin (fcode); return expand_call (exp, target, ignore); @@ -16419,6 +16422,8 @@ rs6000_init_builtins (void) continue; if (e == ENB_P6 && !TARGET_CMPB) continue; + if (e == ENB_P6_64 && !(TARGET_CMPB && TARGET_POWERPC64)) + continue; if (e == ENB_ALTIVEC && !TARGET_ALTIVEC) continue; if (e == ENB_VSX && !TARGET_VSX) diff --git a/gcc/config/rs6000/rs6000-gen-builtins.c b/gcc/config/rs6000/rs6000-gen-builtins.c index 1655a2f..4ce83bd 100644 --- a/gcc/config/rs6000/rs6000-gen-builtins.c +++ b/gcc/config/rs6000/rs6000-gen-builtins.c @@ -212,6 +212,7 @@ enum bif_stanza BSTZ_ALWAYS, BSTZ_P5, BSTZ_P6, + BSTZ_P6_64, BSTZ_ALTIVEC, BSTZ_CELL, BSTZ_VSX, @@ -245,6 +246,7 @@ static stanza_entry stanza_map[NUMBIFSTANZAS] = { "always", BSTZ_ALWAYS }, { "power5", BSTZ_P5 }, { "power6", BSTZ_P6 }, + { "power6-64", BSTZ_P6_64 }, { "altivec", BSTZ_ALTIVEC }, { "cell", BSTZ_CELL }, { "vsx", BSTZ_VSX }, @@ -269,6 +271,7 @@ static const char *enable_string[NUMBIFSTANZAS] = "ENB_ALWAYS", "ENB_P5", "ENB_P6", + "ENB_P6_64", "ENB_ALTIVEC", "ENB_CELL", "ENB_VSX", @@ -2227,6 +2230,7 @@ write_decls (void) fprintf (header_file, " ENB_ALWAYS,\n"); fprintf (header_file, " ENB_P5,\n"); fprintf (header_file, " ENB_P6,\n"); + fprintf (header_file, " ENB_P6_64,\n"); fprintf (header_file, " ENB_ALTIVEC,\n"); fprintf (header_file, " ENB_CELL,\n"); fprintf (header_file, " ENB_VSX,\n"); -- cgit v1.1 From d6024c85a1ce568f874afa1d9431c43eccba2f59 Mon Sep 17 00:00:00 2001 From: Bill Schmidt Date: Thu, 11 Nov 2021 16:11:03 -0600 Subject: rs6000: Better error messages for power8/9 vector builtins 2021-11-11 Bill Schmidt gcc/ * config/rs6000/rs6000-call.c (rs6000_invalid_new_builtin): Change error messages for ENB_P8V and ENB_P9V. --- gcc/config/rs6000/rs6000-call.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c index 310bf13..a532be4 100644 --- a/gcc/config/rs6000/rs6000-call.c +++ b/gcc/config/rs6000/rs6000-call.c @@ -11943,7 +11943,8 @@ rs6000_invalid_new_builtin (enum rs6000_gen_builtins fncode) error ("%qs requires the %qs option", name, "-mcpu=power8"); break; case ENB_P8V: - error ("%qs requires the %qs option", name, "-mpower8-vector"); + error ("%qs requires the %qs and %qs options", name, "-mcpu=power8", + "-mvsx"); break; case ENB_P9: error ("%qs requires the %qs option", name, "-mcpu=power9"); @@ -11953,7 +11954,8 @@ rs6000_invalid_new_builtin (enum rs6000_gen_builtins fncode) name, "-mcpu=power9", "-m64", "-mpowerpc64"); break; case ENB_P9V: - error ("%qs requires the %qs option", name, "-mpower9-vector"); + error ("%qs requires the %qs and %qs options", name, "-mcpu=power9", + "-mvsx"); break; case ENB_IEEE128_HW: error ("%qs requires ISA 3.0 IEEE 128-bit floating point", name); -- cgit v1.1 From 7b7318faf7987ae17806a8c84fbaccaf255e7cbf Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 23 Nov 2021 14:28:30 -0500 Subject: c++: Add static in g++.dg/warn/Waddress-5.C While reviewing some other changes I noticed that this test talks about 'sf' being static, but it wasn't actually marked as such. gcc/testsuite/ChangeLog: * g++.dg/warn/Waddress-5.C: Make sf static. --- gcc/testsuite/g++.dg/warn/Waddress-5.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/warn/Waddress-5.C b/gcc/testsuite/g++.dg/warn/Waddress-5.C index b1ad38a..b1287b2 100644 --- a/gcc/testsuite/g++.dg/warn/Waddress-5.C +++ b/gcc/testsuite/g++.dg/warn/Waddress-5.C @@ -12,7 +12,7 @@ struct A virtual void vf (); virtual void pvf () = 0; - void sf (); + static void sf (); int *p; int a[2]; -- cgit v1.1 From 4b1d3d8d732bea86c7b2aba46c2a437461020824 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 19 Nov 2021 14:22:10 -0500 Subject: c++: -Wuninitialized for mem-inits and empty classes [PR19808] This fixes a bogus -Wuninitialized warning: there's nothing to initialize in empty classes, so don't add them into our uninitialized set. PR c++/19808 gcc/cp/ChangeLog: * init.c (emit_mem_initializers): Don't add is_really_empty_class members into uninitialized. gcc/testsuite/ChangeLog: * g++.dg/warn/Wuninitialized-28.C: Make a class nonempty. * g++.dg/warn/Wuninitialized-29.C: Likewise. * g++.dg/warn/Wuninitialized-31.C: New test. --- gcc/cp/init.c | 3 +- gcc/testsuite/g++.dg/warn/Wuninitialized-28.C | 1 + gcc/testsuite/g++.dg/warn/Wuninitialized-29.C | 1 + gcc/testsuite/g++.dg/warn/Wuninitialized-31.C | 73 +++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-31.C (limited to 'gcc') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 975f2ed..2a4512e 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1470,7 +1470,8 @@ emit_mem_initializers (tree mem_inits) for (tree f = next_initializable_field (TYPE_FIELDS (current_class_type)); f != NULL_TREE; f = next_initializable_field (DECL_CHAIN (f))) - if (!DECL_ARTIFICIAL (f)) + if (!DECL_ARTIFICIAL (f) + && !is_really_empty_class (TREE_TYPE (f), /*ignore_vptr*/false)) uninitialized.add (f); if (mem_inits diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-28.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-28.C index 7dbbf87..816249c 100644 --- a/gcc/testsuite/g++.dg/warn/Wuninitialized-28.C +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-28.C @@ -47,6 +47,7 @@ struct F { }; struct bar { + int a; bar() {} bar(bar&) {} }; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-29.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-29.C index bc74299..da81abf 100644 --- a/gcc/testsuite/g++.dg/warn/Wuninitialized-29.C +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-29.C @@ -47,6 +47,7 @@ struct F { }; struct bar { + int a; bar() {} bar(bar&) {} }; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-31.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-31.C new file mode 100644 index 0000000..e22b150 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-31.C @@ -0,0 +1,73 @@ +// PR c++/19808 +// { dg-do compile } +// { dg-options "-Wuninitialized" } + +class AllocatorWithCleanup { +public: + int *allocate(int); +}; +class SecBlock { + SecBlock() : m_ptr(m_alloc.allocate(0)) {} // { dg-bogus "uninitialized" } + AllocatorWithCleanup m_alloc; + int *m_ptr; +}; + +struct A { + int *allocate(int); +}; + +struct B { + int : 0; + int *allocate(int); +}; + +struct C : B { +}; + +struct D { + char arr[0]; + int *allocate(int); +}; + +struct E { }; + +struct F { + E arr[10]; + int *allocate(int); +}; + +struct G { + E e; + int *allocate(int); +}; + +struct H { + virtual void foo (); + int *allocate(int); +}; + +template +struct X { + X() : m_ptr(t.allocate(0)) {} // { dg-bogus "uninitialized" } + T t; + int *m_ptr; +}; + +struct V { + int a; + int *allocate(int); +}; + +struct Z { + Z() : m_ptr(v.allocate(0)) {} // { dg-warning "uninitialized" } + V v; + int *m_ptr; +}; + +X x1; +X x2; +X x3; +X x4; +X x5; +X x6; +X x7; -- cgit v1.1 From 16e95050f71e9fa408e9bd8ccd415b0e7adc66e5 Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Tue, 23 Nov 2021 21:39:36 +0100 Subject: Fortran: do not attempt simplification of [LU]BOUND for pointer/allocatable gcc/fortran/ChangeLog: PR fortran/103392 * simplify.c (simplify_bound): Do not try to simplify LBOUND/UBOUND for arrays with POINTER or ALLOCATABLE attribute. gcc/testsuite/ChangeLog: PR fortran/103392 * gfortran.dg/bound_simplification_7.f90: New test. --- gcc/fortran/simplify.c | 6 ++++++ gcc/testsuite/gfortran.dg/bound_simplification_7.f90 | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/bound_simplification_7.f90 (limited to 'gcc') diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c index 6a6b3fb..c9e13b5 100644 --- a/gcc/fortran/simplify.c +++ b/gcc/fortran/simplify.c @@ -4266,6 +4266,12 @@ simplify_bound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind, int upper) || (as->type == AS_ASSUMED_SHAPE && upper))) return NULL; + /* 'array' shall not be an unallocated allocatable variable or a pointer that + is not associated. */ + if (array->expr_type == EXPR_VARIABLE + && (gfc_expr_attr (array).allocatable || gfc_expr_attr (array).pointer)) + return NULL; + gcc_assert (!as || (as->type != AS_DEFERRED && array->expr_type == EXPR_VARIABLE diff --git a/gcc/testsuite/gfortran.dg/bound_simplification_7.f90 b/gcc/testsuite/gfortran.dg/bound_simplification_7.f90 new file mode 100644 index 0000000..3efecdf --- /dev/null +++ b/gcc/testsuite/gfortran.dg/bound_simplification_7.f90 @@ -0,0 +1,18 @@ +! { dg-do compile } +! PR fortran/103392 - ICE in simplify_bound + +program p + integer, allocatable :: a(1:1) ! { dg-error "deferred shape or assumed rank" } + integer :: b(1) = lbound(a) ! { dg-error "does not reduce" } + integer :: c(1) = ubound(a) ! { dg-error "does not reduce" } +end + +subroutine s(x, y) + type t + integer :: i(3) + end type t + type(t), pointer :: x(:) + type(t), allocatable :: y(:) + integer, parameter :: m(1) = ubound (x(1)% i) + integer :: n(1) = ubound (y(1)% i) +end subroutine s -- cgit v1.1 From 30ba058f77eedfaf7a0582f5d42aff949710bce4 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Tue, 23 Nov 2021 15:30:29 -0700 Subject: Implement -Winfinite-recursion [PR88232]. Resolves: PR middle-end/88232 - Please implement -Winfinite-recursion gcc/ChangeLog: PR middle-end/88232 * Makefile.in (OBJS): Add gimple-warn-recursion.o. * common.opt: Add -Winfinite-recursion. * doc/invoke.texi (-Winfinite-recursion): Document. * passes.def (pass_warn_recursion): Schedule a new pass. * tree-pass.h (make_pass_warn_recursion): Declare. * gimple-warn-recursion.c: New file. gcc/c-family/ChangeLog: PR middle-end/88232 * c.opt: Add -Winfinite-recursion. gcc/testsuite/ChangeLog: PR middle-end/88232 * c-c++-common/attr-used-5.c: Suppress valid warning. * c-c++-common/attr-used-6.c: Same. * c-c++-common/attr-used-9.c: Same. * g++.dg/warn/Winfinite-recursion-2.C: New test. * g++.dg/warn/Winfinite-recursion-3.C: New test. * g++.dg/warn/Winfinite-recursion.C: New test. * gcc.dg/Winfinite-recursion-2.c: New test. * gcc.dg/Winfinite-recursion.c: New test. --- gcc/Makefile.in | 1 + gcc/c-family/c.opt | 4 + gcc/common.opt | 4 + gcc/doc/invoke.texi | 9 + gcc/gimple-warn-recursion.c | 202 +++++++++++++++++ gcc/passes.def | 1 + gcc/testsuite/c-c++-common/attr-used-5.c | 2 +- gcc/testsuite/c-c++-common/attr-used-6.c | 2 +- gcc/testsuite/c-c++-common/attr-used-9.c | 2 +- gcc/testsuite/g++.dg/warn/Winfinite-recursion-2.C | 75 +++++++ gcc/testsuite/g++.dg/warn/Winfinite-recursion-3.C | 77 +++++++ gcc/testsuite/g++.dg/warn/Winfinite-recursion.C | 34 +++ gcc/testsuite/gcc.dg/Winfinite-recursion-2.c | 252 ++++++++++++++++++++++ gcc/testsuite/gcc.dg/Winfinite-recursion.c | 227 +++++++++++++++++++ gcc/tree-pass.h | 1 + 15 files changed, 890 insertions(+), 3 deletions(-) create mode 100644 gcc/gimple-warn-recursion.c create mode 100644 gcc/testsuite/g++.dg/warn/Winfinite-recursion-2.C create mode 100644 gcc/testsuite/g++.dg/warn/Winfinite-recursion-3.C create mode 100644 gcc/testsuite/g++.dg/warn/Winfinite-recursion.C create mode 100644 gcc/testsuite/gcc.dg/Winfinite-recursion-2.c create mode 100644 gcc/testsuite/gcc.dg/Winfinite-recursion.c (limited to 'gcc') diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 571e9c2..a4344d6 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1420,6 +1420,7 @@ OBJS = \ gimple-streamer-in.o \ gimple-streamer-out.o \ gimple-walk.o \ + gimple-warn-recursion.o \ gimplify.o \ gimplify-me.o \ godump.o \ diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 3976fc3..4b8a094 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -738,6 +738,10 @@ Wincompatible-pointer-types C ObjC Var(warn_incompatible_pointer_types) Init(1) Warning Warn when there is a conversion between pointers that have incompatible types. +Winfinite-recursion +C ObjC C++ LTO ObjC++ Var(warn_infinite_recursion) Warning LangEnabledBy(C ObjC C++ LTO ObjC++, Wall) +Warn for infinitely recursive calls. + Waddress-of-packed-member C ObjC C++ ObjC++ Var(warn_address_of_packed_member) Init(1) Warning Warn when the address of packed member of struct or union is taken. diff --git a/gcc/common.opt b/gcc/common.opt index db6010e..755e1a2 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -636,6 +636,10 @@ Wimplicit-fallthrough= Common Var(warn_implicit_fallthrough) RejectNegative Joined UInteger Warning IntegerRange(0, 5) Warn when a switch case falls through. +Winfinite-recursion +Var(warn_infinite_recursion) Warning +Warn for infinitely recursive calls. + Winline Common Var(warn_inline) Warning Optimization Warn when an inlined function cannot be inlined. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 57675a4..36fe96b 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -359,6 +359,7 @@ Objective-C and Objective-C++ Dialects}. -Wignored-qualifiers -Wno-incompatible-pointer-types @gol -Wimplicit -Wimplicit-fallthrough -Wimplicit-fallthrough=@var{n} @gol -Wno-implicit-function-declaration -Wno-implicit-int @gol +-Winfinite-recursion @gol -Winit-self -Winline -Wno-int-conversion -Wint-in-bool-context @gol -Wno-int-to-pointer-cast -Wno-invalid-memory-model @gol -Winvalid-pch -Wjump-misses-init -Wlarger-than=@var{byte-size} @gol @@ -6194,6 +6195,14 @@ is only active when @option{-fdelete-null-pointer-checks} is active, which is enabled by optimizations in most targets. The precision of the warnings depends on the optimization options used. +@item -Winfinite-recursion +@opindex Winfinite-recursion +@opindex Wno-infinite-recursion +Warn about infinitely recursive calls. The warning is effective at all +optimization levels but requires optimization in order to detect infinite +recursion in calls between two or more functions. +@option{-Winfinite-recursion} is included in @option{-Wall}. + @item -Winit-self @r{(C, C++, Objective-C and Objective-C++ only)} @opindex Winit-self @opindex Wno-init-self diff --git a/gcc/gimple-warn-recursion.c b/gcc/gimple-warn-recursion.c new file mode 100644 index 0000000..4dc61b0 --- /dev/null +++ b/gcc/gimple-warn-recursion.c @@ -0,0 +1,202 @@ +/* -Winfinite-recursion support. + Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Martin Sebor + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "tree-pass.h" +#include "ssa.h" +#include "diagnostic-core.h" +// #include "tree-dfa.h" +#include "attribs.h" +#include "gimple-iterator.h" + +namespace { + +const pass_data warn_recursion_data = +{ + GIMPLE_PASS, /* type */ + "*infinite-recursion", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_warn_recursion : public gimple_opt_pass +{ +public: + pass_warn_recursion (gcc::context *); + +private: + virtual bool gate (function *) { return warn_infinite_recursion; } + + virtual unsigned int execute (function *); + + bool find_function_exit (basic_block); + + /* Recursive calls found in M_FUNC. */ + vec *m_calls; + /* Basic blocks already visited in the current function. */ + bitmap m_visited; + /* The current function. */ + function *m_func; + /* The current function code if it's (also) a built-in. */ + built_in_function m_built_in; + /* True if M_FUNC is a noreturn function. */ + bool noreturn_p; +}; + +/* Initialize the pass and its members. */ + +pass_warn_recursion::pass_warn_recursion (gcc::context *ctxt) + : gimple_opt_pass (warn_recursion_data, ctxt), + m_calls (), m_visited (), m_func (), m_built_in (), noreturn_p () +{ +} + +/* Return true if there is path from BB to M_FUNC exit point along which + there is no (recursive) call to M_FUNC. */ + +bool +pass_warn_recursion::find_function_exit (basic_block bb) +{ + if (!bitmap_set_bit (m_visited, bb->index)) + return false; + + if (bb == EXIT_BLOCK_PTR_FOR_FN (m_func)) + return true; + + /* Iterate over statements in BB, looking for a call to FNDECL. */ + for (auto si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next_nondebug (&si)) + { + gimple *stmt = gsi_stmt (si); + if (!is_gimple_call (stmt)) + continue; + + if (gimple_call_builtin_p (stmt, BUILT_IN_LONGJMP)) + /* A longjmp breaks infinite recursion. */ + return true; + + if (tree fndecl = gimple_call_fndecl (stmt)) + { + /* A throw statement breaks infinite recursion. */ + tree id = DECL_NAME (fndecl); + const char *name = IDENTIFIER_POINTER (id); + if (startswith (name, "__cxa_throw")) + return true; + /* As does a call to POSIX siglongjmp. */ + if (!strcmp (name, "siglongjmp")) + return true; + + if (m_built_in && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL) + && m_built_in == DECL_FUNCTION_CODE (fndecl)) + { + /* The call is being made from the definition of a built-in + (e.g., in a replacement of one) to itself. */ + m_calls->safe_push (stmt); + return false; + } + } + + if (noreturn_p) + { + /* A noreturn call breaks infinite recursion. */ + int flags = gimple_call_flags (stmt); + if (flags & ECF_NORETURN) + return true; + } + + tree callee = gimple_call_fndecl (stmt); + if (!callee || m_func->decl != callee) + continue; + + /* Add the recursive call to the vector and return false. */ + m_calls->safe_push (stmt); + return false; + } + + /* If no call to FNDECL has been found search all BB's successors. */ + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, bb->succs) + if (find_function_exit (e->dest)) + return true; + + return false; +} + + +/* Search FUNC for unconditionally infinitely recursive calls to self + and issue a warning if it is such a function. */ + +unsigned int +pass_warn_recursion::execute (function *func) +{ + auto_bitmap visited; + auto_vec calls; + + m_visited = visited; + m_calls = &calls; + m_func = func; + + /* Avoid diagnosing an apparently infinitely recursive function that + doesn't return where the infinite recursion might be avoided by + a call to another noreturn function. */ + noreturn_p = lookup_attribute ("noreturn", DECL_ATTRIBUTES (m_func->decl)); + + if (fndecl_built_in_p (m_func->decl, BUILT_IN_NORMAL)) + m_built_in = DECL_FUNCTION_CODE (m_func->decl); + else + m_built_in = BUILT_IN_NONE; + + basic_block entry_bb = ENTRY_BLOCK_PTR_FOR_FN (func); + + if (find_function_exit (entry_bb) || m_calls->length () == 0) + return 0; + + if (warning_at (DECL_SOURCE_LOCATION (func->decl), + OPT_Winfinite_recursion, + "infinite recursion detected")) + for (auto stmt: *m_calls) + { + location_t loc = gimple_location (stmt); + if (loc == UNKNOWN_LOCATION) + continue; + + inform (loc, "recursive call"); + } + + return 0; +} + +} // namespace + +gimple_opt_pass * +make_pass_warn_recursion (gcc::context *ctxt) +{ + return new pass_warn_recursion (ctxt); +} diff --git a/gcc/passes.def b/gcc/passes.def index b583d17..37ea0d3 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -71,6 +71,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_rebuild_cgraph_edges); NEXT_PASS (pass_local_fn_summary); NEXT_PASS (pass_early_inline); + NEXT_PASS (pass_warn_recursion); NEXT_PASS (pass_all_early_optimizations); PUSH_INSERT_PASSES_WITHIN (pass_all_early_optimizations) NEXT_PASS (pass_remove_cgraph_callee_edges); diff --git a/gcc/testsuite/c-c++-common/attr-used-5.c b/gcc/testsuite/c-c++-common/attr-used-5.c index 448e19f..7ba5a45 100644 --- a/gcc/testsuite/c-c++-common/attr-used-5.c +++ b/gcc/testsuite/c-c++-common/attr-used-5.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-skip-if "non-ELF target" { *-*-darwin* } } */ -/* { dg-options "-Wall -O2" } */ +/* { dg-options "-Wall -Wno-infinite-recursion -O2" } */ struct dtv_slotinfo_list { diff --git a/gcc/testsuite/c-c++-common/attr-used-6.c b/gcc/testsuite/c-c++-common/attr-used-6.c index b9974e2..00b1282 100644 --- a/gcc/testsuite/c-c++-common/attr-used-6.c +++ b/gcc/testsuite/c-c++-common/attr-used-6.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-skip-if "non-ELF target" { *-*-darwin* } } */ -/* { dg-options "-Wall -O2" } */ +/* { dg-options "-Wall -Wno-infinite-recursion -O2" } */ struct dtv_slotinfo_list { diff --git a/gcc/testsuite/c-c++-common/attr-used-9.c b/gcc/testsuite/c-c++-common/attr-used-9.c index 049c0be..c4d86c1 100644 --- a/gcc/testsuite/c-c++-common/attr-used-9.c +++ b/gcc/testsuite/c-c++-common/attr-used-9.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-skip-if "non-ELF target" { *-*-darwin* } } */ -/* { dg-options "-Wall -O2" } */ +/* { dg-options "-Wall -Wno-infinite-recursion -O2" } */ struct dtv_slotinfo_list { diff --git a/gcc/testsuite/g++.dg/warn/Winfinite-recursion-2.C b/gcc/testsuite/g++.dg/warn/Winfinite-recursion-2.C new file mode 100644 index 0000000..b310283 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Winfinite-recursion-2.C @@ -0,0 +1,75 @@ +/* PR middle-end/88232 - Please implement -Winfinite-recursion + Test case from PR 87742 (see PR 88232, comment 2. + { dg-do compile { target c++11 } } + { dg-options "-Wall -Winfinite-recursion" } */ + +namespace std +{ +class type_info { +public: + void k() const; +}; + +} // namespace std + +using std::type_info; + +template struct f { static constexpr int c = a; }; +struct h { + typedef int e; +}; + +template struct m; +template +struct m : m {}; +template +struct m : f {}; +template struct n; +template +struct n : n {}; +template struct n<0, j, ac...> : h {}; +template class F { + template struct I : m<0, i, l...> {}; + template struct s : n {}; + static const type_info *const b[]; + struct G { + template + operator ag() const // { dg-warning "-Winfinite-recursion" } + { + return *this; + } + }; + unsigned o; + G ah; + +public: + F(); + long t() const { return o; } + const type_info &m_fn3() const { return *b[o]; } + template typename s::e *m_fn4() const { + if (o != ab) + return nullptr; + return ah; + } + template void m_fn5() const { + m_fn4(); + const type_info &r = m_fn3(); + r.k(); + } + template void u() const { m_fn5::c>(); } +}; +template const type_info *const F::b[] {&typeid(l)...}; +using am = unsigned char; +class H { + enum bd : am { be = 2 }; + using bf = F; + bf ah; + template void v() const { ah.u(); } + void w() const; +}; +void H::w() const { + bd d = bd(ah.t()); + switch (d) + case be: + v(); +} diff --git a/gcc/testsuite/g++.dg/warn/Winfinite-recursion-3.C b/gcc/testsuite/g++.dg/warn/Winfinite-recursion-3.C new file mode 100644 index 0000000..166e6d5 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Winfinite-recursion-3.C @@ -0,0 +1,77 @@ +/* PR middle-end/88232 - Please implement -Winfinite-recursion + { dg-do compile } + { dg-options "-Wall -Winfinite-recursion" } */ + +typedef __SIZE_TYPE__ size_t; + +/* Might throw. */ +void f (); + +/* Verify a warning is issued even though a call to f() might throw, + breaking the infinite recursion. */ + +void warn_f_call_r (int n) // { dg-warning "-Winfinite-recursion" } +{ + if (n > 7) + f (); + warn_f_call_r (n - 1); // { dg-message "recursive call" } +} + +void warn_f_do_while_call_r (int n) // { dg-warning "-Winfinite-recursion" } +{ + f (); + do + { + f (); + warn_f_do_while_call_r (n - 1); // { dg-message "recursive call" } + } + while (1); +} + + +struct X +{ + X (int); + ~X (); +}; + +/* Verify a warning even though the X ctor might throw, breaking + the recursion. Using possible throwing to suppress the warning + would make it pretty much useless in C++. */ + +int warn_class_with_ctor (int n) // { dg-warning "-Winfinite-recursion" } +{ + X x (n); + return n + warn_class_with_ctor (n - 1); +} + + +int nowarn_throw (int n) +{ + if (n > 7) + throw "argument too big"; + + return n + nowarn_throw (n - 1); +} + + +/* Verify call operator new doesn't suppress the warning even though + it might throw. */ + +extern int* eipa[]; + +void warn_call_new (int i) // { dg-warning "-Winfinite-recursion" } +{ + eipa[i] = new int; + + warn_call_new (i - 1); +} + +/* Verify a recursive call to operator new. */ + +void* operator new[] (size_t n) // { dg-warning "-Winfinite-recursion" } +{ + char *p = new char[n + sizeof (n)]; // { dg-message "recursive call" } + *(size_t*)p = n; + return p + sizeof n; +} diff --git a/gcc/testsuite/g++.dg/warn/Winfinite-recursion.C b/gcc/testsuite/g++.dg/warn/Winfinite-recursion.C new file mode 100644 index 0000000..faf0984 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Winfinite-recursion.C @@ -0,0 +1,34 @@ +/* PR middle-end/88232 - Please implement -Winfinite-recursion + { dg-do compile } + { dg-options "-Wall -Winfinite-recursion" } */ + +template +struct C +{ + void foo () // { dg-warning "-Winfinite-recursion" } + { + static_cast(this)->foo (); + } +}; + +struct D : C +{ + // this is missing: + // void foo() {} +}; + +void f (D *d) +{ + d->foo (); +} + + +struct E : C +{ + void foo() {} +}; + +void g (E *e) +{ + e->foo (); +} diff --git a/gcc/testsuite/gcc.dg/Winfinite-recursion-2.c b/gcc/testsuite/gcc.dg/Winfinite-recursion-2.c new file mode 100644 index 0000000..2348312 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Winfinite-recursion-2.c @@ -0,0 +1,252 @@ +/* PR middle-end/88232 - Please implement -Winfinite-recursion + Exercise warning with optimization. Same as -Winfinite-recursion.c + plus mutually recursive calls that depend on inlining. + { dg-do compile } + { dg-options "-O2 -Wall -Winfinite-recursion" } */ + +#define NORETURN __attribute__ ((noreturn)) + +typedef __SIZE_TYPE__ size_t; + +extern void abort (void); +extern void exit (int); + +extern int ei; +int (*pfi_v)(void); + + +/* Make sure the warning doesn't assume every call has a DECL. */ + +int nowarn_pfi_v (void) +{ + return pfi_v (); +} + + +int warn_fi_v (void) // { dg-warning "-Winfinite-recursion" } +{ + return warn_fi_v (); // { dg-message "recursive call" } +} + +/* Verify #pragma suppression works. */ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winfinite-recursion" + +int suppress_warn_fi_v (void) +{ + return warn_fi_v (); +} + +#pragma GCC diagnostic pop + +int nowarn_fi_v (void) +{ + if (ei++ == 0) + return nowarn_fi_v (); + return 0; +} + + +int warn_if_i (int i) // { dg-warning "-Winfinite-recursion" } +{ + if (i > 0) + return warn_if_i (--i); // { dg-message "recursive call" } + else if (i < 0) + return warn_if_i (-i); // { dg-message "recursive call" } + else + return warn_if_i (7); // { dg-message "recursive call" } +} + + +int nowarn_if_i (int i) +{ + if (i > 0) + return nowarn_if_i (--i); + else if (i < 0) + return nowarn_if_i (-i); + else + return -1; +} + +int nowarn_switch (int i, int a[]) +{ + switch (i) + { + case 0: return nowarn_switch (a[3], a + 1); + case 1: return nowarn_switch (a[5], a + 2); + case 2: return nowarn_switch (a[7], a + 3); + case 3: return nowarn_switch (a[9], a + 4); + } + return 77; +} + +int warn_switch (int i, int a[]) // { dg-warning "-Winfinite-recursion" } +{ + switch (i) + { + case 0: return warn_switch (a[3], a + 1); + case 1: return warn_switch (a[5], a + 2); + case 2: return warn_switch (a[7], a + 3); + case 3: return warn_switch (a[9], a + 4); + default: return warn_switch (a[1], a + 5); + } +} + +NORETURN void fnoreturn (void); + +/* Verify there's no warning for a function that doesn't return. */ +int nowarn_call_noret (void) +{ + fnoreturn (); +} + +int warn_call_noret_r (void) // { dg-warning "-Winfinite-recursion" } +{ + warn_call_noret_r (); // { dg-message "recursive call" } + fnoreturn (); +} + +/* Verify a warning even though the abort() call would prevent the infinite + recursion. There's no good way to tell the two cases apart and letting + a simple abort prevent the warning would make it ineffective in cases + where it's the result of assert() expansion and not meant to actually + prevent recursion. */ + +int +warn_noret_call_abort_r (char *s, int n) // { dg-warning "-Winfinite-recursion" } +{ + if (!s) + abort (); + + if (n > 7) + abort (); + + return n + warn_noret_call_abort_r (s, n - 1); // { dg-message "recursive call" } +} + +/* Verify that a warning is not issued for an apparently infinitely + recursive function like the one above where the recursion would be + prevented by a call to a noreturn function if the recursive function + is itself declared noreturn. */ + +NORETURN void nowarn_noret_call_abort_r (int n) +{ + if (n > 7) + abort (); + + nowarn_noret_call_abort_r (n - 1); +} + +int warn_call_abort_r (int n) // { dg-warning "-Winfinite-recursion" } +{ + n += warn_call_abort_r (n - 1); // { dg-message "recursive call" } + if (n > 7) // unreachable + abort (); + return n; +} + + +/* And again with exit() for good measure. */ + +int warn_call_exit_r (int n) // { dg-warning "-Winfinite-recursion" } +{ + n += warn_call_exit_r (n - 1); // { dg-message "recursive call" } + if (n > 7) + exit (0); + return n; +} + +struct __jmp_buf_tag { }; +typedef struct __jmp_buf_tag jmp_buf[1]; + +extern jmp_buf jmpbuf; + +/* A call to longjmp() breaks infinite recursion. Verify it suppresses + the warning. */ + +int nowarn_call_longjmp_r (int n) +{ + if (n > 7) + __builtin_longjmp (jmpbuf, 1); + return n + nowarn_call_longjmp_r (n - 1); +} + +int warn_call_longjmp_r (int n) // { dg-warning "-Winfinite-recursion" } +{ + n += warn_call_longjmp_r (n - 1); // { dg-message "recursive call" } + if (n > 7) + __builtin_longjmp (jmpbuf, 1); + return n; +} + + +struct __sigjmp_buf_tag { }; +typedef struct __sigjmp_buf_tag sigjmp_buf[1]; + +extern sigjmp_buf sigjmpbuf; + +/* GCC has no __builtin_siglongjmp(). */ +extern void siglongjmp (sigjmp_buf, int); + +/* A call to longjmp() breaks infinite recursion. Verify it suppresses + the warning. */ + +int nowarn_call_siglongjmp_r (int n) +{ + if (n > 7) + siglongjmp (sigjmpbuf, 1); + return n + nowarn_call_siglongjmp_r (n - 1); +} + + +int nowarn_while_do_call_r (int n) +{ + int z = 0; + while (n) + z += nowarn_while_do_call_r (n--); + return z; +} + +int warn_do_while_call_r (int n) // { dg-warning "-Winfinite-recursion" } +{ + int z = 0; + do + z += warn_do_while_call_r (n); // { dg-message "recursive call" } + while (--n); + return z; +} + + +/* Verify warnings for a naive replacement of a built-in fucntion. */ + +void* malloc (size_t n) // { dg-warning "-Winfinite-recursion" } +{ + size_t *p = + (size_t*)__builtin_malloc (n + sizeof n); // { dg-message "recursive call" } + *p = n; + return p + 1; +} + + +int nowarn_fact (int n) +{ + return n ? n * nowarn_fact (n - 1) : 1; +} + + +static int fi_v (void); + +/* It would seem preferable to issue the warning for the extern function + but as it happens it's the static function that's inlined into a recursive + call to itself and warn_call_fi_v() expands to a call to it. */ + +int warn_call_fi_v (void) // { dg-warning "-Winfinite-recursion" "" { xfail *-*-* } } +{ + return fi_v (); // { dg-message "recursive call" } +} + +static int fi_v (void) // { dg-warning "-Winfinite-recursion" } +{ + return warn_call_fi_v (); +} diff --git a/gcc/testsuite/gcc.dg/Winfinite-recursion.c b/gcc/testsuite/gcc.dg/Winfinite-recursion.c new file mode 100644 index 0000000..e325356 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Winfinite-recursion.c @@ -0,0 +1,227 @@ +/* PR middle-end/88232 - Please implement -Winfinite-recursion + Verify simple cases without optimization. + { dg-do compile } + { dg-options "-Wall -Winfinite-recursion" } */ + +#define NORETURN __attribute__ ((noreturn)) + +typedef __SIZE_TYPE__ size_t; + +extern void abort (void); +extern void exit (int); + +extern int ei; +int (*pfi_v)(void); + + +/* Make sure the warning doesn't assume every call has a DECL. */ + +int nowarn_pfi_v (void) +{ + return pfi_v (); +} + + +int warn_fi_v (void) // { dg-warning "-Winfinite-recursion" } +{ + return warn_fi_v (); // { dg-message "recursive call" } +} + +/* Verify #pragma suppression works. */ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winfinite-recursion" + +int suppress_warn_fi_v (void) +{ + return warn_fi_v (); +} + +#pragma GCC diagnostic pop + + +int nowarn_fi_v (void) +{ + if (ei++ == 0) + return nowarn_fi_v (); + return 0; +} + +int warn_if_i (int i) // { dg-warning "-Winfinite-recursion" } +{ + if (i > 0) + return warn_if_i (--i); // { dg-message "recursive call" } + else if (i < 0) + return warn_if_i (-i); // { dg-message "recursive call" } + else + return warn_if_i (7); // { dg-message "recursive call" } +} + + +int nowarn_if_i (int i) +{ + if (i > 0) + return nowarn_if_i (--i); + else if (i < 0) + return nowarn_if_i (-i); + else + return -1; +} + +int nowarn_switch (int i, int a[]) +{ + switch (i) + { + case 0: return nowarn_switch (a[3], a + 1); + case 1: return nowarn_switch (a[5], a + 2); + case 2: return nowarn_switch (a[7], a + 3); + case 3: return nowarn_switch (a[9], a + 4); + } + return 77; +} + +int warn_switch (int i, int a[]) // { dg-warning "-Winfinite-recursion" } +{ + switch (i) + { + case 0: return warn_switch (a[3], a + 1); + case 1: return warn_switch (a[5], a + 2); + case 2: return warn_switch (a[7], a + 3); + case 3: return warn_switch (a[9], a + 4); + default: return warn_switch (a[1], a + 5); + } +} + +NORETURN void fnoreturn (void); + +/* Verify there's no warning for a function that doesn't return. */ +int nowarn_call_noret (void) +{ + fnoreturn (); +} + +int warn_call_noret_r (void) // { dg-warning "-Winfinite-recursion" } +{ + warn_call_noret_r (); // { dg-message "recursive call" } + fnoreturn (); +} + +/* Verify a warning even though the abort() call would prevent the infinite + recursion. There's no good way to tell the two cases apart and letting + a simple abort prevent the warning would make it ineffective in cases + where it's the result of assert() expansion and not meant to actually + prevent recursion. */ + +int +warn_noret_call_abort_r (char *s, int n) // { dg-warning "-Winfinite-recursion" } +{ + if (!s) + abort (); + + if (n > 7) + abort (); + + return n + warn_noret_call_abort_r (s, n - 1); // { dg-message "recursive call" } +} + +/* Verify that a warning is not issued for an apparently infinitely + recursive function like the one above where the recursion would be + prevented by a call to a noreturn function if the recursive function + is itself declared noreturn. */ + +NORETURN void nowarn_noret_call_abort_r (int n) +{ + if (n > 7) + abort (); + + nowarn_noret_call_abort_r (n - 1); +} + +int warn_call_abort_r (int n) // { dg-warning "-Winfinite-recursion" } +{ + n += warn_call_abort_r (n - 1); // { dg-message "recursive call" } + if (n > 7) // unreachable + abort (); + return n; +} + + +/* And again with exit() for good measure. */ + +int warn_call_exit_r (int n) // { dg-warning "-Winfinite-recursion" } +{ + n += warn_call_exit_r (n - 1); // { dg-message "recursive call" } + if (n > 7) + exit (0); + return n; +} + +struct __jmp_buf_tag { }; +typedef struct __jmp_buf_tag jmp_buf[1]; + +extern jmp_buf jmpbuf; + +/* A call to longjmp() breaks infinite recursion. Verify it suppresses + the warning. */ + +int nowarn_call_longjmp_r (int n) +{ + if (n > 7) + __builtin_longjmp (jmpbuf, 1); + return n + nowarn_call_longjmp_r (n - 1); +} + +int warn_call_longjmp_r (int n) // { dg-warning "-Winfinite-recursion" } +{ + n += warn_call_longjmp_r (n - 1); // { dg-message "recursive call" } + if (n > 7) + __builtin_longjmp (jmpbuf, 1); + return n; +} + + +struct __sigjmp_buf_tag { }; +typedef struct __sigjmp_buf_tag sigjmp_buf[1]; + +extern sigjmp_buf sigjmpbuf; + +/* GCC has no __builtin_siglongjmp(). */ +extern void siglongjmp (sigjmp_buf, int); + +/* A call to longjmp() breaks infinite recursion. Verify it suppresses + the warning. */ + +int nowarn_call_siglongjmp_r (int n) +{ + if (n > 7) + siglongjmp (sigjmpbuf, 1); + return n + nowarn_call_siglongjmp_r (n - 1); +} + + +int nowarn_while_do_call_r (int n) +{ + int z = 0; + while (n) + z += nowarn_while_do_call_r (n--); + return z; +} + +int warn_do_while_call_r (int n) // { dg-warning "-Winfinite-recursion" } +{ + int z = 0; + do + z += warn_do_while_call_r (n); // { dg-message "recursive call" } + while (--n); + return z; +} + +/* Verify warnings for a naive replacement of a built-in fucntion. */ + +void* malloc (size_t n) // { dg-warning "-Winfinite-recursion" } +{ + size_t *p = + (size_t*)__builtin_malloc (n + sizeof n); // { dg-message "recursive call" } + *p = n; + return p + 1; +} diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index d494aff..3559c3c 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -435,6 +435,7 @@ extern gimple_opt_pass *make_pass_object_sizes (gcc::context *ctxt); extern gimple_opt_pass *make_pass_early_object_sizes (gcc::context *ctxt); extern gimple_opt_pass *make_pass_warn_access (gcc::context *ctxt); extern gimple_opt_pass *make_pass_warn_printf (gcc::context *ctxt); +extern gimple_opt_pass *make_pass_warn_recursion (gcc::context *ctxt); extern gimple_opt_pass *make_pass_strlen (gcc::context *ctxt); extern gimple_opt_pass *make_pass_fold_builtins (gcc::context *ctxt); extern gimple_opt_pass *make_pass_post_ipa_warn (gcc::context *ctxt); -- cgit v1.1 From 2dd56aed3e4e1938a9020ab2fe6a410e1a1c2eb3 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Tue, 23 Nov 2021 15:35:31 -0700 Subject: Issue -Waddress also for reference members [PR96507]. Resolves: PR c++/96507 - missing -Waddress for member references gcc/cp/ChangeLog: PR c++/96507 * typeck.c (warn_for_null_address): Handle reference members. gcc/testsuite/ChangeLog: PR c++/96507 * g++.dg/warn/Waddress-8.C: New test. --- gcc/cp/typeck.c | 5 +- gcc/testsuite/g++.dg/warn/Waddress-8.C | 85 ++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/warn/Waddress-8.C (limited to 'gcc') diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 84dcb6f..872e944 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -4677,10 +4677,13 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain) return; } else if (CONVERT_EXPR_P (op) - && TYPE_REF_P (TREE_TYPE (TREE_OPERAND (op, 0)))) + && TYPE_REF_P (TREE_TYPE (TREE_OPERAND (op, 0)))) { STRIP_NOPS (op); + if (TREE_CODE (op) == COMPONENT_REF) + op = TREE_OPERAND (op, 1); + if (DECL_P (op)) warned = warning_at (location, OPT_Waddress, "the compiler can assume that the address of " diff --git a/gcc/testsuite/g++.dg/warn/Waddress-8.C b/gcc/testsuite/g++.dg/warn/Waddress-8.C new file mode 100644 index 0000000..797102d --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Waddress-8.C @@ -0,0 +1,85 @@ +/* PR c++/96507 - missing -Waddress for member references + { dg-do compile } + { dg-options "-Wall" } */ + +typedef void F (); + +extern F 𝔢 +extern int &eir; + +bool warn_ext_rfun () +{ + return &efr != 0; // { dg-warning "-Waddress" } +} + +bool warn_ext_rvar () +{ + return &eir != 0; // { dg-warning "-Waddress" } +} + + +bool warn_parm_rfun (F &rf) +{ + return &rf != 0; // { dg-warning "-Waddress" } +} + +bool warn_parm_rvar (int &ir) +{ + return &ir != 0; // { dg-warning "-Waddress" } +} + +// Comparing the address of a reference argument to null also triggers +// a -Wnonnull-compare (that seems like a bug, hence PR 103363). +// { dg-prune-output "-Wnonnull-compare" } + + +struct S +{ + F &fr; + int &ir; +}; + +extern S es, esa[]; + +bool warn_ext_mem_rfun () +{ + return &es.fr != 0; // { dg-warning "-Waddress" } +} + +bool warn_ext_mem_rvar () +{ + return &es.ir != 0; // { dg-warning "-Waddress" } +} + + +bool warn_ext_arr_mem_rfun (int i) +{ + return &esa[i].fr != 0; // { dg-warning "-Waddress" } +} + +bool warn_ext_arr_mem_rvar (int i) +{ + return &esa[i].ir != 0; // { dg-warning "-Waddress" } +} + + +bool warn_parm_mem_rfun (S &s) +{ + return &s.fr != 0; // { dg-warning "-Waddress" } +} + +bool warn_parm_mem_rvar (S &s) +{ + return &s.ir != 0; // { dg-warning "-Waddress" } +} + + +bool warn_parm_arr_mem_rfun (S sa[], int i) +{ + return &sa[i].fr != 0; // { dg-warning "-Waddress" } +} + +bool warn_parm_arr_mem_rvar (S sa[], int i) +{ + return &sa[i].ir != 0; // { dg-warning "-Waddress" } +} -- cgit v1.1 From e1d4359264585acc8210ba60abb6dfb15bf1fa57 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 24 Nov 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/ChangeLog | 138 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c-family/ChangeLog | 5 ++ gcc/c/ChangeLog | 5 ++ gcc/cp/ChangeLog | 17 ++++++ gcc/fortran/ChangeLog | 14 +++++ gcc/testsuite/ChangeLog | 85 +++++++++++++++++++++++++++++ 7 files changed, 265 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b70adbd..0a9e75c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,141 @@ +2021-11-23 Martin Sebor + + PR middle-end/88232 + * Makefile.in (OBJS): Add gimple-warn-recursion.o. + * common.opt: Add -Winfinite-recursion. + * doc/invoke.texi (-Winfinite-recursion): Document. + * passes.def (pass_warn_recursion): Schedule a new pass. + * tree-pass.h (make_pass_warn_recursion): Declare. + * gimple-warn-recursion.c: New file. + +2021-11-23 Bill Schmidt + + * config/rs6000/rs6000-call.c (rs6000_invalid_new_builtin): Change + error messages for ENB_P8V and ENB_P9V. + +2021-11-23 Bill Schmidt + + * config/rs6000/rs6000-builtin-new.def: Add power6-64 stanza. Move + CMPB to power6-64 stanza. + * config/rs6000/rs6000-call.c (rs6000_invalid_new_builtin): Handle + ENB_P6_64 case. + (rs6000_new_builtin_is_supported): Likewise. + (rs6000_expand_new_builtin): Likewise. Clean up formatting. + (rs6000_init_builtins): Handle ENB_P6_64 case. + * config/rs6000/rs6000-gen-builtins.c (bif_stanza): Add BSTZ_P6_64. + (stanza_map): Add entry mapping power6-64 to BSTZ_P6_64. + (enable_string): Add "ENB_P6_64". + (write_decls): Add ENB_P6_64 to bif_enable enum. + +2021-11-23 Jan Hubicka + + * ipa-modref-tree.h (struct modref_tree): Remove max_bases, max_refs + and max_accesses. + (modref_tree::modref_tree): Remove parametr. + (modref_tree::insert_base): Add max_bases parameter. + (modref_tree::insert): Add max_bases, max_refs, max_accesses + parameters. + (modref_tree::insert): New member function. + (modref_tree::merge): Add max_bases, max_refs, max_accesses + parameters. + (modref_tree::insert): New member function. + * ipa-modref-tree.c (test_insert_search_collapse): Update. + (test_merge): Update. + * ipa-modref.c (dump_records): Don't dump max_refs and max_bases. + (dump_lto_records): Likewise. + (modref_summary::finalize): Fix whitespace. + (get_modref_function_summary): Likewise. + (modref_access_analysis::record_access): Update. + (modref_access_analysis::record_access_lto): Update. + (modref_access_analysis::process_fnspec): Update. + (analyze_function): Update. + (modref_summaries::duplicate): Update. + (modref_summaries_lto::duplicate): Update. + (write_modref_records): Update. + (read_modref_records): Update. + (read_section): Update. + (propagate_unknown_call): Update. + (modref_propagate_in_scc): Update. + (ipa_merge_modref_summary_after_inlining): Update. + +2021-11-23 Martin Liska + + * doc/invoke.texi: Remove 2 more duplicite param descriptions. + +2021-11-23 Richard Biener + + PR tree-optimization/103361 + * gimple-loop-jam.c (adjust_unroll_factor): Use lambda_int + for the dependence distance. + * tree-data-ref.c (print_lambda_vector): Properly print a lambda_int. + +2021-11-23 Jakub Jelinek + + * tree-inline.h (struct copy_body_data): Remove + transform_lang_insert_block member. + * tree-inline.c (remap_block): Don't call + id->transform_lang_insert_block. + (optimize_inline_calls, copy_gimple_seq_and_replace_locals, + tree_function_versioning, maybe_inline_call_in_expr, + copy_fn): Don't initialize id.transform_lang_insert_block. + * gimplify.c (gimplify_omp_loop): Likewise. + +2021-11-23 Jan Hubicka + + PR tree-optimization/103335 + * tree-ssa-dse.c (valid_ao_ref_for_dse): Rename to ... + (valid_ao_ref_kill_for_dse): ... this; do not check that boundaries + are divisible by BITS_PER_UNIT. + (get_byte_aligned_range_containing_ref): New function. + (get_byte_aligned_range_contained_in_ref): New function. + (normalize_ref): Rename to ... + (get_byte_range): ... this one; handle accesses not aligned to byte + boundary; return range in bytes rater than updating ao_ref. + (clear_live_bytes_for_ref): Take write ref by reference; simplify using + get_byte_access. + (setup_live_bytes_from_ref): Likewise. + (clear_bytes_written_by): Update. + (live_bytes_read): Update. + (dse_classify_store): Simplify tech before live_bytes_read checks. + +2021-11-23 Andrew Pinski + + PR tree-optimization/102216 + * gimple-fold.c (fold_stmt_1): Add canonicalization + of "&MEM[ssa_n, CST]" to "ssa_n p+ CST", note this + can only be done if !in_place. + +2021-11-23 Jakub Jelinek + + PR middle-end/102431 + * gimplify.c (replace_reduction_placeholders): Remove. + (note_no_context_vars): New function. + (gimplify_omp_loop): For OMP_PARALLEL's BIND_EXPR create a new + BLOCK. Use copy_tree_body_r with walk_tree instead of unshare_expr + and replace_reduction_placeholders for duplication of + OMP_CLAUSE_REDUCTION_{INIT,MERGE} expressions. Ensure all mentioned + automatic vars have DECL_CONTEXT set to non-NULL before doing so + and reset it afterwards for those vars and their corresponding + vars. + +2021-11-23 Haochen Gui + + PR target/100868 + * config/rs6000/altivec.md (altivec_vreve2 for VEC_K): Use + xxbrq for v16qi, xxbrq + xxbrh for v8hi and xxbrq + xxbrw for v4si + or v4sf when p9_vector is set. + (altivec_vreve2 for VEC_64): Defined. Implemented by xxswapd. + +2021-11-23 Navid Rahimi + + PR tree-optimization/102232 + * match.pd (x * (1 + y / x) - y) -> (x - y % x): New optimization. + +2021-11-23 Navid Rahimi + + PR tree-optimization/96779 + * match.pd (-x == x) -> (x == 0): New optimization. + 2021-11-22 Roger Sayle PR tree-optimization/98953 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index e45f2d0..6a89873 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20211123 +20211124 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 2e0b81d..9cbba19 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2021-11-23 Martin Sebor + + PR middle-end/88232 + * c.opt: Add -Winfinite-recursion. + 2021-11-19 Martin Sebor PR c++/33925 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index d42244d..42e918a 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,8 @@ +2021-11-23 Jakub Jelinek + + * c-typeck.c (c_clone_omp_udr): Don't initialize + id.transform_lang_insert_block. + 2021-11-19 Martin Sebor PR c++/33925 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 836ab86..79cb9f9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,20 @@ +2021-11-23 Martin Sebor + + PR c++/96507 + * typeck.c (warn_for_null_address): Handle reference members. + +2021-11-23 Marek Polacek + + PR c++/19808 + * init.c (emit_mem_initializers): Don't add is_really_empty_class + members into uninitialized. + +2021-11-23 Jakub Jelinek + + * semantics.c (clone_omp_udr): Don't initialize + id.transform_lang_insert_block. + * optimize.c (clone_body): Likewise. + 2021-11-22 Jason Merrill * typeck.c (build_x_unary_op): Set address location. diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f3c885c..ab6584c 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,17 @@ +2021-11-23 Harald Anlauf + + PR fortran/103392 + * simplify.c (simplify_bound): Do not try to simplify + LBOUND/UBOUND for arrays with POINTER or ALLOCATABLE attribute. + +2021-11-23 Harald Anlauf + + PR fortran/87711 + PR fortran/87851 + * trans-array.c (arg_evaluated_for_scalarization): Add LEN_TRIM to + list of intrinsics for which an optional KIND argument needs to be + removed before scalarization. + 2021-11-21 Jakub Jelinek PR debug/103315 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cdf542e..deca255 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,88 @@ +2021-11-23 Martin Sebor + + PR c++/96507 + * g++.dg/warn/Waddress-8.C: New test. + +2021-11-23 Martin Sebor + + PR middle-end/88232 + * c-c++-common/attr-used-5.c: Suppress valid warning. + * c-c++-common/attr-used-6.c: Same. + * c-c++-common/attr-used-9.c: Same. + * g++.dg/warn/Winfinite-recursion-2.C: New test. + * g++.dg/warn/Winfinite-recursion-3.C: New test. + * g++.dg/warn/Winfinite-recursion.C: New test. + * gcc.dg/Winfinite-recursion-2.c: New test. + * gcc.dg/Winfinite-recursion.c: New test. + +2021-11-23 Harald Anlauf + + PR fortran/103392 + * gfortran.dg/bound_simplification_7.f90: New test. + +2021-11-23 Marek Polacek + + PR c++/19808 + * g++.dg/warn/Wuninitialized-28.C: Make a class nonempty. + * g++.dg/warn/Wuninitialized-29.C: Likewise. + * g++.dg/warn/Wuninitialized-31.C: New test. + +2021-11-23 Marek Polacek + + * g++.dg/warn/Waddress-5.C: Make sf static. + +2021-11-23 Bill Schmidt + + * gcc.target/powerpc/test_mffsl.c: Change effective target to + a run-time check. Fix a typo in a debug print statement. + +2021-11-23 Harald Anlauf + + PR fortran/87711 + PR fortran/87851 + * gfortran.dg/len_trim.f90: New test. + +2021-11-23 Richard Biener + + PR tree-optimization/103361 + * g++.dg/torture/pr103361.C: New testcase. + +2021-11-23 Jan Hubicka + + * gcc.dg/tree-ssa/modref-dse-4.c: Update template. + * gcc.dg/tree-ssa/modref-dse-5.c: Update template. + +2021-11-23 Andrew Pinski + + PR tree-optimization/102216 + * g++.dg/tree-ssa/pr102216-1.C: New test. + * g++.dg/tree-ssa/pr102216-2.C: New test. + +2021-11-23 Jakub Jelinek + + PR middle-end/102431 + * c-c++-common/gomp/pr102431.c: New test. + * g++.dg/gomp/pr102431.C: New test. + * gfortran.dg/gomp/pr102431.f90: New test. + +2021-11-23 Haochen Gui + + PR target/100868 + * gcc.target/powerpc/vec_reve_1.c: New test. + * gcc.target/powerpc/vec_reve_2.c: Likewise. + +2021-11-23 Navid Rahimi + + PR tree-optimization/102232 + * gcc.dg/tree-ssa/pr102232.c: Testcase for this optimization. + +2021-11-23 Navid Rahimi + + PR tree-optimization/96779 + * gcc.dg/tree-ssa/pr96779.c: Testcase for this optimization. + * gcc.dg/tree-ssa/pr96779-disabled.c: Testcase for this optimization + when -fwrapv passed. + 2021-11-22 Jason Merrill * g++.dg/template/crash106.C: Adjust. -- cgit v1.1 From 7df89377a7ae3906255e38a79be8e5d962c3a0df Mon Sep 17 00:00:00 2001 From: liuhongt Date: Tue, 16 Nov 2021 13:36:36 +0800 Subject: Enhance optimize_atomic_bit_test_and to handle truncation. r12-5102-gfb161782545224f5 improves integer bit test on __atomic_fetch_[or|and]_* returns only for nop_convert, .i.e. transfrom mask_5 = 1 << bit_4(D); mask.0_1 = (unsigned int) mask_5; _2 = __atomic_fetch_or_4 (a_7(D), mask.0_1, 0); t1_9 = (int) _2; t2_10 = mask_5 & t1_9; to mask_5 = 1 << n_4(D); mask.1_1 = (unsigned int) mask_5; _11 = .ATOMIC_BIT_TEST_AND_SET (&pscc_a_1_4, n_4(D), 0); _8 = (int) _11; And this patch extend the original patch to handle truncation. .i.e. transform long int mask; mask_8 = 1 << n_7(D); mask.0_1 = (long unsigned int) mask_8; _2 = __sync_fetch_and_or_8 (&pscc_a_2_3, mask.0_1); _3 = (unsigned int) _2; _4 = (unsigned int) mask_8; _5 = _3 & _4; _6 = (int) _5; to long int mask; mask_8 = 1 << n_7(D); mask.0_1 = (long unsigned int) mask_8; _14 = .ATOMIC_BIT_TEST_AND_SET (&pscc_a_2_3, n_7(D), 0); _5 = (unsigned int) _14; _6 = (int) _5; 2021-11-17 Hongtao Liu H.J. Lu gcc/ChangeLog: PR tree-optimization/103194 * match.pd (gimple_nop_atomic_bit_test_and_p): Extended to match truncation. * tree-ssa-ccp.c (gimple_nop_convert): Declare. (optimize_atomic_bit_test_and): Enhance optimize_atomic_bit_test_and to handle truncation. gcc/testsuite/ChangeLog: * gcc.target/i386/pr103194-2.c: New test. * gcc.target/i386/pr103194-3.c: New test. * gcc.target/i386/pr103194-4.c: New test. * gcc.target/i386/pr103194-5.c: New test. * gcc.target/i386/pr103194.c: New test. --- gcc/match.pd | 48 +++++++++------ gcc/testsuite/gcc.target/i386/pr103194-2.c | 64 +++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr103194-3.c | 64 +++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr103194-4.c | 61 ++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr103194-5.c | 61 ++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr103194.c | 16 +++++ gcc/tree-ssa-ccp.c | 99 +++++++++++++++--------------- 7 files changed, 345 insertions(+), 68 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr103194-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr103194-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr103194-4.c create mode 100644 gcc/testsuite/gcc.target/i386/pr103194-5.c create mode 100644 gcc/testsuite/gcc.target/i386/pr103194.c (limited to 'gcc') diff --git a/gcc/match.pd b/gcc/match.pd index 886f807..60b4ad5 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -4044,39 +4044,43 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) #if GIMPLE (match (nop_atomic_bit_test_and_p @0 @1 @4) - (bit_and (nop_convert?@4 (ATOMIC_FETCH_OR_XOR_N @2 INTEGER_CST@0 @3)) + (bit_and (convert?@4 (ATOMIC_FETCH_OR_XOR_N @2 INTEGER_CST@0 @3)) INTEGER_CST@1) (with { int ibit = tree_log2 (@0); int ibit2 = tree_log2 (@1); } (if (ibit == ibit2 - && ibit >= 0)))) + && ibit >= 0 + && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@2)))))) (match (nop_atomic_bit_test_and_p @0 @1 @3) - (bit_and (nop_convert?@3 (SYNC_FETCH_OR_XOR_N @2 INTEGER_CST@0)) + (bit_and (convert?@3 (SYNC_FETCH_OR_XOR_N @2 INTEGER_CST@0)) INTEGER_CST@1) (with { int ibit = tree_log2 (@0); int ibit2 = tree_log2 (@1); } (if (ibit == ibit2 - && ibit >= 0)))) + && ibit >= 0 + && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@2)))))) (match (nop_atomic_bit_test_and_p @0 @0 @4) (bit_and:c - (nop_convert?@4 + (convert1?@4 (ATOMIC_FETCH_OR_XOR_N @2 (nop_convert? (lshift@0 integer_onep@5 @6)) @3)) - @0)) + (convert2? @0)) + (if (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@2))))) (match (nop_atomic_bit_test_and_p @0 @0 @4) (bit_and:c - (nop_convert?@4 + (convert1?@4 (SYNC_FETCH_OR_XOR_N @2 (nop_convert? (lshift@0 integer_onep@3 @5)))) - @0)) + (convert2? @0)) + (if (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@2))))) (match (nop_atomic_bit_test_and_p @0 @1 @3) - (bit_and@4 (nop_convert?@3 (ATOMIC_FETCH_AND_N @2 INTEGER_CST@0 @5)) + (bit_and@4 (convert?@3 (ATOMIC_FETCH_AND_N @2 INTEGER_CST@0 @5)) INTEGER_CST@1) (with { int ibit = wi::exact_log2 (wi::zext (wi::bit_not (wi::to_wide (@0)), @@ -4084,11 +4088,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) int ibit2 = tree_log2 (@1); } (if (ibit == ibit2 - && ibit >= 0)))) + && ibit >= 0 + && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@2)))))) (match (nop_atomic_bit_test_and_p @0 @1 @3) (bit_and@4 - (nop_convert?@3 (SYNC_FETCH_AND_AND_N @2 INTEGER_CST@0)) + (convert?@3 (SYNC_FETCH_AND_AND_N @2 INTEGER_CST@0)) INTEGER_CST@1) (with { int ibit = wi::exact_log2 (wi::zext (wi::bit_not (wi::to_wide (@0)), @@ -4096,19 +4101,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) int ibit2 = tree_log2 (@1); } (if (ibit == ibit2 - && ibit >= 0)))) + && ibit >= 0 + && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@2)))))) -(match (nop_atomic_bit_test_and_p @0 @0 @3) +(match (nop_atomic_bit_test_and_p @4 @0 @3) (bit_and:c - (nop_convert?@3 - (ATOMIC_FETCH_AND_N @2 (nop_convert? (bit_not (lshift@0 integer_onep@6 @7))) @5)) - @0)) + (convert1?@3 + (ATOMIC_FETCH_AND_N @2 (nop_convert?@4 (bit_not (lshift@0 integer_onep@6 @7))) @5)) + (convert2? @0)) + (if (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@2))))) -(match (nop_atomic_bit_test_and_p @0 @0 @3) +(match (nop_atomic_bit_test_and_p @4 @0 @3) (bit_and:c - (nop_convert?@3 - (SYNC_FETCH_AND_AND_N @2 (nop_convert? (bit_not (lshift@0 integer_onep@6 @7))))) - @0)) + (convert1?@3 + (SYNC_FETCH_AND_AND_N @2 (nop_convert?@4 (bit_not (lshift@0 integer_onep@6 @7))))) + (convert2? @0)) + (if (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@2))))) #endif diff --git a/gcc/testsuite/gcc.target/i386/pr103194-2.c b/gcc/testsuite/gcc.target/i386/pr103194-2.c new file mode 100644 index 0000000..1a991fe --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr103194-2.c @@ -0,0 +1,64 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +#include +#include + +#define FOO(RTYPE,TYPE,MASK) \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_or_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1 << MASK; \ + return __atomic_fetch_or (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_xor_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1 << MASK; \ + return __atomic_fetch_xor (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_xor_fetch_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1 << MASK; \ + return __atomic_xor_fetch (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_and_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1 << MASK; \ + return __atomic_fetch_and (a, ~mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_or_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1 << MASK; \ + return __sync_fetch_and_or (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_xor_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1 << MASK; \ + return __sync_fetch_and_xor (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_xor_and_fetch_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1 << MASK; \ + return __sync_xor_and_fetch (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_and_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1 << MASK; \ + return __sync_fetch_and_and (a, ~mask) & mask; \ + } \ + +FOO(char, short, 0); +FOO(char, short, 7); +FOO(short, int, 0); +FOO(short, int, 15); + +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*bts" 8 } } */ +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*btc" 16 } } */ +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*btr" 8 } } */ +/* { dg-final { scan-assembler-not "cmpxchg" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr103194-3.c b/gcc/testsuite/gcc.target/i386/pr103194-3.c new file mode 100644 index 0000000..4907598 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr103194-3.c @@ -0,0 +1,64 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2" } */ +#include +#include +typedef long long int64; + +#define FOO(RTYPE, TYPE,MASK) \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_or_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1ll << MASK; \ + return __atomic_fetch_or (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_xor_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1ll << MASK; \ + return __atomic_fetch_xor (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_xor_fetch_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1ll << MASK; \ + return __atomic_xor_fetch (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_and_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1ll << MASK; \ + return __atomic_fetch_and (a, ~mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_or_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1ll << MASK; \ + return __sync_fetch_and_or (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_xor_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1ll << MASK; \ + return __sync_fetch_and_xor (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_xor_and_fetch_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1ll << MASK; \ + return __sync_xor_and_fetch (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_and_##TYPE##_##MASK (_Atomic TYPE* a) \ + { \ + TYPE mask = 1ll << MASK; \ + return __sync_fetch_and_and (a, ~mask) & mask; \ + } \ + + +FOO(int, int64, 1); +FOO(int, int64, 31); + +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*bts" 4 } } */ +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*btc" 8 } } */ +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*btr" 4 } } */ +/* { dg-final { scan-assembler-not "cmpxchg" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr103194-4.c b/gcc/testsuite/gcc.target/i386/pr103194-4.c new file mode 100644 index 0000000..8573016 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr103194-4.c @@ -0,0 +1,61 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +#include +#include + +#define FOO(RTYPE,TYPE) \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_or_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1 << MASK; \ + return __atomic_fetch_or (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_xor_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1 << MASK; \ + return __atomic_fetch_xor (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_xor_fetch_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1 << MASK; \ + return __atomic_xor_fetch (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_and_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1 << MASK; \ + return __atomic_fetch_and (a, ~mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_or_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1 << MASK; \ + return __sync_fetch_and_or (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_xor_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1 << MASK; \ + return __sync_fetch_and_xor (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_xor_and_fetch_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1 << MASK; \ + return __sync_xor_and_fetch (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_and_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1 << MASK; \ + return __sync_fetch_and_and (a, ~mask) & mask; \ + } \ + +FOO(short, int); + +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*bts" 2 } } */ +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*btc" 4 } } */ +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*btr" 2 } } */ +/* { dg-final { scan-assembler-not "cmpxchg" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr103194-5.c b/gcc/testsuite/gcc.target/i386/pr103194-5.c new file mode 100644 index 0000000..dfaddf0 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr103194-5.c @@ -0,0 +1,61 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2" } */ +#include +#include + +#define FOO(RTYPE,TYPE) \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_or_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1ll << MASK; \ + return __atomic_fetch_or (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_xor_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1ll << MASK; \ + return __atomic_fetch_xor (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_xor_fetch_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1ll << MASK; \ + return __atomic_xor_fetch (a, mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + atomic_fetch_and_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1ll << MASK; \ + return __atomic_fetch_and (a, ~mask, __ATOMIC_RELAXED) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_or_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1ll << MASK; \ + return __sync_fetch_and_or (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_xor_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1ll << MASK; \ + return __sync_fetch_and_xor (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_xor_and_fetch_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1ll << MASK; \ + return __sync_xor_and_fetch (a, mask) & mask; \ + } \ + __attribute__((noinline,noclone)) RTYPE \ + sync_fetch_and_and_##TYPE##_##MASK (_Atomic TYPE* a, TYPE MASK) \ + { \ + TYPE mask = 1ll << MASK; \ + return __sync_fetch_and_and (a, ~mask) & mask; \ + } \ + +FOO(int, long); + +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*bts" 2 } } */ +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*btc" 4 } } */ +/* { dg-final { scan-assembler-times "lock;?\[ \t\]*btr" 2 } } */ +/* { dg-final { scan-assembler-not "cmpxchg" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr103194.c b/gcc/testsuite/gcc.target/i386/pr103194.c new file mode 100644 index 0000000..a6d8433 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr103194.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +long pscc_a_2_3; +int pscc_a_1_4; +void pscc() +{ + pscc_a_1_4 = __sync_fetch_and_and(&pscc_a_2_3, 1); +} + +static int si; +long +test_types (long n) +{ + unsigned int u2 = __atomic_fetch_xor (&si, 0, 5); + return u2; +} diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 18d5772..9e12da8 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -3326,6 +3326,7 @@ convert_atomic_bit_not (enum internal_fn fn, gimple *use_stmt, */ extern bool gimple_nop_atomic_bit_test_and_p (tree, tree *, tree (*) (tree)); +extern bool gimple_nop_convert (tree, tree*, tree (*) (tree)); /* Optimize mask_2 = 1 << cnt_1; @@ -3462,16 +3463,16 @@ optimize_atomic_bit_test_and (gimple_stmt_iterator *gsip, ibit = 0; } else if (TYPE_PRECISION (TREE_TYPE (use_lhs)) - == TYPE_PRECISION (TREE_TYPE (use_rhs))) + <= TYPE_PRECISION (TREE_TYPE (use_rhs))) { gimple *use_nop_stmt; if (!single_imm_use (use_lhs, &use_p, &use_nop_stmt) || !is_gimple_assign (use_nop_stmt)) return; + tree use_nop_lhs = gimple_assign_lhs (use_nop_stmt); rhs_code = gimple_assign_rhs_code (use_nop_stmt); if (rhs_code != BIT_AND_EXPR) { - tree use_nop_lhs = gimple_assign_lhs (use_nop_stmt); if (TREE_CODE (use_nop_lhs) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_nop_lhs)) return; @@ -3584,24 +3585,23 @@ optimize_atomic_bit_test_and (gimple_stmt_iterator *gsip, } else { - tree and_expr = gimple_assign_lhs (use_nop_stmt); tree match_op[3]; gimple *g; - if (!gimple_nop_atomic_bit_test_and_p (and_expr, + if (!gimple_nop_atomic_bit_test_and_p (use_nop_lhs, &match_op[0], NULL) || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (match_op[2]) || !single_imm_use (match_op[2], &use_p, &g) || !is_gimple_assign (g)) return; - mask = match_op[1]; - if (TREE_CODE (mask) == INTEGER_CST) + mask = match_op[0]; + if (TREE_CODE (match_op[1]) == INTEGER_CST) { - ibit = tree_log2 (mask); + ibit = tree_log2 (match_op[1]); gcc_assert (ibit >= 0); } else { - g = SSA_NAME_DEF_STMT (mask); + g = SSA_NAME_DEF_STMT (match_op[1]); gcc_assert (is_gimple_assign (g)); bit = gimple_assign_rhs2 (g); } @@ -3623,19 +3623,30 @@ optimize_atomic_bit_test_and (gimple_stmt_iterator *gsip, _1 = __atomic_fetch_and_* (ptr_6, ~mask_7, _3); _12 = _3 & mask_7; _5 = (int) _12; - */ - replace_uses_by (use_lhs, lhs); - tree use_nop_lhs = gimple_assign_lhs (use_nop_stmt); - var = make_ssa_name (TREE_TYPE (use_nop_lhs)); - gimple_assign_set_lhs (use_nop_stmt, var); + + and Convert + _1 = __atomic_fetch_and_4 (ptr_6, ~mask, _3); + _2 = (short int) _1; + _5 = _2 & mask; + to + _1 = __atomic_fetch_and_4 (ptr_6, ~mask, _3); + _8 = _1 & mask; + _5 = (short int) _8; + */ + gimple_seq stmts = NULL; + match_op[1] = gimple_convert (&stmts, + TREE_TYPE (use_rhs), + match_op[1]); + var = gimple_build (&stmts, BIT_AND_EXPR, + TREE_TYPE (use_rhs), use_rhs, match_op[1]); gsi = gsi_for_stmt (use_stmt); gsi_remove (&gsi, true); release_defs (use_stmt); - gsi_remove (gsip, true); - g = gimple_build_assign (use_nop_lhs, NOP_EXPR, var); + use_stmt = gimple_seq_last_stmt (stmts); gsi = gsi_for_stmt (use_nop_stmt); - gsi_insert_after (&gsi, g, GSI_NEW_STMT); - use_stmt = use_nop_stmt; + gsi_insert_seq_before (&gsi, stmts, GSI_SAME_STMT); + gimple_assign_set_rhs_with_ops (&gsi, CONVERT_EXPR, var); + update_stmt (use_nop_stmt); } } else @@ -3671,55 +3682,47 @@ optimize_atomic_bit_test_and (gimple_stmt_iterator *gsip, else if (TREE_CODE (mask) == SSA_NAME) { gimple *g = SSA_NAME_DEF_STMT (mask); - if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET) + tree match_op; + if (gimple_nop_convert (mask, &match_op, NULL)) { - if (!is_gimple_assign (g) - || gimple_assign_rhs_code (g) != BIT_NOT_EXPR) - return; - mask = gimple_assign_rhs1 (g); + mask = match_op; if (TREE_CODE (mask) != SSA_NAME) return; g = SSA_NAME_DEF_STMT (mask); } if (!is_gimple_assign (g)) return; - rhs_code = gimple_assign_rhs_code (g); - if (rhs_code != LSHIFT_EXPR) - { - if (rhs_code != NOP_EXPR) - return; - /* Handle - _1 = 1 << bit_4(D); - mask_5 = (unsigned int) _1; - _2 = __atomic_fetch_or_4 (v_7(D), mask_5, 0); - _3 = _2 & mask_5; - */ - tree nop_lhs = gimple_assign_lhs (g); - tree nop_rhs = gimple_assign_rhs1 (g); - if (TYPE_PRECISION (TREE_TYPE (nop_lhs)) - != TYPE_PRECISION (TREE_TYPE (nop_rhs))) + if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET) + { + if (gimple_assign_rhs_code (g) != BIT_NOT_EXPR) return; - g = SSA_NAME_DEF_STMT (nop_rhs); - if (!is_gimple_assign (g) - || gimple_assign_rhs_code (g) != LSHIFT_EXPR) + mask = gimple_assign_rhs1 (g); + if (TREE_CODE (mask) != SSA_NAME) return; + g = SSA_NAME_DEF_STMT (mask); } - if (!integer_onep (gimple_assign_rhs1 (g))) + + rhs_code = gimple_assign_rhs_code (g); + if (rhs_code != LSHIFT_EXPR + || !integer_onep (gimple_assign_rhs1 (g))) return; bit = gimple_assign_rhs2 (g); } else return; + tree cmp_mask; if (gimple_assign_rhs1 (use_stmt) == lhs) - { - if (!operand_equal_p (gimple_assign_rhs2 (use_stmt), mask, 0)) - return; - } - else if (gimple_assign_rhs2 (use_stmt) != lhs - || !operand_equal_p (gimple_assign_rhs1 (use_stmt), - mask, 0)) + cmp_mask = gimple_assign_rhs2 (use_stmt); + else + cmp_mask = gimple_assign_rhs1 (use_stmt); + + tree match_op; + if (gimple_nop_convert (cmp_mask, &match_op, NULL)) + cmp_mask = match_op; + + if (!operand_equal_p (cmp_mask, mask, 0)) return; } -- cgit v1.1 From 9bf69a8558638ce0cdd69e83a68776deb9b8e053 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 16 Oct 2021 00:04:25 -0400 Subject: timevar: Add auto_cond_timevar class The auto_timevar sentinel class for starting and stopping timevars was added in 2014, but doesn't work for the many uses of timevar_cond_start/stop in the C++ front end. So let's add one that does. This allows us to remove a lot of wrapper functions that were just used to call timevar_cond_stop on all exits from the function. gcc/ChangeLog: * timevar.h (class auto_cond_timevar): New. gcc/cp/ChangeLog: * call.c * decl.c * name-lookup.c: Use auto_cond_timevar instead of timevar_cond_start/stop. Remove wrapper functions. --- gcc/cp/call.c | 106 ++++++----------------- gcc/cp/decl.c | 51 +++-------- gcc/cp/name-lookup.c | 240 ++++++++++++++------------------------------------- gcc/timevar.h | 44 +++++++++- 4 files changed, 149 insertions(+), 292 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4ee21c7..27f4d9e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4432,7 +4432,7 @@ build_user_type_conversion (tree totype, tree expr, int flags, struct z_candidate *cand; tree ret; - bool subtime = timevar_cond_start (TV_OVERLOAD); + auto_cond_timevar tv (TV_OVERLOAD); cand = build_user_type_conversion_1 (totype, expr, flags, complain); if (cand) @@ -4448,7 +4448,6 @@ build_user_type_conversion (tree totype, tree expr, int flags, else ret = NULL_TREE; - timevar_cond_stop (TV_OVERLOAD, subtime); return ret; } @@ -4688,7 +4687,7 @@ perform_overload_resolution (tree fn, tree explicit_targs; int template_only; - bool subtime = timevar_cond_start (TV_OVERLOAD); + auto_cond_timevar tv (TV_OVERLOAD); explicit_targs = NULL_TREE; template_only = 0; @@ -4720,7 +4719,6 @@ perform_overload_resolution (tree fn, else cand = NULL; - timevar_cond_stop (TV_OVERLOAD, subtime); return cand; } @@ -4985,8 +4983,8 @@ build_operator_new_call (tree fnname, vec **args, /* Build a new call to operator(). This may change ARGS. */ -static tree -build_op_call_1 (tree obj, vec **args, tsubst_flags_t complain) +tree +build_op_call (tree obj, vec **args, tsubst_flags_t complain) { struct z_candidate *candidates = 0, *cand; tree fns, convs, first_mem_arg = NULL_TREE; @@ -4994,6 +4992,8 @@ build_op_call_1 (tree obj, vec **args, tsubst_flags_t complain) tree result = NULL_TREE; void *p; + auto_cond_timevar tv (TV_OVERLOAD); + obj = mark_lvalue_use (obj); if (error_operand_p (obj)) @@ -5123,18 +5123,6 @@ build_op_call_1 (tree obj, vec **args, tsubst_flags_t complain) return result; } -/* Wrapper for above. */ - -tree -build_op_call (tree obj, vec **args, tsubst_flags_t complain) -{ - tree ret; - bool subtime = timevar_cond_start (TV_OVERLOAD); - ret = build_op_call_1 (obj, args, complain); - timevar_cond_stop (TV_OVERLOAD, subtime); - return ret; -} - /* Called by op_error to prepare format strings suitable for the error function. It concatenates a prefix (controlled by MATCH), ERRMSG, and a suffix (controlled by NTYPES). */ @@ -5326,10 +5314,10 @@ conditional_conversion (tree e1, tree e2, tsubst_flags_t complain) /* Implement [expr.cond]. ARG1, ARG2, and ARG3 are the three arguments to the conditional expression. */ -static tree -build_conditional_expr_1 (const op_location_t &loc, - tree arg1, tree arg2, tree arg3, - tsubst_flags_t complain) +tree +build_conditional_expr (const op_location_t &loc, + tree arg1, tree arg2, tree arg3, + tsubst_flags_t complain) { tree arg2_type; tree arg3_type; @@ -5341,6 +5329,8 @@ build_conditional_expr_1 (const op_location_t &loc, void *p; tree orig_arg2, orig_arg3; + auto_cond_timevar tv (TV_OVERLOAD); + /* As a G++ extension, the second argument to the conditional can be omitted. (So that `a ? : c' is roughly equivalent to `a ? a : c'.) If the second operand is omitted, make sure it is @@ -5406,8 +5396,8 @@ build_conditional_expr_1 (const op_location_t &loc, && !VECTOR_TYPE_P (arg3_type)) { /* Rely on the error messages of the scalar version. */ - tree scal = build_conditional_expr_1 (loc, integer_one_node, - orig_arg2, orig_arg3, complain); + tree scal = build_conditional_expr (loc, integer_one_node, + orig_arg2, orig_arg3, complain); if (scal == error_mark_node) return error_mark_node; tree stype = TREE_TYPE (scal); @@ -5964,20 +5954,6 @@ build_conditional_expr_1 (const op_location_t &loc, return result; } -/* Wrapper for above. */ - -tree -build_conditional_expr (const op_location_t &loc, - tree arg1, tree arg2, tree arg3, - tsubst_flags_t complain) -{ - tree ret; - bool subtime = timevar_cond_start (TV_OVERLOAD); - ret = build_conditional_expr_1 (loc, arg1, arg2, arg3, complain); - timevar_cond_stop (TV_OVERLOAD, subtime); - return ret; -} - /* OPERAND is an operand to an expression. Perform necessary steps required before using it. If OPERAND is NULL_TREE, NULL_TREE is returned. */ @@ -6479,10 +6455,10 @@ add_operator_candidates (z_candidate **candidates, return NULL_TREE; } -static tree -build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, - tree arg1, tree arg2, tree arg3, tree *overload, - tsubst_flags_t complain) +tree +build_new_op (const op_location_t &loc, enum tree_code code, int flags, + tree arg1, tree arg2, tree arg3, tree *overload, + tsubst_flags_t complain) { struct z_candidate *candidates = 0, *cand; vec *arglist; @@ -6496,6 +6472,8 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, bool strict_p; bool any_viable_p; + auto_cond_timevar tv (TV_OVERLOAD); + if (error_operand_p (arg1) || error_operand_p (arg2) || error_operand_p (arg3)) @@ -6631,8 +6609,8 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, code = PREINCREMENT_EXPR; else code = PREDECREMENT_EXPR; - result = build_new_op_1 (loc, code, flags, arg1, NULL_TREE, - NULL_TREE, overload, complain); + result = build_new_op (loc, code, flags, arg1, NULL_TREE, + NULL_TREE, overload, complain); break; /* The caller will deal with these. */ @@ -6954,21 +6932,6 @@ build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags, return NULL_TREE; } -/* Wrapper for above. */ - -tree -build_new_op (const op_location_t &loc, enum tree_code code, int flags, - tree arg1, tree arg2, tree arg3, - tree *overload, tsubst_flags_t complain) -{ - tree ret; - bool subtime = timevar_cond_start (TV_OVERLOAD); - ret = build_new_op_1 (loc, code, flags, arg1, arg2, arg3, - overload, complain); - timevar_cond_stop (TV_OVERLOAD, subtime); - return ret; -} - /* CALL was returned by some call-building function; extract the actual CALL_EXPR from any bits that have been tacked on, e.g. by convert_from_reference. */ @@ -10694,10 +10657,10 @@ complain_about_no_candidates_for_method_call (tree instance, be set, upon return, to the function called. ARGS may be NULL. This may change ARGS. */ -static tree -build_new_method_call_1 (tree instance, tree fns, vec **args, - tree conversion_path, int flags, - tree *fn_p, tsubst_flags_t complain) +tree +build_new_method_call (tree instance, tree fns, vec **args, + tree conversion_path, int flags, + tree *fn_p, tsubst_flags_t complain) { struct z_candidate *candidates = 0, *cand; tree explicit_targs = NULL_TREE; @@ -10717,6 +10680,8 @@ build_new_method_call_1 (tree instance, tree fns, vec **args, vec *orig_args = NULL; void *p; + auto_cond_timevar tv (TV_OVERLOAD); + gcc_assert (instance != NULL_TREE); /* We don't know what function we're going to call, yet. */ @@ -11096,21 +11061,6 @@ build_new_method_call_1 (tree instance, tree fns, vec **args, return call; } -/* Wrapper for above. */ - -tree -build_new_method_call (tree instance, tree fns, vec **args, - tree conversion_path, int flags, - tree *fn_p, tsubst_flags_t complain) -{ - tree ret; - bool subtime = timevar_cond_start (TV_OVERLOAD); - ret = build_new_method_call_1 (instance, fns, args, conversion_path, flags, - fn_p, complain); - timevar_cond_stop (TV_OVERLOAD, subtime); - return ret; -} - /* Returns true iff standard conversion sequence ICS1 is a proper subsequence of ICS2. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 9f68d1a..375079f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -598,7 +598,7 @@ poplevel (int keep, int reverse, int functionbody) tree decl; scope_kind kind; - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); restart: block = NULL_TREE; @@ -830,7 +830,6 @@ poplevel (int keep, int reverse, int functionbody) if (kind == sk_cleanup) goto restart; - timevar_cond_stop (TV_NAME_LOOKUP, subtime); return block; } @@ -909,7 +908,7 @@ static GTY((deletable)) vec *local_entities; void determine_local_discriminator (tree decl) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); retrofit_lang_decl (decl); tree ctx = DECL_CONTEXT (decl); tree name = (TREE_CODE (decl) == TYPE_DECL @@ -944,8 +943,6 @@ determine_local_discriminator (tree decl) local_entities->quick_push (decl); local_entities->quick_push (name); } - - timevar_cond_stop (TV_NAME_LOOKUP, subtime); } @@ -3284,6 +3281,8 @@ named_label_hash::equal (const value_type entry, compare_type name) static named_label_entry * lookup_label_1 (tree id, bool making_local_p) { + auto_cond_timevar tv (TV_NAME_LOOKUP); + /* You can't use labels at global scope. */ if (current_function_decl == NULL_TREE) { @@ -3346,18 +3345,14 @@ lookup_label_1 (tree id, bool making_local_p) tree lookup_label (tree id) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); named_label_entry *ent = lookup_label_1 (id, false); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ent ? ent->label_decl : NULL_TREE; } tree declare_local_label (tree id) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); named_label_entry *ent = lookup_label_1 (id, true); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ent ? ent->label_decl : NULL_TREE; } @@ -3688,9 +3683,11 @@ check_omp_return (void) /* Define a label, specifying the location in the source file. Return the LABEL_DECL node for the label. */ -static tree -define_label_1 (location_t location, tree name) +tree +define_label (location_t location, tree name) { + auto_cond_timevar tv (TV_NAME_LOOKUP); + /* After labels, make any new cleanups in the function go into their own new (temporary) binding contour. */ for (cp_binding_level *p = current_binding_level; @@ -3724,18 +3721,6 @@ define_label_1 (location_t location, tree name) return decl; } -/* Wrapper for define_label_1. */ - -tree -define_label (location_t location, tree name) -{ - bool running = timevar_cond_start (TV_NAME_LOOKUP); - tree ret = define_label_1 (location, name); - timevar_cond_stop (TV_NAME_LOOKUP, running); - return ret; -} - - struct cp_switch { cp_binding_level *level; @@ -15499,13 +15484,15 @@ lookup_and_check_tag (enum tag_types tag_code, tree name, TEMPLATE_HEADER_P is true when this declaration is preceded by a set of template parameters. */ -static tree -xref_tag_1 (enum tag_types tag_code, tree name, - TAG_how how, bool template_header_p) +tree +xref_tag (enum tag_types tag_code, tree name, + TAG_how how, bool template_header_p) { enum tree_code code; tree context = NULL_TREE; + auto_cond_timevar tv (TV_NAME_LOOKUP); + gcc_assert (identifier_p (name)); switch (tag_code) @@ -15654,18 +15641,6 @@ xref_tag_1 (enum tag_types tag_code, tree name, return t; } -/* Wrapper for xref_tag_1. */ - -tree -xref_tag (enum tag_types tag_code, tree name, - TAG_how how, bool template_header_p) -{ - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - tree ret = xref_tag_1 (tag_code, name, how, template_header_p); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return ret; -} - /* Create the binfo hierarchy for REF with (possibly NULL) base list BASE_LIST. For each element on BASE_LIST the TREE_PURPOSE is an access_* node, and the TREE_VALUE is the type of the base-class. diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 035bcf5..0806928 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -39,7 +39,6 @@ along with GCC; see the file COPYING3. If not see static cxx_binding *cxx_binding_make (tree value, tree type); static cp_binding_level *innermost_nonclass_level (void); -static tree do_pushdecl (tree decl, bool hiding); static void set_identifier_type_value_with_scope (tree id, tree decl, cp_binding_level *b); static name_hint maybe_suggest_missing_std_header (location_t location, @@ -1725,11 +1724,9 @@ static void diagnose_name_conflict (tree, tree); tree lookup_arg_dependent (tree name, tree fns, vec *args) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); name_lookup lookup (name); - fns = lookup.search_adl (fns, args); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return fns; + return lookup.search_adl (fns, args); } /* FNS is an overload set of conversion functions. Return the @@ -2595,8 +2592,10 @@ anticipated_builtin_p (tree ovl) was successful. */ static bool -supplement_binding_1 (cxx_binding *binding, tree decl) +supplement_binding (cxx_binding *binding, tree decl) { + auto_cond_timevar tv (TV_NAME_LOOKUP); + tree bval = binding->value; bool ok = true; tree target_bval = strip_using_decl (bval); @@ -2736,18 +2735,6 @@ diagnose_name_conflict (tree decl, tree bval) inform (location_of (bval), "previous declaration %q#D", bval); } -/* Wrapper for supplement_binding_1. */ - -static bool -supplement_binding (cxx_binding *binding, tree decl) -{ - bool ret; - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - ret = supplement_binding_1 (binding, decl); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return ret; -} - /* Replace BINDING's current value on its scope's name list with NEWVAL. */ @@ -3472,7 +3459,7 @@ push_local_extern_decl_alias (tree decl) /* Expected default linkage is from the namespace. */ TREE_PUBLIC (alias) = TREE_PUBLIC (ns); push_nested_namespace (ns); - alias = do_pushdecl (alias, /* hiding= */true); + alias = pushdecl (alias, /* hiding= */true); pop_nested_namespace (ns); if (VAR_P (decl) && CP_DECL_THREAD_LOCAL_P (decl) @@ -3620,16 +3607,20 @@ check_module_override (tree decl, tree mvec, bool hiding, /* Record DECL as belonging to the current lexical scope. Check for errors (such as an incompatible declaration for the same name - already seen in the same scope). IS_FRIEND is true if DECL is - declared as a friend. + already seen in the same scope). + + The new binding is hidden if HIDING is true (an anticipated builtin + or hidden friend). Returns either DECL or an old decl for the same name. If an old decl is returned, it may have been smashed to agree with what DECL says. */ -static tree -do_pushdecl (tree decl, bool hiding) +tree +pushdecl (tree decl, bool hiding) { + auto_cond_timevar tv (TV_NAME_LOOKUP); + if (decl == error_mark_node) return error_mark_node; @@ -3845,19 +3836,6 @@ do_pushdecl (tree decl, bool hiding) return decl; } -/* Record a decl-node X as belonging to the current lexical scope. - The new binding is hidden if HIDING is true (an anticipated builtin - or hidden friend). */ - -tree -pushdecl (tree x, bool hiding) -{ - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - tree ret = do_pushdecl (x, hiding); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return ret; -} - /* A mergeable entity is being loaded into namespace NS slot NAME. Create and return the appropriate vector slot for that. Either a GMF slot or a module-specific one. */ @@ -4786,7 +4764,7 @@ do_pushdecl_with_scope (tree x, cp_binding_level *level, bool hiding = false) current_function_decl = NULL_TREE; b = current_binding_level; current_binding_level = level; - x = do_pushdecl (x, hiding); + x = pushdecl (x, hiding); current_binding_level = b; current_function_decl = function_decl; } @@ -4799,17 +4777,14 @@ tree pushdecl_outermost_localscope (tree x) { cp_binding_level *b = NULL; - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); /* Find the scope just inside the function parms. */ for (cp_binding_level *n = current_binding_level; n->kind != sk_function_parms; n = b->level_chain) b = n; - tree ret = b ? do_pushdecl_with_scope (x, b) : error_mark_node; - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - - return ret; + return b ? do_pushdecl_with_scope (x, b) : error_mark_node; } /* Process a local-scope or namespace-scope using declaration. LOOKUP @@ -5198,7 +5173,7 @@ poplevel_class (void) size_t i; tree shadowed; - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); gcc_assert (level != 0); /* If we're leaving a toplevel class, cache its binding level. */ @@ -5225,7 +5200,6 @@ poplevel_class (void) `pushlevel_class' routine. */ gcc_assert (current_binding_level == level); leave_scope (); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); } /* Set INHERITED_VALUE_BINDING_P on BINDING to true or false, as @@ -5268,14 +5242,13 @@ bool pushdecl_class_level (tree x) { bool is_valid = true; - bool subtime; /* Do nothing if we're adding to an outer lambda closure type, outer_binding will add it later if it's needed. */ if (current_class_type != class_binding_level->this_entity) return true; - subtime = timevar_cond_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); /* Get the name of X. */ tree name = OVL_NAME (x); @@ -5315,7 +5288,6 @@ pushdecl_class_level (tree x) } input_location = save_location; } - timevar_cond_stop (TV_NAME_LOOKUP, subtime); return is_valid; } @@ -5361,13 +5333,15 @@ get_class_binding (tree name, cp_binding_level *scope) /* Make the declaration(s) of X appear in CLASS scope under the name NAME. Returns true if the binding is valid. */ -static bool -push_class_level_binding_1 (tree name, tree x) +bool +push_class_level_binding (tree name, tree x) { cxx_binding *binding; tree decl = x; bool ok; + auto_cond_timevar tv (TV_NAME_LOOKUP); + /* The class_binding_level will be NULL if x is a template parameter name in a member template. */ if (!class_binding_level) @@ -5539,18 +5513,6 @@ push_class_level_binding_1 (tree name, tree x) return ok; } -/* Wrapper for push_class_level_binding_1. */ - -bool -push_class_level_binding (tree name, tree x) -{ - bool ret; - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - ret = push_class_level_binding_1 (name, x); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return ret; -} - /* Process and lookup a using decl SCOPE::lookup.name, filling in lookup.values & lookup.type. Return a USING_DECL, or NULL_TREE on failure. */ @@ -5794,7 +5756,7 @@ do_class_using_decl (tree scope, tree name) tree get_namespace_binding (tree ns, tree name) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); if (!ns) ns = global_namespace; gcc_checking_assert (!DECL_NAMESPACE_ALIAS (ns)); @@ -5810,7 +5772,6 @@ get_namespace_binding (tree ns, tree name) ret = MAYBE_STAT_DECL (ret); } - timevar_cond_stop (TV_NAME_LOOKUP, subtime); return ret; } @@ -5821,7 +5782,7 @@ get_namespace_binding (tree ns, tree name) void set_global_binding (tree decl) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); tree *slot = find_namespace_slot (global_namespace, DECL_NAME (decl), true); @@ -5831,8 +5792,6 @@ set_global_binding (tree decl) /* Force the binding, so compiler internals continue to work. */ *slot = decl; - - timevar_cond_stop (TV_NAME_LOOKUP, subtime); } /* Set the context of a declaration to scope. Complain if we are not @@ -6125,11 +6084,9 @@ do_namespace_alias (tree alias, tree name_space) tree pushdecl_namespace_level (tree decl, bool hiding) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - tree res = do_pushdecl_with_scope (decl, NAMESPACE_LEVEL (current_namespace), - hiding); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return res; + auto_cond_timevar tv (TV_NAME_LOOKUP); + return do_pushdecl_with_scope (decl, NAMESPACE_LEVEL (current_namespace), + hiding); } /* Wrapper around push_local_binding to push the bindings for @@ -7692,11 +7649,13 @@ innermost_non_namespace_value (tree name) WANT can also have LOOK_want::HIDDEN_FRIEND or LOOK_want::HIDDEN_LAMBDa added to it. */ -static tree -lookup_name_1 (tree name, LOOK_where where, LOOK_want want) +tree +lookup_name (tree name, LOOK_where where, LOOK_want want) { tree val = NULL_TREE; + auto_cond_timevar tv (TV_NAME_LOOKUP); + gcc_checking_assert (unsigned (where) != 0); /* If we're looking for hidden lambda things, we shouldn't be looking in namespace scope. */ @@ -7797,17 +7756,6 @@ lookup_name_1 (tree name, LOOK_where where, LOOK_want want) return val; } -/* Wrapper for lookup_name_1. */ - -tree -lookup_name (tree name, LOOK_where where, LOOK_want want) -{ - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - tree ret = lookup_name_1 (name, where, want); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return ret; -} - tree lookup_name (tree name) { @@ -7827,9 +7775,11 @@ lookup_name (tree name) A TYPE_DECL best matching the NAME is returned. Catching error and issuing diagnostics are caller's responsibility. */ -static tree -lookup_elaborated_type_1 (tree name, TAG_how how) +tree +lookup_elaborated_type (tree name, TAG_how how) { + auto_cond_timevar tv (TV_NAME_LOOKUP); + cp_binding_level *b = current_binding_level; if (b->kind != sk_namespace) @@ -8013,17 +7963,6 @@ lookup_elaborated_type_1 (tree name, TAG_how how) return NULL_TREE; } -/* Wrapper for lookup_type_scope_1. */ - -tree -lookup_elaborated_type (tree name, TAG_how how) -{ - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - tree ret = lookup_elaborated_type_1 (name, how); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return ret; -} - /* The type TYPE is being declared. If it is a class template, or a specialization of a class template, do any processing required and perform error-checking. If IS_FRIEND is nonzero, this TYPE is @@ -8101,13 +8040,15 @@ maybe_process_template_type_declaration (tree type, int is_friend, Returns TYPE upon success and ERROR_MARK_NODE otherwise. */ -static tree -do_pushtag (tree name, tree type, TAG_how how) +tree +pushtag (tree name, tree type, TAG_how how) { tree decl; gcc_assert (identifier_p (name)); + auto_cond_timevar tv (TV_NAME_LOOKUP); + cp_binding_level *b = current_binding_level; while (true) { @@ -8251,18 +8192,6 @@ do_pushtag (tree name, tree type, TAG_how how) return type; } - -/* Wrapper for do_pushtag. */ - -tree -pushtag (tree name, tree type, TAG_how how) -{ - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - tree ret = do_pushtag (name, type, how); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); - return ret; -} - /* Subroutines for reverting temporarily to top-level for instantiation of templates and such. We actually need to clear out the class- and @@ -8311,7 +8240,7 @@ store_bindings (tree names, vec **old_bindings) tree t, id; size_t i; - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); for (t = names; t; t = TREE_CHAIN (t)) { if (TREE_CODE (t) == TREE_LIST) @@ -8333,7 +8262,6 @@ store_bindings (tree names, vec **old_bindings) } bindings_need_stored.truncate (0); } - timevar_cond_stop (TV_NAME_LOOKUP, subtime); } /* Like store_bindings, but NAMES is a vector of cp_class_binding @@ -8364,8 +8292,8 @@ store_class_bindings (vec *names, static GTY((deletable)) struct saved_scope *free_saved_scope; -static void -do_push_to_top_level (void) +void +push_to_top_level (void) { struct saved_scope *s; cp_binding_level *b; @@ -8373,6 +8301,8 @@ do_push_to_top_level (void) size_t i; bool need_pop; + auto_cond_timevar tv (TV_NAME_LOOKUP); + /* Reuse or create a new structure for this saved scope. */ if (free_saved_scope != NULL) { @@ -8450,13 +8380,15 @@ do_push_to_top_level (void) suppress_location_wrappers = 0; } -static void -do_pop_from_top_level (void) +void +pop_from_top_level (void) { struct saved_scope *s = scope_chain; cxx_saved_binding *saved; size_t i; + auto_cond_timevar tv (TV_NAME_LOOKUP); + /* Clear out class-level bindings cache. */ if (previous_class_level) invalidate_class_lookup_cache (); @@ -8491,14 +8423,15 @@ do_pop_from_top_level (void) /* Push into the scope of the namespace NS, even if it is deeply nested within another namespace. */ -static void -do_push_nested_namespace (tree ns) +void +push_nested_namespace (tree ns) { + auto_cond_timevar tv (TV_NAME_LOOKUP); if (ns == global_namespace) - do_push_to_top_level (); + push_to_top_level (); else { - do_push_nested_namespace (CP_DECL_CONTEXT (ns)); + push_nested_namespace (CP_DECL_CONTEXT (ns)); resume_scope (NAMESPACE_LEVEL (ns)); current_namespace = ns; } @@ -8507,9 +8440,10 @@ do_push_nested_namespace (tree ns) /* Pop back from the scope of the namespace NS, which was previously entered with push_nested_namespace. */ -static void -do_pop_nested_namespace (tree ns) +void +pop_nested_namespace (tree ns) { + auto_cond_timevar tv (TV_NAME_LOOKUP); while (ns != global_namespace) { ns = CP_DECL_CONTEXT (ns); @@ -8517,7 +8451,7 @@ do_pop_nested_namespace (tree ns) leave_scope (); } - do_pop_from_top_level (); + pop_from_top_level (); } /* Add TARGET to USINGS, if it does not already exist there. We used @@ -8597,13 +8531,12 @@ finish_using_directive (tree target, tree attribs) tree pushdecl_top_level (tree x) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - do_push_to_top_level (); + auto_cond_timevar tv (TV_NAME_LOOKUP); + push_to_top_level (); gcc_checking_assert (!DECL_CONTEXT (x)); DECL_CONTEXT (x) = FROB_CONTEXT (global_namespace); x = pushdecl_namespace_level (x); - do_pop_from_top_level (); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); + pop_from_top_level (); return x; } @@ -8613,14 +8546,13 @@ pushdecl_top_level (tree x) tree pushdecl_top_level_and_finish (tree x, tree init) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - do_push_to_top_level (); + auto_cond_timevar tv (TV_NAME_LOOKUP); + push_to_top_level (); gcc_checking_assert (!DECL_CONTEXT (x)); DECL_CONTEXT (x) = FROB_CONTEXT (global_namespace); x = pushdecl_namespace_level (x); cp_finish_decl (x, init, false, NULL_TREE, 0); - do_pop_from_top_level (); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); + pop_from_top_level (); return x; } @@ -8730,7 +8662,7 @@ make_namespace_finish (tree ns, tree *slot, bool from_import = false) int push_namespace (tree name, bool make_inline) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); int count = 0; /* We should not get here if the global_namespace is not yet constructed @@ -8877,7 +8809,6 @@ push_namespace (tree name, bool make_inline) count++; } - timevar_cond_stop (TV_NAME_LOOKUP, subtime); return count; } @@ -8886,14 +8817,12 @@ push_namespace (tree name, bool make_inline) void pop_namespace (void) { - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); + auto_cond_timevar tv (TV_NAME_LOOKUP); gcc_assert (current_namespace != global_namespace); current_namespace = CP_DECL_CONTEXT (current_namespace); /* The binding level is not popped, as it might be re-opened later. */ leave_scope (); - - timevar_cond_stop (TV_NAME_LOOKUP, subtime); } /* An IMPORT is an import that is defining namespace NAME inside CTX. Find or @@ -8960,43 +8889,6 @@ add_imported_namespace (tree ctx, tree name, location_t loc, unsigned import, return decl; } -/* External entry points for do_{push_to/pop_from}_top_level. */ - -void -push_to_top_level (void) -{ - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - do_push_to_top_level (); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); -} - -void -pop_from_top_level (void) -{ - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - do_pop_from_top_level (); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); -} - -/* External entry points for do_{push,pop}_nested_namespace. */ - -void -push_nested_namespace (tree ns) -{ - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - do_push_nested_namespace (ns); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); -} - -void -pop_nested_namespace (tree ns) -{ - bool subtime = timevar_cond_start (TV_NAME_LOOKUP); - gcc_assert (current_namespace == ns); - do_pop_nested_namespace (ns); - timevar_cond_stop (TV_NAME_LOOKUP, subtime); -} - /* Pop off extraneous binding levels left over due to syntax errors. We don't pop past namespaces, as they might be valid. */ diff --git a/gcc/timevar.h b/gcc/timevar.h index 72e31ad..ccaa42e 100644 --- a/gcc/timevar.h +++ b/gcc/timevar.h @@ -247,13 +247,53 @@ class auto_timevar m_timer->pop (m_tv); } + // Disallow copies. + auto_timevar (const auto_timevar &) = delete; + private: + timer *m_timer; + timevar_id_t m_tv; +}; + +// As above, but use cond_start/stop. +class auto_cond_timevar +{ + public: + auto_cond_timevar (timer *t, timevar_id_t tv) + : m_timer (t), + m_tv (tv) + { + start (); + } + + explicit auto_cond_timevar (timevar_id_t tv) + : m_timer (g_timer) + , m_tv (tv) + { + start (); + } + + ~auto_cond_timevar () + { + if (m_timer && !already_running) + m_timer->cond_stop (m_tv); + } + + // Disallow copies. + auto_cond_timevar (const auto_cond_timevar &) = delete; - // Private to disallow copies. - auto_timevar (const auto_timevar &); + private: + void start() + { + if (m_timer) + already_running = m_timer->cond_start (m_tv); + else + already_running = false; + } timer *m_timer; timevar_id_t m_tv; + bool already_running; }; extern void print_time (const char *, long); -- cgit v1.1 From d71d019f63ed5d3fdb34579023bafa4dcf323f2c Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Mon, 22 Nov 2021 14:09:25 -0500 Subject: c++: Fix missing NSDMI diagnostic in C++98 [PR103347] Here the problem is that we aren't detecting a NSDMI in C++98: struct A { void *x = NULL; }; because maybe_warn_cpp0x uses input_location and that happens to point to NULL which comes from a system header. Jakub suggested changing the location to the '=', thereby avoiding the system header problem. To that end, I've added a new location_t member into cp_declarator. This member is used when this declarator is part of an init-declarator. The rest of the changes is obvious. I've also taken the liberty of adding loc_or_input_loc, since I want to avoid checking for UNKNOWN_LOCATION. PR c++/103347 gcc/cp/ChangeLog: * cp-tree.h (struct cp_declarator): Add a location_t member. (maybe_warn_cpp0x): Add a location_t parameter with a default argument. (loc_or_input_loc): New. * decl.c (grokdeclarator): Use loc_or_input_loc. Pass init_loc down to maybe_warn_cpp0x. * error.c (maybe_warn_cpp0x): Add a location_t parameter. Use it. * parser.c (make_declarator): Initialize init_loc. (cp_parser_member_declaration): Set init_loc. (cp_parser_condition): Likewise. (cp_parser_init_declarator): Likewise. (cp_parser_parameter_declaration): Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/nsdmi-warn1.C: New test. * g++.dg/cpp0x/nsdmi-warn1.h: New file. --- gcc/cp/cp-tree.h | 16 ++++++++++++---- gcc/cp/decl.c | 22 +++++++++++++--------- gcc/cp/error.c | 32 ++++++++++++++++---------------- gcc/cp/parser.c | 8 ++++++++ gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C | 10 ++++++++++ gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h | 2 ++ 6 files changed, 61 insertions(+), 29 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h (limited to 'gcc') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3f56cb9..2037082 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6231,9 +6231,11 @@ struct cp_declarator { /* If this declarator is parenthesized, this the open-paren. It is UNKNOWN_LOCATION when not parenthesized. */ location_t parenthesized; - - location_t id_loc; /* Currently only set for cdk_id, cdk_decomp and - cdk_function. */ + /* Currently only set for cdk_id, cdk_decomp and cdk_function. */ + location_t id_loc; + /* If this declarator is part of an init-declarator, the location of the + initializer. */ + location_t init_loc; /* GNU Attributes that apply to this declarator. If the declarator is a pointer or a reference, these attribute apply to the type pointed to. */ @@ -6878,7 +6880,8 @@ extern const char *lang_decl_dwarf_name (tree, int, bool); extern const char *language_to_string (enum languages); extern const char *class_key_or_enum_as_string (tree); extern void maybe_warn_variadic_templates (void); -extern void maybe_warn_cpp0x (cpp0x_warn_str str); +extern void maybe_warn_cpp0x (cpp0x_warn_str str, + location_t = input_location); extern bool pedwarn_cxx98 (location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); extern location_t location_of (tree); extern void qualified_name_lookup_error (tree, tree, tree, @@ -7996,6 +7999,11 @@ extern bool decl_in_std_namespace_p (tree); extern void require_complete_eh_spec_types (tree, tree); extern void cxx_incomplete_type_diagnostic (location_t, const_tree, const_tree, diagnostic_t); +inline location_t +loc_or_input_loc (location_t loc) +{ + return loc == UNKNOWN_LOCATION ? input_location : loc; +} inline location_t cp_expr_loc_or_loc (const_tree t, location_t or_loc) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 375079f..588094b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -11507,14 +11507,18 @@ grokdeclarator (const cp_declarator *declarator, if (initialized == SD_DEFAULTED || initialized == SD_DELETED) funcdef_flag = true; - location_t typespec_loc = smallest_type_location (type_quals, - declspecs->locations); - if (typespec_loc == UNKNOWN_LOCATION) - typespec_loc = input_location; - - location_t id_loc = declarator ? declarator->id_loc : input_location; - if (id_loc == UNKNOWN_LOCATION) - id_loc = input_location; + location_t typespec_loc = loc_or_input_loc (smallest_type_location + (type_quals, + declspecs->locations)); + location_t id_loc; + location_t init_loc; + if (declarator) + { + id_loc = loc_or_input_loc (declarator->id_loc); + init_loc = loc_or_input_loc (declarator->init_loc); + } + else + init_loc = id_loc = input_location; /* Look inside a declarator for the name being declared and get it as a string, for an error message. */ @@ -14027,7 +14031,7 @@ grokdeclarator (const cp_declarator *declarator, { /* An attempt is being made to initialize a non-static member. This is new in C++11. */ - maybe_warn_cpp0x (CPP0X_NSDMI); + maybe_warn_cpp0x (CPP0X_NSDMI, init_loc); /* If this has been parsed with static storage class, but errors forced staticp to be cleared, ensure NSDMI is diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 8724793..98c1f0e 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -4428,84 +4428,84 @@ cp_printer (pretty_printer *pp, text_info *text, const char *spec, /* Warn about the use of C++0x features when appropriate. */ void -maybe_warn_cpp0x (cpp0x_warn_str str) +maybe_warn_cpp0x (cpp0x_warn_str str, location_t loc/*=input_location*/) { if (cxx_dialect == cxx98) switch (str) { case CPP0X_INITIALIZER_LISTS: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "extended initializer lists " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_EXPLICIT_CONVERSION: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "explicit conversion operators " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_VARIADIC_TEMPLATES: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "variadic templates " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_LAMBDA_EXPR: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "lambda expressions " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_AUTO: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "C++11 auto only available with %<-std=c++11%> or " "%<-std=gnu++11%>"); break; case CPP0X_SCOPED_ENUMS: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "scoped enums only available with %<-std=c++11%> or " "%<-std=gnu++11%>"); break; case CPP0X_DEFAULTED_DELETED: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "defaulted and deleted functions " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_INLINE_NAMESPACES: if (pedantic) - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "inline namespaces " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_OVERRIDE_CONTROLS: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "override controls (override/final) " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_NSDMI: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "non-static data member initializers " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_USER_DEFINED_LITERALS: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "user-defined literals " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_DELEGATING_CTORS: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "delegating constructors " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_INHERITING_CTORS: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "inheriting constructors " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_ATTRIBUTES: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "C++11 attributes " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_REF_QUALIFIER: - pedwarn (input_location, OPT_Wc__11_extensions, + pedwarn (loc, OPT_Wc__11_extensions, "ref-qualifiers " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e2b5d68..7a6a302 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1542,6 +1542,7 @@ make_declarator (cp_declarator_kind kind) declarator->declarator = NULL; declarator->parameter_pack_p = false; declarator->id_loc = UNKNOWN_LOCATION; + declarator->init_loc = UNKNOWN_LOCATION; return declarator; } @@ -13286,6 +13287,7 @@ cp_parser_condition (cp_parser* parser) attributes, prefix_attributes, &pushed_scope); + declarator->init_loc = cp_lexer_peek_token (parser->lexer)->location; /* Parse the initializer. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { @@ -22492,6 +22494,7 @@ cp_parser_init_declarator (cp_parser* parser, { is_initialized = SD_INITIALIZED; initialization_kind = token->type; + declarator->init_loc = token->location; if (maybe_range_for_decl) *maybe_range_for_decl = error_mark_node; tmp_init_loc = token->location; @@ -24751,6 +24754,8 @@ cp_parser_parameter_declaration (cp_parser *parser, { tree type = decl_specifiers.type; token = cp_lexer_peek_token (parser->lexer); + if (declarator) + declarator->init_loc = token->location; /* If we are defining a class, then the tokens that make up the default argument must be saved and processed later. */ if (!template_parm_p && at_class_scope_p () @@ -27143,6 +27148,7 @@ cp_parser_member_declaration (cp_parser* parser) constant-initializer. When we call `grokfield', it will perform more stringent semantics checks. */ initializer_token_start = cp_lexer_peek_token (parser->lexer); + declarator->init_loc = initializer_token_start->location; if (function_declarator_p (declarator) || (decl_specifiers.type && TREE_CODE (decl_specifiers.type) == TYPE_DECL @@ -27171,6 +27177,8 @@ cp_parser_member_declaration (cp_parser* parser) && !function_declarator_p (declarator)) { bool x; + declarator->init_loc + = cp_lexer_peek_token (parser->lexer)->location; if (decl_specifiers.storage_class != sc_static) initializer = cp_parser_save_nsdmi (parser); else diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C new file mode 100644 index 0000000..aacc8b2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.C @@ -0,0 +1,10 @@ +// PR c++/103347 +// { dg-do compile { target c++11_down } } + +#include "nsdmi-warn1.h" + +struct A { + void *x = NULL; // { dg-error "11:only available" "" { target c++98_only } } + void *y{NULL}; // { dg-error "only available|extended initializer" "" { target c++98_only } } + int z = 1 + 2; // { dg-error "9:only available" "" { target c++98_only } } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h b/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h new file mode 100644 index 0000000..ee5be5a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-warn1.h @@ -0,0 +1,2 @@ +#pragma GCC system_header +#define NULL (void *)0 -- cgit v1.1 From 0888d6bbe97e10de0e624f4ab46acc276e5ee1d7 Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Wed, 24 Nov 2021 06:38:18 +0000 Subject: middle-end: Convert bitclear + cmp #0 into cm This optimizes the case where a mask Y which fulfills ~Y + 1 == pow2 is used to clear a some bits and then compared against 0 into one without the masking and a compare against a different bit immediate. We can do this for all unsigned compares and for signed we can do it for comparisons of EQ and NE: (x & (~255)) == 0 becomes x <= 255. Which for leaves it to the target to optimally deal with the comparison. This transformation has to be done in the mid-end because in RTL you don't have the signs of the comparison operands and if the target needs an immediate this should be floated outside of the loop. The RTL loop invariant hoisting is done before split1. i.e. void fun1(int32_t *x, int n) { for (int i = 0; i < (n & -16); i++) x[i] = (x[i]&(~255)) == 0; } now generates: .L3: ldr q0, [x0] cmhs v0.4s, v2.4s, v0.4s and v0.16b, v1.16b, v0.16b str q0, [x0], 16 cmp x0, x1 bne .L3 and floats the immediate out of the loop. instead of: .L3: ldr q0, [x0] bic v0.4s, #255 cmeq v0.4s, v0.4s, #0 and v0.16b, v1.16b, v0.16b str q0, [x0], 16 cmp x0, x1 bne .L3 In order to not break IVopts and CSE I have added a requirement for the scalar version to be single use. gcc/ChangeLog: * tree.c (bitmask_inv_cst_vector_p): New. * tree.h (bitmask_inv_cst_vector_p): New. * match.pd: Use it in new bitmask compare pattern. gcc/testsuite/ChangeLog: * gcc.dg/bic-bitmask-10.c: New test. * gcc.dg/bic-bitmask-11.c: New test. * gcc.dg/bic-bitmask-12.c: New test. * gcc.dg/bic-bitmask-13.c: New test. * gcc.dg/bic-bitmask-14.c: New test. * gcc.dg/bic-bitmask-15.c: New test. * gcc.dg/bic-bitmask-16.c: New test. * gcc.dg/bic-bitmask-17.c: New test. * gcc.dg/bic-bitmask-18.c: New test. * gcc.dg/bic-bitmask-19.c: New test. * gcc.dg/bic-bitmask-2.c: New test. * gcc.dg/bic-bitmask-20.c: New test. * gcc.dg/bic-bitmask-21.c: New test. * gcc.dg/bic-bitmask-22.c: New test. * gcc.dg/bic-bitmask-23.c: New test. * gcc.dg/bic-bitmask-3.c: New test. * gcc.dg/bic-bitmask-4.c: New test. * gcc.dg/bic-bitmask-5.c: New test. * gcc.dg/bic-bitmask-6.c: New test. * gcc.dg/bic-bitmask-7.c: New test. * gcc.dg/bic-bitmask-8.c: New test. * gcc.dg/bic-bitmask-9.c: New test. * gcc.dg/bic-bitmask.h: New test. * gcc.target/aarch64/bic-bitmask-1.c: New test. --- gcc/match.pd | 21 +++++++++- gcc/testsuite/gcc.dg/bic-bitmask-10.c | 26 ++++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-11.c | 25 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-12.c | 17 ++++++++ gcc/testsuite/gcc.dg/bic-bitmask-13.c | 24 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-14.c | 24 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-15.c | 24 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-16.c | 24 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-17.c | 24 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-18.c | 24 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-19.c | 24 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-2.c | 25 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-20.c | 24 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-21.c | 25 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-22.c | 24 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-23.c | 16 +++++++ gcc/testsuite/gcc.dg/bic-bitmask-3.c | 25 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-4.c | 25 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-5.c | 25 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-6.c | 25 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-7.c | 24 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-8.c | 25 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask-9.c | 25 +++++++++++ gcc/testsuite/gcc.dg/bic-bitmask.h | 43 +++++++++++++++++++ gcc/testsuite/gcc.target/aarch64/bic-bitmask-1.c | 13 ++++++ gcc/tree.c | 53 ++++++++++++++++++++++++ gcc/tree.h | 5 +++ 27 files changed, 658 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-10.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-11.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-12.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-13.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-14.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-15.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-16.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-17.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-18.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-19.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-2.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-20.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-21.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-22.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-23.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-3.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-4.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-5.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-6.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-7.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-8.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask-9.c create mode 100644 gcc/testsuite/gcc.dg/bic-bitmask.h create mode 100644 gcc/testsuite/gcc.target/aarch64/bic-bitmask-1.c (limited to 'gcc') diff --git a/gcc/match.pd b/gcc/match.pd index 60b4ad5..3e54e2cf 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -38,7 +38,8 @@ along with GCC; see the file COPYING3. If not see uniform_integer_cst_p HONOR_NANS uniform_vector_p - expand_vec_cmp_expr_p) + expand_vec_cmp_expr_p + bitmask_inv_cst_vector_p) /* Operator lists. */ (define_operator_list tcc_comparison @@ -5207,6 +5208,24 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (eqcmp (bit_and @1 { wide_int_to_tree (ty, mask - rhs); }) { build_zero_cst (ty); })))))) +/* Transform comparisons of the form (X & Y) CMP 0 to X CMP2 Z + where ~Y + 1 == pow2 and Z = ~Y. */ +(for cst (VECTOR_CST INTEGER_CST) + (for cmp (le eq ne ge gt) + icmp (le le gt le gt) + (simplify + (cmp (bit_and:c@2 @0 cst@1) integer_zerop) + (with { tree csts = bitmask_inv_cst_vector_p (@1); } + (switch + (if (csts && TYPE_UNSIGNED (TREE_TYPE (@1)) + && (VECTOR_TYPE_P (TREE_TYPE (@1)) || single_use (@2))) + (icmp @0 { csts; })) + (if (csts && !TYPE_UNSIGNED (TREE_TYPE (@1)) + && (cmp == EQ_EXPR || cmp == NE_EXPR) + && (VECTOR_TYPE_P (TREE_TYPE (@1)) || single_use (@2))) + (with { tree utype = unsigned_type_for (TREE_TYPE (@1)); } + (icmp (convert:utype @0) { csts; })))))))) + /* -A CMP -B -> B CMP A. */ (for cmp (tcc_comparison) scmp (swapped_tcc_comparison) diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-10.c b/gcc/testsuite/gcc.dg/bic-bitmask-10.c new file mode 100644 index 0000000..0d04160 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-10.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(int32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +__attribute__((noinline, noipa, optimize("O1"))) +void fun2(int32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +#define TYPE int32_t +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump {<=\s*.+\{ 255,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s*.+\{ 4294967290,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-11.c b/gcc/testsuite/gcc.dg/bic-bitmask-11.c new file mode 100644 index 0000000..0e589c9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-11.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) != 0; +} + +__attribute__((noinline, noipa, optimize("O1"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) != 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump {>\s*.+\{ 255,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s*.+\{ 4294967290,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-12.c b/gcc/testsuite/gcc.dg/bic-bitmask-12.c new file mode 100644 index 0000000..50eb563 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-12.c @@ -0,0 +1,17 @@ +/* { dg-do assemble } */ +/* { dg-options "-O3 -fdump-tree-dce" } */ + +#include + +typedef unsigned int v4si __attribute__ ((vector_size (16))); + +__attribute__((noinline, noipa)) +void fun(v4si *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +/* { dg-final { scan-tree-dump {<=\s*.+\{ 255,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s*.+\{ 4294967290,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-13.c b/gcc/testsuite/gcc.dg/bic-bitmask-13.c new file mode 100644 index 0000000..bac86c2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-13.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-O0 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +__attribute__((noinline, noipa, optimize("O1"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {<=\s* 255} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s* 4294967040} dce7 { target vect_int } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-14.c b/gcc/testsuite/gcc.dg/bic-bitmask-14.c new file mode 100644 index 0000000..ec3bd6a --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-14.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +__attribute__((noinline, noipa, optimize("O0"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {<=\s* 255} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s* 4294967040} dce7 { target vect_int } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-15.c b/gcc/testsuite/gcc.dg/bic-bitmask-15.c new file mode 100644 index 0000000..8bdf1ea --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-15.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) >= 0; +} + +__attribute__((noinline, noipa, optimize("O0"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) >= 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {=\s* 1} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s* 4294967040} dce7 { target vect_int } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-16.c b/gcc/testsuite/gcc.dg/bic-bitmask-16.c new file mode 100644 index 0000000..cfea925 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-16.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) > 0; +} + +__attribute__((noinline, noipa, optimize("O0"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) > 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {>\s* 255} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s* 4294967040} dce7 { target vect_int } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-17.c b/gcc/testsuite/gcc.dg/bic-bitmask-17.c new file mode 100644 index 0000000..86873b9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-17.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) <= 0; +} + +__attribute__((noinline, noipa, optimize("O0"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) <= 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {<=\s* 255} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s* 4294967040} dce7 { target vect_int } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-18.c b/gcc/testsuite/gcc.dg/bic-bitmask-18.c new file mode 100644 index 0000000..9d11b3b --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-18.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~1)) < 0; +} + +__attribute__((noinline, noipa, optimize("O0"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~1)) < 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {= 0} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-19.c b/gcc/testsuite/gcc.dg/bic-bitmask-19.c new file mode 100644 index 0000000..c4620df --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-19.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~1)) != 0; +} + +__attribute__((noinline, noipa, optimize("O0"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~1)) != 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {>\s* 1} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s* 4294967294} dce7 { target vect_int } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-2.c b/gcc/testsuite/gcc.dg/bic-bitmask-2.c new file mode 100644 index 0000000..59ba9a4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-2.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +__attribute__((noinline, noipa, optimize("O1"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {<=\s*.+\{ 255,.+\}} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s*.+\{ 4294967040,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-20.c b/gcc/testsuite/gcc.dg/bic-bitmask-20.c new file mode 100644 index 0000000..a114122 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-20.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~5)) == 0; +} + +__attribute__((noinline, noipa, optimize("O0"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~5)) == 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-not {<=\s* 4294967289} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump {&\s* 4294967290} dce7 { target vect_int } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-21.c b/gcc/testsuite/gcc.dg/bic-bitmask-21.c new file mode 100644 index 0000000..bd12a58 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-21.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(int32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +__attribute__((noinline, noipa, optimize("O0"))) +void fun2(int32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +#define TYPE int32_t +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump {<=\s* 255} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s* 4294967290} dce7 { target vect_int } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-22.c b/gcc/testsuite/gcc.dg/bic-bitmask-22.c new file mode 100644 index 0000000..a9f0867 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-22.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) != 0; +} + +__attribute__((noinline, noipa, optimize("O0"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) != 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump {>\s* 255} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s* 4294967290} dce7 { target vect_int } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-23.c b/gcc/testsuite/gcc.dg/bic-bitmask-23.c new file mode 100644 index 0000000..b41651b --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-23.c @@ -0,0 +1,16 @@ +/* { dg-do assemble } */ +/* { dg-options "-O1 -fdump-tree-dce" } */ + +#include + +typedef unsigned int v4si __attribute__ ((vector_size (16))); + +__attribute__((noinline, noipa)) +v4si fun(v4si x) +{ + v4si mask = { 255, 15, 1, 0xFFFF }; + v4si zeros = {0}; + return (x & ~mask) == zeros; +} + +/* { dg-final { scan-tree-dump {<=\s*.+\{ 255, 15, 1, 65535 \}} dce7 { target vect_int } } } */ diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-3.c b/gcc/testsuite/gcc.dg/bic-bitmask-3.c new file mode 100644 index 0000000..59ba9a4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-3.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +__attribute__((noinline, noipa, optimize("O1"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) == 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {<=\s*.+\{ 255,.+\}} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s*.+\{ 4294967040,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-4.c b/gcc/testsuite/gcc.dg/bic-bitmask-4.c new file mode 100644 index 0000000..7e0614d --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-4.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) >= 0; +} + +__attribute__((noinline, noipa, optimize("O1"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) >= 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {=\s*.+\{ 1,.+\}} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s*.+\{ 4294967040,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-5.c b/gcc/testsuite/gcc.dg/bic-bitmask-5.c new file mode 100644 index 0000000..e71b17d --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-5.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) > 0; +} + +__attribute__((noinline, noipa, optimize("O1"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) > 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {>\s*.+\{ 255,.+\}} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s*.+\{ 4294967040,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-6.c b/gcc/testsuite/gcc.dg/bic-bitmask-6.c new file mode 100644 index 0000000..a48a226 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-6.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) <= 0; +} + +__attribute__((noinline, noipa, optimize("O1"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~255)) <= 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {<=\s*.+\{ 255,.+\}} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s*.+\{ 4294967040,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-7.c b/gcc/testsuite/gcc.dg/bic-bitmask-7.c new file mode 100644 index 0000000..bc49f29 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-7.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~1)) < 0; +} + +__attribute__((noinline, noipa, optimize("O1"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~1)) < 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {__builtin_memset} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-8.c b/gcc/testsuite/gcc.dg/bic-bitmask-8.c new file mode 100644 index 0000000..cd06e0c --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-8.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~1)) != 0; +} + +__attribute__((noinline, noipa, optimize("O1"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~1)) != 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-times {>\s*.+\{ 1,.+\}} 1 dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {&\s*.+\{ 4294967294,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask-9.c b/gcc/testsuite/gcc.dg/bic-bitmask-9.c new file mode 100644 index 0000000..3d88b74 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask-9.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -save-temps -fdump-tree-dce" } */ + +#include + +__attribute__((noinline, noipa)) +void fun1(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~5)) == 0; +} + +__attribute__((noinline, noipa, optimize("O1"))) +void fun2(uint32_t *x, int n) +{ + for (int i = 0; i < (n & -16); i++) + x[i] = (x[i]&(~5)) == 0; +} + +#include "bic-bitmask.h" + +/* { dg-final { scan-tree-dump-not {<=\s*.+\{ 4294967289,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump {&\s*.+\{ 4294967290,.+\}} dce7 { target vect_int } } } */ +/* { dg-final { scan-tree-dump-not {\s+bic\s+} dce7 { target { aarch64*-*-* } } } } */ + diff --git a/gcc/testsuite/gcc.dg/bic-bitmask.h b/gcc/testsuite/gcc.dg/bic-bitmask.h new file mode 100644 index 0000000..faf80b9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bic-bitmask.h @@ -0,0 +1,43 @@ +#include + +#ifndef N +#define N 65 +#endif + +#ifndef TYPE +#define TYPE uint32_t +#endif + +#ifndef DEBUG +#define DEBUG 0 +#endif + +#define BASE ((TYPE) -1 < 0 ? -126 : 4) + +int main () +{ + TYPE a[N]; + TYPE b[N]; + + for (int i = 0; i < N; ++i) + { + a[i] = BASE + i * 13; + b[i] = BASE + i * 13; + if (DEBUG) + printf ("%d: 0x%x\n", i, a[i]); + } + + fun1 (a, N); + fun2 (b, N); + + for (int i = 0; i < N; ++i) + { + if (DEBUG) + printf ("%d = 0x%x == 0x%x\n", i, a[i], b[i]); + + if (a[i] != b[i]) + __builtin_abort (); + } + return 0; +} + diff --git a/gcc/testsuite/gcc.target/aarch64/bic-bitmask-1.c b/gcc/testsuite/gcc.target/aarch64/bic-bitmask-1.c new file mode 100644 index 0000000..568c1ff --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/bic-bitmask-1.c @@ -0,0 +1,13 @@ +/* { dg-do assemble } */ +/* { dg-options "-O2 -save-temps" } */ + +#include + +uint32x4_t foo (int32x4_t a) +{ + int32x4_t cst = vdupq_n_s32 (255); + int32x4_t zero = vdupq_n_s32 (0); + return vceqq_s32 (vbicq_s32 (a, cst), zero); +} + +/* { dg-final { scan-assembler-not {\tbic\t} { xfail { aarch64*-*-* } } } } */ diff --git a/gcc/tree.c b/gcc/tree.c index 62d9d78..910fb06 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -10273,6 +10273,59 @@ uniform_integer_cst_p (tree t) return NULL_TREE; } +/* Checks to see if T is a constant or a constant vector and if each element E + adheres to ~E + 1 == pow2 then return ~E otherwise NULL_TREE. */ + +tree +bitmask_inv_cst_vector_p (tree t) +{ + + tree_code code = TREE_CODE (t); + tree type = TREE_TYPE (t); + + if (!INTEGRAL_TYPE_P (type) + && !VECTOR_INTEGER_TYPE_P (type)) + return NULL_TREE; + + unsigned HOST_WIDE_INT nelts = 1; + tree cst; + unsigned int idx = 0; + bool uniform = uniform_integer_cst_p (t); + tree newtype = unsigned_type_for (type); + tree_vector_builder builder; + if (code == INTEGER_CST) + cst = t; + else + { + if (!VECTOR_CST_NELTS (t).is_constant (&nelts)) + return NULL_TREE; + + cst = vector_cst_elt (t, 0); + builder.new_vector (newtype, nelts, 1); + } + + tree ty = unsigned_type_for (TREE_TYPE (cst)); + + do { + if (idx > 0) + cst = vector_cst_elt (t, idx); + wide_int icst = wi::to_wide (cst); + wide_int inv = wi::bit_not (icst); + icst = wi::add (1, inv); + if (wi::popcount (icst) != 1) + return NULL_TREE; + + tree newcst = wide_int_to_tree (ty, inv); + + if (uniform) + return build_uniform_cst (newtype, newcst); + + builder.quick_push (newcst); + } while (++idx < nelts); + + return builder.build (); +} + /* If VECTOR_CST T has a single nonzero element, return the index of that element, otherwise return -1. */ diff --git a/gcc/tree.h b/gcc/tree.h index 03719b18..f0e72b5 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4922,6 +4922,11 @@ extern bool integer_minus_onep (const_tree); extern bool integer_pow2p (const_tree); +/* Checks to see if T is a constant or a constant vector and if each element E + adheres to ~E + 1 == pow2 then return ~E otherwise NULL_TREE. */ + +extern tree bitmask_inv_cst_vector_p (tree); + /* integer_nonzerop (tree x) is nonzero if X is an integer constant with a nonzero value. */ -- cgit v1.1 From 755c2e7d71cbab89b2bd1d787db46428a604efb2 Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Wed, 24 Nov 2021 06:39:05 +0000 Subject: middle-end: Fix failures with bitclear patterns on signed values During testing after rebasing to commit I noticed a failing testcase with the bitmask compare patch. Consider the following C++ testcase: #include #define A __attribute__((noipa)) A bool f5 (double i, double j) { auto c = i <=> j; return c >= 0; } This turns into a comparison against chars, on systems where chars are signed the pattern inserts an unsigned convert such that it's able to do the transformation. i.e.: # RANGE [-1, 2] # c$_M_value_22 = PHI <-1(3), 0(2), 2(5), 1(4)> # RANGE ~[3, 254] _11 = (unsigned char) c$_M_value_22; _19 = _11 <= 1; # .MEM_24 = VDEF <.MEM_6(D)> D.10434 ={v} {CLOBBER}; # .MEM_14 = VDEF <.MEM_24> D.10407 ={v} {CLOBBER}; # VUSE <.MEM_14> return _19; instead of: # RANGE [-1, 2] # c$_M_value_5 = PHI <-1(3), 0(2), 2(5), 1(4)> # RANGE [-2, 2] _3 = c$_M_value_5 & -2; _19 = _3 == 0; # .MEM_24 = VDEF <.MEM_6(D)> D.10440 ={v} {CLOBBER}; # .MEM_14 = VDEF <.MEM_24> D.10413 ={v} {CLOBBER}; # VUSE <.MEM_14> return _19; This causes much worse codegen under -ffast-math due to phiops no longer recognizing the pattern. It turns out that phiopts spaceship_replacement is looking for the exact form that was just changed. The comments seems to suggest this code only checks for (res & ~1) == 0 but the implementation seems to suggest it's broader. As such I added a case to check to see if the value comparison we found is a type cast. and strips away the type cast and continues. In match.pd the typecasts are only added for signed comparisons to == 0 and != 0 which are then rewritten into comparisons with 1. As such I only check for 1 and LE and GT, which is what match.pd would have rewritten it to. This fixes the regression but this is not code I 100% understand, since I don't really know the semantics of the spaceship operator so would appreciate an extra look. gcc/ChangeLog: * tree-ssa-phiopt.c (spaceship_replacement): Handle new canonical codegen. --- gcc/tree-ssa-phiopt.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index 2fa7069..3eac9b1 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -2055,11 +2055,36 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, gimple *orig_use_stmt = use_stmt; tree orig_use_lhs = NULL_TREE; int prec = TYPE_PRECISION (TREE_TYPE (phires)); - if (is_gimple_assign (use_stmt) - && gimple_assign_rhs_code (use_stmt) == BIT_AND_EXPR - && TREE_CODE (gimple_assign_rhs2 (use_stmt)) == INTEGER_CST - && (wi::to_wide (gimple_assign_rhs2 (use_stmt)) - == wi::shifted_mask (1, prec - 1, false, prec))) + bool is_cast = false; + + /* Deal with the case when match.pd has rewritten the (res & ~1) == 0 + into res <= 1 and has left a type-cast for signed types. */ + if (gimple_assign_cast_p (use_stmt)) + { + orig_use_lhs = gimple_assign_lhs (use_stmt); + /* match.pd would have only done this for a signed type, + so the conversion must be to an unsigned one. */ + tree ty1 = TREE_TYPE (gimple_assign_rhs1 (use_stmt)); + tree ty2 = TREE_TYPE (orig_use_lhs); + + if (!TYPE_UNSIGNED (ty2) || !INTEGRAL_TYPE_P (ty2)) + return false; + if (TYPE_PRECISION (ty1) != TYPE_PRECISION (ty2)) + return false; + if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig_use_lhs)) + return false; + if (EDGE_COUNT (phi_bb->preds) != 4) + return false; + if (!single_imm_use (orig_use_lhs, &use_p, &use_stmt)) + return false; + + is_cast = true; + } + else if (is_gimple_assign (use_stmt) + && gimple_assign_rhs_code (use_stmt) == BIT_AND_EXPR + && TREE_CODE (gimple_assign_rhs2 (use_stmt)) == INTEGER_CST + && (wi::to_wide (gimple_assign_rhs2 (use_stmt)) + == wi::shifted_mask (1, prec - 1, false, prec))) { /* For partial_ordering result operator>= with unspec as second argument is (res & 1) == res, folded by match.pd into @@ -2116,7 +2141,43 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, || !tree_fits_shwi_p (rhs) || !IN_RANGE (tree_to_shwi (rhs), -1, 1)) return false; - if (orig_use_lhs) + + if (is_cast) + { + if (TREE_CODE (rhs) != INTEGER_CST) + return false; + /* As for -ffast-math we assume the 2 return to be + impossible, canonicalize (unsigned) res <= 1U or + (unsigned) res < 2U into res >= 0 and (unsigned) res > 1U + or (unsigned) res >= 2U as res < 0. */ + switch (cmp) + { + case LE_EXPR: + if (!integer_onep (rhs)) + return false; + cmp = GE_EXPR; + break; + case LT_EXPR: + if (wi::ne_p (wi::to_widest (rhs), 2)) + return false; + cmp = GE_EXPR; + break; + case GT_EXPR: + if (!integer_onep (rhs)) + return false; + cmp = LT_EXPR; + break; + case GE_EXPR: + if (wi::ne_p (wi::to_widest (rhs), 2)) + return false; + cmp = LT_EXPR; + break; + default: + return false; + } + rhs = build_zero_cst (TREE_TYPE (phires)); + } + else if (orig_use_lhs) { if ((cmp != EQ_EXPR && cmp != NE_EXPR) || !integer_zerop (rhs)) return false; @@ -2411,6 +2472,7 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, use_operand_p use_p; imm_use_iterator iter; bool has_debug_uses = false; + bool has_cast_debug_uses = false; FOR_EACH_IMM_USE_FAST (use_p, iter, phires) { gimple *use_stmt = USE_STMT (use_p); @@ -2422,12 +2484,14 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, } if (orig_use_lhs) { - if (!has_debug_uses) + if (!has_debug_uses || is_cast) FOR_EACH_IMM_USE_FAST (use_p, iter, orig_use_lhs) { gimple *use_stmt = USE_STMT (use_p); gcc_assert (is_gimple_debug (use_stmt)); has_debug_uses = true; + if (is_cast) + has_cast_debug_uses = true; } gimple_stmt_iterator gsi = gsi_for_stmt (orig_use_stmt); tree zero = build_zero_cst (TREE_TYPE (orig_use_lhs)); @@ -2459,7 +2523,21 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, gsi_insert_before (&gsi, g, GSI_SAME_STMT); replace_uses_by (phires, temp2); if (orig_use_lhs) - replace_uses_by (orig_use_lhs, temp2); + { + if (has_cast_debug_uses) + { + tree temp3 = make_node (DEBUG_EXPR_DECL); + DECL_ARTIFICIAL (temp3) = 1; + TREE_TYPE (temp3) = TREE_TYPE (orig_use_lhs); + SET_DECL_MODE (temp3, TYPE_MODE (type)); + t = fold_convert (TREE_TYPE (temp3), temp2); + g = gimple_build_debug_bind (temp3, t, phi); + gsi_insert_before (&gsi, g, GSI_SAME_STMT); + replace_uses_by (orig_use_lhs, temp3); + } + else + replace_uses_by (orig_use_lhs, temp2); + } } } -- cgit v1.1 From 52554dde7bf625c66192504cef01890bacc79694 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 23 Nov 2021 13:51:10 +0100 Subject: Avoid redundant get_loop_body calls in IVOPTs This removes redundant get_loop_body calls in IVOPTs by passing around the body we're gathering early. 2021-11-23 Richard Biener * tree-ssa-loop-ivopts.c (find_givs): Take loop body as argument instead of re-computing it. (find_interesting_uses): Likewise. (find_induction_variables): Pass through loop body. (tree_ssa_iv_optimize_loop): Pass down loop body. --- gcc/tree-ssa-loop-ivopts.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 5a7fd30..4769b65 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -1462,22 +1462,20 @@ find_givs_in_bb (struct ivopts_data *data, basic_block bb) /* Finds general ivs. */ static void -find_givs (struct ivopts_data *data) +find_givs (struct ivopts_data *data, basic_block *body) { class loop *loop = data->current_loop; - basic_block *body = get_loop_body_in_dom_order (loop); unsigned i; for (i = 0; i < loop->num_nodes; i++) find_givs_in_bb (data, body[i]); - free (body); } /* For each ssa name defined in LOOP determines whether it is an induction variable and if so, its initial value and step. */ static bool -find_induction_variables (struct ivopts_data *data) +find_induction_variables (struct ivopts_data *data, basic_block *body) { unsigned i; bitmap_iterator bi; @@ -1485,7 +1483,7 @@ find_induction_variables (struct ivopts_data *data) if (!find_bivs (data)) return false; - find_givs (data); + find_givs (data, body); mark_bivs (data); if (dump_file && (dump_flags & TDF_DETAILS)) @@ -2736,11 +2734,10 @@ split_address_groups (struct ivopts_data *data) /* Finds uses of the induction variables that are interesting. */ static void -find_interesting_uses (struct ivopts_data *data) +find_interesting_uses (struct ivopts_data *data, basic_block *body) { basic_block bb; gimple_stmt_iterator bsi; - basic_block *body = get_loop_body (data->current_loop); unsigned i; edge e; @@ -2760,7 +2757,6 @@ find_interesting_uses (struct ivopts_data *data) if (!is_gimple_debug (gsi_stmt (bsi))) find_interesting_uses_stmt (data, gsi_stmt (bsi)); } - free (body); split_address_groups (data); @@ -8077,11 +8073,11 @@ tree_ssa_iv_optimize_loop (struct ivopts_data *data, class loop *loop, /* For each ssa name determines whether it behaves as an induction variable in some loop. */ - if (!find_induction_variables (data)) + if (!find_induction_variables (data, body)) goto finish; /* Finds interesting uses (item 1). */ - find_interesting_uses (data); + find_interesting_uses (data, body); if (data->vgroups.length () > MAX_CONSIDERED_GROUPS) goto finish; -- cgit v1.1 From 04eccbbe3d9a4e9d2f8f43dba8ac4cb686029fb2 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 24 Nov 2021 09:54:44 +0100 Subject: bswap: Fix up symbolic merging for xor and plus [PR103376] On Mon, Nov 22, 2021 at 08:39:42AM -0000, Roger Sayle wrote: > This patch implements PR tree-optimization/103345 to merge adjacent > loads when combined with addition or bitwise xor. The current code > in gimple-ssa-store-merging.c's find_bswap_or_nop alreay handles ior, > so that all that's required is to treat PLUS_EXPR and BIT_XOR_EXPR in > the same way at BIT_IOR_EXPR. Unfortunately they aren't exactly the same. They work the same if always at least one operand (or corresponding byte in it) is known to be 0, 0 | 0 = 0 ^ 0 = 0 + 0 = 0. But for | also x | x = x for any other x, so perform_symbolic_merge has been accepting either that at least one of the bytes is 0 or that both are the same, but that is wrong for ^ and +. The following patch fixes that by passing through the code of binary operation and allowing non-zero masked1 == masked2 through only for BIT_IOR_EXPR. Thinking more about it, perhaps we could do more for BIT_XOR_EXPR. We could allow masked1 == masked2 case for it, but would need to do something different than the n->n = n1->n | n2->n; we do on all the bytes together. In particular, for masked1 == masked2 if masked1 != 0 (well, for 0 both variants are the same) and masked1 != 0xff we would need to clear corresponding n->n byte instead of setting it to the input as x ^ x = 0 (but if we don't know what x and y are, the result is also don't know). Now, for plus it is much harder, because not only for non-zero operands we don't know what the result is, but it can modify upper bytes as well. So perhaps only if current's byte masked1 && masked2 set the resulting byte to 0xff (unknown) iff the byte above it is 0 and 0, and set that resulting byte to 0xff too. Also, even for | we could instead of return NULL just set the resulting byte to 0xff if it is different, perhaps it will be masked off later on. 2021-11-24 Jakub Jelinek PR tree-optimization/103376 * gimple-ssa-store-merging.c (perform_symbolic_merge): Add CODE argument. If CODE is not BIT_IOR_EXPR, ensure that one of masked1 or masked2 is 0. (find_bswap_or_nop_1, find_bswap_or_nop, imm_store_chain_info::try_coalesce_bswap): Adjust perform_symbolic_merge callers. * gcc.c-torture/execute/pr103376.c: New test. --- gcc/gimple-ssa-store-merging.c | 20 +++++++++++------- gcc/testsuite/gcc.c-torture/execute/pr103376.c | 29 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr103376.c (limited to 'gcc') diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c index 1740c9e..35df0fe 100644 --- a/gcc/gimple-ssa-store-merging.c +++ b/gcc/gimple-ssa-store-merging.c @@ -434,14 +434,14 @@ find_bswap_or_nop_load (gimple *stmt, tree ref, struct symbolic_number *n) return true; } -/* Compute the symbolic number N representing the result of a bitwise OR on 2 - symbolic number N1 and N2 whose source statements are respectively - SOURCE_STMT1 and SOURCE_STMT2. */ +/* Compute the symbolic number N representing the result of a bitwise OR, + bitwise XOR or plus on 2 symbolic number N1 and N2 whose source statements + are respectively SOURCE_STMT1 and SOURCE_STMT2. CODE is the operation. */ gimple * perform_symbolic_merge (gimple *source_stmt1, struct symbolic_number *n1, gimple *source_stmt2, struct symbolic_number *n2, - struct symbolic_number *n) + struct symbolic_number *n, enum tree_code code) { int i, size; uint64_t mask; @@ -563,7 +563,9 @@ perform_symbolic_merge (gimple *source_stmt1, struct symbolic_number *n1, masked1 = n1->n & mask; masked2 = n2->n & mask; - if (masked1 && masked2 && masked1 != masked2) + /* For BIT_XOR_EXPR or PLUS_EXPR, at least one of masked1 and masked2 + has to be 0, for BIT_IOR_EXPR x | x is still x. */ + if (masked1 && masked2 && (code != BIT_IOR_EXPR || masked1 != masked2)) return NULL; } n->n = n1->n | n2->n; @@ -769,7 +771,8 @@ find_bswap_or_nop_1 (gimple *stmt, struct symbolic_number *n, int limit) return NULL; source_stmt - = perform_symbolic_merge (source_stmt1, &n1, source_stmt2, &n2, n); + = perform_symbolic_merge (source_stmt1, &n1, source_stmt2, &n2, n, + code); if (!source_stmt) return NULL; @@ -943,7 +946,8 @@ find_bswap_or_nop (gimple *stmt, struct symbolic_number *n, bool *bswap, else if (!do_shift_rotate (LSHIFT_EXPR, &n0, eltsz)) return NULL; ins_stmt - = perform_symbolic_merge (ins_stmt, &n0, source_stmt, &n1, n); + = perform_symbolic_merge (ins_stmt, &n0, source_stmt, &n1, n, + BIT_IOR_EXPR); if (!ins_stmt) return NULL; @@ -2881,7 +2885,7 @@ imm_store_chain_info::try_coalesce_bswap (merged_store_group *merged_store, end = MAX (end, info->bitpos + info->bitsize); ins_stmt = perform_symbolic_merge (ins_stmt, &n, info->ins_stmt, - &this_n, &n); + &this_n, &n, BIT_IOR_EXPR); if (ins_stmt == NULL) return false; } diff --git a/gcc/testsuite/gcc.c-torture/execute/pr103376.c b/gcc/testsuite/gcc.c-torture/execute/pr103376.c new file mode 100644 index 0000000..22e2019 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr103376.c @@ -0,0 +1,29 @@ +/* PR tree-optimization/103376 */ + +long long a = 0x123456789abcdef0LL, f; +int b, c, *d; + +__attribute__((noipa)) void +foo (int x) +{ + asm volatile ("" : : "r" (x)); +} + +int +main () +{ + long long e; + e = a; + if (b) + { + foo (c); + d = (int *) 0; + while (*d) + ; + } + f = a ^ e; + asm volatile ("" : "+m" (f)); + if (f != 0) + __builtin_abort (); + return 0; +} -- cgit v1.1 From 709716b9f49f2fcf46f319000562cf6e61bd2f71 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 24 Nov 2021 10:08:35 +0100 Subject: attribs: Fix ICEs on attributes starting with _ [PR103365] As the patch shows, we have quite a few asserts that we don't call lookup_attribute etc. with attr_name that starts with an underscore, to make sure nobody is trying to call it with non-canonicalized attribute name like "__cold__" instead of "cold". We canonicalize only attributes that start with 2 underscores and end with 2 underscores though. Before Marek's patch, that wasn't an issue, we had no attributes like "_foo" or "__bar_" etc., so lookup_scoped_attribute_spec would always return NULL for those and we wouldn't try to register them, look them up etc., just with -Wattributes would warn about them. But now, as the new testcases show, users can actually request such attributes to be ignored, and we ICE for those during register_scoped_attribute and when that is fixed, ICE later on when somebody uses those attributes because they will be looked up to find out that they should be ignored. So, the following patch instead of or in addition to, depending on how performance sensitive a particular spot is, checking that attribute doesn't start with underscore allows attribute names that start with underscore as long as it doesn't canonicalize (i.e. doesn't start and end with 2 underscores). In addition to that, I've noticed lookup_attribute_by_prefix was calling get_attribute_name twice unnecessarily, and 2 tests were running in c++98 mode with -std=c++98 -std=c++11 which IMHO isn't useful because -std=c++11 testing is done too when testing all language versions. 2021-11-24 Jakub Jelinek PR middle-end/103365 * attribs.h (lookup_attribute): Allow attr_name to start with underscore, as long as canonicalize_attr_name returns false. (lookup_attribute_by_prefix): Don't call get_attribute_name twice. * attribs.c (extract_attribute_substring): Reimplement using canonicalize_attr_name. (register_scoped_attribute): Change gcc_assert into gcc_checking_assert, verify !canonicalize_attr_name rather than that str.str doesn't start with '_'. * c-c++-common/Wno-attributes-1.c: Require effective target c || c++11 and drop dg-additional-options. * c-c++-common/Wno-attributes-2.c: Likewise. * c-c++-common/Wno-attributes-4.c: New test. * c-c++-common/Wno-attributes-5.c: New test. --- gcc/attribs.c | 9 ++------- gcc/attribs.h | 11 ++++++++--- gcc/testsuite/c-c++-common/Wno-attributes-1.c | 3 +-- gcc/testsuite/c-c++-common/Wno-attributes-2.c | 3 +-- gcc/testsuite/c-c++-common/Wno-attributes-4.c | 7 +++++++ gcc/testsuite/c-c++-common/Wno-attributes-5.c | 8 ++++++++ 6 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/Wno-attributes-4.c create mode 100644 gcc/testsuite/c-c++-common/Wno-attributes-5.c (limited to 'gcc') diff --git a/gcc/attribs.c b/gcc/attribs.c index 0284e5b..c252f5a 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -115,12 +115,7 @@ static const struct attribute_spec empty_attribute_table[] = static void extract_attribute_substring (struct substring *str) { - if (str->length > 4 && str->str[0] == '_' && str->str[1] == '_' - && str->str[str->length - 1] == '_' && str->str[str->length - 2] == '_') - { - str->length -= 4; - str->str += 2; - } + canonicalize_attr_name (str->str, str->length); } /* Insert an array of attributes ATTRIBUTES into a namespace. This @@ -387,7 +382,7 @@ register_scoped_attribute (const struct attribute_spec *attr, /* Attribute names in the table must be in the form 'text' and not in the form '__text__'. */ - gcc_assert (str.length > 0 && str.str[0] != '_'); + gcc_checking_assert (!canonicalize_attr_name (str.str, str.length)); slot = name_space->attribute_hash ->find_slot_with_hash (&str, substring_hash (str.str, str.length), diff --git a/gcc/attribs.h b/gcc/attribs.h index ba65788..73f0ccc 100644 --- a/gcc/attribs.h +++ b/gcc/attribs.h @@ -188,7 +188,11 @@ is_attribute_p (const char *attr_name, const_tree ident) static inline tree lookup_attribute (const char *attr_name, tree list) { - gcc_checking_assert (attr_name[0] != '_'); + if (CHECKING_P && attr_name[0] != '_') + { + size_t attr_len = strlen (attr_name); + gcc_checking_assert (!canonicalize_attr_name (attr_name, attr_len)); + } /* In most cases, list is NULL_TREE. */ if (list == NULL_TREE) return NULL_TREE; @@ -219,7 +223,8 @@ lookup_attribute_by_prefix (const char *attr_name, tree list) size_t attr_len = strlen (attr_name); while (list) { - size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list)); + tree name = get_attribute_name (list); + size_t ident_len = IDENTIFIER_LENGTH (name); if (attr_len > ident_len) { @@ -227,7 +232,7 @@ lookup_attribute_by_prefix (const char *attr_name, tree list) continue; } - const char *p = IDENTIFIER_POINTER (get_attribute_name (list)); + const char *p = IDENTIFIER_POINTER (name); gcc_checking_assert (attr_len == 0 || p[0] != '_'); if (strncmp (attr_name, p, attr_len) == 0) diff --git a/gcc/testsuite/c-c++-common/Wno-attributes-1.c b/gcc/testsuite/c-c++-common/Wno-attributes-1.c index aac1a69..84a84ea 100644 --- a/gcc/testsuite/c-c++-common/Wno-attributes-1.c +++ b/gcc/testsuite/c-c++-common/Wno-attributes-1.c @@ -1,6 +1,5 @@ /* PR c++/101940 */ -/* { dg-do compile } */ -/* { dg-additional-options "-std=c++11" { target c++ } } */ +/* { dg-do compile { target { c || c++11 } } } */ /* { dg-additional-options "-Wno-attributes=company::,yoyodyne::attr" } */ /* { dg-additional-options "-Wno-attributes=c1::attr,c1::attr,c1::__attr__" } */ /* { dg-additional-options "-Wno-attributes=c2::,c2::attr" } */ diff --git a/gcc/testsuite/c-c++-common/Wno-attributes-2.c b/gcc/testsuite/c-c++-common/Wno-attributes-2.c index 4307c74..8e04401 100644 --- a/gcc/testsuite/c-c++-common/Wno-attributes-2.c +++ b/gcc/testsuite/c-c++-common/Wno-attributes-2.c @@ -1,6 +1,5 @@ /* PR c++/101940 */ -/* { dg-do compile } */ -/* { dg-additional-options "-std=c++11" { target c++ } } */ +/* { dg-do compile { target { c || c++11 } } } */ #pragma GCC diagnostic ignored_attributes "company::,yoyodyne::attr" #pragma GCC diagnostic ignored_attributes "c1::attr,c1::attr,c1::__attr__" diff --git a/gcc/testsuite/c-c++-common/Wno-attributes-4.c b/gcc/testsuite/c-c++-common/Wno-attributes-4.c new file mode 100644 index 0000000..c5ea3e3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wno-attributes-4.c @@ -0,0 +1,7 @@ +/* PR middle-end/103365 */ +/* { dg-do compile { target { c || c++11 } } } */ +/* { dg-additional-options "-Wno-attributes=foo::_bar" } */ +/* { dg-additional-options "-Wno-attributes=_foo::bar" } */ + +[[foo::_bar]] void foo (void); +[[_foo::bar]] void bar (void); diff --git a/gcc/testsuite/c-c++-common/Wno-attributes-5.c b/gcc/testsuite/c-c++-common/Wno-attributes-5.c new file mode 100644 index 0000000..9c0c3da --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wno-attributes-5.c @@ -0,0 +1,8 @@ +/* PR middle-end/103365 */ +/* { dg-do compile { target { c || c++11 } } } */ + +#pragma GCC diagnostic ignored_attributes "foo::_bar" +#pragma GCC diagnostic ignored_attributes "_foo::bar" + +[[foo::_bar]] void foo (void); +[[_foo::bar]] void bar (void); -- cgit v1.1 From 5bca26742cf3357bf4e20ec97eee4c7f7de17ce0 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 24 Nov 2021 10:30:32 +0100 Subject: openmp: Fix up handling of kind(host) and kind(nohost) in ACCEL_COMPILERs [PR103384] As the testcase shows, we weren't handling kind(host) and kind(nohost) properly in the ACCEL_COMPILERs, the code written in there is valid for the host compiler only, where if we are maybe offloaded, we defer resolution after IPA, otherwise return 0 for kind(nohost) and accept it for kind(host). Note, omp_maybe_offloaded is false after IPA. If ACCEL_COMPILER is defined, it is the other way around, but also we know we are after IPA. 2021-11-24 Jakub Jelinek PR middle-end/103384 gcc/ * omp-general.c (omp_context_selector_matches): For ACCEL_COMPILER, return 0 for kind(host) and continue for kind(nohost). libgomp/ * testsuite/libgomp.c/declare-variant-2.c: New test. --- gcc/omp-general.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc') diff --git a/gcc/omp-general.c b/gcc/omp-general.c index 4452755..8fcca73 100644 --- a/gcc/omp-general.c +++ b/gcc/omp-general.c @@ -1487,16 +1487,22 @@ omp_context_selector_matches (tree ctx) continue; if (!strcmp (prop, "host")) { +#ifdef ACCEL_COMPILER + return 0; +#else if (omp_maybe_offloaded ()) ret = -1; continue; +#endif } if (!strcmp (prop, "nohost")) { +#ifndef ACCEL_COMPILER if (omp_maybe_offloaded ()) ret = -1; else return 0; +#endif continue; } int r = 0; -- cgit v1.1 From d9ca2ca381e44a332703155d07b50b84aa21f80d Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 15 Nov 2021 12:13:40 +0100 Subject: middle-end/103193 - avoid canonicalizing <= and >= to == for floats This avoids doing aforementioned canoncalization when -ftrapping-math is in effect and we honor NaNs. 2021-11-15 Richard Biener PR middle-end/103193 * match.pd: Avoid canonicalizing (le/ge @0 @0) to (eq @0 @0) with NaNs and -ftrapping-math. --- gcc/match.pd | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/match.pd b/gcc/match.pd index 3e54e2cf..5adcd6b 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -4671,7 +4671,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (! FLOAT_TYPE_P (TREE_TYPE (@0)) || ! HONOR_NANS (@0)) { constant_boolean_node (true, type); } - (if (cmp != EQ_EXPR) + (if (cmp != EQ_EXPR + /* With -ftrapping-math conversion to EQ loses an exception. */ + && (! FLOAT_TYPE_P (TREE_TYPE (@0)) + || ! flag_trapping_math)) (eq @0 @0))))) (for cmp (ne gt lt) (simplify -- cgit v1.1 From c2e681059bcd7f76f13029988f133858dc82c205 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 24 Nov 2021 10:15:34 +0100 Subject: jit: Initialize function::m_blocks in ctor This resolves the problem reported here: https://mail.gnu.org/archive/html/bug-gnu-emacs/2021-11/msg00606.html https://bugzilla.opensuse.org/show_bug.cgi?id=1192951 gcc/jit/ChangeLog: * jit-playback.c (function): Initialize m_blocks vector. --- gcc/jit/jit-playback.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 59399de..b412eae 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -1484,7 +1484,8 @@ function (context *ctxt, : m_ctxt(ctxt), m_inner_fndecl (fndecl), m_inner_bind_expr (NULL), - m_kind (kind) + m_kind (kind), + m_blocks () { if (m_kind != GCC_JIT_FUNCTION_IMPORTED) { -- cgit v1.1 From fdd34569e7a9fc2b6c638a7ef62b965ed7e832ce Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Mon, 22 Nov 2021 17:29:09 +0100 Subject: Restore previous OpenACC implicit data clauses ordering [PR103244] Follow-up for recent commit b7e20480630e3eeb9eed8b3941da3b3f0c22c969 "openmp: Relax handling of implicit map vs. existing device mappings". As discussed, we likely also for OpenACC ought to use 'OMP_CLAUSE_MAP_RUNTIME_IMPLICIT_P' and do the appropriate implicit clauses ordering -- but that's for a separate step. gcc/ PR middle-end/103244 * gimplify.c (gimplify_adjust_omp_clauses): Restore previous OpenACC behavior. gcc/testsuite/ PR middle-end/103244 * c-c++-common/goacc/combined-reduction.c: Revert/expect previous OpenACC behavior. * c-c++-common/goacc/firstprivate-mappings-1.c: Likewise. * c-c++-common/goacc/mdc-1.c: Likewise. * g++.dg/goacc/firstprivate-mappings-1.C: Likewise. --- gcc/gimplify.c | 22 ++++++++++++++-------- .../c-c++-common/goacc/combined-reduction.c | 2 +- .../c-c++-common/goacc/firstprivate-mappings-1.c | 7 ++++++- gcc/testsuite/c-c++-common/goacc/mdc-1.c | 2 +- .../g++.dg/goacc/firstprivate-mappings-1.C | 2 +- 5 files changed, 23 insertions(+), 12 deletions(-) (limited to 'gcc') diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 816cdaf..8624f82 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -11501,15 +11501,21 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, list_p = &OMP_CLAUSE_CHAIN (c); } - /* Add in any implicit data sharing. Implicit clauses are added at the start - of the clause list, but after any non-map clauses. */ + /* Add in any implicit data sharing. */ struct gimplify_adjust_omp_clauses_data data; - tree *implicit_add_list_p = orig_list_p; - while (*implicit_add_list_p - && OMP_CLAUSE_CODE (*implicit_add_list_p) != OMP_CLAUSE_MAP) - implicit_add_list_p = &OMP_CLAUSE_CHAIN (*implicit_add_list_p); - - data.list_p = implicit_add_list_p; + if ((gimplify_omp_ctxp->region_type & ORT_ACC) == 0) + { + /* OpenMP. Implicit clauses are added at the start of the clause list, + but after any non-map clauses. */ + tree *implicit_add_list_p = orig_list_p; + while (*implicit_add_list_p + && OMP_CLAUSE_CODE (*implicit_add_list_p) != OMP_CLAUSE_MAP) + implicit_add_list_p = &OMP_CLAUSE_CHAIN (*implicit_add_list_p); + data.list_p = implicit_add_list_p; + } + else + /* OpenACC. */ + data.list_p = list_p; data.pre_p = pre_p; splay_tree_foreach (ctx->variables, gimplify_adjust_omp_clauses_1, &data); diff --git a/gcc/testsuite/c-c++-common/goacc/combined-reduction.c b/gcc/testsuite/c-c++-common/goacc/combined-reduction.c index 74ab05b..ecf23f5 100644 --- a/gcc/testsuite/c-c++-common/goacc/combined-reduction.c +++ b/gcc/testsuite/c-c++-common/goacc/combined-reduction.c @@ -23,7 +23,7 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "omp target oacc_parallel reduction.+:v1. firstprivate.n. map.tofrom:v1" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "omp target oacc_parallel reduction.+:v1. map.tofrom:v1" 1 "gimple" } } */ /* { dg-final { scan-tree-dump-times "acc loop reduction.+:v1. private.i." 1 "gimple" } } */ /* { dg-final { scan-tree-dump-times "omp target oacc_kernels map.force_tofrom:n .len: 4.. map.force_tofrom:v1 .len: 4.." 1 "gimple" } } */ /* { dg-final { scan-tree-dump-times "acc loop reduction.+:v1. private.i." 1 "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/goacc/firstprivate-mappings-1.c b/gcc/testsuite/c-c++-common/goacc/firstprivate-mappings-1.c index 5134ef6..7987bea 100644 --- a/gcc/testsuite/c-c++-common/goacc/firstprivate-mappings-1.c +++ b/gcc/testsuite/c-c++-common/goacc/firstprivate-mappings-1.c @@ -419,7 +419,12 @@ vla (int array_li) copyout (array_so) /* The gimplifier has created an implicit 'firstprivate' clause for the array length. - { dg-final { scan-tree-dump {(?n)#pragma omp target oacc_parallel firstprivate\(array_li.[0-9]+\) map\(from:array_so \[len: 4\]\) \[} omplower } } */ + { dg-final { scan-tree-dump {(?n)#pragma omp target oacc_parallel map\(from:array_so \[len: 4\]\) firstprivate\(array_li.[0-9]+\)} omplower { target { ! c++ } } } } + { dg-final { scan-tree-dump {(?n)#pragma omp target oacc_parallel map\(from:array_so \[len: 4\]\) firstprivate\(} omplower { target { c++ } } } } + (C++ computes an intermediate value, so can't scan for 'firstprivate(array_li)'.) */ + /* For C, non-LP64, the gimplifier has also created a mapping for the array + itself; PR90859. + { dg-final { scan-tree-dump {(?n)#pragma omp target oacc_parallel map\(from:array_so \[len: 4\]\) firstprivate\(array_li.[0-9]+\) map\(tofrom:\(\*array.[0-9]+\) \[len: D\.[0-9]+\]\) map\(firstprivate:array \[pointer assign, bias: 0\]\) \[} omplower { target { c && { ! lp64 } } } } } */ { array_so = sizeof array; } diff --git a/gcc/testsuite/c-c++-common/goacc/mdc-1.c b/gcc/testsuite/c-c++-common/goacc/mdc-1.c index 0a123be..c2b8dc6 100644 --- a/gcc/testsuite/c-c++-common/goacc/mdc-1.c +++ b/gcc/testsuite/c-c++-common/goacc/mdc-1.c @@ -45,7 +45,7 @@ t1 () /* { dg-final { scan-tree-dump-times "pragma omp target oacc_enter_data map.to:s .len: 32.." 1 "omplower" } } */ /* { dg-final { scan-tree-dump-times "pragma omp target oacc_data map.tofrom:.z .len: 40.. map.struct:s .len: 1.. map.alloc:s.a .len: 8.. map.tofrom:._1 .len: 40.. map.attach:s.a .bias: 0.." 1 "omplower" } } */ -/* { dg-final { scan-tree-dump-times "pragma omp target oacc_parallel map.tofrom:s .len: 32.. map.attach:s.e .bias: 0.." 1 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_parallel map.attach:s.e .bias: 0.. map.tofrom:s .len: 32" 1 "omplower" } } */ /* { dg-final { scan-tree-dump-times "pragma omp target oacc_enter_data map.attach:a .bias: 0.." 1 "omplower" } } */ /* { dg-final { scan-tree-dump-times "pragma omp target oacc_exit_data map.detach:a .bias: 0.." 1 "omplower" } } */ /* { dg-final { scan-tree-dump-times "pragma omp target oacc_enter_data map.to:a .len: 8.." 1 "omplower" } } */ diff --git a/gcc/testsuite/g++.dg/goacc/firstprivate-mappings-1.C b/gcc/testsuite/g++.dg/goacc/firstprivate-mappings-1.C index 99a3bd4..1b1badb 100644 --- a/gcc/testsuite/g++.dg/goacc/firstprivate-mappings-1.C +++ b/gcc/testsuite/g++.dg/goacc/firstprivate-mappings-1.C @@ -416,7 +416,7 @@ vla (int &array_li) copyout (array_so) /* The gimplifier has created an implicit 'firstprivate' clause for the array length. - { dg-final { scan-tree-dump {(?n)#pragma omp target oacc_parallel firstprivate\([^)]+\) map\(from:array_so \[len: 4\]\)} omplower } } + { dg-final { scan-tree-dump {(?n)#pragma omp target oacc_parallel map\(from:array_so \[len: 4\]\) firstprivate\(} omplower } } (C++ computes an intermediate value, so can't scan for 'firstprivate(array_li)'.) */ { array_so = sizeof array; -- cgit v1.1 From 6180f5c8d6d1dc7b6634c41a46f0f8f5ca2e5b9d Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 24 Nov 2021 09:08:44 +0100 Subject: tree-optimization/103168 - Improve VN of pure function calls This improves value-numbering of calls that read memory, calls to const functions with aggregate arguments and calls to pure functions where the latter include const functions we demoted to pure for the fear of interposing with a less optimized version. Note that for pure functions we do not handle functions that access global memory. 2021-11-24 Richard Biener Jan Hubicka PR tree-optimization/103168 * ipa-modref.h (struct modref_summary): Add load_accesses. * ipa-modref.c (modref_summary::finalize): Initialize load_accesses. * tree-ssa-sccvn.c (visit_reference_op_call): Use modref info to walk the virtual use->def chain to CSE const/pure function calls possibly reading from memory. * g++.dg/tree-ssa/pr103168.C: New testcase. --- gcc/ipa-modref.c | 17 +++++ gcc/ipa-modref.h | 2 + gcc/testsuite/g++.dg/tree-ssa/pr103168.C | 24 ++++++ gcc/tree-ssa-sccvn.c | 126 +++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+) create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr103168.C (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 79d7d77..923ae6c 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -721,6 +721,23 @@ modref_summary::finalize (tree fun) break; } } + if (loads->every_base) + load_accesses = 1; + else + { + load_accesses = 0; + for (auto base_node : loads->bases) + { + if (base_node->every_ref) + load_accesses++; + else + for (auto ref_node : base_node->refs) + if (ref_node->every_access) + load_accesses++; + else + load_accesses += ref_node->accesses->length (); + } + } } /* Get function summary for FUNC if it exists, return NULL otherwise. */ diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h index f868eb6..a0247f5 100644 --- a/gcc/ipa-modref.h +++ b/gcc/ipa-modref.h @@ -53,6 +53,8 @@ struct GTY(()) modref_summary /* Flags coputed by finalize method. */ + /* Total number of accesses in loads tree. */ + unsigned int load_accesses; /* global_memory_read is not set for functions calling functions with !binds_to_current_def which, after interposition, may read global memory but do nothing useful with it (except for crashing if some diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr103168.C b/gcc/testsuite/g++.dg/tree-ssa/pr103168.C new file mode 100644 index 0000000..82924a3 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr103168.C @@ -0,0 +1,24 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-tree-fre1-details" } + +struct a +{ + int a; + static __attribute__ ((noinline)) + int ret (int v) {return v;} + + __attribute__ ((noinline)) + int inca () {return a++;} +}; + +int +test() +{ + struct a av; + av.a=1; + int val = av.ret (0) + av.inca(); + av.a=2; + return val + av.ret(0) + av.inca(); +} + +/* { dg-final { scan-tree-dump-times "Replaced a::ret" 1 "fre1" } } */ diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index 149674e..d31bf32 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -71,6 +71,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-loop-niter.h" #include "builtins.h" #include "fold-const-call.h" +#include "ipa-modref-tree.h" +#include "ipa-modref.h" #include "tree-ssa-sccvn.h" /* This algorithm is based on the SCC algorithm presented by Keith @@ -5084,12 +5086,136 @@ visit_reference_op_call (tree lhs, gcall *stmt) struct vn_reference_s vr1; vn_reference_t vnresult = NULL; tree vdef = gimple_vdef (stmt); + modref_summary *summary; /* Non-ssa lhs is handled in copy_reference_ops_from_call. */ if (lhs && TREE_CODE (lhs) != SSA_NAME) lhs = NULL_TREE; vn_reference_lookup_call (stmt, &vnresult, &vr1); + + /* If the lookup did not succeed for pure functions try to use + modref info to find a candidate to CSE to. */ + const unsigned accesses_limit = 8; + if (!vnresult + && !vdef + && lhs + && gimple_vuse (stmt) + && (((summary = get_modref_function_summary (stmt, NULL)) + && !summary->global_memory_read + && summary->load_accesses < accesses_limit) + || gimple_call_flags (stmt) & ECF_CONST)) + { + /* First search if we can do someting useful and build a + vector of all loads we have to check. */ + bool unknown_memory_access = false; + auto_vec accesses; + unsigned load_accesses = summary ? summary->load_accesses : 0; + if (!unknown_memory_access) + /* Add loads done as part of setting up the call arguments. + That's also necessary for CONST functions which will + not have a modref summary. */ + for (unsigned i = 0; i < gimple_call_num_args (stmt); ++i) + { + tree arg = gimple_call_arg (stmt, i); + if (TREE_CODE (arg) != SSA_NAME + && !is_gimple_min_invariant (arg)) + { + if (accesses.length () >= accesses_limit - load_accesses) + { + unknown_memory_access = true; + break; + } + accesses.quick_grow (accesses.length () + 1); + ao_ref_init (&accesses.last (), arg); + } + } + if (summary && !unknown_memory_access) + { + /* Add loads as analyzed by IPA modref. */ + for (auto base_node : summary->loads->bases) + if (unknown_memory_access) + break; + else for (auto ref_node : base_node->refs) + if (unknown_memory_access) + break; + else for (auto access_node : ref_node->accesses) + { + accesses.quick_grow (accesses.length () + 1); + ao_ref *r = &accesses.last (); + if (!access_node.get_ao_ref (stmt, r)) + { + /* Initialize a ref based on the argument and + unknown offset if possible. */ + tree arg = access_node.get_call_arg (stmt); + if (arg && TREE_CODE (arg) == SSA_NAME) + arg = SSA_VAL (arg); + if (arg + && TREE_CODE (arg) == ADDR_EXPR + && (arg = get_base_address (arg)) + && DECL_P (arg)) + { + ao_ref_init (r, arg); + r->ref = NULL_TREE; + r->base = arg; + } + else + { + unknown_memory_access = true; + break; + } + } + r->base_alias_set = base_node->base; + r->ref_alias_set = ref_node->ref; + } + } + + /* Walk the VUSE->VDEF chain optimistically trying to find an entry + for the call in the hashtable. */ + unsigned limit = (unknown_memory_access + ? 0 + : (param_sccvn_max_alias_queries_per_access + / (accesses.length () + 1))); + tree saved_vuse = vr1.vuse; + hashval_t saved_hashcode = vr1.hashcode; + while (limit > 0 && !vnresult && !SSA_NAME_IS_DEFAULT_DEF (vr1.vuse)) + { + vr1.hashcode = vr1.hashcode - SSA_NAME_VERSION (vr1.vuse); + gimple *def = SSA_NAME_DEF_STMT (vr1.vuse); + /* ??? We could use fancy stuff like in walk_non_aliased_vuses, but + do not bother for now. */ + if (is_a (def)) + break; + vr1.vuse = vuse_ssa_val (gimple_vuse (def)); + vr1.hashcode = vr1.hashcode + SSA_NAME_VERSION (vr1.vuse); + vn_reference_lookup_1 (&vr1, &vnresult); + limit--; + } + + /* If we found a candidate to CSE to verify it is valid. */ + if (vnresult && !accesses.is_empty ()) + { + tree vuse = vuse_ssa_val (gimple_vuse (stmt)); + while (vnresult && vuse != vr1.vuse) + { + gimple *def = SSA_NAME_DEF_STMT (vuse); + for (auto &ref : accesses) + { + /* ??? stmt_may_clobber_ref_p_1 does per stmt constant + analysis overhead that we might be able to cache. */ + if (stmt_may_clobber_ref_p_1 (def, &ref, true)) + { + vnresult = NULL; + break; + } + } + vuse = vuse_ssa_val (gimple_vuse (def)); + } + } + vr1.vuse = saved_vuse; + vr1.hashcode = saved_hashcode; + } + if (vnresult) { if (vnresult->result_vdef && vdef) -- cgit v1.1 From 29e1cbdc0c6e7d3de10478ef2b881900545c2a55 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 24 Nov 2021 13:15:06 +0000 Subject: PR middle-end/103059: reload: Also accept ASHIFT with indexed addressing Correct a `vax-netbsdelf' target regression ultimately caused by commit c605a8bf9270 ("VAX: Accept ASHIFT in address expressions") (needed for LRA) and as of commit 4a960d548b7d ("Avoid invalid loop transformations in jump threading registry.") causing a build error in libgcc: .../libgcc/libgcov-driver.c: In function 'gcov_do_dump': .../libgcc/libgcov-driver.c:686:1: error: insn does not satisfy its constraints: 686 | } | ^ (insn 2051 2050 2052 185 (set (reg/f:SI 0 %r0 [555]) (plus:SI (ashift:SI (mem/c:SI (plus:SI (reg/f:SI 13 %fp) (const_int -28 [0xffffffffffffffe4])) [40 %sfp+-28 S4 A32]) (const_int 3 [0x3])) (plus:SI (reg/v/f:SI 9 %r9 [orig:176 fn_buffer ] [176]) (const_int 24 [0x18])))) ".../libgcc/libgcov-driver.c":172:40 614 {movaddrdi} (nil)) during RTL pass: postreload .../libgcc/libgcov-driver.c:686:1: internal compiler error: in extract_constrain_insn, at recog.c:2670 0x1122a5ff _fatal_insn(char const*, rtx_def const*, char const*, int, char const*) .../gcc/rtl-error.c:108 0x1122a697 _fatal_insn_not_found(rtx_def const*, char const*, int, char const*) .../gcc/rtl-error.c:118 0x111b5f2f extract_constrain_insn(rtx_insn*) .../gcc/recog.c:2670 0x11143eef reload_cse_simplify_operands .../gcc/postreload.c:407 0x11142fdb reload_cse_simplify .../gcc/postreload.c:132 0x11143533 reload_cse_regs_1 .../gcc/postreload.c:238 0x11142ce7 reload_cse_regs .../gcc/postreload.c:66 0x1114af33 execute .../gcc/postreload.c:2355 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See for instructions. This is because reload does not recognize the ASHIFT form of scaled indexed addressing that the offending commit enabled the backend to produce, and as seen in the RTL above lets the pseudo holding the index part become the original memory reference rather than reloading it into a hard register. Fix it then by adding said form to reload, removing the build failure and numerous similar regressions throughout `vax-netbsdelf' test suites run with the source as at right before the build regression. Cf. , and commit 6b3034eaba83 ("lra: Canonicalize mult to shift in address reloads"). gcc/ PR middle-end/103059 * reload.c (find_reloads_address_1): Also accept the ASHIFT form of indexed addressing. (find_reloads): Adjust accordingly. --- gcc/reload.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/reload.c b/gcc/reload.c index 4c55ca5..190db6a 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -2846,10 +2846,11 @@ find_reloads (rtx_insn *insn, int replace, int ind_levels, int live_known, i, operand_type[i], ind_levels, insn); /* If we now have a simple operand where we used to have a - PLUS or MULT, re-recognize and try again. */ + PLUS or MULT or ASHIFT, re-recognize and try again. */ if ((OBJECT_P (*recog_data.operand_loc[i]) || GET_CODE (*recog_data.operand_loc[i]) == SUBREG) && (GET_CODE (recog_data.operand[i]) == MULT + || GET_CODE (recog_data.operand[i]) == ASHIFT || GET_CODE (recog_data.operand[i]) == PLUS)) { INSN_CODE (insn) = -1; @@ -5562,7 +5563,8 @@ find_reloads_address_1 (machine_mode mode, addr_space_t as, return 1; } - if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE + if (code0 == MULT || code0 == ASHIFT + || code0 == SIGN_EXTEND || code0 == TRUNCATE || code0 == ZERO_EXTEND || code1 == MEM) { find_reloads_address_1 (mode, as, orig_op0, 1, PLUS, SCRATCH, @@ -5573,7 +5575,8 @@ find_reloads_address_1 (machine_mode mode, addr_space_t as, insn); } - else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE + else if (code1 == MULT || code1 == ASHIFT + || code1 == SIGN_EXTEND || code1 == TRUNCATE || code1 == ZERO_EXTEND || code0 == MEM) { find_reloads_address_1 (mode, as, orig_op0, 0, PLUS, code1, -- cgit v1.1 From a031bb7a585f789df2aed856a57646b8c45d0878 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Fri, 19 Nov 2021 13:27:18 -0500 Subject: Range-on-edge trace tweak. Trace formatting gets out of sync when range on edge is called with a constant. * gimple-range.cc (gimple_ranger::range_on_edge): Call trailer when a constant is encountered to terminate the trace. --- gcc/gimple-range.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index a2b68b2..9ca568c 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -216,7 +216,7 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) bool res = true; if (!gimple_range_ssa_p (name)) - return get_tree_range (r, name, NULL); + res = get_tree_range (r, name, NULL); else { range_on_exit (r, e->src, name); @@ -230,7 +230,7 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) if (idx) tracer.trailer (idx, "range_on_edge", res, name, r); - return true; + return res; } // fold_range wrapper for range_of_stmt to use as an internal client. -- cgit v1.1 From d986ff50b4aad62c45d7ac62915e072643ddfca1 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Fri, 19 Nov 2021 12:59:12 -0500 Subject: Split return functionality of get_non_stale_global_range. Get_non_stale_global_range returns true only when there is a cache entry that is not out of date. Change it so that it returns true if there was a cache value, but return the temporal comparison result in an auxiallary flag. * gimple-range-cache.cc (ranger_cache::get_global_range): Always return a range, return if it came from the cache or not. (get_non_stale_global_range): Rename to get_global_range, and return the temporal state in a flag. * gimple-range-cache.h (get_non_stale_global_range): Rename and adjust. * gimple-range.cc (gimple_ranger::range_of_expr): No need to query get_global_range. (gimple_ranger::range_of_stmt): Adjust for global cache temporal state returned in a flag. --- gcc/gimple-range-cache.cc | 55 ++++++++++++++++++++++++----------------------- gcc/gimple-range-cache.h | 2 +- gcc/gimple-range.cc | 21 ++++++++++-------- 3 files changed, 41 insertions(+), 37 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index b347ede..fe31e94 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -923,44 +923,45 @@ ranger_cache::dump_bb (FILE *f, basic_block bb) } // Get the global range for NAME, and return in R. Return false if the -// global range is not set. +// global range is not set, and return the legacy global value in R. bool ranger_cache::get_global_range (irange &r, tree name) const { - return m_globals.get_global_range (r, name); + if (m_globals.get_global_range (r, name)) + return true; + r = gimple_range_global (name); + return false; } -// Get the global range for NAME, and return in R if the value is not stale. -// If the range is set, but is stale, mark it current and return false. -// If it is not set pick up the legacy global value, mark it current, and -// return false. -// Note there is always a value returned in R. The return value indicates -// whether that value is an up-to-date calculated value or not.. +// Get the global range for NAME, and return in R. Return false if the +// global range is not set, and R will contain the legacy global value. +// CURRENT_P is set to true if the value was in cache and not stale. +// Otherwise, set CURRENT_P to false and mark as it always current. +// If the global cache did not have a value, initialize it as well. +// After this call, the global cache will have a value. bool -ranger_cache::get_non_stale_global_range (irange &r, tree name) +ranger_cache::get_global_range (irange &r, tree name, bool ¤t_p) { - if (m_globals.get_global_range (r, name)) - { - // Use this value if the range is constant or current. - if (r.singleton_p () - || m_temporal->current_p (name, m_gori.depend1 (name), - m_gori.depend2 (name))) - return true; - } + bool had_global = get_global_range (r, name); + + // If there was a global value, set current flag, otherwise set a value. + current_p = false; + if (had_global) + current_p = r.singleton_p () + || m_temporal->current_p (name, m_gori.depend1 (name), + m_gori.depend2 (name)); else - { - // Global has never been accessed, so pickup the legacy global value. - r = gimple_range_global (name); - m_globals.set_global_range (name, r); - } - // After a stale check failure, mark the value as always current until a - // new one is set. - m_temporal->set_always_current (name); - return false; + m_globals.set_global_range (name, r); + + // If the existing value was not current, mark it as always current. + if (!current_p) + m_temporal->set_always_current (name); + return current_p; } -// Set the global range of NAME to R. + +// Set the global range of NAME to R and give it a timestamp. void ranger_cache::set_global_range (tree name, const irange &r) diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h index 49c13d1..eb7a875 100644 --- a/gcc/gimple-range-cache.h +++ b/gcc/gimple-range-cache.h @@ -100,7 +100,7 @@ public: bool block_range (irange &r, basic_block bb, tree name, bool calc = true); bool get_global_range (irange &r, tree name) const; - bool get_non_stale_global_range (irange &r, tree name); + bool get_global_range (irange &r, tree name, bool ¤t_p); void set_global_range (tree name, const irange &r); void propagate_updated_value (tree name, basic_block bb); diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index 9ca568c..e3ab3a8 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -85,8 +85,7 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) if (!stmt) { int_range_max tmp; - if (!m_cache.get_global_range (r, expr)) - r = gimple_range_global (expr); + m_cache.get_global_range (r, expr); // Pick up implied context information from the on-entry cache // if current_bb is set. Do not attempt any new calculations. if (current_bb && m_cache.block_range (tmp, current_bb, expr, false)) @@ -282,15 +281,19 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name) } else if (!gimple_range_ssa_p (name)) res = get_tree_range (r, name, NULL); - // Check if the stmt has already been processed, and is not stale. - else if (m_cache.get_non_stale_global_range (r, name)) - { - if (idx) - tracer.trailer (idx, " cached", true, name, r); - return true; - } else { + bool current; + // Check if the stmt has already been processed, and is not stale. + if (m_cache.get_global_range (r, name, current)) + { + if (current) + { + if (idx) + tracer.trailer (idx, " cached", true, name, r); + return true; + } + } // Otherwise calculate a new value. int_range_max tmp; fold_range_internal (tmp, s, name); -- cgit v1.1 From 5deacf6058d1bc7261a75c9fd1f116c4442e9e60 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Mon, 22 Nov 2021 14:39:41 -0500 Subject: Directly resolve range_of_stmt dependencies. All ranger API entries eventually call range_of_stmt to ensure there is an initial global value to work with. This can cause very deep call chains when satisfied via the normal API. Instead, push any dependencies onto a stack and evaluate them in a depth first manner, mirroring what would have happened via the normal API calls. PR tree-optimization/103231 gcc/ * gimple-range.cc (gimple_ranger::gimple_ranger): Create stmt stack. (gimple_ranger::gimple_ranger): Delete stmt stack. (gimple_ranger::range_of_stmt): Process depenedencies if they have no global cache entry. (gimple_ranger::prefill_name): New. (gimple_ranger::prefill_stmt_dependencies): New. * gimple-range.h (class gimple_ranger): Add prototypes. --- gcc/gimple-range.cc | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++- gcc/gimple-range.h | 4 ++ 2 files changed, 109 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index e3ab3a8..178a470 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -46,6 +46,9 @@ gimple_ranger::gimple_ranger () : m_oracle = m_cache.oracle (); if (dump_file && (param_ranger_debug & RANGER_DEBUG_TRACE)) tracer.enable_trace (); + m_stmt_list.create (0); + m_stmt_list.safe_grow (num_ssa_names); + m_stmt_list.truncate (0); // Ensure the not_executable flag is clear everywhere. if (flag_checking) @@ -61,6 +64,11 @@ gimple_ranger::gimple_ranger () : } } +gimple_ranger::~gimple_ranger () +{ + m_stmt_list.release (); +} + bool gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) { @@ -284,9 +292,10 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name) else { bool current; - // Check if the stmt has already been processed, and is not stale. + // Check if the stmt has already been processed. if (m_cache.get_global_range (r, name, current)) { + // If it isn't stale, use this cached value. if (current) { if (idx) @@ -294,7 +303,10 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name) return true; } } - // Otherwise calculate a new value. + else + prefill_stmt_dependencies (name); + + // Calculate a new value. int_range_max tmp; fold_range_internal (tmp, s, name); @@ -311,6 +323,97 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name) return res; } + +// Check if NAME is a dependency that needs resolving, and push it on the +// stack if so. R is a scratch range. + +inline void +gimple_ranger::prefill_name (irange &r, tree name) +{ + if (!gimple_range_ssa_p (name)) + return; + gimple *stmt = SSA_NAME_DEF_STMT (name); + if (!gimple_range_handler (stmt)) + return; + + bool current; + // If this op has not been processed yet, then push it on the stack + if (!m_cache.get_global_range (r, name, current)) + m_stmt_list.safe_push (name); +} + +// This routine will seed the global cache with most of the depnedencies of +// NAME. This prevents excessive call depth through the normal API. + +void +gimple_ranger::prefill_stmt_dependencies (tree ssa) +{ + if (SSA_NAME_IS_DEFAULT_DEF (ssa)) + return; + + int_range_max r; + unsigned idx; + gimple *stmt = SSA_NAME_DEF_STMT (ssa); + gcc_checking_assert (stmt && gimple_bb (stmt)); + + // Only pre-process range-ops. + if (!gimple_range_handler (stmt)) + return; + + // Mark where on the stack we are starting. + unsigned start = m_stmt_list.length (); + m_stmt_list.safe_push (ssa); + + idx = tracer.header ("ROS dependence fill\n"); + + // Loop until back at the start point. + while (m_stmt_list.length () > start) + { + tree name = m_stmt_list.last (); + // NULL is a marker which indicates the next name in the stack has now + // been fully resolved, so we can fold it. + if (!name) + { + // Pop the NULL, then pop the name. + m_stmt_list.pop (); + name = m_stmt_list.pop (); + // Don't fold initial request, it will be calculated upon return. + if (m_stmt_list.length () > start) + { + // Fold and save the value for NAME. + stmt = SSA_NAME_DEF_STMT (name); + fold_range_internal (r, stmt, name); + m_cache.set_global_range (name, r); + } + continue; + } + + // Add marker indicating previous NAME in list should be folded + // when we get to this NULL. + m_stmt_list.safe_push (NULL_TREE); + stmt = SSA_NAME_DEF_STMT (name); + + if (idx) + { + tracer.print (idx, "ROS dep fill ("); + print_generic_expr (dump_file, name, TDF_SLIM); + fputs (") at stmt ", dump_file); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + } + + gcc_checking_assert (gimple_range_handler (stmt)); + tree op = gimple_range_operand2 (stmt); + if (op) + prefill_name (r, op); + op = gimple_range_operand1 (stmt); + if (op) + prefill_name (r, op); + } + if (idx) + tracer.trailer (idx, "ROS ", false, ssa, r); +} + + // This routine will invoke the gimple fold_stmt routine, providing context to // range_of_expr calls via an private interal API. diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index 615496e..c2923c5 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -47,6 +47,7 @@ class gimple_ranger : public range_query { public: gimple_ranger (); + ~gimple_ranger (); virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL) OVERRIDE; virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) OVERRIDE; virtual bool range_on_edge (irange &r, edge e, tree name) OVERRIDE; @@ -61,9 +62,12 @@ public: bool fold_stmt (gimple_stmt_iterator *gsi, tree (*) (tree)); protected: bool fold_range_internal (irange &r, gimple *s, tree name); + void prefill_name (irange &r, tree name); + void prefill_stmt_dependencies (tree ssa); ranger_cache m_cache; range_tracer tracer; basic_block current_bb; + vec m_stmt_list; }; /* Create a new ranger instance and associate it with a function. -- cgit v1.1 From 9e026da720091704ca0456d405f16a3bc5f3a799 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Fri, 30 Jul 2021 09:23:20 +0200 Subject: Reduce scope of a few 'class loop *loop' variables Further clean-up after commit e41ba804ba5f5ca433e09238d561b1b4c8b10985 "Use range-based for loops for traversing loops". No functional change. gcc/ * cfgloop.c (verify_loop_structure): Reduce scope of 'class loop *loop' variable. * ipa-fnsummary.c (analyze_function_body): Likewise. * loop-init.c (fix_loop_structure): Likewise. * loop-invariant.c (calculate_loop_reg_pressure): Likewise. * predict.c (predict_loops): Likewise. * tree-loop-distribution.c (loop_distribution::execute): Likewise. * tree-vectorizer.c (pass_vectorize::execute): Likewise. --- gcc/cfgloop.c | 3 +-- gcc/ipa-fnsummary.c | 3 +-- gcc/loop-init.c | 2 +- gcc/loop-invariant.c | 4 ++-- gcc/predict.c | 3 +-- gcc/tree-loop-distribution.c | 2 +- gcc/tree-vectorizer.c | 5 ++--- 7 files changed, 9 insertions(+), 13 deletions(-) (limited to 'gcc') diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c index 20c24c1..3190d12 100644 --- a/gcc/cfgloop.c +++ b/gcc/cfgloop.c @@ -1398,7 +1398,6 @@ verify_loop_structure (void) { unsigned *sizes, i, j; basic_block bb, *bbs; - class loop *loop; int err = 0; edge e; unsigned num = number_of_loops (cfun); @@ -1689,7 +1688,7 @@ verify_loop_structure (void) for (; exit; exit = exit->next_e) eloops++; - for (loop = bb->loop_father; + for (class loop *loop = bb->loop_father; loop != e->dest->loop_father /* When a loop exit is also an entry edge which can happen when avoiding CFG manipulations diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c index 7e9201a..cb13d2e 100644 --- a/gcc/ipa-fnsummary.c +++ b/gcc/ipa-fnsummary.c @@ -2934,7 +2934,6 @@ analyze_function_body (struct cgraph_node *node, bool early) if (nonconstant_names.exists () && !early) { ipa_fn_summary *s = ipa_fn_summaries->get (node); - class loop *loop; unsigned max_loop_predicates = opt_for_fn (node->decl, param_ipa_max_loop_predicates); @@ -2978,7 +2977,7 @@ analyze_function_body (struct cgraph_node *node, bool early) /* To avoid quadratic behavior we analyze stride predicates only with respect to the containing loop. Thus we simply iterate over all defs in the outermost loop body. */ - for (loop = loops_for_fn (cfun)->tree_root->inner; + for (class loop *loop = loops_for_fn (cfun)->tree_root->inner; loop != NULL; loop = loop->next) { ipa_predicate loop_stride = true; diff --git a/gcc/loop-init.c b/gcc/loop-init.c index 04054ef..f0931a9 100644 --- a/gcc/loop-init.c +++ b/gcc/loop-init.c @@ -201,7 +201,6 @@ fix_loop_structure (bitmap changed_bbs) { basic_block bb; int record_exits = 0; - class loop *loop; unsigned old_nloops, i; timevar_push (TV_LOOP_INIT); @@ -279,6 +278,7 @@ fix_loop_structure (bitmap changed_bbs) /* Finally free deleted loops. */ bool any_deleted = false; + class loop *loop; FOR_EACH_VEC_ELT (*get_loops (cfun), i, loop) if (loop && loop->header == NULL) { diff --git a/gcc/loop-invariant.c b/gcc/loop-invariant.c index fca0c2b..5eee2e5 100644 --- a/gcc/loop-invariant.c +++ b/gcc/loop-invariant.c @@ -2134,7 +2134,7 @@ calculate_loop_reg_pressure (void) basic_block bb; rtx_insn *insn; rtx link; - class loop *loop, *parent; + class loop *parent; for (auto loop : loops_list (cfun, 0)) if (loop->aux == NULL) @@ -2151,7 +2151,7 @@ calculate_loop_reg_pressure (void) if (curr_loop == current_loops->tree_root) continue; - for (loop = curr_loop; + for (class loop *loop = curr_loop; loop != current_loops->tree_root; loop = loop_outer (loop)) bitmap_ior_into (&LOOP_DATA (loop)->regs_live, DF_LR_IN (bb)); diff --git a/gcc/predict.c b/gcc/predict.c index 68b1113..3cb4e3c 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -1927,7 +1927,6 @@ predict_extra_loop_exits (edge exit_edge) static void predict_loops (void) { - class loop *loop; basic_block bb; hash_set with_recursion(10); @@ -1941,7 +1940,7 @@ predict_loops (void) && (decl = gimple_call_fndecl (gsi_stmt (gsi))) != NULL && recursive_call_p (current_function_decl, decl)) { - loop = bb->loop_father; + class loop *loop = bb->loop_father; while (loop && !with_recursion.add (loop)) loop = loop_outer (loop); } diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c index 583c01a..c9e1873 100644 --- a/gcc/tree-loop-distribution.c +++ b/gcc/tree-loop-distribution.c @@ -3737,7 +3737,6 @@ prepare_perfect_loop_nest (class loop *loop) unsigned int loop_distribution::execute (function *fun) { - class loop *loop; bool changed = false; basic_block bb; control_dependences *cd = NULL; @@ -3845,6 +3844,7 @@ loop_distribution::execute (function *fun) /* Destroy loop bodies that could not be reused. Do this late as we otherwise can end up refering to stale data in control dependences. */ unsigned i; + class loop *loop; FOR_EACH_VEC_ELT (loops_to_be_destroyed, i, loop) destroy_loop (loop); diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index 0e1cee9..f4a2873 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -1209,7 +1209,6 @@ pass_vectorize::execute (function *fun) unsigned int i; unsigned int num_vectorized_loops = 0; unsigned int vect_loops_num; - class loop *loop; hash_table *simduid_to_vf_htab = NULL; hash_table *simd_array_to_simduid_htab = NULL; bool any_ifcvt_loops = false; @@ -1293,7 +1292,7 @@ pass_vectorize::execute (function *fun) if (any_ifcvt_loops) for (i = 1; i < number_of_loops (fun); i++) { - loop = get_loop (fun, i); + class loop *loop = get_loop (fun, i); if (loop && loop->dont_vectorize) { gimple *g = vect_loop_vectorized_call (loop); @@ -1342,7 +1341,7 @@ pass_vectorize::execute (function *fun) loop_vec_info loop_vinfo; bool has_mask_store; - loop = get_loop (fun, i); + class loop *loop = get_loop (fun, i); if (!loop || !loop->aux) continue; loop_vinfo = (loop_vec_info) loop->aux; -- cgit v1.1 From 16e85390507ea92331c9052393b591202007f5ab Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 24 Nov 2021 22:27:17 +0100 Subject: Fix handling of static chain in ipa_merge_modref_summary_after_inlining gcc/ChangeLog: 2021-11-24 Jan Hubicka * ipa-modref.c (implicit_eaf_flags_for_edge_and_arg): Break out from... (modref_merge_call_site_flags): ... here. (ipa_merge_modref_summary_after_inlining): Use it. gcc/testsuite/ChangeLog: 2021-11-24 Jan Hubicka * gcc.c-torture/execute/pr103405.c: New test. --- gcc/ipa-modref.c | 68 +++++++++++++++++++------- gcc/testsuite/gcc.c-torture/execute/pr103405.c | 37 ++++++++++++++ 2 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr103405.c (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 923ae6c..c2edc0d 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -4827,6 +4827,30 @@ modref_propagate_dump_scc (cgraph_node *component_node) } } +/* Determine EAF flags know for call E with CALLEE_ECF_FLAGS and ARG. */ + +int +implicit_eaf_flags_for_edge_and_arg (cgraph_edge *e, int callee_ecf_flags, + bool ignore_stores, int arg) +{ + /* Returning the value is already accounted to at local propagation. */ + int implicit_flags = EAF_NOT_RETURNED_DIRECTLY + | EAF_NOT_RETURNED_INDIRECTLY; + if (ignore_stores) + implicit_flags |= ignore_stores_eaf_flags; + if (callee_ecf_flags & ECF_PURE) + implicit_flags |= implicit_pure_eaf_flags; + if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS)) + implicit_flags |= implicit_const_eaf_flags; + class fnspec_summary *fnspec_sum = fnspec_summaries->get (e); + if (fnspec_sum) + { + attr_fnspec fnspec (fnspec_sum->fnspec); + implicit_flags |= fnspec.arg_eaf_flags (arg); + } + return implicit_flags; +} + /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY and SUMMARY_LTO to CUR_SUMMARY_LTO. Return true if something changed. */ @@ -4857,9 +4881,8 @@ modref_merge_call_site_flags (escape_summary *sum, { int flags = 0; int flags_lto = 0; - /* Returning the value is already accounted to at local propagation. */ - int implicit_flags = EAF_NOT_RETURNED_DIRECTLY - | EAF_NOT_RETURNED_INDIRECTLY; + int implicit_flags = implicit_eaf_flags_for_edge_and_arg + (e, callee_ecf_flags, ignore_stores, ee->arg); if (summary && ee->arg < summary->arg_flags.length ()) flags = summary->arg_flags[ee->arg]; @@ -4995,6 +5018,7 @@ modref_propagate_flags_in_scc (cgraph_node *component_node) if (ecf_flags & (ECF_CONST | ECF_NOVOPS) || !callee_edge->inline_failed) continue; + /* Get the callee and its summary. */ enum availability avail; callee = callee_edge->callee->function_or_virtual_thunk_symbol @@ -5081,6 +5105,9 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) class modref_summary_lto *callee_info_lto = summaries_lto ? summaries_lto->get (edge->callee) : NULL; int flags = flags_from_decl_or_type (edge->callee->decl); + /* Combine in outer flags. */ + for (cgraph_node *n = edge->caller; n->inlined_to; n = n->callers->caller) + flags |= flags_from_decl_or_type (edge->callee->decl); bool ignore_stores = ignore_stores_p (edge->caller->decl, flags); if (!callee_info && to_info) @@ -5148,10 +5175,11 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) FOR_EACH_VEC_ELT (sum->esc, i, ee) { bool needed = false; - /* TODO: We do not have jump functions for return slots, so we - never propagate them to outer function. */ - if (ee->parm_index < 0) - continue; + int implicit_flags = implicit_eaf_flags_for_edge_and_arg + (edge, flags, ignore_stores, + ee->arg); + if (!ee->direct) + implicit_flags = deref_flags (implicit_flags, ignore_stores); if (to_info && (int)to_info->arg_flags.length () > ee->parm_index) { int flags = callee_info @@ -5159,11 +5187,14 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) ? callee_info->arg_flags[ee->arg] : 0; if (!ee->direct) flags = deref_flags (flags, ignore_stores); - else if (ignore_stores) - flags |= ignore_stores_eaf_flags; - flags |= ee->min_flags; - to_info->arg_flags[ee->parm_index] &= flags; - if (to_info->arg_flags[ee->parm_index]) + flags |= ee->min_flags | implicit_flags; + eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM + ? to_info->retslot_flags + : ee->parm_index == MODREF_STATIC_CHAIN_PARM + ? to_info->static_chain_flags + : to_info->arg_flags[ee->parm_index]; + f &= flags; + if (f) needed = true; } if (to_info_lto @@ -5174,11 +5205,14 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) ? callee_info_lto->arg_flags[ee->arg] : 0; if (!ee->direct) flags = deref_flags (flags, ignore_stores); - else if (ignore_stores) - flags |= ignore_stores_eaf_flags; - flags |= ee->min_flags; - to_info_lto->arg_flags[ee->parm_index] &= flags; - if (to_info_lto->arg_flags[ee->parm_index]) + flags |= ee->min_flags | implicit_flags; + eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM + ? to_info_lto->retslot_flags + : ee->parm_index == MODREF_STATIC_CHAIN_PARM + ? to_info_lto->static_chain_flags + : to_info_lto->arg_flags[ee->parm_index]; + f &= flags; + if (f) needed = true; } struct escape_map entry = {ee->parm_index, ee->direct}; diff --git a/gcc/testsuite/gcc.c-torture/execute/pr103405.c b/gcc/testsuite/gcc.c-torture/execute/pr103405.c new file mode 100644 index 0000000..f6005dc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr103405.c @@ -0,0 +1,37 @@ +typedef __SIZE_TYPE__ size_t; +void *malloc(size_t); + +static inline int *starter(int a) +{ + int *b = malloc(sizeof(int)); + *b = a; + return b; +} + +static inline _Bool equal(int *l, int *r) +{ + if (l == 0) + __builtin_abort(); + if (r == 0) + __builtin_abort(); + return *r == *l; +} + +int main(void) +{ + int *i; + int *j; + void check(_Bool a) + { + _Bool t = equal(i, j); + if (a && t) __builtin_abort (); + _Bool t1 = equal(i, j); + if (!a && !t1) __builtin_abort (); + } + i = starter(1); + j = starter(0); + check(1); + i = starter(0); + check(0); + +} -- cgit v1.1 From d9ca4b45bd1ab00d74d38cba94a84990d40918ca Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 25 Nov 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/ChangeLog | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/cp/ChangeLog | 23 +++++++++ gcc/jit/ChangeLog | 4 ++ gcc/testsuite/ChangeLog | 75 +++++++++++++++++++++++++++ 5 files changed, 238 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0a9e75c..6e08b0b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,138 @@ +2021-11-24 Jan Hubicka + + * ipa-modref.c (implicit_eaf_flags_for_edge_and_arg): Break out from... + (modref_merge_call_site_flags): ... here. + (ipa_merge_modref_summary_after_inlining): Use it. + +2021-11-24 Thomas Schwinge + + * cfgloop.c (verify_loop_structure): Reduce scope of + 'class loop *loop' variable. + * ipa-fnsummary.c (analyze_function_body): Likewise. + * loop-init.c (fix_loop_structure): Likewise. + * loop-invariant.c (calculate_loop_reg_pressure): Likewise. + * predict.c (predict_loops): Likewise. + * tree-loop-distribution.c (loop_distribution::execute): Likewise. + * tree-vectorizer.c (pass_vectorize::execute): Likewise. + +2021-11-24 Andrew MacLeod + + PR tree-optimization/103231 + * gimple-range.cc (gimple_ranger::gimple_ranger): Create stmt stack. + (gimple_ranger::gimple_ranger): Delete stmt stack. + (gimple_ranger::range_of_stmt): Process depenedencies if they have no + global cache entry. + (gimple_ranger::prefill_name): New. + (gimple_ranger::prefill_stmt_dependencies): New. + * gimple-range.h (class gimple_ranger): Add prototypes. + +2021-11-24 Andrew MacLeod + + * gimple-range-cache.cc (ranger_cache::get_global_range): Always + return a range, return if it came from the cache or not. + (get_non_stale_global_range): Rename to get_global_range, and return + the temporal state in a flag. + * gimple-range-cache.h (get_non_stale_global_range): Rename and adjust. + * gimple-range.cc (gimple_ranger::range_of_expr): No need to query + get_global_range. + (gimple_ranger::range_of_stmt): Adjust for global cache temporal state + returned in a flag. + +2021-11-24 Andrew MacLeod + + * gimple-range.cc (gimple_ranger::range_on_edge): Call trailer when + a constant is encountered to terminate the trace. + +2021-11-24 Maciej W. Rozycki + + PR middle-end/103059 + * reload.c (find_reloads_address_1): Also accept the ASHIFT form + of indexed addressing. + (find_reloads): Adjust accordingly. + +2021-11-24 Richard Biener + Jan Hubicka + + PR tree-optimization/103168 + * ipa-modref.h (struct modref_summary): Add load_accesses. + * ipa-modref.c (modref_summary::finalize): Initialize load_accesses. + * tree-ssa-sccvn.c (visit_reference_op_call): Use modref + info to walk the virtual use->def chain to CSE const/pure + function calls possibly reading from memory. + +2021-11-24 Thomas Schwinge + + PR middle-end/103244 + * gimplify.c (gimplify_adjust_omp_clauses): Restore previous + OpenACC behavior. + +2021-11-24 Richard Biener + + PR middle-end/103193 + * match.pd: Avoid canonicalizing (le/ge @0 @0) to (eq @0 @0) + with NaNs and -ftrapping-math. + +2021-11-24 Jakub Jelinek + + PR middle-end/103384 + * omp-general.c (omp_context_selector_matches): For ACCEL_COMPILER, + return 0 for kind(host) and continue for kind(nohost). + +2021-11-24 Jakub Jelinek + + PR middle-end/103365 + * attribs.h (lookup_attribute): Allow attr_name to start with + underscore, as long as canonicalize_attr_name returns false. + (lookup_attribute_by_prefix): Don't call get_attribute_name twice. + * attribs.c (extract_attribute_substring): Reimplement using + canonicalize_attr_name. + (register_scoped_attribute): Change gcc_assert into + gcc_checking_assert, verify !canonicalize_attr_name rather than + that str.str doesn't start with '_'. + +2021-11-24 Jakub Jelinek + + PR tree-optimization/103376 + * gimple-ssa-store-merging.c (perform_symbolic_merge): Add CODE + argument. If CODE is not BIT_IOR_EXPR, ensure that one of masked1 + or masked2 is 0. + (find_bswap_or_nop_1, find_bswap_or_nop, + imm_store_chain_info::try_coalesce_bswap): Adjust + perform_symbolic_merge callers. + +2021-11-24 Richard Biener + + * tree-ssa-loop-ivopts.c (find_givs): Take loop body as + argument instead of re-computing it. + (find_interesting_uses): Likewise. + (find_induction_variables): Pass through loop body. + (tree_ssa_iv_optimize_loop): Pass down loop body. + +2021-11-24 Tamar Christina + + * tree-ssa-phiopt.c (spaceship_replacement): Handle new canonical + codegen. + +2021-11-24 Tamar Christina + + * tree.c (bitmask_inv_cst_vector_p): New. + * tree.h (bitmask_inv_cst_vector_p): New. + * match.pd: Use it in new bitmask compare pattern. + +2021-11-24 Jason Merrill + + * timevar.h (class auto_cond_timevar): New. + +2021-11-24 Hongtao Liu + H.J. Lu + + PR tree-optimization/103194 + * match.pd (gimple_nop_atomic_bit_test_and_p): Extended to + match truncation. + * tree-ssa-ccp.c (gimple_nop_convert): Declare. + (optimize_atomic_bit_test_and): Enhance + optimize_atomic_bit_test_and to handle truncation. + 2021-11-23 Martin Sebor PR middle-end/88232 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 6a89873..f9671d2 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20211124 +20211125 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 79cb9f9..663f36e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2021-11-24 Marek Polacek + + PR c++/103347 + * cp-tree.h (struct cp_declarator): Add a location_t member. + (maybe_warn_cpp0x): Add a location_t parameter with a default argument. + (loc_or_input_loc): New. + * decl.c (grokdeclarator): Use loc_or_input_loc. Pass init_loc down + to maybe_warn_cpp0x. + * error.c (maybe_warn_cpp0x): Add a location_t parameter. Use it. + * parser.c (make_declarator): Initialize init_loc. + (cp_parser_member_declaration): Set init_loc. + (cp_parser_condition): Likewise. + (cp_parser_init_declarator): Likewise. + (cp_parser_parameter_declaration): Likewise. + +2021-11-24 Jason Merrill + + * call.c + * decl.c + * name-lookup.c: + Use auto_cond_timevar instead of timevar_cond_start/stop. + Remove wrapper functions. + 2021-11-23 Martin Sebor PR c++/96507 diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index c2fc2bd..f5a836a 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,7 @@ +2021-11-24 Martin Liska + + * jit-playback.c (function): Initialize m_blocks vector. + 2021-11-20 Antoni Boucher PR target/96889 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index deca255..17f0681 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,78 @@ +2021-11-24 Jan Hubicka + + * gcc.c-torture/execute/pr103405.c: New test. + +2021-11-24 Richard Biener + Jan Hubicka + + PR tree-optimization/103168 + * g++.dg/tree-ssa/pr103168.C: New testcase. + +2021-11-24 Thomas Schwinge + + PR middle-end/103244 + * c-c++-common/goacc/combined-reduction.c: Revert/expect previous + OpenACC behavior. + * c-c++-common/goacc/firstprivate-mappings-1.c: Likewise. + * c-c++-common/goacc/mdc-1.c: Likewise. + * g++.dg/goacc/firstprivate-mappings-1.C: Likewise. + +2021-11-24 Jakub Jelinek + + PR middle-end/103365 + * c-c++-common/Wno-attributes-1.c: Require effective target + c || c++11 and drop dg-additional-options. + * c-c++-common/Wno-attributes-2.c: Likewise. + * c-c++-common/Wno-attributes-4.c: New test. + * c-c++-common/Wno-attributes-5.c: New test. + +2021-11-24 Jakub Jelinek + + PR tree-optimization/103376 + * gcc.c-torture/execute/pr103376.c: New test. + +2021-11-24 Tamar Christina + + * gcc.dg/bic-bitmask-10.c: New test. + * gcc.dg/bic-bitmask-11.c: New test. + * gcc.dg/bic-bitmask-12.c: New test. + * gcc.dg/bic-bitmask-13.c: New test. + * gcc.dg/bic-bitmask-14.c: New test. + * gcc.dg/bic-bitmask-15.c: New test. + * gcc.dg/bic-bitmask-16.c: New test. + * gcc.dg/bic-bitmask-17.c: New test. + * gcc.dg/bic-bitmask-18.c: New test. + * gcc.dg/bic-bitmask-19.c: New test. + * gcc.dg/bic-bitmask-2.c: New test. + * gcc.dg/bic-bitmask-20.c: New test. + * gcc.dg/bic-bitmask-21.c: New test. + * gcc.dg/bic-bitmask-22.c: New test. + * gcc.dg/bic-bitmask-23.c: New test. + * gcc.dg/bic-bitmask-3.c: New test. + * gcc.dg/bic-bitmask-4.c: New test. + * gcc.dg/bic-bitmask-5.c: New test. + * gcc.dg/bic-bitmask-6.c: New test. + * gcc.dg/bic-bitmask-7.c: New test. + * gcc.dg/bic-bitmask-8.c: New test. + * gcc.dg/bic-bitmask-9.c: New test. + * gcc.dg/bic-bitmask.h: New test. + * gcc.target/aarch64/bic-bitmask-1.c: New test. + +2021-11-24 Marek Polacek + + PR c++/103347 + * g++.dg/cpp0x/nsdmi-warn1.C: New test. + * g++.dg/cpp0x/nsdmi-warn1.h: New file. + +2021-11-24 Hongtao Liu + H.J. Lu + + * gcc.target/i386/pr103194-2.c: New test. + * gcc.target/i386/pr103194-3.c: New test. + * gcc.target/i386/pr103194-4.c: New test. + * gcc.target/i386/pr103194-5.c: New test. + * gcc.target/i386/pr103194.c: New test. + 2021-11-23 Martin Sebor PR c++/96507 -- cgit v1.1 From f88e50780137503365192011b261498b06c75930 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 24 Nov 2021 20:16:13 -0800 Subject: pr103194-5.c: Replace long with int64_t Replace long with int64_t to work with -mx32. * gcc.target/i386/pr103194-5.c: Include . Replace long with int64_t. --- gcc/testsuite/gcc.target/i386/pr103194-5.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/pr103194-5.c b/gcc/testsuite/gcc.target/i386/pr103194-5.c index dfaddf0..2e33528 100644 --- a/gcc/testsuite/gcc.target/i386/pr103194-5.c +++ b/gcc/testsuite/gcc.target/i386/pr103194-5.c @@ -2,6 +2,7 @@ /* { dg-options "-O2" } */ #include #include +#include #define FOO(RTYPE,TYPE) \ __attribute__((noinline,noclone)) RTYPE \ @@ -53,7 +54,7 @@ return __sync_fetch_and_and (a, ~mask) & mask; \ } \ -FOO(int, long); +FOO(int, int64_t); /* { dg-final { scan-assembler-times "lock;?\[ \t\]*bts" 2 } } */ /* { dg-final { scan-assembler-times "lock;?\[ \t\]*btc" 4 } } */ -- cgit v1.1 From b38c9cf6d570f6c4c1109e00c8b81d82d0f24df3 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 25 Nov 2021 08:36:20 +0100 Subject: c++: Implement C++23 P2128R6 - Multidimensional subscript operator [PR102611] The following patch implements the C++23 Multidimensional subscript operator P2128R6 paper. As C++20 and older only allow a single expression in between []s (albeit for C++20 with a deprecation warning if it is a comma expression) and even in C++23 and for the coming years I think the vast majority of subscript expressions will still have a single expression and even in C++23 it is quite special, as e.g. the builtin operator requires exactly one assignment expression, the patch attempts to optimize for that case and if possible not to slow down that common case (or use more memory for it). So, already during parsing it differentiates between that (uses a single index_exp tree in that case) and the new cases (zero or two+ expressions in the list), for which it sets index_exp to NULL_TREE and uses a releasing_vec instead similarly to how e.g. finish_call_expr uses it. In call.c it introduces new functions build_op_subscript{,_1} which are something in between build_new_op{,_1} and build_op_call{,_1}. The former requires fixed number of arguments (and the patch still uses it for the common case of subscript with exactly one index expression), the latter handles variable number of arguments but is too CALL_EXPR specific and handles various cases that are unnecessary for the subscript. Right now the subscript for 0 or 2+ expressions doesn't need to deal with builtin candidates and so is quite simple. As discussed in the paper, for backwards compatibility, if for 2+ index expressions build_op_subscript fails (called with tf_none) and the expressions together form a valid comma expression (again checked with tf_none), it is used that C++20-ish way with a pedwarn about it, but if even that fails, build_op_subscript is called again with standard complain flags to diagnose it in the new way. And similarly for the builtin case. The -Wcomma-subscript warning used to be enabled by default unless -Wno-deprecated. Since the C/C++98..20 behavior is no longer deprecated, but ill-formed or changed meaning, it is now for C++23 enabled by default regardless of -Wno-deprecated and controls the pedwarn (but not the errors emitted if something wasn't valid before and isn't valid in C++23 either). 2021-11-25 Jakub Jelinek PR c++/102611 gcc/ * doc/invoke.texi (-Wcomma-subscript): Document that for -std=c++20 the option isn't enabled by default with -Wno-deprecated but for -std=c++23 it is. gcc/c-family/ * c-opts.c (c_common_post_options): Enable -Wcomma-subscript by default for C++23 regardless of warn_deprecated. * c-cppbuiltin.c (c_cpp_builtins): Predefine __cpp_multidimensional_subscript=202110L for C++23. gcc/cp/ * cp-tree.h (build_op_subscript): Implement P2128R6 - Multidimensional subscript operator. Declare. (class releasing_vec): Add release method. (grok_array_decl): Remove bool argument, add vec ** and tsubst_flags_t arguments. (build_min_non_dep_op_overload): Declare another overload. * parser.c (cp_parser_parenthesized_expression_list_elt): New function. (cp_parser_postfix_open_square_expression): Mention C++23 syntax in function comment. For C++23 parse zero or more than one initializer clauses in expression list, adjust grok_array_decl caller. (cp_parser_parenthesized_expression_list): Use cp_parser_parenthesized_expression_list_elt. (cp_parser_builtin_offsetof): Adjust grok_array_decl caller. * decl.c (grok_op_properties): For C++23 don't check number of arguments of operator[]. * decl2.c (grok_array_decl): Remove decltype_p argument, add index_exp_list and complain arguments. If index_exp is NULL, handle *index_exp_list as the subscript expression list. * tree.c (build_min_non_dep_op_overload): New overload. * call.c (add_operator_candidates, build_over_call): Adjust comments for removal of build_new_op_1. (build_op_subscript): New function. * pt.c (tsubst_copy_and_build_call_args): New function. (tsubst_copy_and_build) : If second operand is magic CALL_EXPR with ovl_op_identifier (ARRAY_REF) as CALL_EXPR_FN, tsubst CALL_EXPR arguments including expanding pack expressions in it and call grok_array_decl instead of build_x_array_ref. : Use tsubst_copy_and_build_call_args. * semantics.c (handle_omp_array_sections_1): Adjust grok_array_decl caller. gcc/testsuite/ * g++.dg/cpp2a/comma1.C: Expect different diagnostics for C++23. * g++.dg/cpp2a/comma3.C: Likewise. * g++.dg/cpp2a/comma4.C: Expect diagnostics for C++23. * g++.dg/cpp2a/comma5.C: Expect different diagnostics for C++23. * g++.dg/cpp23/feat-cxx2b.C: Test __cpp_multidimensional_subscript predefined macro. * g++.dg/cpp23/subscript1.C: New test. * g++.dg/cpp23/subscript2.C: New test. * g++.dg/cpp23/subscript3.C: New test. * g++.dg/cpp23/subscript4.C: New test. * g++.dg/cpp23/subscript5.C: New test. * g++.dg/cpp23/subscript6.C: New test. --- gcc/c-family/c-cppbuiltin.c | 1 + gcc/c-family/c-opts.c | 3 +- gcc/cp/call.c | 115 ++++++++++++++++++++++++- gcc/cp/cp-tree.h | 12 ++- gcc/cp/decl.c | 2 + gcc/cp/decl2.c | 125 +++++++++++++++++++++++---- gcc/cp/parser.c | 147 +++++++++++++++++++++++--------- gcc/cp/pt.c | 101 +++++++++++++++------- gcc/cp/semantics.c | 3 +- gcc/cp/tree.c | 31 ++++++- gcc/doc/invoke.texi | 16 +++- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C | 6 ++ gcc/testsuite/g++.dg/cpp23/subscript1.C | 55 ++++++++++++ gcc/testsuite/g++.dg/cpp23/subscript2.C | 51 +++++++++++ gcc/testsuite/g++.dg/cpp23/subscript3.C | 90 +++++++++++++++++++ gcc/testsuite/g++.dg/cpp23/subscript4.C | 44 ++++++++++ gcc/testsuite/g++.dg/cpp23/subscript5.C | 28 ++++++ gcc/testsuite/g++.dg/cpp23/subscript6.C | 31 +++++++ gcc/testsuite/g++.dg/cpp2a/comma1.C | 15 ++-- gcc/testsuite/g++.dg/cpp2a/comma3.C | 15 ++-- gcc/testsuite/g++.dg/cpp2a/comma4.C | 5 ++ gcc/testsuite/g++.dg/cpp2a/comma5.C | 18 ++-- 22 files changed, 796 insertions(+), 118 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp23/subscript1.C create mode 100644 gcc/testsuite/g++.dg/cpp23/subscript2.C create mode 100644 gcc/testsuite/g++.dg/cpp23/subscript3.C create mode 100644 gcc/testsuite/g++.dg/cpp23/subscript4.C create mode 100644 gcc/testsuite/g++.dg/cpp23/subscript5.C create mode 100644 gcc/testsuite/g++.dg/cpp23/subscript6.C (limited to 'gcc') diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index eb34d5a..feb7e61 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -1073,6 +1073,7 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_size_t_suffix=202011L"); cpp_define (pfile, "__cpp_if_consteval=202106L"); cpp_define (pfile, "__cpp_constexpr=202110L"); + cpp_define (pfile, "__cpp_multidimensional_subscript=202110L"); } if (flag_concepts) { diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 62f5829..2030eb1 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -946,7 +946,8 @@ c_common_post_options (const char **pfilename) /* -Wcomma-subscript is enabled by default in C++20. */ SET_OPTION_IF_UNSET (&global_options, &global_options_set, warn_comma_subscript, - cxx_dialect >= cxx20 && warn_deprecated); + cxx_dialect >= cxx23 + || (cxx_dialect == cxx20 && warn_deprecated)); /* -Wvolatile is enabled by default in C++20. */ SET_OPTION_IF_UNSET (&global_options, &global_options_set, warn_volatile, diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 27f4d9e..28bd8e0c 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -6283,7 +6283,7 @@ op_is_ordered (tree_code code) } } -/* Subroutine of build_new_op_1: Add to CANDIDATES all candidates for the +/* Subroutine of build_new_op: Add to CANDIDATES all candidates for the operator indicated by CODE/CODE2. This function calls itself recursively to handle C++20 rewritten comparison operator candidates. */ @@ -6932,6 +6932,117 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags, return NULL_TREE; } +/* Build a new call to operator[]. This may change ARGS. */ + +tree +build_op_subscript (const op_location_t &loc, tree obj, + vec **args, tree *overload, + tsubst_flags_t complain) +{ + struct z_candidate *candidates = 0, *cand; + tree fns, first_mem_arg = NULL_TREE; + bool any_viable_p; + tree result = NULL_TREE; + void *p; + + auto_cond_timevar tv (TV_OVERLOAD); + + obj = mark_lvalue_use (obj); + + if (error_operand_p (obj)) + return error_mark_node; + + tree type = TREE_TYPE (obj); + + obj = prep_operand (obj); + + if (TYPE_BINFO (type)) + { + fns = lookup_fnfields (TYPE_BINFO (type), ovl_op_identifier (ARRAY_REF), + 1, complain); + if (fns == error_mark_node) + return error_mark_node; + } + else + fns = NULL_TREE; + + if (args != NULL && *args != NULL) + { + *args = resolve_args (*args, complain); + if (*args == NULL) + return error_mark_node; + } + + /* Get the high-water mark for the CONVERSION_OBSTACK. */ + p = conversion_obstack_alloc (0); + + if (fns) + { + first_mem_arg = obj; + + add_candidates (BASELINK_FUNCTIONS (fns), + first_mem_arg, *args, NULL_TREE, + NULL_TREE, false, + BASELINK_BINFO (fns), BASELINK_ACCESS_BINFO (fns), + LOOKUP_NORMAL, &candidates, complain); + } + + /* Be strict here because if we choose a bad conversion candidate, the + errors we get won't mention the call context. */ + candidates = splice_viable (candidates, true, &any_viable_p); + if (!any_viable_p) + { + if (complain & tf_error) + { + auto_diagnostic_group d; + error ("no match for call to %<%T::operator[] (%A)%>", + TREE_TYPE (obj), build_tree_list_vec (*args)); + print_z_candidates (loc, candidates); + } + result = error_mark_node; + } + else + { + cand = tourney (candidates, complain); + if (cand == 0) + { + if (complain & tf_error) + { + auto_diagnostic_group d; + error ("call of %<%T::operator[] (%A)%> is ambiguous", + TREE_TYPE (obj), build_tree_list_vec (*args)); + print_z_candidates (loc, candidates); + } + result = error_mark_node; + } + else if (TREE_CODE (cand->fn) == FUNCTION_DECL + && DECL_OVERLOADED_OPERATOR_P (cand->fn) + && DECL_OVERLOADED_OPERATOR_IS (cand->fn, ARRAY_REF)) + { + if (overload) + *overload = cand->fn; + result = build_over_call (cand, LOOKUP_NORMAL, complain); + if (trivial_fn_p (cand->fn) || DECL_IMMEDIATE_FUNCTION_P (cand->fn)) + /* There won't be a CALL_EXPR. */; + else if (result && result != error_mark_node) + { + tree call = extract_call_expr (result); + CALL_EXPR_OPERATOR_SYNTAX (call) = true; + + /* Specify evaluation order as per P0145R2. */ + CALL_EXPR_ORDERED_ARGS (call) = op_is_ordered (ARRAY_REF) == 1; + } + } + else + gcc_unreachable (); + } + + /* Free all the conversions we allocated. */ + obstack_free (&conversion_obstack, p); + + return result; +} + /* CALL was returned by some call-building function; extract the actual CALL_EXPR from any bits that have been tacked on, e.g. by convert_from_reference. */ @@ -9748,7 +9859,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) if (cand->flags & LOOKUP_LIST_INIT_CTOR) { tree c = extract_call_expr (call); - /* build_new_op_1 will clear this when appropriate. */ + /* build_new_op will clear this when appropriate. */ CALL_EXPR_ORDERED_ARGS (c) = true; } if (warned_p) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2037082..4779969 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1007,7 +1007,9 @@ public: (bootstrap/91828). */ tree& operator[] (ptrdiff_t i) const { return (*v)[i]; } - ~releasing_vec() { release_tree_vector (v); } + void release () { release_tree_vector (v); v = NULL; } + + ~releasing_vec () { release_tree_vector (v); } private: vec_t *v; }; @@ -6471,6 +6473,9 @@ inline tree build_new_op (const op_location_t &loc, enum tree_code code, } extern tree build_op_call (tree, vec **, tsubst_flags_t); +extern tree build_op_subscript (const op_location_t &, tree, + vec **, tree *, + tsubst_flags_t); extern bool aligned_allocation_fn_p (tree); extern tree destroying_delete_p (tree); extern bool usual_deallocation_fn_p (tree); @@ -6813,7 +6818,8 @@ extern void maybe_make_one_only (tree); extern bool vague_linkage_p (tree); extern void grokclassfn (tree, tree, enum overload_flags); -extern tree grok_array_decl (location_t, tree, tree, bool); +extern tree grok_array_decl (location_t, tree, tree, + vec **, tsubst_flags_t); extern tree delete_sanity (location_t, tree, tree, bool, int, tsubst_flags_t); extern tree check_classfn (tree, tree, tree); @@ -7711,6 +7717,8 @@ extern tree build_min_nt_loc (location_t, enum tree_code, ...); extern tree build_min_non_dep (enum tree_code, tree, ...); extern tree build_min_non_dep_op_overload (enum tree_code, tree, tree, ...); +extern tree build_min_non_dep_op_overload (tree, tree, tree, + vec *); extern tree build_min_nt_call_vec (tree, vec *); extern tree build_min_non_dep_call_vec (tree, tree, vec *); extern vec* vec_copy_and_insert (vec*, tree, unsigned); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 588094b..56f8077 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -15140,6 +15140,8 @@ grok_op_properties (tree decl, bool complain) case OVL_OP_FLAG_BINARY: if (arity != 2) { + if (operator_code == ARRAY_REF && cxx_dialect >= cxx23) + break; error_at (loc, methodp ? G_("%qD must have exactly one argument") diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 32d3fe3..99f5dc7 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -363,16 +363,20 @@ grokclassfn (tree ctype, tree function, enum overload_flags flags) } /* Create an ARRAY_REF, checking for the user doing things backwards - along the way. DECLTYPE_P is for N3276, as in the parser. */ + along the way. + If INDEX_EXP is non-NULL, then that is the index expression, + otherwise INDEX_EXP_LIST is the list of index expressions. */ tree grok_array_decl (location_t loc, tree array_expr, tree index_exp, - bool decltype_p) + vec **index_exp_list, tsubst_flags_t complain) { tree type; tree expr; tree orig_array_expr = array_expr; tree orig_index_exp = index_exp; + vec *orig_index_exp_list + = index_exp_list ? *index_exp_list : NULL; tree overload = NULL_TREE; if (error_operand_p (array_expr) || error_operand_p (index_exp)) @@ -381,11 +385,23 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp, if (processing_template_decl) { if (type_dependent_expression_p (array_expr) - || type_dependent_expression_p (index_exp)) - return build_min_nt_loc (loc, ARRAY_REF, array_expr, index_exp, - NULL_TREE, NULL_TREE); + || (index_exp ? type_dependent_expression_p (index_exp) + : any_type_dependent_arguments_p (*index_exp_list))) + { + if (index_exp == NULL) + index_exp = build_min_nt_call_vec (ovl_op_identifier (ARRAY_REF), + *index_exp_list); + return build_min_nt_loc (loc, ARRAY_REF, array_expr, index_exp, + NULL_TREE, NULL_TREE); + } array_expr = build_non_dependent_expr (array_expr); - index_exp = build_non_dependent_expr (index_exp); + if (index_exp) + index_exp = build_non_dependent_expr (index_exp); + else + { + orig_index_exp_list = make_tree_vector_copy (*index_exp_list); + make_args_non_dependent (*index_exp_list); + } } type = TREE_TYPE (array_expr); @@ -393,13 +409,44 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp, type = non_reference (type); /* If they have an `operator[]', use that. */ - if (MAYBE_CLASS_TYPE_P (type) || MAYBE_CLASS_TYPE_P (TREE_TYPE (index_exp))) - { - tsubst_flags_t complain = tf_warning_or_error; - if (decltype_p) - complain |= tf_decltype; - expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, array_expr, - index_exp, NULL_TREE, &overload, complain); + if (MAYBE_CLASS_TYPE_P (type) + || (index_exp && MAYBE_CLASS_TYPE_P (TREE_TYPE (index_exp))) + || (index_exp == NULL_TREE + && !(*index_exp_list)->is_empty () + && MAYBE_CLASS_TYPE_P (TREE_TYPE ((*index_exp_list)->last ())))) + { + if (index_exp) + expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, array_expr, + index_exp, NULL_TREE, &overload, complain); + else if ((*index_exp_list)->is_empty ()) + expr = build_op_subscript (loc, array_expr, index_exp_list, &overload, + complain); + else + { + expr = build_op_subscript (loc, array_expr, index_exp_list, + &overload, complain & tf_decltype); + if (expr == error_mark_node) + { + tree idx = build_x_compound_expr_from_vec (*index_exp_list, NULL, + tf_none); + if (idx != error_mark_node) + expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, array_expr, + idx, NULL_TREE, &overload, + complain & tf_decltype); + if (expr == error_mark_node) + { + overload = NULL_TREE; + expr = build_op_subscript (loc, array_expr, index_exp_list, + &overload, complain); + } + else + /* If it would be valid albeit deprecated expression in C++20, + just pedwarn on it and treat it as if wrapped in (). */ + pedwarn (loc, OPT_Wcomma_subscript, + "top-level comma expression in array subscript " + "changed meaning in C++23"); + } + } } else { @@ -415,6 +462,31 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp, else p1 = build_expr_type_conversion (WANT_POINTER, array_expr, false); + if (index_exp == NULL_TREE) + { + if ((*index_exp_list)->is_empty ()) + { + error_at (loc, "built-in subscript operator without expression " + "list"); + return error_mark_node; + } + tree idx = build_x_compound_expr_from_vec (*index_exp_list, NULL, + tf_none); + if (idx != error_mark_node) + /* If it would be valid albeit deprecated expression in C++20, + just pedwarn on it and treat it as if wrapped in (). */ + pedwarn (loc, OPT_Wcomma_subscript, + "top-level comma expression in array subscript " + "changed meaning in C++23"); + else + { + error_at (loc, "built-in subscript operator with more than one " + "expression in expression list"); + return error_mark_node; + } + index_exp = idx; + } + if (TREE_CODE (TREE_TYPE (index_exp)) == ARRAY_TYPE) p2 = index_exp; else @@ -457,11 +529,30 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp, if (processing_template_decl && expr != error_mark_node) { if (overload != NULL_TREE) - return (build_min_non_dep_op_overload - (ARRAY_REF, expr, overload, orig_array_expr, orig_index_exp)); + { + if (orig_index_exp == NULL_TREE) + { + expr = build_min_non_dep_op_overload (expr, overload, + orig_array_expr, + orig_index_exp_list); + release_tree_vector (orig_index_exp_list); + return expr; + } + return build_min_non_dep_op_overload (ARRAY_REF, expr, overload, + orig_array_expr, + orig_index_exp); + } + + if (orig_index_exp == NULL_TREE) + { + orig_index_exp + = build_min_nt_call_vec (ovl_op_identifier (ARRAY_REF), + orig_index_exp_list); + release_tree_vector (orig_index_exp_list); + } - return build_min_non_dep (ARRAY_REF, expr, orig_array_expr, orig_index_exp, - NULL_TREE, NULL_TREE); + return build_min_non_dep (ARRAY_REF, expr, orig_array_expr, + orig_index_exp, NULL_TREE, NULL_TREE); } return expr; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7a6a302..0bd5852 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7898,11 +7898,62 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, return error_mark_node; } +/* Helper function for cp_parser_parenthesized_expression_list and + cp_parser_postfix_open_square_expression. Parse a single element + of parenthesized expression list. */ + +static cp_expr +cp_parser_parenthesized_expression_list_elt (cp_parser *parser, bool cast_p, + bool allow_expansion_p, + bool fold_expr_p, + bool *non_constant_p) +{ + cp_expr expr (NULL_TREE); + bool expr_non_constant_p; + + /* Parse the next assignment-expression. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + /* A braced-init-list. */ + cp_lexer_set_source_position (parser->lexer); + maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); + expr = cp_parser_braced_list (parser, &expr_non_constant_p); + if (non_constant_p && expr_non_constant_p) + *non_constant_p = true; + } + else if (non_constant_p) + { + expr = cp_parser_constant_expression (parser, + /*allow_non_constant_p=*/true, + &expr_non_constant_p); + if (expr_non_constant_p) + *non_constant_p = true; + } + else + expr = cp_parser_assignment_expression (parser, /*pidk=*/NULL, cast_p); + + if (fold_expr_p) + expr = instantiate_non_dependent_expr (expr); + + /* If we have an ellipsis, then this is an expression expansion. */ + if (allow_expansion_p + && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) + { + /* Consume the `...'. */ + cp_lexer_consume_token (parser->lexer); + + /* Build the argument pack. */ + expr = make_pack_expansion (expr); + } + return expr; +} + /* A subroutine of cp_parser_postfix_expression that also gets hijacked by cp_parser_builtin_offsetof. We're looking for postfix-expression [ expression ] postfix-expression [ braced-init-list ] (C++11) + postfix-expression [ expression-list[opt] ] (C++23) FOR_OFFSETOF is set if we're being called in that context, which changes how we deal with integer constant expressions. */ @@ -7914,6 +7965,7 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, bool decltype_p) { tree index = NULL_TREE; + releasing_vec expression_list = NULL; location_t loc = cp_lexer_peek_token (parser->lexer)->location; bool saved_greater_than_is_operator_p; @@ -7935,7 +7987,49 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, index = cp_parser_constant_expression (parser); else { - if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + if (cxx_dialect >= cxx23 + && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) + *&expression_list = make_tree_vector (); + else if (cxx_dialect >= cxx23) + { + while (true) + { + cp_expr expr + = cp_parser_parenthesized_expression_list_elt (parser, + /*cast_p=*/ + false, + /*allow_exp_p=*/ + true, + /*fold_expr_p=*/ + false, + /*non_cst_p=*/ + NULL); + + if (expr == error_mark_node) + index = error_mark_node; + else if (expression_list.get () == NULL + && !PACK_EXPANSION_P (expr.get_value ())) + index = expr.get_value (); + else + vec_safe_push (expression_list, expr.get_value ()); + + /* If the next token isn't a `,', then we are done. */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + + if (expression_list.get () == NULL && index != error_mark_node) + { + *&expression_list = make_tree_vector_single (index); + index = NULL_TREE; + } + + /* Otherwise, consume the `,' and keep going. */ + cp_lexer_consume_token (parser->lexer); + } + if (expression_list.get () && index == error_mark_node) + expression_list.release (); + } + else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { bool expr_nonconst_p; cp_lexer_set_source_position (parser->lexer); @@ -7955,7 +8049,9 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, /* Build the ARRAY_REF. */ postfix_expression = grok_array_decl (loc, postfix_expression, - index, decltype_p); + index, &expression_list, + tf_warning_or_error + | (decltype_p ? tf_decltype : 0)); /* When not doing offsetof, array references are not permitted in constant-expressions. */ @@ -8315,44 +8411,11 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, } else { - bool expr_non_constant_p; - - /* Parse the next assignment-expression. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) - { - /* A braced-init-list. */ - cp_lexer_set_source_position (parser->lexer); - maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); - expr = cp_parser_braced_list (parser, &expr_non_constant_p); - if (non_constant_p && expr_non_constant_p) - *non_constant_p = true; - } - else if (non_constant_p) - { - expr = (cp_parser_constant_expression - (parser, /*allow_non_constant_p=*/true, - &expr_non_constant_p)); - if (expr_non_constant_p) - *non_constant_p = true; - } - else - expr = cp_parser_assignment_expression (parser, /*pidk=*/NULL, - cast_p); - - if (fold_expr_p) - expr = instantiate_non_dependent_expr (expr); - - /* If we have an ellipsis, then this is an expression - expansion. */ - if (allow_expansion_p - && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)) - { - /* Consume the `...'. */ - cp_lexer_consume_token (parser->lexer); - - /* Build the argument pack. */ - expr = make_pack_expansion (expr); - } + expr + = cp_parser_parenthesized_expression_list_elt (parser, cast_p, + allow_expansion_p, + fold_expr_p, + non_constant_p); if (wrap_locations_p) expr.maybe_add_location_wrapper (); @@ -10625,8 +10688,8 @@ cp_parser_builtin_offsetof (cp_parser *parser) case CPP_DEREF: /* offsetof-member-designator "->" identifier */ - expr = grok_array_decl (token->location, expr, - integer_zero_node, false); + expr = grok_array_decl (token->location, expr, integer_zero_node, + NULL, tf_warning_or_error); /* FALLTHRU */ case CPP_DOT: diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 288625e..49e5745 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -19654,6 +19654,49 @@ maybe_fold_fn_template_args (tree fn, tsubst_flags_t complain) return fold_targs_r (targs, complain); } +/* Helper function for tsubst_copy_and_build CALL_EXPR and ARRAY_REF + handling. */ + +static void +tsubst_copy_and_build_call_args (tree t, tree args, tsubst_flags_t complain, + tree in_decl, + bool integral_constant_expression_p, + releasing_vec &call_args) +{ + unsigned int nargs = call_expr_nargs (t); + for (unsigned int i = 0; i < nargs; ++i) + { + tree arg = CALL_EXPR_ARG (t, i); + + if (!PACK_EXPANSION_P (arg)) + vec_safe_push (call_args, + tsubst_copy_and_build (arg, args, complain, in_decl, + /*function_p=*/false, + integral_constant_expression_p)); + else + { + /* Expand the pack expansion and push each entry onto CALL_ARGS. */ + arg = tsubst_pack_expansion (arg, args, complain, in_decl); + if (TREE_CODE (arg) == TREE_VEC) + { + unsigned int len, j; + + len = TREE_VEC_LENGTH (arg); + for (j = 0; j < len; ++j) + { + tree value = TREE_VEC_ELT (arg, j); + if (value != NULL_TREE) + value = convert_from_reference (value); + vec_safe_push (call_args, value); + } + } + else + /* A partial substitution. Add one entry. */ + vec_safe_push (call_args, arg); + } + } +} + /* Like tsubst but deals with expressions and performs semantic analysis. FUNCTION_P is true if T is the "F" in "F (ARGS)" or "F (ARGS)". */ @@ -20053,6 +20096,28 @@ tsubst_copy_and_build (tree t, case ARRAY_REF: op1 = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0), args, complain, in_decl); + if (TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR + && (CALL_EXPR_FN (TREE_OPERAND (t, 1)) + == ovl_op_identifier (ARRAY_REF))) + { + tree c = TREE_OPERAND (t, 1); + releasing_vec index_exp_list; + tsubst_copy_and_build_call_args (c, args, complain, in_decl, + integral_constant_expression_p, + index_exp_list); + + tree r; + if (vec_safe_length (index_exp_list) == 1 + && !PACK_EXPANSION_P (index_exp_list[0])) + r = grok_array_decl (EXPR_LOCATION (t), op1, + index_exp_list[0], NULL, + complain | decltype_flag); + else + r = grok_array_decl (EXPR_LOCATION (t), op1, + NULL_TREE, &index_exp_list, + complain | decltype_flag); + RETURN (r); + } RETURN (build_x_array_ref (EXPR_LOCATION (t), op1, RECUR (TREE_OPERAND (t, 1)), complain|decltype_flag)); @@ -20261,7 +20326,7 @@ tsubst_copy_and_build (tree t, case CALL_EXPR: { tree function; - unsigned int nargs, i; + unsigned int nargs; bool qualified_p; bool koenig_p; tree ret; @@ -20344,37 +20409,9 @@ tsubst_copy_and_build (tree t, nargs = call_expr_nargs (t); releasing_vec call_args; - for (i = 0; i < nargs; ++i) - { - tree arg = CALL_EXPR_ARG (t, i); - - if (!PACK_EXPANSION_P (arg)) - vec_safe_push (call_args, RECUR (CALL_EXPR_ARG (t, i))); - else - { - /* Expand the pack expansion and push each entry onto - CALL_ARGS. */ - arg = tsubst_pack_expansion (arg, args, complain, in_decl); - if (TREE_CODE (arg) == TREE_VEC) - { - unsigned int len, j; - - len = TREE_VEC_LENGTH (arg); - for (j = 0; j < len; ++j) - { - tree value = TREE_VEC_ELT (arg, j); - if (value != NULL_TREE) - value = convert_from_reference (value); - vec_safe_push (call_args, value); - } - } - else - { - /* A partial substitution. Add one entry. */ - vec_safe_push (call_args, arg); - } - } - } + tsubst_copy_and_build_call_args (t, args, complain, in_decl, + integral_constant_expression_p, + call_args); /* Stripped-down processing for a call in a thunk. Specifically, in the thunk template for a generic lambda. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 79b8162..cd19564 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5394,7 +5394,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION); - ret = grok_array_decl (OMP_CLAUSE_LOCATION (c), ret, low_bound, false); + ret = grok_array_decl (OMP_CLAUSE_LOCATION (c), ret, low_bound, NULL, + tf_warning_or_error); return ret; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 7050a53..7c58e23 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3671,7 +3671,7 @@ build_min_non_dep_op_overload (enum tree_code op, } } else - gcc_unreachable (); + gcc_unreachable (); va_end (p); call = build_min_non_dep_call_vec (non_dep, fn, args); @@ -3685,6 +3685,35 @@ build_min_non_dep_op_overload (enum tree_code op, return call; } +/* Similar to above build_min_non_dep_op_overload, but arguments + are taken from ARGS vector. */ + +tree +build_min_non_dep_op_overload (tree non_dep, tree overload, tree object, + vec *args) +{ + non_dep = extract_call_expr (non_dep); + + unsigned int nargs = call_expr_nargs (non_dep); + gcc_assert (TREE_CODE (TREE_TYPE (overload)) == METHOD_TYPE); + tree binfo = TYPE_BINFO (TREE_TYPE (object)); + tree method = build_baselink (binfo, binfo, overload, NULL_TREE); + tree fn = build_min (COMPONENT_REF, TREE_TYPE (overload), + object, method, NULL_TREE); + nargs--; + gcc_assert (vec_safe_length (args) == nargs); + + tree call = build_min_non_dep_call_vec (non_dep, fn, args); + + tree call_expr = extract_call_expr (call); + KOENIG_LOOKUP_P (call_expr) = KOENIG_LOOKUP_P (non_dep); + CALL_EXPR_OPERATOR_SYNTAX (call_expr) = true; + CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (non_dep); + CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (non_dep); + + return call; +} + /* Return a new tree vec copied from VEC, with ELT inserted at index IDX. */ vec * diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 36fe96b..d0ac597 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -3479,19 +3479,27 @@ about ABI tags. @opindex Wcomma-subscript @opindex Wno-comma-subscript Warn about uses of a comma expression within a subscripting expression. -This usage was deprecated in C++20. However, a comma expression wrapped -in @code{( )} is not deprecated. Example: +This usage was deprecated in C++20 and is going to be removed in C++23. +However, a comma expression wrapped in @code{( )} is not deprecated. Example: @smallexample @group void f(int *a, int b, int c) @{ - a[b,c]; // deprecated + a[b,c]; // deprecated in C++20, invalid in C++23 a[(b,c)]; // OK @} @end group @end smallexample -Enabled by default with @option{-std=c++20}. +In C++23 it is valid to have comma separated expressions in a subscript +when an overloaded subscript operator is found and supports the right +number and types of arguments. G++ will accept the formerly valid syntax +for code that is not valid in C++23 but used to be valid but deprecated +in C++20 with a pedantic warning that can be disabled with +@option{-Wno-comma-subscript}. + +Enabled by default with @option{-std=c++20} unless @option{-Wno-deprecated}, +and with @option{-std=c++23} regardless of @option{-Wno-deprecated}. @item -Wctad-maybe-unsupported @r{(C++ and Objective-C++ only)} @opindex Wctad-maybe-unsupported diff --git a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C index 8bb3bf1..923e6bcf 100644 --- a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C +++ b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C @@ -551,3 +551,9 @@ #elif __cpp_if_consteval != 202106 # error "__cpp_if_consteval != 202106" #endif + +#ifndef __cpp_multidimensional_subscript +# error "__cpp_multidimensional_subscript" +#elif __cpp_multidimensional_subscript != 202110 +# error "__cpp_multidimensional_subscript != 202110" +#endif diff --git a/gcc/testsuite/g++.dg/cpp23/subscript1.C b/gcc/testsuite/g++.dg/cpp23/subscript1.C new file mode 100644 index 0000000..a96c93e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/subscript1.C @@ -0,0 +1,55 @@ +// P2128R6 +// { dg-do run } +// { dg-options "-std=c++23" } + +extern "C" void abort (); + +struct S +{ + constexpr S () : a {} {}; + constexpr S (int x, int y, int z) : a {x, y, z} {}; + constexpr int &operator[] () { return a[0]; } + constexpr int &operator[] (int x) { return a[x]; } + constexpr int &operator[] (int x, long y) { return a[x + y * 8]; } + int a[64]; +}; + +struct T +{ + operator int () { return 42; }; +}; + +int buf[64]; + +struct U +{ + operator int * () { return buf; } +}; + +static_assert (S ()[1] == 0); +static_assert (S (1, 2, 42)[2] == 42); +static_assert (S ()[3, 4] == 0); +static_assert (S (1, 43, 2)[1, 0] == 43); +static_assert (S ()[] == 0); +static_assert (S (44, 1, 2)[] == 44); + +int +main () +{ + S s; + for (int i = 0; i < 64; i++) + s.a[i] = 64 - i; + if (s[] != 64 || s[3] != 61 || s[4, 5] != 20) + abort (); + s[]++; + s[42]++; + ++s[3, 2]; + if (s.a[0] != 65 || s.a[42] != 23 || s.a[19] != 46) + abort (); + T t; + U u; + if (&u[t] != &buf[42]) + abort (); + if (&t[u] != &buf[42]) + abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/subscript2.C b/gcc/testsuite/g++.dg/cpp23/subscript2.C new file mode 100644 index 0000000..f8ec87d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/subscript2.C @@ -0,0 +1,51 @@ +// P2128R6 +// { dg-do compile } +// { dg-options "-std=c++23" } + +struct S +{ + S () : a {} {}; + int &operator[] () { return a[0]; } + int &operator[] (int x) { return a[x]; } + int &operator[] (int x, long y) { return a[x + y * 8]; } + int a[64]; +}; + +struct T +{ + operator int () { return 42; }; +}; + +int buf[64]; + +struct U +{ + operator int * () { return buf; } +}; + +struct V +{ + V () : a {} {}; + V (int x, int y, int z) : a {x, y, z} {}; + int &operator[] () { return a[0]; } // { dg-message "candidate" } + int &operator[] (int x, long y) { return a[x + y * 8]; } // { dg-message "candidate" } + int a[64]; +}; + +void +foo () +{ + S s; + T t; + U u; + V v; + auto &a = buf[]; // { dg-error "built-in subscript operator without expression list" } + auto &b = buf[1, 2]; // { dg-warning "top-level comma expression in array subscript changed meaning in" } + auto &c = s[1, 2, 3]; // { dg-warning "top-level comma expression in array subscript changed meaning in" } + auto &d = v[1]; // { dg-error "no match for 'operator\\\[\\\]' in 'v\\\[1\\\]' \\\(operand types are 'V' and 'int'\\\)" } + auto &e = v[1, 2, 3]; // { dg-error "no match for call to 'V::operator\\\[\\\] \\\(int, int, int\\\)'" } + auto &f = t[42, u]; // { dg-warning "top-level comma expression in array subscript changed meaning in" } + auto &g = u[42, t]; // { dg-warning "top-level comma expression in array subscript changed meaning in" } + auto &h = buf[42, 2.5]; // { dg-warning "top-level comma expression in array subscript changed meaning in" } + // { dg-error "invalid types \[^\n\r]* for array subscript" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/g++.dg/cpp23/subscript3.C b/gcc/testsuite/g++.dg/cpp23/subscript3.C new file mode 100644 index 0000000..2d735e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/subscript3.C @@ -0,0 +1,90 @@ +// P2128R6 +// { dg-do run } +// { dg-options "-std=c++23" } + +extern "C" void abort (); + +struct S +{ + constexpr S () : a {} {}; + constexpr S (int x, int y, int z) : a {x, y, z} {}; + constexpr int &operator[] () { return a[0]; } + constexpr int &operator[] (int x) { return a[x]; } + constexpr int &operator[] (int x, long y) { return a[x + y * 8]; } + int a[64]; +}; + +struct T +{ + operator int () { return 42; }; +}; + +int buf[64]; + +struct U +{ + operator int * () { return buf; } +}; + +template +void +foo () +{ + static_assert (S ()[1] == 0); + static_assert (S (1, 2, 42)[2] == 42); + static_assert (S ()[3, 4] == 0); + static_assert (S (1, 43, 2)[1, 0] == 43); + static_assert (S ()[] == 0); + static_assert (S (44, 1, 2)[] == 44); + S s; + for (int i = 0; i < 64; i++) + s.a[i] = 64 - i; + if (s[] != 64 || s[3] != 61 || s[4, 5] != 20) + abort (); + s[]++; + s[42]++; + ++s[3, 2]; + if (s.a[0] != 65 || s.a[42] != 23 || s.a[19] != 46) + abort (); + T t; + U u; + if (&u[t] != &buf[42]) + abort (); + if (&t[u] != &buf[42]) + abort (); +} + +template +void +bar () +{ + static_assert (V ()[1] == 0); + static_assert (V (1, 2, 42)[2] == 42); + static_assert (V ()[3, 4] == 0); + static_assert (V (1, 43, 2)[1, 0] == 43); + static_assert (V ()[] == 0); + static_assert (V (44, 1, 2)[] == 44); + V s; + for (int i = 0; i < 64; i++) + s.a[i] = 64 - i; + if (s[] != 64 || s[3] != 61 || s[4, 5] != 20) + abort (); + s[]++; + s[42]++; + ++s[3, 2]; + if (s.a[0] != 65 || s.a[42] != 23 || s.a[19] != 46) + abort (); + W t; + X u; + if (&u[t] != &buf[42]) + abort (); + if (&t[u] != &buf[42]) + abort (); +} + +int +main () +{ + foo <0> (); + bar (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/subscript4.C b/gcc/testsuite/g++.dg/cpp23/subscript4.C new file mode 100644 index 0000000..085095d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/subscript4.C @@ -0,0 +1,44 @@ +// P2128R6 +// { dg-do run } +// { dg-options "-std=c++23" } + +extern "C" void abort (); + +struct S +{ + constexpr S () : a {} {}; + constexpr S (int x, int y, int z) : a {x, y, z} {}; + constexpr int &operator[] () { return a[0]; } + constexpr int &operator[] (int x) { return a[x]; } + constexpr int &operator[] (int x, long y) { return a[x + y * 8]; } + int a[64]; +}; +int buf[26]; + +template +auto & +foo (S &s, Ts... args) +{ + return s[args...]; +} + +template +auto & +bar (T &s, Ts... args) +{ + return s[args...]; +} + +int +main () +{ + S s; + if (&foo (s) != &s.a[0] + || &foo (s, 42) != &s.a[42] + || &foo (s, 5, 4) != &s.a[37] + || &bar (s) != &s.a[0] + || &bar (s, 22) != &s.a[22] + || &bar (s, 17, 3L) != &s.a[41] + || &bar (buf, 5) != &buf[5]) + abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/subscript5.C b/gcc/testsuite/g++.dg/cpp23/subscript5.C new file mode 100644 index 0000000..b36bc77 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/subscript5.C @@ -0,0 +1,28 @@ +// P2128R6 +// { dg-do run { target c++11 } } + +#include +#include + +struct S +{ + S () : a {} {}; + int &operator[] (std::initializer_list l) { + int sum = 0; + for (auto x : l) + sum += x; + return a[sum]; + } + int a[64]; +}; + +int +main () +{ + S s; + if (&s[{0}] != &s.a[0] + || &s[{42}] != &s.a[42] + || &s[{5, 7, 9}] != &s.a[5 + 7 + 9] + || &s[{1, 2, 3, 4}] != &s.a[1 + 2 + 3 + 4]) + abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/subscript6.C b/gcc/testsuite/g++.dg/cpp23/subscript6.C new file mode 100644 index 0000000..72c7aef --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/subscript6.C @@ -0,0 +1,31 @@ +// P2128R6 +// { dg-do run } +// { dg-options "-std=c++23" } + +#include +#include + +struct S +{ + S () : a {} {}; + int &operator[] (std::initializer_list l, std::initializer_list m) { + int sum = 0; + for (auto x : l) + sum += x; + for (auto x : m) + sum += x; + return a[sum]; + } + int a[64]; +}; + +int +main () +{ + S s; + if (&s[{0}, {3, 1, 2}] != &s.a[0 + 3 + 1 + 2] + || &s[{42}, {11, 1}] != &s.a[42 + 11 + 1] + || &s[{5, 7, 9}, {3}] != &s.a[5 + 7 + 9 + 3] + || &s[{1, 2, 3, 4}, {3, 5, 8}] != &s.a[1 + 2 + 3 + 4 + 3 + 5 + 8]) + abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/comma1.C b/gcc/testsuite/g++.dg/cpp2a/comma1.C index d9c140d..1799c18 100644 --- a/gcc/testsuite/g++.dg/cpp2a/comma1.C +++ b/gcc/testsuite/g++.dg/cpp2a/comma1.C @@ -8,19 +8,24 @@ struct S { void fn (int *a, int b, int c) { - a[b,c]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20 } } + a[b,c]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_only } } + // { dg-error "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[(b,c)]; - a[(void) b, c]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20 } } + a[(void) b, c]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_only } } + // { dg-error "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[((void) b, c)]; - a[(void) b, (void) c, (void) b, b]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20 } } + a[(void) b, (void) c, (void) b, b]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_only } } + // { dg-error "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[((void) b, (void) c, (void) b, b)]; - a[S(), 10]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20 } } + a[S(), 10]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_only } } + // { dg-error "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[(S(), 10)]; a[int{(1,2)}]; - a[int{(1,2)}, int{}]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20 } } + a[int{(1,2)}, int{}]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_only } } + // { dg-error "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[(int{(1,2)}, int{})]; } diff --git a/gcc/testsuite/g++.dg/cpp2a/comma3.C b/gcc/testsuite/g++.dg/cpp2a/comma3.C index c39dd4b..daf5359 100644 --- a/gcc/testsuite/g++.dg/cpp2a/comma3.C +++ b/gcc/testsuite/g++.dg/cpp2a/comma3.C @@ -9,19 +9,24 @@ struct S { void fn (int *a, int b, int c) { - a[b,c]; // { dg-warning "top-level comma expression in array subscript is deprecated" } + a[b,c]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_down } } + // { dg-warning "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[(b,c)]; - a[(void) b, c]; // { dg-warning "top-level comma expression in array subscript is deprecated" } + a[(void) b, c]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_down } } + // { dg-warning "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[((void) b, c)]; - a[(void) b, (void) c, (void) b, b]; // { dg-warning "top-level comma expression in array subscript is deprecated" } + a[(void) b, (void) c, (void) b, b]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_down } } + // { dg-warning "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[((void) b, (void) c, (void) b, b)]; - a[S(), 10]; // { dg-warning "top-level comma expression in array subscript is deprecated" } + a[S(), 10]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_down } } + // { dg-warning "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[(S(), 10)]; a[int{(1,2)}]; - a[int{(1,2)}, int{}]; // { dg-warning "top-level comma expression in array subscript is deprecated" } + a[int{(1,2)}, int{}]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_down } } + // { dg-warning "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[(int{(1,2)}, int{})]; } diff --git a/gcc/testsuite/g++.dg/cpp2a/comma4.C b/gcc/testsuite/g++.dg/cpp2a/comma4.C index 0d149c7..11aff99 100644 --- a/gcc/testsuite/g++.dg/cpp2a/comma4.C +++ b/gcc/testsuite/g++.dg/cpp2a/comma4.C @@ -10,18 +10,23 @@ void fn (int *a, int b, int c) { a[b,c]; // { dg-bogus "top-level comma expression in array subscript is deprecated" } + // { dg-warning "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[(b,c)]; a[(void) b, c]; // { dg-bogus "top-level comma expression in array subscript is deprecated" } + // { dg-warning "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[((void) b, c)]; a[(void) b, (void) c, (void) b, b]; // { dg-bogus "top-level comma expression in array subscript is deprecated" } + // { dg-warning "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[((void) b, (void) c, (void) b, b)]; a[S(), 10]; // { dg-bogus "top-level comma expression in array subscript is deprecated" } + // { dg-warning "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[(S(), 10)]; a[int{(1,2)}]; a[int{(1,2)}, int{}]; // { dg-bogus "top-level comma expression in array subscript is deprecated" } + // { dg-warning "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[(int{(1,2)}, int{})]; } diff --git a/gcc/testsuite/g++.dg/cpp2a/comma5.C b/gcc/testsuite/g++.dg/cpp2a/comma5.C index acf5d43..8bf94d1 100644 --- a/gcc/testsuite/g++.dg/cpp2a/comma5.C +++ b/gcc/testsuite/g++.dg/cpp2a/comma5.C @@ -8,14 +8,20 @@ void fn (int *a, int b, int c) { a[foo(1, 2)]; - a[foo(1, 2), foo(3, 4)]; // { dg-warning "24:top-level comma expression in array subscript is deprecated" } + a[foo(1, 2), foo(3, 4)]; // { dg-warning "24:top-level comma expression in array subscript is deprecated" "" { target c++20_down } } + // { dg-error "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } - a[b < c, b < c]; // { dg-warning "top-level comma expression in array subscript is deprecated" } - a[b < c, b > c]; // { dg-warning "top-level comma expression in array subscript is deprecated" } - a[b > c, b > c]; // { dg-warning "top-level comma expression in array subscript is deprecated" } - a[b > c, b < c]; // { dg-warning "top-level comma expression in array subscript is deprecated" } + a[b < c, b < c]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_down } } + // { dg-error "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } + a[b < c, b > c]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_down } } + // { dg-error "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } + a[b > c, b > c]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_down } } + // { dg-error "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } + a[b > c, b < c]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_down } } + // { dg-error "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[(b < c, b < c)]; a[(b < c, b > c)]; - a[b << c, b << c]; // { dg-warning "top-level comma expression in array subscript is deprecated" } + a[b << c, b << c]; // { dg-warning "top-level comma expression in array subscript is deprecated" "" { target c++20_down } } + // { dg-error "top-level comma expression in array subscript changed meaning in" "" { target c++23 } .-1 } a[(b << c, b << c)]; } -- cgit v1.1 From 8e86218f05c1a866b43ae5af3e303f91fb6d7ff0 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 25 Nov 2021 08:39:35 +0100 Subject: c++: Return early in apply_late_template_attributes if there are no late attribs [PR101180] The r12-299-ga0fdff3cf33f7284 change can result in cplus_decl_attributes being called even if there are no late attributes (but at least one early attribute) in apply_late_template_attributes. This patch fixes that, so that we return early if there are no late attrs, only arrange for TYPE_ATTRIBUTES to get the early attribute list. 2021-11-25 Jakub Jelinek PR c++/101180 * pt.c (apply_late_template_attributes): Return early if there are no dependent attributes. --- gcc/cp/pt.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gcc') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 49e5745..221628a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11712,6 +11712,9 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, /* Apply any non-dependent attributes. */ *p = nondep; + if (nondep == attributes) + return true; + /* And then any dependent ones. */ tree late_attrs = NULL_TREE; tree *q = &late_attrs; -- cgit v1.1 From 531dae29a67e915a145d908bd2f46d22bc369c11 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 25 Nov 2021 10:38:33 +0100 Subject: bswap: Improve perform_symbolic_merge [PR103376] Thinking more about it, perhaps we could do more for BIT_XOR_EXPR. We could allow masked1 == masked2 case for it, but would need to do something different than the n->n = n1->n | n2->n; we do on all the bytes together. In particular, for masked1 == masked2 if masked1 != 0 (well, for 0 both variants are the same) and masked1 != 0xff we would need to clear corresponding n->n byte instead of setting it to the input as x ^ x = 0 (but if we don't know what x and y are, the result is also don't know). Now, for plus it is much harder, because not only for non-zero operands we don't know what the result is, but it can modify upper bytes as well. So perhaps only if current's byte masked1 && masked2 set the resulting byte to 0xff (unknown) iff the byte above it is 0 and 0, and set that resulting byte to 0xff too. Also, even for | we could instead of return NULL just set the resulting byte to 0xff if it is different, perhaps it will be masked off later on. This patch just punts on plus if both corresponding bytes are non-zero, otherwise implements the above. 2021-11-25 Jakub Jelinek PR tree-optimization/103376 * gimple-ssa-store-merging.c (perform_symbolic_merge): For BIT_IOR_EXPR, if masked1 && masked2 && masked1 != masked2, don't punt, but set the corresponding result byte to MARKER_BYTE_UNKNOWN. For BIT_XOR_EXPR similarly and if masked1 == masked2 and the byte isn't MARKER_BYTE_UNKNOWN, set the corresponding result byte to 0. * gcc.dg/optimize-bswapsi-7.c: New test. --- gcc/gimple-ssa-store-merging.c | 32 +++++++++++++++++++++----- gcc/testsuite/gcc.dg/optimize-bswapsi-7.c | 37 +++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/optimize-bswapsi-7.c (limited to 'gcc') diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c index 35df0fe..e7c90ba 100644 --- a/gcc/gimple-ssa-store-merging.c +++ b/gcc/gimple-ssa-store-merging.c @@ -556,6 +556,7 @@ perform_symbolic_merge (gimple *source_stmt1, struct symbolic_number *n1, n->bytepos = n_start->bytepos; n->type = n_start->type; size = TYPE_PRECISION (n->type) / BITS_PER_UNIT; + uint64_t res_n = n1->n | n2->n; for (i = 0, mask = MARKER_MASK; i < size; i++, mask <<= BITS_PER_MARKER) { @@ -563,12 +564,33 @@ perform_symbolic_merge (gimple *source_stmt1, struct symbolic_number *n1, masked1 = n1->n & mask; masked2 = n2->n & mask; - /* For BIT_XOR_EXPR or PLUS_EXPR, at least one of masked1 and masked2 - has to be 0, for BIT_IOR_EXPR x | x is still x. */ - if (masked1 && masked2 && (code != BIT_IOR_EXPR || masked1 != masked2)) - return NULL; + /* If at least one byte is 0, all of 0 | x == 0 ^ x == 0 + x == x. */ + if (masked1 && masked2) + { + /* + can carry into upper bits, just punt. */ + if (code == PLUS_EXPR) + return NULL; + /* x | x is still x. */ + if (code == BIT_IOR_EXPR && masked1 == masked2) + continue; + if (code == BIT_XOR_EXPR) + { + /* x ^ x is 0, but MARKER_BYTE_UNKNOWN stands for + unknown values and unknown ^ unknown is unknown. */ + if (masked1 == masked2 + && masked1 != ((uint64_t) MARKER_BYTE_UNKNOWN + << i * BITS_PER_MARKER)) + { + res_n &= ~mask; + continue; + } + } + /* Otherwise set the byte to unknown, it might still be + later masked off. */ + res_n |= mask; + } } - n->n = n1->n | n2->n; + n->n = res_n; n->n_ops = n1->n_ops + n2->n_ops; return source_stmt; diff --git a/gcc/testsuite/gcc.dg/optimize-bswapsi-7.c b/gcc/testsuite/gcc.dg/optimize-bswapsi-7.c new file mode 100644 index 0000000..1e4db5e --- /dev/null +++ b/gcc/testsuite/gcc.dg/optimize-bswapsi-7.c @@ -0,0 +1,37 @@ +/* PR tree-optimization/103376 */ +/* { dg-do compile } */ +/* { dg-require-effective-target bswap } */ +/* { dg-options "-O2 -fno-tree-vectorize -fdump-tree-optimized" } */ +/* { dg-additional-options "-march=z900" { target s390-*-* } } */ + +static unsigned int +f1 (unsigned int x) +{ + return (x << 24) | (x >> 8); +} + +unsigned int +f2 (unsigned *p) +{ + return ((f1 (p[0]) | (p[0] >> 8)) & 0xff000000U) | (p[0] >> 24) | ((p[0] & 0xff00U) << 8) | ((p[0] & 0xff0000U) >> 8); +} + +unsigned int +f3 (unsigned *p) +{ + return ((f1 (p[0]) | (p[0] & 0x00ff00ffU)) & 0xff00ff00U) | (f1 (f1 (f1 (p[0]))) & 0x00ff00ffU); +} + +unsigned int +f4 (unsigned *p) +{ + return (f1 (p[0]) ^ (p[0] >> 8)) ^ (p[0] >> 24) ^ ((p[0] & 0xff00U) << 8) ^ ((p[0] & 0xff0000U) >> 8); +} + +unsigned int +f5 (unsigned *p) +{ + return (((f1 (p[0]) | (p[0] >> 16)) ^ (p[0] >> 8)) & 0xffff0000U) ^ (p[0] >> 24) ^ ((p[0] & 0xff00U) << 8) ^ ((p[0] & 0xff0000U) >> 8); +} + +/* { dg-final { scan-tree-dump-times "= __builtin_bswap32 \\\(" 4 "optimized" } } */ -- cgit v1.1 From 94912212d3d1be0b1c490e9b5f45165ef5f30d8a Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 25 Nov 2021 10:47:24 +0100 Subject: match.pd: Fix up the recent bitmask_inv_cst_vector_p simplification [PR103417] The following testcase is miscompiled since the r12-5489-g0888d6bbe97e10 changes. The simplification triggers on (x & 4294967040U) >= 0U and turns it into: x <= 255U which is incorrect, it should fold to 1 because unsigned >= 0U is always true and normally the /* Non-equality compare simplifications from fold_binary */ (if (wi::to_wide (cst) == min) (if (cmp == GE_EXPR) { constant_boolean_node (true, type); }) simplification folds that, but this simplification was done earlier. The simplification correctly doesn't include lt which has the same reason why it shouldn't be handled, we'll fold it to 0 elsewhere. But, IMNSHO while it isn't incorrect to handle le and gt there, it is unnecessary. Because (x & cst) <= 0U and (x & cst) > 0U should never appear, again in /* Non-equality compare simplifications from fold_binary */ we have a simplification for it: (if (cmp == LE_EXPR) (eq @2 @1)) (if (cmp == GT_EXPR) (ne @2 @1)))) This is done for (cmp (convert?@2 @0) uniform_integer_cst_p@1) and so should be done for both integers and vectors. As the bitmask_inv_cst_vector_p simplification only handles eq and ne for signed types, I think it can be simplified to just following patch. 2021-11-25 Jakub Jelinek PR tree-optimization/103417 * match.pd ((X & Y) CMP 0): Only handle eq and ne. Commonalize common tests. * gcc.c-torture/execute/pr103417.c: New test. --- gcc/match.pd | 22 +++++++++------------- gcc/testsuite/gcc.c-torture/execute/pr103417.c | 11 +++++++++++ 2 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr103417.c (limited to 'gcc') diff --git a/gcc/match.pd b/gcc/match.pd index 5adcd6b..39fd77d 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -5214,20 +5214,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* Transform comparisons of the form (X & Y) CMP 0 to X CMP2 Z where ~Y + 1 == pow2 and Z = ~Y. */ (for cst (VECTOR_CST INTEGER_CST) - (for cmp (le eq ne ge gt) - icmp (le le gt le gt) - (simplify - (cmp (bit_and:c@2 @0 cst@1) integer_zerop) - (with { tree csts = bitmask_inv_cst_vector_p (@1); } - (switch - (if (csts && TYPE_UNSIGNED (TREE_TYPE (@1)) - && (VECTOR_TYPE_P (TREE_TYPE (@1)) || single_use (@2))) - (icmp @0 { csts; })) - (if (csts && !TYPE_UNSIGNED (TREE_TYPE (@1)) - && (cmp == EQ_EXPR || cmp == NE_EXPR) - && (VECTOR_TYPE_P (TREE_TYPE (@1)) || single_use (@2))) + (for cmp (eq ne) + icmp (le gt) + (simplify + (cmp (bit_and:c@2 @0 cst@1) integer_zerop) + (with { tree csts = bitmask_inv_cst_vector_p (@1); } + (if (csts && (VECTOR_TYPE_P (TREE_TYPE (@1)) || single_use (@2))) + (if (TYPE_UNSIGNED (TREE_TYPE (@1))) + (icmp @0 { csts; }) (with { tree utype = unsigned_type_for (TREE_TYPE (@1)); } - (icmp (convert:utype @0) { csts; })))))))) + (icmp (convert:utype @0) { csts; })))))))) /* -A CMP -B -> B CMP A. */ (for cmp (tcc_comparison) diff --git a/gcc/testsuite/gcc.c-torture/execute/pr103417.c b/gcc/testsuite/gcc.c-torture/execute/pr103417.c new file mode 100644 index 0000000..0fef890 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr103417.c @@ -0,0 +1,11 @@ +/* PR tree-optimization/103417 */ + +struct { int a : 8; int b : 24; } c = { 0, 1 }; + +int +main () +{ + if (c.b && !c.b) + __builtin_abort (); + return 0; +} -- cgit v1.1 From 8acbd7bef6edbf537e3037174907029b530212f6 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 24 Nov 2021 09:43:36 +0100 Subject: path solver: Compute ranges in path in gimple order. Andrew's patch for this PR103254 papered over some underlying performance issues in the path solver that I'd like to address. We are currently solving the SSA's defined in the current block in bitmap order, which amounts to random order for all purposes. This is causing unnecessary recursion in gori. This patch changes the order to gimple order, thus solving dependencies before uses. There is no change in threadable paths with this change. Tested on x86-64 & ppc64le Linux. gcc/ChangeLog: PR tree-optimization/103254 * gimple-range-path.cc (path_range_query::compute_ranges_defined): New (path_range_query::compute_ranges_in_block): Move to compute_ranges_defined. * gimple-range-path.h (compute_ranges_defined): New. --- gcc/gimple-range-path.cc | 33 ++++++++++++++++++++++----------- gcc/gimple-range-path.h | 1 + 2 files changed, 23 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc index 4aa666d..e240866 100644 --- a/gcc/gimple-range-path.cc +++ b/gcc/gimple-range-path.cc @@ -401,6 +401,27 @@ path_range_query::compute_ranges_in_phis (basic_block bb) } } +// Compute ranges defined in block. + +void +path_range_query::compute_ranges_defined (basic_block bb) +{ + int_range_max r; + + compute_ranges_in_phis (bb); + + // Iterate in gimple order to minimize recursion. + for (auto gsi = gsi_start_nondebug_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + if (gimple_has_lhs (gsi_stmt (gsi))) + { + tree name = gimple_get_lhs (gsi_stmt (gsi)); + if (TREE_CODE (name) == SSA_NAME + && bitmap_bit_p (m_imports, SSA_NAME_VERSION (name)) + && range_defined_in_block (r, name, bb)) + set_cache (r, name); + } +} + // Compute ranges defined in the current block, or exported to the // next block. @@ -423,17 +444,7 @@ path_range_query::compute_ranges_in_block (basic_block bb) clear_cache (name); } - // Solve imports defined in this block, starting with the PHIs... - compute_ranges_in_phis (bb); - // ...and then the rest of the imports. - EXECUTE_IF_SET_IN_BITMAP (m_imports, 0, i, bi) - { - tree name = ssa_name (i); - - if (gimple_code (SSA_NAME_DEF_STMT (name)) != GIMPLE_PHI - && range_defined_in_block (r, name, bb)) - set_cache (r, name); - } + compute_ranges_defined (bb); if (at_exit ()) return; diff --git a/gcc/gimple-range-path.h b/gcc/gimple-range-path.h index 57a9ae9..81c87d4 100644 --- a/gcc/gimple-range-path.h +++ b/gcc/gimple-range-path.h @@ -58,6 +58,7 @@ private: // Methods to compute ranges for the given path. bool range_defined_in_block (irange &, tree name, basic_block bb); void compute_ranges_in_block (basic_block bb); + void compute_ranges_defined (basic_block bb); void compute_ranges_in_phis (basic_block bb); void adjust_for_non_null_uses (basic_block bb); void ssa_range_in_phi (irange &r, gphi *phi); -- cgit v1.1 From d1c1919ef8a18eea9d5c1741f8c9adaabf5571f2 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 24 Nov 2021 17:58:43 +0100 Subject: path solver: Move boolean import code to compute_imports. In a follow-up patch I will be pruning the set of exported ranges within blocks to avoid unnecessary work. In order to do this, all the interesting SSA names must be in the internal import bitmap ahead of time. I had already abstracted them out into compute_imports, but I missed the boolean code. This fixes the oversight. There's a net gain of 25 threadable paths, which is unexpected but welcome. Tested on x86-64 & ppc64le Linux. gcc/ChangeLog: PR tree-optimization/103254 * gimple-range-path.cc (path_range_query::compute_ranges): Move exported boolean code... (path_range_query::compute_imports): ...here. --- gcc/gimple-range-path.cc | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc index e240866..806bce9 100644 --- a/gcc/gimple-range-path.cc +++ b/gcc/gimple-range-path.cc @@ -537,7 +537,8 @@ void path_range_query::compute_imports (bitmap imports, basic_block exit) { // Start with the imports from the exit block... - bitmap r_imports = m_ranger->gori ().imports (exit); + gori_compute &gori = m_ranger->gori (); + bitmap r_imports = gori.imports (exit); bitmap_copy (imports, r_imports); auto_vec worklist (bitmap_count_bits (imports)); @@ -579,6 +580,16 @@ path_range_query::compute_imports (bitmap imports, basic_block exit) } } } + // Exported booleans along the path, may help conditionals. + if (m_resolve) + for (i = 0; i < m_path.length (); ++i) + { + basic_block bb = m_path[i]; + tree name; + FOR_EACH_GORI_EXPORT_NAME (gori, bb, name) + if (TREE_CODE (TREE_TYPE (name)) == BOOLEAN_TYPE) + bitmap_set_bit (imports, SSA_NAME_VERSION (name)); + } } // Compute the ranges for IMPORTS along PATH. @@ -622,18 +633,6 @@ path_range_query::compute_ranges (const vec &path, { basic_block bb = curr_bb (); - if (m_resolve) - { - gori_compute &gori = m_ranger->gori (); - tree name; - - // Exported booleans along the path, may help conditionals. - // Add them as interesting imports. - FOR_EACH_GORI_EXPORT_NAME (gori, bb, name) - if (TREE_CODE (TREE_TYPE (name)) == BOOLEAN_TYPE) - bitmap_set_bit (m_imports, SSA_NAME_VERSION (name)); - } - compute_ranges_in_block (bb); adjust_for_non_null_uses (bb); -- cgit v1.1 From 1167d4890f7aba2bc173a4f4abb10d86e306864c Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 25 Nov 2021 12:13:59 +0100 Subject: docs: Add missing @option keyword. gcc/ChangeLog: * doc/invoke.texi: Use @option for -Wuninitialized. --- gcc/doc/invoke.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d0ac597..3bddfba 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -12117,8 +12117,8 @@ Initialize automatic variables with either a pattern or with zeroes to increase the security and predictability of a program by preventing uninitialized memory disclosure and use. GCC still considers an automatic variable that doesn't have an explicit -initializer as uninitialized, -Wuninitialized will still report warning messages -on such automatic variables. +initializer as uninitialized, @option{-Wuninitialized} will still report +warning messages on such automatic variables. With this option, GCC will also initialize any padding of automatic variables that have structure or union types to zeroes. -- cgit v1.1