From 9faaa091e53db9cb4aee137bb4a6a9c6a18c7af5 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Mon, 31 May 2021 16:38:05 +0200 Subject: gfortran.dg/gomp/depend-iterator-{1,2}.f90: Use dg-do compile 'dg-do run' is pointless -1 due to dg-error. And it won't work except by chance for gomp tests; as -2 only has depend(out:), a 'dg-do compile' is sufficient. gcc/testsuite/ChangeLog: * gfortran.dg/gomp/depend-iterator-1.f90: Use dg-do compile. * gfortran.dg/gomp/depend-iterator-2.f90: Use dg-do compile. --- gcc/testsuite/gfortran.dg/gomp/depend-iterator-1.f90 | 2 +- gcc/testsuite/gfortran.dg/gomp/depend-iterator-2.f90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gfortran.dg/gomp/depend-iterator-1.f90 b/gcc/testsuite/gfortran.dg/gomp/depend-iterator-1.f90 index cad36aa..d852b95 100644 --- a/gcc/testsuite/gfortran.dg/gomp/depend-iterator-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/depend-iterator-1.f90 @@ -1,4 +1,4 @@ -! { dg-do run } +! { dg-do compile } module mymod implicit none (type, external) diff --git a/gcc/testsuite/gfortran.dg/gomp/depend-iterator-2.f90 b/gcc/testsuite/gfortran.dg/gomp/depend-iterator-2.f90 index fa826a7..21fc327 100644 --- a/gcc/testsuite/gfortran.dg/gomp/depend-iterator-2.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/depend-iterator-2.f90 @@ -1,4 +1,4 @@ -! { dg-do run } +! { dg-do compile } module mymod implicit none (type, external) -- cgit v1.1 From a87efd32384ee78ee33d20703deaa65fba81cb2d Mon Sep 17 00:00:00 2001 From: Indu Bhagat Date: Mon, 31 May 2021 09:19:38 -0700 Subject: PR testsuite/100749 - gcc.dg/pch/valid-1.c fails after r12-949 Fix failing pch testcases. Use xstrdup to retain a reliable copy of the debug format str containing the names (df_set_names is a static string var). 2021-05-31 Indu Bhagat gcc/c-family/ PR testsuite/100749 * c-pch.c (c_common_valid_pch): Use xstrdup for debug format set names. --- gcc/c-family/c-pch.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/c-family/c-pch.c b/gcc/c-family/c-pch.c index 8f0f760..5da6042 100644 --- a/gcc/c-family/c-pch.c +++ b/gcc/c-family/c-pch.c @@ -255,10 +255,13 @@ c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) if (v.pch_write_symbols != write_symbols && write_symbols != NO_DEBUG) { + char *created_str = xstrdup (debug_set_names (v.pch_write_symbols)); + char *used_str = xstrdup (debug_set_names (write_symbols)); cpp_warning (pfile, CPP_W_INVALID_PCH, "%s: created with '%s' debug info, but used with '%s'", name, - debug_set_names (v.pch_write_symbols), - debug_set_names (write_symbols)); + created_str, used_str); + free (created_str); + free (used_str); return 2; } -- cgit v1.1 From ee682192755bb88af0ee10852e7c873b844d449f Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 1 Jun 2021 00:16:37 +0000 Subject: Daily bump. --- gcc/ChangeLog | 27 +++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c-family/ChangeLog | 15 +++++++++++++++ gcc/c/ChangeLog | 6 ++++++ gcc/cp/ChangeLog | 13 +++++++++++++ gcc/lto/ChangeLog | 5 +++++ gcc/testsuite/ChangeLog | 18 ++++++++++++++++++ 7 files changed, 85 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 05e1640..e1ae7fa 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,30 @@ +2021-05-31 Martin Liska + + * tree-streamer-in.c (unpack_ts_function_decl_value_fields): + Unpack FUNCTION_DECL_DECL_TYPE. + * tree-streamer-out.c (pack_ts_function_decl_value_fields): + Stream FUNCTION_DECL_DECL_TYPE instead of + DECL_IS_OPERATOR_NEW_P. + * tree.h (set_function_decl_type): Use FUNCTION_DECL_DECL_TYPE + macro. + (DECL_IS_OPERATOR_NEW_P): Likewise. + (DECL_IS_OPERATOR_DELETE_P): Likewise. + (DECL_LAMBDA_FUNCTION_P): Likewise. + +2021-05-31 Richard Biener + + PR c++/88601 + * internal-fn.c (expand_SHUFFLEVECTOR): Define. + * internal-fn.def (SHUFFLEVECTOR): New. + * internal-fn.h (expand_SHUFFLEVECTOR): Declare. + * doc/extend.texi: Document __builtin_shufflevector. + +2021-05-31 Peter Bergner + + PR target/99842 + * config/rs6000/predicates.md(mma_assemble_input_operand): Allow + indexed form addresses. + 2021-05-29 Jeff Law * config/h8300/h8300.c (h8300_emit_stack_adjustment): Drop unused diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 9bfad84..6b43bb2 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210531 +20210601 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 2905179..e85a6bf 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,18 @@ +2021-05-31 Indu Bhagat + + PR testsuite/100749 + * c-pch.c (c_common_valid_pch): Use xstrdup for debug format set names. + +2021-05-31 Richard Biener + + PR c++/88601 + * c-common.c: Include tree-vector-builder.h and + vec-perm-indices.h. + (c_common_reswords): Add __builtin_shufflevector. + (c_build_shufflevector): New funtion. + * c-common.h (enum rid): Add RID_BUILTIN_SHUFFLEVECTOR. + (c_build_shufflevector): Declare. + 2021-05-28 Jakub Jelinek PR middle-end/99928 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 411058f..b6f76b3 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2021-05-31 Richard Biener + + PR c++/88601 + * c-decl.c (names_builtin_p): Handle RID_BUILTIN_SHUFFLEVECTOR. + * c-parser.c (c_parser_postfix_expression): Likewise. + 2021-05-28 Richard Biener PR c/100803 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 882c8eb..c764713 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2021-05-31 Richard Biener + + PR c++/88601 + * cp-objcp-common.c (names_builtin_p): Handle + RID_BUILTIN_SHUFFLEVECTOR. + * cp-tree.h (build_x_shufflevector): Declare. + * parser.c (cp_parser_postfix_expression): Handle + RID_BUILTIN_SHUFFLEVECTOR. + * pt.c (tsubst_copy_and_build): Handle IFN_SHUFFLEVECTOR. + * typeck.c (build_x_shufflevector): Build either a lowered + VEC_PERM_EXPR or an unlowered shufflevector via a temporary + internal function IFN_SHUFFLEVECTOR. + 2021-05-28 Jason Merrill * constexpr.c (build_data_member_initialization): Use tsi_range. diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 426f1c0..301e5f4 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,8 @@ +2021-05-31 Martin Liska + + * lto-common.c (compare_tree_sccs_1): Compare + FUNCTION_DECL_DECL_TYPE. + 2021-05-24 Wang Liushuai * lto-dump.c (get_size): Fix the NPD error about the thunk symbol. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f8eedd47..e55bbf2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,21 @@ +2021-05-31 Tobias Burnus + + * gfortran.dg/gomp/depend-iterator-1.f90: Use dg-do compile. + * gfortran.dg/gomp/depend-iterator-2.f90: Use dg-do compile. + +2021-05-31 Richard Biener + + PR c++/88601 + * c-c++-common/builtin-shufflevector-2.c: New testcase. + * c-c++-common/torture/builtin-shufflevector-1.c: Likewise. + * g++.dg/ext/builtin-shufflevector-1.C: Likewise. + * g++.dg/ext/builtin-shufflevector-2.C: Likewise. + +2021-05-31 Peter Bergner + + PR target/99842 + * g++.target/powerpc/pr99842.C: New. + 2021-05-29 Bernd Edlinger * gcc.dg/plugin/diagnostic_plugin_show_trees.c (plugin_init): Fix caret_max_with. -- cgit v1.1 From 1ffbfc2659e7e8fa5c5d633869870af8fca5e8ee Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 27 May 2021 11:19:10 -0400 Subject: Range invariant global values are also always current. when a range evolves to the point where it becomes a constant, it is marked as invariant. Rather than marking it as always_current in the timestamp, give it the correct timestamp and just never flag it as stale. This will allow other names which use this value to become stale and be recomputed using the newly invariant value. gcc/ PR tree-optimization/100774 * gimple-range-cache.cc (ranger_cache::get_non_stale_global_range): Constant values are also not stale. (ranger_cache::set_global_range): Range invariant values should also have the correct timestamp. gcc/testsuite PR tree-optimization/100774 * g++.dg/pr100774.C: New. --- gcc/gimple-range-cache.cc | 16 ++++++++-------- gcc/testsuite/g++.dg/pr100774.C | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/pr100774.C (limited to 'gcc') diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index 889cac1..ef3bc04 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -639,7 +639,9 @@ ranger_cache::get_non_stale_global_range (irange &r, tree name) { if (m_globals.get_global_range (r, name)) { - if (m_temporal->current_p (name, depend1 (name), depend2 (name))) + // Use this value if the range is constant or current. + if (r.singleton_p () + || m_temporal->current_p (name, depend1 (name), depend2 (name))) return true; } else @@ -674,15 +676,13 @@ ranger_cache::set_global_range (tree name, const irange &r) // undefined. Propagation works better with constants. PR 100512. // Pointers which resolve to non-zero also do not need // tracking in the cache as they will never change. See PR 98866. - // Otherwise mark the value as up-to-date. + // Timestamp must always be updated, or dependent calculations may + // not include this latest value. PR 100774. + if (r.singleton_p () || (POINTER_TYPE_P (TREE_TYPE (name)) && r.nonzero_p ())) - { - set_range_invariant (name); - m_temporal->set_always_current (name); - } - else - m_temporal->set_timestamp (name); + set_range_invariant (name); + m_temporal->set_timestamp (name); } // Push a request for a new lookup in block BB of name. Return true if diff --git a/gcc/testsuite/g++.dg/pr100774.C b/gcc/testsuite/g++.dg/pr100774.C new file mode 100644 index 0000000..345fcfa --- /dev/null +++ b/gcc/testsuite/g++.dg/pr100774.C @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-tree-forwprop --param=evrp-mode=ranger -fcompare-debug " } */ + +extern void __attribute__((noreturn)) error(); + +int x; + +static inline int bar(void) { + char n = 1; + int i = x & 1U << n - 1; + return i; +} + +void foo() +{ + int a = bar(); + for (;;) { + bool b; + int d = a; + b = a < 2; + if (!b) + error(); + } +} -- cgit v1.1 From 47ea02bb862d6be9a200ebccbd5d64b31a003ec2 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Mon, 31 May 2021 16:00:16 -0400 Subject: Move Ranger cache to range-query and fur_source model. Flatten and simplify gori-computes. Tweak debug output. range-cache now provides range_of_expr and range_on_edge in the standard formats, but in a "query what you have" mode rather than "go figure out anything that is missing" mode. * gimple-range-cache.cc (ranger_cache::ranger_cache): Adjust for gori_compute being a member rather than base class. dervied call to member call. (ranger_cache::dump): No longer dump gori_map. (ranger_cache::dump_bb): New. (ranger_cache::get_non_stale_global_range): Adjust for gori_compute being a member rather than base class. (ranger_cache::set_global_range): Ditto. (ranger_cache::ssa_range_in_bb): Ditto. (ranger_cache::range_of_expr): New. (ranger_cache::range_on_edge): New. (ranger_cache::block_range): Adjust for gori_computes. Debug changes. (ranger_cache::propagate_cache): Adjust debugging output. (ranger_cache::fill_block_cache): Adjust for gori_computes. Debug output changes. * gimple-range-cache.h (class ranger_cache): Make gori_compute a member, and inherit from range_query instead. (ranger_cache::dump_bb): New. split from dump. * gimple-range-gori.cc (gori_compute::ssa_range_in_bb): Delete. (gori_compute::expr_range_at_stmt): Delete. (gori_compute::compute_name_range_op): Delete. (gori_compute::compute_operand_range_switch): Add fur_source. (gori_compute::compute_operand_range): Add fur_source param, inline old compute_name_range_op and optimize_logical_operands. (struct tf_range): Delete. (gori_compute::logical_combine): Adjust (gori_compute::optimize_logical_operands): Delete. (gori_compute::compute_logical_operands_in_chain): Delete. (gori_compute::compute_logical_operands): Adjust. (gori_compute::compute_operand1_range): Adjust to fur_source. (gori_compute::compute_operand2_range): Ditto. (gori_compute::compute_operand1_and_operand2_range): Ditto. (gori_compute::outgoing_edge_range_p): Add range_query parameter, and adjust to fur_source. * gimple-range-gori.h (class gori_compute): Simplify and adjust to range_query and fur_source. * gimple-range.cc (gimple_ranger::range_on_edge): Query range_on_edge from the ranger_cache.. (gimple_ranger::fold_range_internal): Adjust to base class change of ranger_cache. (gimple_ranger::dump_bb): Adjust dump. * gimple-range.h (gimple_ranger):export gori computes object. --- gcc/gimple-range-cache.cc | 79 ++++++---- gcc/gimple-range-cache.h | 11 +- gcc/gimple-range-gori.cc | 371 +++++++++++++++++----------------------------- gcc/gimple-range-gori.h | 47 +++--- gcc/gimple-range.cc | 10 +- gcc/gimple-range.h | 3 +- 6 files changed, 223 insertions(+), 298 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index ef3bc04..e776bed 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -583,7 +583,7 @@ ranger_cache::ranger_cache (gimple_ranger &q) : query (q) { basic_block bb = BASIC_BLOCK_FOR_FN (cfun, x); if (bb) - exports (bb); + m_gori.exports (bb); } } @@ -599,22 +599,18 @@ ranger_cache::~ranger_cache () // gori map as well. void -ranger_cache::dump (FILE *f, bool gori_dump) +ranger_cache::dump (FILE *f) { m_globals.dump (f); - if (gori_dump) - { - fprintf (f, "\nDUMPING GORI MAP\n"); - gori_compute::dump (f); - } fprintf (f, "\n"); } // Dump the caches for basic block BB to file F. void -ranger_cache::dump (FILE *f, basic_block bb) +ranger_cache::dump_bb (FILE *f, basic_block bb) { + m_gori.gori_map::dump (f, bb, false); m_on_entry.dump (f, bb); } @@ -641,7 +637,8 @@ ranger_cache::get_non_stale_global_range (irange &r, tree name) { // Use this value if the range is constant or current. if (r.singleton_p () - || m_temporal->current_p (name, depend1 (name), depend2 (name))) + || m_temporal->current_p (name, m_gori.depend1 (name), + m_gori.depend2 (name))) return true; } else @@ -681,7 +678,7 @@ ranger_cache::set_global_range (tree name, const irange &r) if (r.singleton_p () || (POINTER_TYPE_P (TREE_TYPE (name)) && r.nonzero_p ())) - set_range_invariant (name); + m_gori.set_range_invariant (name); m_temporal->set_timestamp (name); } @@ -745,7 +742,7 @@ ranger_cache::ssa_range_in_bb (irange &r, tree name, basic_block bb) // If it has no entry but should, then mark this as a poor value. // Its not a poor value if it does not have *any* edge ranges, // Then global range is as good as it gets. - if (has_edge_range_p (name) && push_poor_value (bb, name)) + if (m_gori.has_edge_range_p (name) && push_poor_value (bb, name)) { if (DEBUG_RANGE_CACHE) { @@ -759,7 +756,6 @@ ranger_cache::ssa_range_in_bb (irange &r, tree name, basic_block bb) if (!m_globals.get_global_range (r, name)) r = gimple_range_global (name); } - // Check if pointers have any non-null dereferences. Non-call // exceptions mean we could throw in the middle of the block, so just // punt for now on those. @@ -768,6 +764,29 @@ ranger_cache::ssa_range_in_bb (irange &r, tree name, basic_block bb) r = range_nonzero (TREE_TYPE (name)); } +// Implement range_of_expr. + +bool +ranger_cache::range_of_expr (irange &r, tree expr, gimple *stmt) +{ + if (gimple_range_ssa_p (expr)) + ssa_range_in_bb (r, expr, gimple_bb (stmt)); + else + get_tree_range (r, expr); + return true; +} + +// Implement range_on_edge which returns true ONLY if there is a range +// calculated. + +bool +ranger_cache::range_on_edge (irange &r, edge e, tree expr) +{ + if (gimple_range_ssa_p (expr)) + return m_gori.outgoing_edge_range_p (r, e, expr, *this); + return false; +} + // Return a static range for NAME on entry to basic block BB in R. If // calc is true, fill any cache entries required between BB and the // def block for NAME. Otherwise, return false if the cache is empty. @@ -779,7 +798,7 @@ ranger_cache::block_range (irange &r, basic_block bb, tree name, bool calc) // If there are no range calculations anywhere in the IL, global range // applies everywhere, so don't bother caching it. - if (!has_edge_range_p (name)) + if (!m_gori.has_edge_range_p (name)) return false; if (calc) @@ -842,6 +861,15 @@ ranger_cache::propagate_cache (tree name) gcc_checking_assert (m_on_entry.bb_range_p (name, bb)); m_on_entry.get_bb_range (current_range, name, bb); + if (DEBUG_RANGE_CACHE) + { + fprintf (dump_file, "FWD visiting block %d for ", bb->index); + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, " starting range : "); + current_range.dump (dump_file); + fprintf (dump_file, "\n"); + } + // Calculate the "new" range on entry by unioning the pred edges. new_range.set_undefined (); FOR_EACH_EDGE (e, ei, bb->preds) @@ -849,13 +877,13 @@ ranger_cache::propagate_cache (tree name) if (DEBUG_RANGE_CACHE) fprintf (dump_file, " edge %d->%d :", e->src->index, bb->index); // Get whatever range we can for this edge. - if (!outgoing_edge_range_p (e_range, e, name)) + if (!m_gori.outgoing_edge_range_p (e_range, e, name, *this)) { ssa_range_in_bb (e_range, name, e->src); if (DEBUG_RANGE_CACHE) { fprintf (dump_file, "No outgoing edge range, picked up "); - e_range.dump(dump_file); + e_range.dump (dump_file); fprintf (dump_file, "\n"); } } @@ -864,7 +892,7 @@ ranger_cache::propagate_cache (tree name) if (DEBUG_RANGE_CACHE) { fprintf (dump_file, "outgoing range :"); - e_range.dump(dump_file); + e_range.dump (dump_file); fprintf (dump_file, "\n"); } } @@ -873,15 +901,6 @@ ranger_cache::propagate_cache (tree name) break; } - if (DEBUG_RANGE_CACHE) - { - fprintf (dump_file, "FWD visiting block %d for ", bb->index); - print_generic_expr (dump_file, name, TDF_SLIM); - fprintf (dump_file, " starting range : "); - current_range.dump (dump_file); - fprintf (dump_file, "\n"); - } - // If the range on entry has changed, update it. if (new_range != current_range) { @@ -1042,8 +1061,12 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb) if (m_on_entry.get_bb_range (r, name, pred)) { if (DEBUG_RANGE_CACHE) - fprintf (dump_file, "has cache, "); - if (!r.undefined_p () || has_edge_range_p (name, e)) + { + fprintf (dump_file, "has cache, "); + r.dump (dump_file); + fprintf (dump_file, ", "); + } + if (!r.undefined_p () || m_gori.has_edge_range_p (name, e)) { add_to_update (node); if (DEBUG_RANGE_CACHE) @@ -1053,7 +1076,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb) } if (DEBUG_RANGE_CACHE) - fprintf (dump_file, "pushing undefined pred block. "); + fprintf (dump_file, "pushing undefined pred block.\n"); // If the pred hasn't been visited (has no range), add it to // the list. gcc_checking_assert (!m_on_entry.bb_range_p (name, pred)); diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h index fe781e0..ac50219 100644 --- a/gcc/gimple-range-cache.h +++ b/gcc/gimple-range-cache.h @@ -86,13 +86,15 @@ private: // them available for gori-computes to query so outgoing edges can be // properly calculated. -class ranger_cache : public gori_compute +class ranger_cache : public range_query { public: ranger_cache (class gimple_ranger &q); ~ranger_cache (); - virtual void ssa_range_in_bb (irange &r, tree name, basic_block bb); + virtual bool range_of_expr (irange &r, tree expr, gimple *stmt); + virtual bool range_on_edge (irange &r, edge e, tree expr); + void ssa_range_in_bb (irange &r, tree name, basic_block bb); bool block_range (irange &r, basic_block bb, tree name, bool calc = true); bool get_global_range (irange &r, tree name) const; @@ -100,9 +102,10 @@ public: void set_global_range (tree name, const irange &r); non_null_ref m_non_null; + gori_compute m_gori; - void dump (FILE *f, bool dump_gori = true); - void dump (FILE *f, basic_block bb); + void dump_bb (FILE *f, basic_block bb); + virtual void dump (FILE *f) OVERRIDE; private: ssa_global_cache m_globals; block_range_cache m_on_entry; diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index c51e6ce..2c53606 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -575,68 +575,6 @@ gori_compute::gori_compute () m_bool_one = int_range<2> (boolean_true_node, boolean_true_node); } -// Provide a default of VARYING for all incoming SSA names. - -void -gori_compute::ssa_range_in_bb (irange &r, tree name, basic_block) -{ - r.set_varying (TREE_TYPE (name)); -} - -void -gori_compute::expr_range_at_stmt (irange &r, tree expr, gimple *s) -{ - if (gimple_range_ssa_p (expr)) - ssa_range_in_bb (r, expr, gimple_bb (s)); - else - get_tree_range (r, expr); -} - -// Calculate the range for NAME if the lhs of statement S has the -// range LHS. Return the result in R. Return false if no range can be -// calculated. - -bool -gori_compute::compute_name_range_op (irange &r, gimple *stmt, - const irange &lhs, tree name) -{ - int_range_max op1_range, op2_range; - - tree op1 = gimple_range_operand1 (stmt); - tree op2 = gimple_range_operand2 (stmt); - - // Operand 1 is the name being looked for, evaluate it. - if (op1 == name) - { - expr_range_at_stmt (op1_range, op1, stmt); - if (!op2) - { - // The second parameter to a unary operation is the range - // for the type of operand1, but if it can be reduced - // further, the results will be better. Start with what we - // know of the range of OP1 instead of the full type. - return gimple_range_calc_op1 (r, stmt, lhs, op1_range); - } - // If we need the second operand, get a value and evaluate. - expr_range_at_stmt (op2_range, op2, stmt); - if (gimple_range_calc_op1 (r, stmt, lhs, op2_range)) - r.intersect (op1_range); - else - r = op1_range; - return true; - } - - if (op2 == name) - { - expr_range_at_stmt (op1_range, op1, stmt); - expr_range_at_stmt (r, op2, stmt); - if (gimple_range_calc_op2 (op2_range, stmt, lhs, op1_range)) - r.intersect (op2_range); - return true; - } - return false; -} - // Given the switch S, return an evaluation in R for NAME when the lhs // evaluates to LHS. Returning false means the name being looked for // was not resolvable. @@ -644,7 +582,7 @@ gori_compute::compute_name_range_op (irange &r, gimple *stmt, bool gori_compute::compute_operand_range_switch (irange &r, gswitch *s, const irange &lhs, - tree name) + tree name, fur_source &src) { tree op1 = gimple_switch_index (s); @@ -659,7 +597,7 @@ gori_compute::compute_operand_range_switch (irange &r, gswitch *s, // If op1 is in the defintion chain, pass lhs back. if (gimple_range_ssa_p (op1) && in_chain_p (name, op1)) - return compute_operand_range (r, SSA_NAME_DEF_STMT (op1), lhs, name); + return compute_operand_range (r, SSA_NAME_DEF_STMT (op1), lhs, name, src); return false; } @@ -671,8 +609,13 @@ gori_compute::compute_operand_range_switch (irange &r, gswitch *s, bool gori_compute::compute_operand_range (irange &r, gimple *stmt, - const irange &lhs, tree name) + const irange &lhs, tree name, + fur_source &src) { + // If the lhs doesn't tell us anything, neither will unwinding further. + if (lhs.varying_p ()) + return false; + // Empty ranges are viral as they are on an unexecutable path. if (lhs.undefined_p ()) { @@ -680,35 +623,55 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt, return true; } if (is_a (stmt)) - return compute_operand_range_switch (r, as_a (stmt), lhs, name); + return compute_operand_range_switch (r, as_a (stmt), lhs, name, + src); if (!gimple_range_handler (stmt)) return false; tree op1 = gimple_range_ssa_p (gimple_range_operand1 (stmt)); tree op2 = gimple_range_ssa_p (gimple_range_operand2 (stmt)); - // The base ranger handles NAME on this statement. - if (op1 == name || op2 == name) - return compute_name_range_op (r, stmt, lhs, name); - - if (is_gimple_logical_p (stmt)) - return compute_logical_operands (r, stmt, lhs, name); + // Handle end of lookup first. + if (op1 == name) + return compute_operand1_range (r, stmt, lhs, name, src); + if (op2 == name) + return compute_operand2_range (r, stmt, lhs, name, src); // NAME is not in this stmt, but one of the names in it ought to be // derived from it. bool op1_in_chain = op1 && in_chain_p (name, op1); bool op2_in_chain = op2 && in_chain_p (name, op2); + + // If neither operand is derived, then this stmt tells us nothing. + if (!op1_in_chain && !op2_in_chain) + return false; + + // Process logicals as they have special handling. + if (is_gimple_logical_p (stmt)) + { + int_range_max op1_trange, op1_frange; + int_range_max op2_trange, op2_frange; + compute_logical_operands (op1_trange, op1_frange, stmt, lhs, + name, src, op1, op1_in_chain); + compute_logical_operands (op2_trange, op2_frange, stmt, lhs, + name, src, op2, op2_in_chain); + return logical_combine (r, gimple_expr_code (stmt), lhs, + op1_trange, op1_frange, op2_trange, op2_frange); + } + + // Follow the appropriate operands now. if (op1_in_chain && op2_in_chain) - return compute_operand1_and_operand2_range (r, stmt, lhs, name); + return compute_operand1_and_operand2_range (r, stmt, lhs, name, src); if (op1_in_chain) - return compute_operand1_range (r, stmt, lhs, name); + return compute_operand1_range (r, stmt, lhs, name, src); if (op2_in_chain) - return compute_operand2_range (r, stmt, lhs, name); + return compute_operand2_range (r, stmt, lhs, name, src); // If neither operand is derived, this statement tells us nothing. return false; } + // Return TRUE if range R is either a true or false compatible range. static bool @@ -724,19 +687,6 @@ range_is_either_true_or_false (const irange &r) return (r.singleton_p () || !r.contains_p (build_zero_cst (type))); } -// A pair of ranges for true/false paths. - -struct tf_range -{ - tf_range () { } - tf_range (const irange &t_range, const irange &f_range) - { - true_range = t_range; - false_range = f_range; - } - int_range_max true_range, false_range; -}; - // Evaluate a binary logical expression by combining the true and // false ranges for each of the operands based on the result value in // the LHS. @@ -744,12 +694,11 @@ struct tf_range bool gori_compute::logical_combine (irange &r, enum tree_code code, const irange &lhs, - const tf_range &op1, const tf_range &op2) + const irange &op1_true, const irange &op1_false, + const irange &op2_true, const irange &op2_false) { - if (op1.true_range.varying_p () - && op1.false_range.varying_p () - && op2.true_range.varying_p () - && op2.false_range.varying_p ()) + if (op1_true.varying_p () && op1_false.varying_p () + && op2_true.varying_p () && op2_false.varying_p ()) return false; // This is not a simple fold of a logical expression, rather it @@ -790,8 +739,10 @@ gori_compute::logical_combine (irange &r, enum tree_code code, if (!range_is_either_true_or_false (lhs)) { int_range_max r1; - if (logical_combine (r1, code, m_bool_zero, op1, op2) - && logical_combine (r, code, m_bool_one, op1, op2)) + if (logical_combine (r1, code, m_bool_zero, op1_true, op1_false, + op2_true, op2_false) + && logical_combine (r, code, m_bool_one, op1_true, op1_false, + op2_true, op2_false)) { r.union_ (r1); return true; @@ -808,18 +759,18 @@ gori_compute::logical_combine (irange &r, enum tree_code code, if (!lhs.zero_p ()) { // The TRUE side is the intersection of the the 2 true ranges. - r = op1.true_range; - r.intersect (op2.true_range); + r = op1_true; + r.intersect (op2_true); } else { // The FALSE side is the union of the other 3 cases. - int_range_max ff (op1.false_range); - ff.intersect (op2.false_range); - int_range_max tf (op1.true_range); - tf.intersect (op2.false_range); - int_range_max ft (op1.false_range); - ft.intersect (op2.true_range); + int_range_max ff (op1_false); + ff.intersect (op2_false); + int_range_max tf (op1_true); + tf.intersect (op2_false); + int_range_max ft (op1_false); + ft.intersect (op2_true); r = ff; r.union_ (tf); r.union_ (ft); @@ -834,19 +785,19 @@ gori_compute::logical_combine (irange &r, enum tree_code code, // An OR operation will only take the FALSE path if both // operands are false simlulateously, which means they should // be intersected. !(x || y) == !x && !y - r = op1.false_range; - r.intersect (op2.false_range); + r = op1_false; + r.intersect (op2_false); } else { // The TRUE side of an OR operation will be the union of // the other three combinations. - int_range_max tt (op1.true_range); - tt.intersect (op2.true_range); - int_range_max tf (op1.true_range); - tf.intersect (op2.false_range); - int_range_max ft (op1.false_range); - ft.intersect (op2.true_range); + int_range_max tt (op1_true); + tt.intersect (op2_true); + int_range_max tf (op1_true); + tf.intersect (op2_false); + int_range_max ft (op1_false); + ft.intersect (op2_true); r = tt; r.union_ (tf); r.union_ (ft); @@ -859,103 +810,54 @@ gori_compute::logical_combine (irange &r, enum tree_code code, return true; } -// Helper function for compute_logical_operands_in_chain that computes -// the range of logical statements that can be computed without -// chasing down operands. These are things like [0 = x | y] where we -// know neither operand can be non-zero, or [1 = x & y] where we know -// neither operand can be zero. - -bool -gori_compute::optimize_logical_operands (tf_range &range, - gimple *stmt, - const irange &lhs, - tree name, - tree op) -{ - enum tree_code code = gimple_expr_code (stmt); - - // Optimize [0 = x | y], since neither operand can ever be non-zero. - if ((code == BIT_IOR_EXPR || code == TRUTH_OR_EXPR) && lhs.zero_p ()) - { - if (!compute_operand_range (range.false_range, SSA_NAME_DEF_STMT (op), - m_bool_zero, name)) - expr_range_at_stmt (range.false_range, name, stmt); - range.true_range = range.false_range; - return true; - } - // Optimize [1 = x & y], since neither operand can ever be zero. - if ((code == BIT_AND_EXPR || code == TRUTH_AND_EXPR) && lhs == m_bool_one) - { - if (!compute_operand_range (range.true_range, SSA_NAME_DEF_STMT (op), - m_bool_one, name)) - expr_range_at_stmt (range.true_range, name, stmt); - range.false_range = range.true_range; - return true; - } - return false; -} // Given a logical STMT, calculate true and false ranges for each // potential path of NAME, assuming NAME came through the OP chain if // OP_IN_CHAIN is true. void -gori_compute::compute_logical_operands_in_chain (tf_range &range, - gimple *stmt, - const irange &lhs, - tree name, - tree op, bool op_in_chain) +gori_compute::compute_logical_operands (irange &true_range, irange &false_range, + gimple *stmt, + const irange &lhs, + tree name, fur_source &src, + tree op, bool op_in_chain) { gimple *src_stmt = gimple_range_ssa_p (op) ? SSA_NAME_DEF_STMT (op) : NULL; - if (!op_in_chain || (src_stmt != NULL - && gimple_bb (stmt) != gimple_bb (src_stmt))) + if (!op_in_chain || !src_stmt || chain_import_p (gimple_get_lhs (stmt), op)) { // If op is not in the def chain, or defined in this block, // use its known value on entry to the block. - expr_range_at_stmt (range.true_range, name, stmt); - range.false_range = range.true_range; + src.get_operand (true_range, name); + false_range = true_range; return; } - if (optimize_logical_operands (range, stmt, lhs, name, op)) - return; - // Calculate ranges for true and false on both sides, since the false - // path is not always a simple inversion of the true side. - if (!compute_operand_range (range.true_range, src_stmt, m_bool_one, name)) - expr_range_at_stmt (range.true_range, name, stmt); - if (!compute_operand_range (range.false_range, src_stmt, m_bool_zero, name)) - expr_range_at_stmt (range.false_range, name, stmt); -} - -// Given a logical STMT, calculate true and false for each potential -// path using NAME, and resolve the outcome based on the logical -// operator. - -bool -gori_compute::compute_logical_operands (irange &r, gimple *stmt, - const irange &lhs, - tree name) -{ - // Reaching this point means NAME is not in this stmt, but one of - // the names in it ought to be derived from it. - tree op1 = gimple_range_operand1 (stmt); - tree op2 = gimple_range_operand2 (stmt); - gcc_checking_assert (op1 != name && op2 != name); - - bool op1_in_chain = (gimple_range_ssa_p (op1) && in_chain_p (name, op1)); - bool op2_in_chain = (gimple_range_ssa_p (op2) && in_chain_p (name, op2)); + enum tree_code code = gimple_expr_code (stmt); + // Optimize [0 = x | y], since neither operand can ever be non-zero. + if ((code == BIT_IOR_EXPR || code == TRUTH_OR_EXPR) && lhs.zero_p ()) + { + if (!compute_operand_range (false_range, src_stmt, m_bool_zero, name, + src)) + src.get_operand (false_range, name); + true_range = false_range; + return; + } - // If neither operand is derived, then this stmt tells us nothing. - if (!op1_in_chain && !op2_in_chain) - return false; + // Optimize [1 = x & y], since neither operand can ever be zero. + if ((code == BIT_AND_EXPR || code == TRUTH_AND_EXPR) && lhs == m_bool_one) + { + if (!compute_operand_range (true_range, src_stmt, m_bool_one, name, src)) + src.get_operand (true_range, name); + false_range = true_range; + return; + } - tf_range op1_range, op2_range; - compute_logical_operands_in_chain (op1_range, stmt, lhs, - name, op1, op1_in_chain); - compute_logical_operands_in_chain (op2_range, stmt, lhs, - name, op2, op2_in_chain); - return logical_combine (r, gimple_expr_code (stmt), lhs, - op1_range, op2_range); + // Calculate ranges for true and false on both sides, since the false + // path is not always a simple inversion of the true side. + if (!compute_operand_range (true_range, src_stmt, m_bool_one, name, src)) + src.get_operand (true_range, name); + if (!compute_operand_range (false_range, src_stmt, m_bool_zero, name, src)) + src.get_operand (false_range, name); } // Calculate a range for NAME from the operand 1 position of STMT @@ -964,18 +866,20 @@ gori_compute::compute_logical_operands (irange &r, gimple *stmt, bool gori_compute::compute_operand1_range (irange &r, gimple *stmt, - const irange &lhs, tree name) + const irange &lhs, tree name, + fur_source &src) { int_range_max op1_range, op2_range; tree op1 = gimple_range_operand1 (stmt); tree op2 = gimple_range_operand2 (stmt); - expr_range_at_stmt (op1_range, op1, stmt); + // Fetch the known range for op1 in this block. + src.get_operand (op1_range, op1); - // Now calcuated the operand and put that result in r. + // Now range-op calcuate and put that result in r. if (op2) { - expr_range_at_stmt (op2_range, op2, stmt); + src.get_operand (op2_range, op2); if (!gimple_range_calc_op1 (r, stmt, lhs, op2_range)) return false; } @@ -988,20 +892,20 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt, return false; } - // Intersect the calculated result with the known result. + // Intersect the calculated result with the known result and return if done. + if (op1 == name) + { + r.intersect (op1_range); + return true; + } + // If the calculation continues, we're using op1_range as the new LHS. op1_range.intersect (r); gimple *src_stmt = SSA_NAME_DEF_STMT (op1); - // If def stmt is outside of this BB, then name must be an import. - if (!src_stmt || (gimple_bb (src_stmt) != gimple_bb (stmt))) - { - // If this isn't the right import statement, then abort calculation. - if (!src_stmt || gimple_get_lhs (src_stmt) != name) - return false; - return compute_name_range_op (r, src_stmt, op1_range, name); - } + gcc_checking_assert (src_stmt); + // Then feed this range back as the LHS of the defining statement. - return compute_operand_range (r, src_stmt, op1_range, name); + return compute_operand_range (r, src_stmt, op1_range, name, src); } @@ -1011,31 +915,35 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt, bool gori_compute::compute_operand2_range (irange &r, gimple *stmt, - const irange &lhs, tree name) + const irange &lhs, tree name, + fur_source &src) { int_range_max op1_range, op2_range; tree op1 = gimple_range_operand1 (stmt); tree op2 = gimple_range_operand2 (stmt); - expr_range_at_stmt (op1_range, op1, stmt); - expr_range_at_stmt (op2_range, op2, stmt); + src.get_operand (op1_range, op1); + src.get_operand (op2_range, op2); // Intersect with range for op2 based on lhs and op1. if (!gimple_range_calc_op2 (r, stmt, lhs, op1_range)) return false; - op2_range.intersect (r); - gimple *src_stmt = SSA_NAME_DEF_STMT (op2); - // If def stmt is outside of this BB, then name must be an import. - if (!src_stmt || (gimple_bb (src_stmt) != gimple_bb (stmt))) + // Intersect the calculated result with the known result and return if done. + if (op2 == name) { - // If this isn't the right src statement, then abort calculation. - if (!src_stmt || gimple_get_lhs (src_stmt) != name) - return false; - return compute_name_range_op (r, src_stmt, op2_range, name); + r.intersect (op2_range); + return true; } + // If the calculation continues, we're using op2_range as the new LHS. + op2_range.intersect (r); + + gimple *src_stmt = SSA_NAME_DEF_STMT (op2); + gcc_checking_assert (src_stmt); +// gcc_checking_assert (!is_import_p (op2, find.bb)); + // Then feed this range back as the LHS of the defining statement. - return compute_operand_range (r, src_stmt, op2_range, name); + return compute_operand_range (r, src_stmt, op2_range, name, src); } // Calculate a range for NAME from both operand positions of S @@ -1043,29 +951,27 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt, // R, or false if no range could be calculated. bool -gori_compute::compute_operand1_and_operand2_range - (irange &r, - gimple *stmt, - const irange &lhs, - tree name) +gori_compute::compute_operand1_and_operand2_range (irange &r, + gimple *stmt, + const irange &lhs, + tree name, + fur_source &src) { int_range_max op_range; // Calculate a good a range for op2. Since op1 == op2, this will // have already included whatever the actual range of name is. - if (!compute_operand2_range (op_range, stmt, lhs, name)) + if (!compute_operand2_range (op_range, stmt, lhs, name, src)) return false; // Now get the range thru op1. - if (!compute_operand1_range (r, stmt, lhs, name)) + if (!compute_operand1_range (r, stmt, lhs, name, src)) return false; - // Whichever range is the most permissive is the one we need to - // use. (?) OR is that true? Maybe this should be intersection? - r.union_ (op_range); + // Both operands have to be simultaneously true, so perform an intersection. + r.intersect (op_range); return true; } - // Return TRUE if a range can be calcalated for NAME on edge E. bool @@ -1091,7 +997,8 @@ gori_compute::dump (FILE *f) // control edge or NAME is not defined by this edge. bool -gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name) +gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, + range_query &q) { int_range_max lhs; @@ -1101,10 +1008,12 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name) if (!stmt) return false; + fur_source src (&q, NULL, e, stmt); + // If NAME can be calculated on the edge, use that. if (is_export_p (name, e->src)) { - if (compute_operand_range (r, stmt, lhs, name)) + if (compute_operand_range (r, stmt, lhs, name, src)) { // Sometimes compatible types get interchanged. See PR97360. // Make sure we are returning the type of the thing we asked for. diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h index f41dee3..06f3b79 100644 --- a/gcc/gimple-range-gori.h +++ b/gcc/gimple-range-gori.h @@ -153,41 +153,30 @@ class gori_compute : public gori_map { public: gori_compute (); - bool outgoing_edge_range_p (irange &r, edge e, tree name); + bool outgoing_edge_range_p (irange &r, edge e, tree name, range_query &q); bool has_edge_range_p (tree name, edge e = NULL); void dump (FILE *f); -protected: - virtual void ssa_range_in_bb (irange &r, tree name, basic_block bb); - bool compute_operand_range (irange &r, gimple *stmt, - const irange &lhs, tree name); - - void expr_range_at_stmt (irange &r, tree expr, gimple *s); - bool compute_logical_operands (irange &r, gimple *stmt, - const irange &lhs, - tree name); - void compute_logical_operands_in_chain (class tf_range &range, - gimple *stmt, const irange &lhs, - tree name, tree op, - bool op_in_chain); - bool optimize_logical_operands (tf_range &range, gimple *stmt, - const irange &lhs, tree name, tree op); - bool logical_combine (irange &r, enum tree_code code, const irange &lhs, - const class tf_range &op1_range, - const class tf_range &op2_range); - int_range<2> m_bool_zero; // Boolean false cached. - int_range<2> m_bool_one; // Boolean true cached. - private: - bool compute_operand_range_switch (irange &r, gswitch *stmt, - const irange &lhs, tree name); - bool compute_name_range_op (irange &r, gimple *stmt, const irange &lhs, - tree name); + bool compute_operand_range (irange &r, gimple *stmt, const irange &lhs, + tree name, class fur_source &src); + bool compute_operand_range_switch (irange &r, gswitch *s, const irange &lhs, + tree name, fur_source &src); bool compute_operand1_range (irange &r, gimple *stmt, const irange &lhs, - tree name); + tree name, fur_source &src); bool compute_operand2_range (irange &r, gimple *stmt, const irange &lhs, - tree name); + tree name, fur_source &src); bool compute_operand1_and_operand2_range (irange &r, gimple *stmt, - const irange &lhs, tree name); + const irange &lhs, tree name, + fur_source &src); + void compute_logical_operands (irange &true_range, irange &false_range, + gimple *stmt, const irange &lhs, + tree name, fur_source &src, tree op, + bool op_in_chain); + bool logical_combine (irange &r, enum tree_code code, const irange &lhs, + const irange &op1_true, const irange &op1_false, + const irange &op2_true, const irange &op2_false); + int_range<2> m_bool_zero; // Boolean false cached. + int_range<2> m_bool_one; // Boolean true cached. gimple_outgoing_range outgoing; // Edge values for COND_EXPR & SWITCH_EXPR. }; diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index b4dfaa9..d58e151 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -1051,7 +1051,7 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) || range_compatible_p (r.type(), TREE_TYPE (name))); // Check to see if NAME is defined on edge e. - if (m_cache.outgoing_edge_range_p (edge_range, e, name)) + if (m_cache.range_on_edge (edge_range, e, name)) r.intersect (edge_range); return true; @@ -1063,7 +1063,7 @@ bool gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name) { fold_using_range f; - fur_source src (this, &m_cache, NULL, s); + fur_source src (this, &(gori ()), NULL, s); return f.fold_stmt (r, s, src, name); } @@ -1164,7 +1164,7 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb) edge e; int_range_max range; fprintf (f, "\n=========== BB %d ============\n", bb->index); - m_cache.dump (f, bb); + m_cache.dump_bb (f, bb); ::dump_bb (f, bb, 4, TDF_NONE); @@ -1193,7 +1193,7 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb) for (x = 1; x < num_ssa_names; x++) { tree name = gimple_range_ssa_p (ssa_name (x)); - if (name && m_cache.outgoing_edge_range_p (range, e, name)) + if (name && m_cache.range_on_edge (range, e, name)) { gimple *s = SSA_NAME_DEF_STMT (name); // Only print the range if this is the def block, or @@ -1236,7 +1236,7 @@ gimple_ranger::dump (FILE *f) FOR_EACH_BB_FN (bb, cfun) dump_bb (f, bb); - m_cache.dump (f, false); + m_cache.dump (f); } // If SCEV has any information about phi node NAME, return it as a range in R. diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index ecd332a..65f62e4 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -25,10 +25,10 @@ along with GCC; see the file COPYING3. If not see #include "range.h" #include "range-op.h" +#include "value-query.h" #include "gimple-range-edge.h" #include "gimple-range-gori.h" #include "gimple-range-cache.h" -#include "value-query.h" // This file is the main include point for gimple ranges. // There are two fold_range routines of interest: @@ -65,6 +65,7 @@ public: virtual void range_on_entry (irange &r, basic_block bb, tree name); virtual void range_on_exit (irange &r, basic_block bb, tree name); void export_global_ranges (); + inline gori_compute &gori () { return m_cache.m_gori; } virtual void dump (FILE *f) OVERRIDE; void dump_bb (FILE *f, basic_block bb); protected: -- cgit v1.1 From 2e0f3246e0bd92643ce36b9e7b9dde91650ac02a Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Mon, 31 May 2021 16:41:27 -0400 Subject: Replace ssa_range_in_bb with entry exit and def range Split the old functionality of ssa_name_in_bb into the components for definition in a block, entry and exit range. Call these as appropriate. * gimple-range-cache.cc (ranger_cache::ssa_range_in_bb): Delete. (ranger_cache::range_of_def): New. (ranger_cache::entry_range): New. (ranger_cache::exit_range): New. (ranger_cache::range_of_expr): Adjust. (ranger_cache::range_on_edge): Adjust. (ranger_cache::propagate_cache): Call exit_range directly. * gimple-range-cache.h (class ranger_cache): Adjust. --- gcc/gimple-range-cache.cc | 126 +++++++++++++++++++++++++++++++++------------- gcc/gimple-range-cache.h | 7 ++- 2 files changed, 97 insertions(+), 36 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index e776bed..dc32841 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see #include "ssa.h" #include "gimple-pretty-print.h" #include "gimple-range.h" +#include "tree-cfg.h" // During contructor, allocate the vector of ssa_names. @@ -708,36 +709,51 @@ ranger_cache::push_poor_value (basic_block bb, tree name) // of an ssa_name in any given basic block. Note, this does no additonal // lookups, just accesses the data that is already known. +// Get the range of NAME when the def occurs in block BB + void -ranger_cache::ssa_range_in_bb (irange &r, tree name, basic_block bb) +ranger_cache::range_of_def (irange &r, tree name, basic_block bb) { - gimple *s = SSA_NAME_DEF_STMT (name); - basic_block def_bb = ((s && gimple_bb (s)) ? gimple_bb (s) : - ENTRY_BLOCK_PTR_FOR_FN (cfun)); - if (bb == def_bb) + gcc_checking_assert (gimple_range_ssa_p (name)); + gcc_checking_assert (bb == gimple_bb (SSA_NAME_DEF_STMT (name))); + + if (!m_globals.get_global_range (r, name)) { - // NAME is defined in this block, so request its current value - if (!m_globals.get_global_range (r, name)) + // If it doesn't have a value calculated, it means it's a + // "poor" value being used in some calculation. Queue it up + // as a poor value to be improved later. + r = gimple_range_global (name); + if (push_poor_value (bb, name)) { - // If it doesn't have a value calculated, it means it's a - // "poor" value being used in some calculation. Queue it up - // as a poor value to be improved later. - r = gimple_range_global (name); - if (push_poor_value (bb, name)) + if (DEBUG_RANGE_CACHE) { - if (DEBUG_RANGE_CACHE) - { - fprintf (dump_file, - "*CACHE* no global def in bb %d for ", bb->index); - print_generic_expr (dump_file, name, TDF_SLIM); - fprintf (dump_file, " depth : %d\n", - m_poor_value_list.length ()); - } + fprintf (dump_file, + "*CACHE* no global def in bb %d for ", bb->index); + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, " depth : %d\n", + m_poor_value_list.length ()); } - } + } } + if (r.varying_p () && m_non_null.non_null_deref_p (name, bb, false) && + !cfun->can_throw_non_call_exceptions) + r = range_nonzero (TREE_TYPE (name)); +} + +// Get the range of NAME as it occurs on entry to block BB. If it is not set, +// mark it as a poor value for possible later improvement. + +void +ranger_cache::entry_range (irange &r, tree name, basic_block bb) +{ + if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)) + { + r = gimple_range_global (name); + return; + } + // Look for the on-entry value of name in BB from the cache. - else if (!m_on_entry.get_bb_range (r, name, bb)) + if (!m_on_entry.get_bb_range (r, name, bb)) { // If it has no entry but should, then mark this as a poor value. // Its not a poor value if it does not have *any* edge ranges, @@ -764,29 +780,71 @@ ranger_cache::ssa_range_in_bb (irange &r, tree name, basic_block bb) r = range_nonzero (TREE_TYPE (name)); } +// Get the range of NAME as it occurs on exit from block BB. + +void +ranger_cache::exit_range (irange &r, tree name, basic_block bb) +{ + if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)) + { + r = gimple_range_global (name); + return; + } + + gimple *s = SSA_NAME_DEF_STMT (name); + basic_block def_bb = gimple_bb (s); + if (def_bb == bb) + range_of_def (r, name, bb); + else + entry_range (r, name, bb); + } + + // Implement range_of_expr. bool -ranger_cache::range_of_expr (irange &r, tree expr, gimple *stmt) +ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt) { - if (gimple_range_ssa_p (expr)) - ssa_range_in_bb (r, expr, gimple_bb (stmt)); + if (!gimple_range_ssa_p (name)) + { + get_tree_range (r, name); + return true; + } + + basic_block bb = gimple_bb (stmt); + gimple *def_stmt = SSA_NAME_DEF_STMT (name); + basic_block def_bb = gimple_bb (def_stmt); + + if (bb == def_bb) + range_of_def (r, name, bb); else - get_tree_range (r, expr); + entry_range (r, name, bb); return true; } -// Implement range_on_edge which returns true ONLY if there is a range -// calculated. -bool -ranger_cache::range_on_edge (irange &r, edge e, tree expr) -{ - if (gimple_range_ssa_p (expr)) - return m_gori.outgoing_edge_range_p (r, e, expr, *this); +// Implement range_on_edge. Return TRUE if the edge generates a range, +// otherwise false.. but still return a range. + + bool + ranger_cache::range_on_edge (irange &r, edge e, tree expr) + { + if (gimple_range_ssa_p (expr)) + { + exit_range (r, expr, e->src); + int_range_max edge_range; + if (m_gori.outgoing_edge_range_p (edge_range, e, expr, *this)) + { + r.intersect (edge_range); + return true; + } + } + else + get_tree_range (r, expr); return false; } + // Return a static range for NAME on entry to basic block BB in R. If // calc is true, fill any cache entries required between BB and the // def block for NAME. Otherwise, return false if the cache is empty. @@ -879,7 +937,7 @@ ranger_cache::propagate_cache (tree name) // Get whatever range we can for this edge. if (!m_gori.outgoing_edge_range_p (e_range, e, name, *this)) { - ssa_range_in_bb (e_range, name, e->src); + exit_range (e_range, name, e->src); if (DEBUG_RANGE_CACHE) { fprintf (dump_file, "No outgoing edge range, picked up "); diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h index ac50219..fee69bc 100644 --- a/gcc/gimple-range-cache.h +++ b/gcc/gimple-range-cache.h @@ -92,9 +92,8 @@ public: ranger_cache (class gimple_ranger &q); ~ranger_cache (); - virtual bool range_of_expr (irange &r, tree expr, gimple *stmt); + virtual bool range_of_expr (irange &r, tree name, gimple *stmt); virtual bool range_on_edge (irange &r, edge e, tree expr); - void ssa_range_in_bb (irange &r, tree name, basic_block bb); bool block_range (irange &r, basic_block bb, tree name, bool calc = true); bool get_global_range (irange &r, tree name) const; @@ -114,6 +113,10 @@ private: void fill_block_cache (tree name, basic_block bb, basic_block def_bb); void propagate_cache (tree name); + void range_of_def (irange &r, tree name, basic_block bb); + void entry_range (irange &r, tree expr, basic_block bb); + void exit_range (irange &r, tree expr, basic_block bb); + void propagate_updated_value (tree name, basic_block bb); vec m_workback; -- cgit v1.1 From 715914d3f9e4e40af58d22103c7650cdd720ef92 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Mon, 31 May 2021 12:13:50 -0400 Subject: Do not calculate new values when evaluating a debug statement. Add a flag to enable/disable immediately improving poor values found during cache propagation. Then disable it when processing debug statements. gcc/ PR tree-optimization/100781 * gimple-range-cache.cc (ranger_cache::ranger_cache): Enable new value calculation by default. (ranger_cache::enable_new_values): New. (ranger_cache::disable_new_values): New. (ranger_cache::push_poor_value): Check if new values are allowed. * gimple-range-cache.h (class ranger_cache): New member/methods. * gimple-range.cc (gimple_ranger::range_of_expr): Check for debug statement, and disable/renable new value calculation. gcc/testsuite/ PR tree-optimization/100781 * gcc.dg/pr100781.c: New. --- gcc/gimple-range-cache.cc | 20 ++++++++++++++++++++ gcc/gimple-range-cache.h | 3 +++ gcc/gimple-range.cc | 9 +++++++++ gcc/testsuite/gcc.dg/pr100781.c | 25 +++++++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/pr100781.c (limited to 'gcc') diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index dc32841..cc27574 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -586,6 +586,7 @@ ranger_cache::ranger_cache (gimple_ranger &q) : query (q) if (bb) m_gori.exports (bb); } + enable_new_values (); } ranger_cache::~ranger_cache () @@ -606,6 +607,23 @@ ranger_cache::dump (FILE *f) fprintf (f, "\n"); } +// Allow the cache to flag and query new values when propagation is forced +// to use an unknown value. + +void +ranger_cache::enable_new_values () +{ + m_new_value_p = true; +} + +// Disable new value querying. + +void +ranger_cache::disable_new_values () +{ + m_new_value_p = false; +} + // Dump the caches for basic block BB to file F. void @@ -689,6 +707,8 @@ ranger_cache::set_global_range (tree name, const irange &r) bool ranger_cache::push_poor_value (basic_block bb, tree name) { + if (!m_new_value_p) + return false; if (m_poor_value_list.length ()) { // Don't push anything else to the same block. If there are multiple diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h index fee69bc..4af461d 100644 --- a/gcc/gimple-range-cache.h +++ b/gcc/gimple-range-cache.h @@ -100,6 +100,8 @@ public: bool get_non_stale_global_range (irange &r, tree name); void set_global_range (tree name, const irange &r); + void enable_new_values (); + void disable_new_values (); non_null_ref m_non_null; gori_compute m_gori; @@ -131,6 +133,7 @@ private: bool push_poor_value (basic_block bb, tree name); vec m_poor_value_list; class gimple_ranger &query; + bool m_new_value_p; }; #endif // GCC_SSA_RANGE_CACHE_H diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index d58e151..ed0a0c9 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -971,6 +971,15 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) return true; } + // For a debug stmt, pick the best value currently available, do not + // trigger new value calculations. PR 100781. + if (is_gimple_debug (stmt)) + { + m_cache.disable_new_values (); + m_cache.range_of_expr (r, expr, stmt); + m_cache.enable_new_values (); + return true; + } basic_block bb = gimple_bb (stmt); gimple *def_stmt = SSA_NAME_DEF_STMT (expr); diff --git a/gcc/testsuite/gcc.dg/pr100781.c b/gcc/testsuite/gcc.dg/pr100781.c new file mode 100644 index 0000000..c0e008a --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr100781.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 --param=evrp-mode=ranger -fcompare-debug " } */ + +struct a { + int b; +}; +long c(short d, long e, struct a f) { +g:; + int h = f.b <= e, i = d, n = h >= d; + if (!n) + goto j; + goto k; +j:; + long l = 5; + if (l) + goto m; + d = 0; +m: + if (d) + return f.b; +k: + goto g; +} +int main() { } + -- cgit v1.1 From 28daadc98094501175c9dfe4a985871fa6aa4f94 Mon Sep 17 00:00:00 2001 From: liuhongt Date: Wed, 6 Jan 2021 16:33:27 +0800 Subject: Extend is_cond_scalar_reduction to handle nop_expr after/before scalar reduction.[PR98365] gcc/ChangeLog: PR tree-optimization/98365 * tree-if-conv.c (strip_nop_cond_scalar_reduction): New function. (is_cond_scalar_reduction): Handle nop_expr in cond scalar reduction. (convert_scalar_cond_reduction): Ditto. (predicate_scalar_phi): Ditto. gcc/testsuite/ChangeLog: PR tree-optimization/98365 * gcc.target/i386/pr98365.c: New test. --- gcc/testsuite/gcc.target/i386/pr98365.c | 22 +++++ gcc/tree-if-conv.c | 142 ++++++++++++++++++++++++++++---- 2 files changed, 146 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr98365.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/pr98365.c b/gcc/testsuite/gcc.target/i386/pr98365.c new file mode 100644 index 0000000..652210d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr98365.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx2 -ftree-vectorize -fdump-tree-vect-details" } */ +/* { dg-final { scan-tree-dump-times "vectorized \[1-3] loops" 2 "vect" } } */ +short foo1 (short* a, short* c, int n) +{ + int i; + short cnt=0; + for (int i = 0;i != n; i++) + if (a[i] == c[i]) + cnt++; + return cnt; +} + +char foo2 (char* a, char* c, int n) +{ + int i; + char cnt=0; + for (int i = 0;i != n; i++) + if (a[i] == c[i]) + cnt++; + return cnt; +} diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c index 716eae4..345488e 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -1579,6 +1579,31 @@ if_convertible_loop_p (class loop *loop) return res; } +/* Return reduc_1 if has_nop. + + if (...) + tmp1 = (unsigned type) reduc_1; + tmp2 = tmp1 + rhs2; + reduc_3 = (signed type) tmp2. */ +static tree +strip_nop_cond_scalar_reduction (bool has_nop, tree op) +{ + if (!has_nop) + return op; + + if (TREE_CODE (op) != SSA_NAME) + return NULL_TREE; + + gassign *stmt = safe_dyn_cast (SSA_NAME_DEF_STMT (op)); + if (!stmt + || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt)) + || !tree_nop_conversion_p (TREE_TYPE (op), TREE_TYPE + (gimple_assign_rhs1 (stmt)))) + return NULL_TREE; + + return gimple_assign_rhs1 (stmt); +} + /* Returns true if def-stmt for phi argument ARG is simple increment/decrement which is in predicated basic block. In fact, the following PHI pattern is searching: @@ -1595,9 +1620,10 @@ if_convertible_loop_p (class loop *loop) static bool is_cond_scalar_reduction (gimple *phi, gimple **reduc, tree arg_0, tree arg_1, - tree *op0, tree *op1, bool extended) + tree *op0, tree *op1, bool extended, bool* has_nop, + gimple **nop_reduc) { - tree lhs, r_op1, r_op2; + tree lhs, r_op1, r_op2, r_nop1, r_nop2; gimple *stmt; gimple *header_phi = NULL; enum tree_code reduction_op; @@ -1608,7 +1634,7 @@ is_cond_scalar_reduction (gimple *phi, gimple **reduc, tree arg_0, tree arg_1, use_operand_p use_p; edge e; edge_iterator ei; - bool result = false; + bool result = *has_nop = false; if (TREE_CODE (arg_0) != SSA_NAME || TREE_CODE (arg_1) != SSA_NAME) return false; @@ -1656,18 +1682,77 @@ is_cond_scalar_reduction (gimple *phi, gimple **reduc, tree arg_0, tree arg_1, return false; reduction_op = gimple_assign_rhs_code (stmt); + + /* Catch something like below + + loop-header: + reduc_1 = PHI <..., reduc_2> + ... + if (...) + tmp1 = (unsigned type) reduc_1; + tmp2 = tmp1 + rhs2; + reduc_3 = (signed type) tmp2; + + reduc_2 = PHI + + and convert to + + reduc_2 = PHI <0, reduc_3> + tmp1 = (unsigned type)reduce_1; + ifcvt = cond_expr ? rhs2 : 0 + tmp2 = tmp1 +/- ifcvt; + reduce_1 = (signed type)tmp2; */ + + if (CONVERT_EXPR_CODE_P (reduction_op)) + { + lhs = gimple_assign_rhs1 (stmt); + if (TREE_CODE (lhs) != SSA_NAME + || !has_single_use (lhs)) + return false; + + *nop_reduc = stmt; + stmt = SSA_NAME_DEF_STMT (lhs); + if (gimple_bb (stmt) != gimple_bb (*nop_reduc) + || !is_gimple_assign (stmt)) + return false; + + *has_nop = true; + reduction_op = gimple_assign_rhs_code (stmt); + } + if (reduction_op != PLUS_EXPR && reduction_op != MINUS_EXPR) return false; r_op1 = gimple_assign_rhs1 (stmt); r_op2 = gimple_assign_rhs2 (stmt); + r_nop1 = strip_nop_cond_scalar_reduction (*has_nop, r_op1); + r_nop2 = strip_nop_cond_scalar_reduction (*has_nop, r_op2); + /* Make R_OP1 to hold reduction variable. */ - if (r_op2 == PHI_RESULT (header_phi) + if (r_nop2 == PHI_RESULT (header_phi) && reduction_op == PLUS_EXPR) - std::swap (r_op1, r_op2); - else if (r_op1 != PHI_RESULT (header_phi)) + { + std::swap (r_op1, r_op2); + std::swap (r_nop1, r_nop2); + } + else if (r_nop1 != PHI_RESULT (header_phi)) return false; + if (*has_nop) + { + /* Check that R_NOP1 is used in nop_stmt or in PHI only. */ + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, r_nop1) + { + gimple *use_stmt = USE_STMT (use_p); + if (is_gimple_debug (use_stmt)) + continue; + if (use_stmt == SSA_NAME_DEF_STMT (r_op1)) + continue; + if (use_stmt != phi) + return false; + } + } + /* Check that R_OP1 is used in reduction stmt or in PHI only. */ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, r_op1) { @@ -1705,7 +1790,8 @@ is_cond_scalar_reduction (gimple *phi, gimple **reduc, tree arg_0, tree arg_1, static tree convert_scalar_cond_reduction (gimple *reduc, gimple_stmt_iterator *gsi, - tree cond, tree op0, tree op1, bool swap) + tree cond, tree op0, tree op1, bool swap, + bool has_nop, gimple* nop_reduc) { gimple_stmt_iterator stmt_it; gimple *new_assign; @@ -1714,6 +1800,7 @@ convert_scalar_cond_reduction (gimple *reduc, gimple_stmt_iterator *gsi, tree tmp = make_temp_ssa_name (TREE_TYPE (rhs1), NULL, "_ifc_"); tree c; tree zero = build_zero_cst (TREE_TYPE (rhs1)); + gimple_seq stmts = NULL; if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -1732,8 +1819,18 @@ convert_scalar_cond_reduction (gimple *reduc, gimple_stmt_iterator *gsi, new_assign = gimple_build_assign (tmp, c); gsi_insert_before (gsi, new_assign, GSI_SAME_STMT); /* Build rhs for unconditional increment/decrement. */ - rhs = fold_build2 (gimple_assign_rhs_code (reduc), - TREE_TYPE (rhs1), op0, tmp); + rhs = gimple_build (&stmts, gimple_assign_rhs_code (reduc), + TREE_TYPE (rhs1), op0, tmp); + + if (has_nop) + { + rhs = gimple_convert (&stmts, + TREE_TYPE (gimple_assign_lhs (nop_reduc)), rhs); + stmt_it = gsi_for_stmt (nop_reduc); + gsi_remove (&stmt_it, true); + release_defs (nop_reduc); + } + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); /* Delete original reduction stmt. */ stmt_it = gsi_for_stmt (reduc); @@ -1808,7 +1905,7 @@ ifcvt_follow_ssa_use_edges (tree val) static void predicate_scalar_phi (gphi *phi, gimple_stmt_iterator *gsi) { - gimple *new_stmt = NULL, *reduc; + gimple *new_stmt = NULL, *reduc, *nop_reduc; tree rhs, res, arg0, arg1, op0, op1, scev; tree cond; unsigned int index0; @@ -1816,6 +1913,7 @@ predicate_scalar_phi (gphi *phi, gimple_stmt_iterator *gsi) edge e; basic_block bb; unsigned int i; + bool has_nop; res = gimple_phi_result (phi); if (virtual_operand_p (res)) @@ -1876,10 +1974,15 @@ predicate_scalar_phi (gphi *phi, gimple_stmt_iterator *gsi) arg1 = gimple_phi_arg_def (phi, 1); } if (is_cond_scalar_reduction (phi, &reduc, arg0, arg1, - &op0, &op1, false)) - /* Convert reduction stmt into vectorizable form. */ - rhs = convert_scalar_cond_reduction (reduc, gsi, cond, op0, op1, - true_bb != gimple_bb (reduc)); + &op0, &op1, false, &has_nop, + &nop_reduc)) + { + /* Convert reduction stmt into vectorizable form. */ + rhs = convert_scalar_cond_reduction (reduc, gsi, cond, op0, op1, + true_bb != gimple_bb (reduc), + has_nop, nop_reduc); + redundant_ssa_names.safe_push (std::make_pair (res, rhs)); + } else /* Build new RHS using selected condition and arguments. */ rhs = fold_build_cond_expr (TREE_TYPE (res), unshare_expr (cond), @@ -1961,14 +2064,17 @@ predicate_scalar_phi (gphi *phi, gimple_stmt_iterator *gsi) is_gimple_condexpr, NULL_TREE, true, GSI_SAME_STMT); if (!(is_cond_scalar_reduction (phi, &reduc, arg0 , arg1, - &op0, &op1, true))) + &op0, &op1, true, &has_nop, &nop_reduc))) rhs = fold_build_cond_expr (TREE_TYPE (res), unshare_expr (cond), swap? arg1 : arg0, swap? arg0 : arg1); else - /* Convert reduction stmt into vectorizable form. */ - rhs = convert_scalar_cond_reduction (reduc, gsi, cond, op0, op1, - swap); + { + /* Convert reduction stmt into vectorizable form. */ + rhs = convert_scalar_cond_reduction (reduc, gsi, cond, op0, op1, + swap,has_nop, nop_reduc); + redundant_ssa_names.safe_push (std::make_pair (res, rhs)); + } new_stmt = gimple_build_assign (res, rhs); gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); update_stmt (new_stmt); -- cgit v1.1 From f6bf436d9ab907d090823895abb7a2d5ba7ff50c Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Tue, 1 Jun 2021 12:46:37 +0200 Subject: Fortran/OpenMP: Support (parallel) master taskloop (simd) [PR99928] PR middle-end/99928 gcc/fortran/ChangeLog: * dump-parse-tree.c (show_omp_node, show_code_node): Handle (parallel) master taskloop (simd). * frontend-passes.c (gfc_code_walker): Set in_omp_workshare to false for parallel master taskloop (simd). * gfortran.h (enum gfc_statement): Add ST_OMP_(END_)(PARALLEL_)MASTER_TASKLOOP(_SIMD). (enum gfc_exec_op): EXEC_OMP_(PARALLEL_)MASTER_TASKLOOP(_SIMD). * match.h (gfc_match_omp_master_taskloop, gfc_match_omp_master_taskloop_simd, gfc_match_omp_parallel_master_taskloop, gfc_match_omp_parallel_master_taskloop_simd): New prototype. * openmp.c (gfc_match_omp_parallel_master_taskloop, gfc_match_omp_parallel_master_taskloop_simd, gfc_match_omp_master_taskloop, gfc_match_omp_master_taskloop_simd): New. (gfc_match_omp_taskloop_simd): Permit 'reduction' clause. (resolve_omp_clauses): Handle new combined directives; remove inscan-reduction check to reduce multiple errors; add task-reduction error for 'taskloop simd'. (gfc_resolve_omp_parallel_blocks, resolve_omp_do, omp_code_to_statement, gfc_resolve_omp_directive): Handle new combined constructs. * parse.c (decode_omp_directive, next_statement, gfc_ascii_statement, parse_omp_do, parse_omp_structured_block, parse_executable): Likewise. * resolve.c (gfc_resolve_blocks, gfc_resolve_code): Likewise. * st.c (gfc_free_statement): Likewise. * trans.c (trans_code): Likewise. * trans-openmp.c (gfc_split_omp_clauses, gfc_trans_omp_directive): Likewise. (gfc_trans_omp_parallel_master): Move after gfc_trans_omp_master_taskloop; handle parallel master taskloop (simd) as well. (gfc_trans_omp_taskloop): Take gfc_exec_op as arg. (gfc_trans_omp_master_taskloop): New. gcc/testsuite/ChangeLog: * gfortran.dg/gomp/reduction5.f90: Remove dg-error; the issue is now diagnosed with less error output. * gfortran.dg/gomp/scan-1.f90: Likewise. * gfortran.dg/gomp/pr99928-3.f90: New test. * gfortran.dg/gomp/taskloop-1.f90: New test. --- gcc/fortran/dump-parse-tree.c | 12 +++ gcc/fortran/frontend-passes.c | 2 + gcc/fortran/gfortran.h | 10 +- gcc/fortran/match.h | 4 + gcc/fortran/openmp.c | 85 ++++++++++++++-- gcc/fortran/parse.c | 73 +++++++++++++- gcc/fortran/resolve.c | 10 ++ gcc/fortran/st.c | 4 + gcc/fortran/trans-openmp.c | 112 ++++++++++++++++----- gcc/fortran/trans.c | 4 + gcc/testsuite/gfortran.dg/gomp/pr99928-3.f90 | 139 ++++++++++++++++++++++++++ gcc/testsuite/gfortran.dg/gomp/reduction5.f90 | 4 +- gcc/testsuite/gfortran.dg/gomp/scan-1.f90 | 4 +- gcc/testsuite/gfortran.dg/gomp/taskloop-1.f90 | 126 +++++++++++++++++++++++ 14 files changed, 550 insertions(+), 39 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/gomp/pr99928-3.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/taskloop-1.f90 (limited to 'gcc') diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c index 93ff572..0e7fe1c 100644 --- a/gcc/fortran/dump-parse-tree.c +++ b/gcc/fortran/dump-parse-tree.c @@ -1898,12 +1898,18 @@ show_omp_node (int level, gfc_code *c) case EXEC_OMP_DO_SIMD: name = "DO SIMD"; break; case EXEC_OMP_FLUSH: name = "FLUSH"; break; case EXEC_OMP_MASTER: name = "MASTER"; break; + case EXEC_OMP_MASTER_TASKLOOP: name = "MASTER TASKLOOP"; break; + case EXEC_OMP_MASTER_TASKLOOP_SIMD: name = "MASTER TASKLOOP SIMD"; break; case EXEC_OMP_ORDERED: name = "ORDERED"; break; case EXEC_OMP_DEPOBJ: name = "DEPOBJ"; break; case EXEC_OMP_PARALLEL: name = "PARALLEL"; break; case EXEC_OMP_PARALLEL_DO: name = "PARALLEL DO"; break; case EXEC_OMP_PARALLEL_DO_SIMD: name = "PARALLEL DO SIMD"; break; case EXEC_OMP_PARALLEL_MASTER: name = "PARALLEL MASTER"; break; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + name = "PARALLEL MASTER TASKLOOP"; break; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + name = "PARALLEL MASTER TASKLOOP SIMD"; break; case EXEC_OMP_PARALLEL_SECTIONS: name = "PARALLEL SECTIONS"; break; case EXEC_OMP_PARALLEL_WORKSHARE: name = "PARALLEL WORKSHARE"; break; case EXEC_OMP_SCAN: name = "SCAN"; break; @@ -1976,6 +1982,8 @@ show_omp_node (int level, gfc_code *c) case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SCAN: @@ -3184,11 +3192,15 @@ show_code_node (int level, gfc_code *c) case EXEC_OMP_DO_SIMD: case EXEC_OMP_FLUSH: case EXEC_OMP_MASTER: + case EXEC_OMP_MASTER_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_ORDERED: case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SCAN: diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c index ffe2db4..e3b1d15 100644 --- a/gcc/fortran/frontend-passes.c +++ b/gcc/fortran/frontend-passes.c @@ -5543,6 +5543,8 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn, case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: in_omp_workshare = false; diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 55fba04..2020ab4 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -267,7 +267,11 @@ enum gfc_statement ST_GET_FCN_CHARACTERISTICS, ST_LOCK, ST_UNLOCK, ST_EVENT_POST, ST_EVENT_WAIT, ST_FAIL_IMAGE, ST_FORM_TEAM, ST_CHANGE_TEAM, ST_END_TEAM, ST_SYNC_TEAM, ST_OMP_PARALLEL_MASTER, - ST_OMP_END_PARALLEL_MASTER, ST_NONE + ST_OMP_END_PARALLEL_MASTER, ST_OMP_PARALLEL_MASTER_TASKLOOP, + ST_OMP_END_PARALLEL_MASTER_TASKLOOP, ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD, + ST_OMP_END_PARALLEL_MASTER_TASKLOOP_SIMD, ST_OMP_MASTER_TASKLOOP, + ST_OMP_END_MASTER_TASKLOOP, ST_OMP_MASTER_TASKLOOP_SIMD, + ST_OMP_END_MASTER_TASKLOOP_SIMD, ST_NONE }; /* Types of interfaces that we can have. Assignment interfaces are @@ -2711,7 +2715,9 @@ enum gfc_exec_op EXEC_OMP_TARGET_PARALLEL, EXEC_OMP_TARGET_PARALLEL_DO, EXEC_OMP_TARGET_PARALLEL_DO_SIMD, EXEC_OMP_TARGET_SIMD, EXEC_OMP_TASKLOOP, EXEC_OMP_TASKLOOP_SIMD, EXEC_OMP_SCAN, EXEC_OMP_DEPOBJ, - EXEC_OMP_PARALLEL_MASTER + EXEC_OMP_PARALLEL_MASTER, EXEC_OMP_PARALLEL_MASTER_TASKLOOP, + EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD, EXEC_OMP_MASTER_TASKLOOP, + EXEC_OMP_MASTER_TASKLOOP_SIMD }; typedef struct gfc_code diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h index 09c5723..bcedf8e 100644 --- a/gcc/fortran/match.h +++ b/gcc/fortran/match.h @@ -169,12 +169,16 @@ match gfc_match_omp_do (void); match gfc_match_omp_do_simd (void); match gfc_match_omp_flush (void); match gfc_match_omp_master (void); +match gfc_match_omp_master_taskloop (void); +match gfc_match_omp_master_taskloop_simd (void); match gfc_match_omp_ordered (void); match gfc_match_omp_ordered_depend (void); match gfc_match_omp_parallel (void); match gfc_match_omp_parallel_do (void); match gfc_match_omp_parallel_do_simd (void); match gfc_match_omp_parallel_master (void); +match gfc_match_omp_parallel_master_taskloop (void); +match gfc_match_omp_parallel_master_taskloop_simd (void); match gfc_match_omp_parallel_sections (void); match gfc_match_omp_parallel_workshare (void); match gfc_match_omp_requires (void); diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index 4ed6a0d..9dba165 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -3995,6 +3995,22 @@ gfc_match_omp_parallel_master (void) return match_omp (EXEC_OMP_PARALLEL_MASTER, OMP_PARALLEL_CLAUSES); } +match +gfc_match_omp_parallel_master_taskloop (void) +{ + return match_omp (EXEC_OMP_PARALLEL_MASTER_TASKLOOP, + (OMP_PARALLEL_CLAUSES | OMP_TASKLOOP_CLAUSES) + & ~(omp_mask (OMP_CLAUSE_IN_REDUCTION))); +} + +match +gfc_match_omp_parallel_master_taskloop_simd (void) +{ + return match_omp (EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD, + (OMP_PARALLEL_CLAUSES | OMP_TASKLOOP_CLAUSES + | OMP_SIMD_CLAUSES) + & ~(omp_mask (OMP_CLAUSE_IN_REDUCTION))); +} match gfc_match_omp_parallel_sections (void) @@ -4429,8 +4445,7 @@ match gfc_match_omp_taskloop_simd (void) { return match_omp (EXEC_OMP_TASKLOOP_SIMD, - (OMP_TASKLOOP_CLAUSES | OMP_SIMD_CLAUSES) - & ~(omp_mask (OMP_CLAUSE_REDUCTION))); + OMP_TASKLOOP_CLAUSES | OMP_SIMD_CLAUSES); } @@ -4533,6 +4548,18 @@ gfc_match_omp_master (void) return MATCH_YES; } +match +gfc_match_omp_master_taskloop (void) +{ + return match_omp (EXEC_OMP_MASTER_TASKLOOP, OMP_TASKLOOP_CLAUSES); +} + +match +gfc_match_omp_master_taskloop_simd (void) +{ + return match_omp (EXEC_OMP_MASTER_TASKLOOP_SIMD, + OMP_TASKLOOP_CLAUSES | OMP_SIMD_CLAUSES); +} match gfc_match_omp_ordered (void) @@ -5073,6 +5100,16 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_SIMD; break; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_TASKLOOP; + break; + + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + ok = (ifc == OMP_IF_PARALLEL + || ifc == OMP_IF_TASKLOOP + || ifc == OMP_IF_SIMD); + break; + case EXEC_OMP_SIMD: case EXEC_OMP_DO_SIMD: case EXEC_OMP_DISTRIBUTE_SIMD: @@ -5085,10 +5122,12 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, break; case EXEC_OMP_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP: ok = ifc == OMP_IF_TASKLOOP; break; case EXEC_OMP_TASKLOOP_SIMD: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: ok = ifc == OMP_IF_TASKLOOP || ifc == OMP_IF_SIMD; break; @@ -5848,11 +5887,16 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, n->sym->name, name, &n->where); switch (list) { - case OMP_LIST_REDUCTION_INSCAN: case OMP_LIST_REDUCTION_TASK: - if (code && (code->op == EXEC_OMP_TASKLOOP - || code->op == EXEC_OMP_TEAMS - || code->op == EXEC_OMP_TEAMS_DISTRIBUTE)) + if (code + && (code->op == EXEC_OMP_TASKLOOP + || code->op == EXEC_OMP_TASKLOOP_SIMD + || code->op == EXEC_OMP_MASTER_TASKLOOP + || code->op == EXEC_OMP_MASTER_TASKLOOP_SIMD + || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP + || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD + || code->op == EXEC_OMP_TEAMS + || code->op == EXEC_OMP_TEAMS_DISTRIBUTE)) { gfc_error ("Only DEFAULT permitted as reduction-" "modifier in REDUCTION clause at %L", @@ -5863,6 +5907,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, case OMP_LIST_REDUCTION: case OMP_LIST_IN_REDUCTION: case OMP_LIST_TASK_REDUCTION: + case OMP_LIST_REDUCTION_INSCAN: switch (n->u.reduction_op) { case OMP_REDUCTION_PLUS: @@ -6766,6 +6811,10 @@ gfc_resolve_omp_parallel_blocks (gfc_code *code, gfc_namespace *ns) case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_MASTER_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_TARGET_PARALLEL_DO: case EXEC_OMP_TARGET_PARALLEL_DO_SIMD: case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE: @@ -6909,6 +6958,18 @@ resolve_omp_do (gfc_code *code) name = "!$OMP PARALLEL DO SIMD"; is_simd = true; break; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + name = "!$OMP PARALLEL MASTER TASKLOOP"; + break; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + name = "!$OMP PARALLEL MASTER TASKLOOP SIMD"; + is_simd = true; + break; + case EXEC_OMP_MASTER_TASKLOOP: name = "!$OMP MASTER TASKLOOP"; break; + case EXEC_OMP_MASTER_TASKLOOP_SIMD: + name = "!$OMP MASTER TASKLOOP SIMD"; + is_simd = true; + break; case EXEC_OMP_SIMD: name = "!$OMP SIMD"; is_simd = true; break; case EXEC_OMP_TARGET_PARALLEL_DO: name = "!$OMP TARGET PARALLEL DO"; break; case EXEC_OMP_TARGET_PARALLEL_DO_SIMD: @@ -7063,6 +7124,10 @@ omp_code_to_statement (gfc_code *code) return ST_OMP_PARALLEL; case EXEC_OMP_PARALLEL_MASTER: return ST_OMP_PARALLEL_MASTER; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + return ST_OMP_PARALLEL_MASTER_TASKLOOP; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + return ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD; case EXEC_OMP_PARALLEL_SECTIONS: return ST_OMP_PARALLEL_SECTIONS; case EXEC_OMP_SECTIONS: @@ -7073,6 +7138,10 @@ omp_code_to_statement (gfc_code *code) return ST_OMP_CRITICAL; case EXEC_OMP_MASTER: return ST_OMP_MASTER; + case EXEC_OMP_MASTER_TASKLOOP: + return ST_OMP_MASTER_TASKLOOP; + case EXEC_OMP_MASTER_TASKLOOP_SIMD: + return ST_OMP_MASTER_TASKLOOP_SIMD; case EXEC_OMP_SINGLE: return ST_OMP_SINGLE; case EXEC_OMP_TASK: @@ -7561,6 +7630,10 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns) case EXEC_OMP_DO_SIMD: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_MASTER_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_SIMD: case EXEC_OMP_TARGET_PARALLEL_DO: case EXEC_OMP_TARGET_PARALLEL_DO_SIMD: diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c index 6efb3fd..c44e23c 100644 --- a/gcc/fortran/parse.c +++ b/gcc/fortran/parse.c @@ -920,11 +920,19 @@ decode_omp_directive (void) matchs ("end do simd", gfc_match_omp_end_nowait, ST_OMP_END_DO_SIMD); matcho ("end do", gfc_match_omp_end_nowait, ST_OMP_END_DO); matchs ("end simd", gfc_match_omp_eos_error, ST_OMP_END_SIMD); + matcho ("end master taskloop simd", gfc_match_omp_eos_error, + ST_OMP_END_MASTER_TASKLOOP_SIMD); + matcho ("end master taskloop", gfc_match_omp_eos_error, + ST_OMP_END_MASTER_TASKLOOP); matcho ("end master", gfc_match_omp_eos_error, ST_OMP_END_MASTER); matchs ("end ordered", gfc_match_omp_eos_error, ST_OMP_END_ORDERED); matchs ("end parallel do simd", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_DO_SIMD); matcho ("end parallel do", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_DO); + matcho ("end parallel master taskloop simd", gfc_match_omp_eos_error, + ST_OMP_END_PARALLEL_MASTER_TASKLOOP_SIMD); + matcho ("end parallel master taskloop", gfc_match_omp_eos_error, + ST_OMP_END_PARALLEL_MASTER_TASKLOOP); matcho ("end parallel master", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_MASTER); matcho ("end parallel sections", gfc_match_omp_eos_error, @@ -974,6 +982,10 @@ decode_omp_directive (void) matcho ("flush", gfc_match_omp_flush, ST_OMP_FLUSH); break; case 'm': + matcho ("master taskloop simd", gfc_match_omp_master_taskloop_simd, + ST_OMP_MASTER_TASKLOOP_SIMD); + matcho ("master taskloop", gfc_match_omp_master_taskloop, + ST_OMP_MASTER_TASKLOOP); matcho ("master", gfc_match_omp_master, ST_OMP_MASTER); break; case 'o': @@ -992,6 +1004,12 @@ decode_omp_directive (void) matchs ("parallel do simd", gfc_match_omp_parallel_do_simd, ST_OMP_PARALLEL_DO_SIMD); matcho ("parallel do", gfc_match_omp_parallel_do, ST_OMP_PARALLEL_DO); + matcho ("parallel master taskloop simd", + gfc_match_omp_parallel_master_taskloop_simd, + ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD); + matcho ("parallel master taskloop", + gfc_match_omp_parallel_master_taskloop, + ST_OMP_PARALLEL_MASTER_TASKLOOP); matcho ("parallel master", gfc_match_omp_parallel_master, ST_OMP_PARALLEL_MASTER); matcho ("parallel sections", gfc_match_omp_parallel_sections, @@ -1610,8 +1628,11 @@ next_statement (void) case ST_IF_BLOCK: case ST_BLOCK: case ST_ASSOCIATE: \ case ST_WHERE_BLOCK: case ST_SELECT_CASE: case ST_SELECT_TYPE: \ case ST_SELECT_RANK: case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_MASTER: \ + case ST_OMP_PARALLEL_MASTER_TASKLOOP: \ + case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: \ case ST_OMP_PARALLEL_SECTIONS: case ST_OMP_SECTIONS: case ST_OMP_ORDERED: \ - case ST_OMP_CRITICAL: case ST_OMP_MASTER: case ST_OMP_SINGLE: \ + case ST_OMP_CRITICAL: case ST_OMP_MASTER: case ST_OMP_MASTER_TASKLOOP: \ + case ST_OMP_MASTER_TASKLOOP_SIMD: case ST_OMP_SINGLE: \ case ST_OMP_DO: case ST_OMP_PARALLEL_DO: case ST_OMP_ATOMIC: \ case ST_OMP_WORKSHARE: case ST_OMP_PARALLEL_WORKSHARE: \ case ST_OMP_TASK: case ST_OMP_TASKGROUP: case ST_OMP_SIMD: \ @@ -2341,6 +2362,12 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_END_MASTER: p = "!$OMP END MASTER"; break; + case ST_OMP_END_MASTER_TASKLOOP: + p = "!$OMP END MASTER TASKLOOP"; + break; + case ST_OMP_END_MASTER_TASKLOOP_SIMD: + p = "!$OMP END MASTER TASKLOOP SIMD"; + break; case ST_OMP_END_ORDERED: p = "!$OMP END ORDERED"; break; @@ -2356,6 +2383,12 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_END_PARALLEL_MASTER: p = "!$OMP END PARALLEL MASTER"; break; + case ST_OMP_END_PARALLEL_MASTER_TASKLOOP: + p = "!$OMP END PARALLEL MASTER TASKLOOP"; + break; + case ST_OMP_END_PARALLEL_MASTER_TASKLOOP_SIMD: + p = "!$OMP END PARALLEL MASTER TASKLOOP SIMD"; + break; case ST_OMP_END_PARALLEL_SECTIONS: p = "!$OMP END PARALLEL SECTIONS"; break; @@ -2437,6 +2470,12 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_MASTER: p = "!$OMP MASTER"; break; + case ST_OMP_MASTER_TASKLOOP: + p = "!$OMP MASTER TASKLOOP"; + break; + case ST_OMP_MASTER_TASKLOOP_SIMD: + p = "!$OMP MASTER TASKLOOP SIMD"; + break; case ST_OMP_ORDERED: case ST_OMP_ORDERED_DEPEND: p = "!$OMP ORDERED"; @@ -2453,6 +2492,12 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_PARALLEL_MASTER: p = "!$OMP PARALLEL MASTER"; break; + case ST_OMP_PARALLEL_MASTER_TASKLOOP: + p = "!$OMP PARALLEL MASTER TASKLOOP"; + break; + case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + p = "!$OMP PARALLEL MASTER TASKLOOP SIMD"; + break; case ST_OMP_PARALLEL_SECTIONS: p = "!$OMP PARALLEL SECTIONS"; break; @@ -5025,6 +5070,16 @@ parse_omp_do (gfc_statement omp_st) break; case ST_OMP_TASKLOOP: omp_end_st = ST_OMP_END_TASKLOOP; break; case ST_OMP_TASKLOOP_SIMD: omp_end_st = ST_OMP_END_TASKLOOP_SIMD; break; + case ST_OMP_MASTER_TASKLOOP: omp_end_st = ST_OMP_END_MASTER_TASKLOOP; break; + case ST_OMP_MASTER_TASKLOOP_SIMD: + omp_end_st = ST_OMP_END_MASTER_TASKLOOP_SIMD; + break; + case ST_OMP_PARALLEL_MASTER_TASKLOOP: + omp_end_st = ST_OMP_END_PARALLEL_MASTER_TASKLOOP; + break; + case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + omp_end_st = ST_OMP_END_PARALLEL_MASTER_TASKLOOP_SIMD; + break; case ST_OMP_TEAMS_DISTRIBUTE: omp_end_st = ST_OMP_END_TEAMS_DISTRIBUTE; break; @@ -5268,6 +5323,12 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only) case ST_OMP_PARALLEL_MASTER: omp_end_st = ST_OMP_END_PARALLEL_MASTER; break; + case ST_OMP_PARALLEL_MASTER_TASKLOOP: + omp_end_st = ST_OMP_END_PARALLEL_MASTER_TASKLOOP; + break; + case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + omp_end_st = ST_OMP_END_PARALLEL_MASTER_TASKLOOP_SIMD; + break; case ST_OMP_PARALLEL_SECTIONS: omp_end_st = ST_OMP_END_PARALLEL_SECTIONS; break; @@ -5283,6 +5344,12 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only) case ST_OMP_MASTER: omp_end_st = ST_OMP_END_MASTER; break; + case ST_OMP_MASTER_TASKLOOP: + omp_end_st = ST_OMP_END_MASTER_TASKLOOP; + break; + case ST_OMP_MASTER_TASKLOOP_SIMD: + omp_end_st = ST_OMP_END_MASTER_TASKLOOP_SIMD; + break; case ST_OMP_SINGLE: omp_end_st = ST_OMP_END_SINGLE; break; @@ -5624,6 +5691,10 @@ parse_executable (gfc_statement st) case ST_OMP_DO_SIMD: case ST_OMP_PARALLEL_DO: case ST_OMP_PARALLEL_DO_SIMD: + case ST_OMP_PARALLEL_MASTER_TASKLOOP: + case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case ST_OMP_MASTER_TASKLOOP: + case ST_OMP_MASTER_TASKLOOP_SIMD: case ST_OMP_SIMD: case ST_OMP_TARGET_PARALLEL_DO: case ST_OMP_TARGET_PARALLEL_DO_SIMD: diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 747516f..fed6dce 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -10798,11 +10798,15 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns) case EXEC_OMP_DO: case EXEC_OMP_DO_SIMD: case EXEC_OMP_MASTER: + case EXEC_OMP_MASTER_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_ORDERED: case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SECTIONS: @@ -11765,6 +11769,8 @@ gfc_resolve_code (gfc_code *code, gfc_namespace *ns) case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_TARGET_PARALLEL: case EXEC_OMP_TARGET_PARALLEL_DO: @@ -12214,6 +12220,8 @@ start: case EXEC_OMP_DO: case EXEC_OMP_DO_SIMD: case EXEC_OMP_MASTER: + case EXEC_OMP_MASTER_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_ORDERED: case EXEC_OMP_SCAN: case EXEC_OMP_SECTIONS: @@ -12252,6 +12260,8 @@ start: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: omp_workshare_save = omp_workshare_flag; diff --git a/gcc/fortran/st.c b/gcc/fortran/st.c index 7d0e2c1..9f6fe49 100644 --- a/gcc/fortran/st.c +++ b/gcc/fortran/st.c @@ -226,11 +226,15 @@ gfc_free_statement (gfc_code *p) case EXEC_OMP_DO: case EXEC_OMP_DO_SIMD: case EXEC_OMP_END_SINGLE: + case EXEC_OMP_MASTER_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_ORDERED: case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SCAN: diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 7ea7aa3..2917d3d 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -5380,6 +5380,14 @@ gfc_split_omp_clauses (gfc_code *code, mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_DO | GFC_OMP_MASK_SIMD; innermost = GFC_OMP_SPLIT_SIMD; break; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD; + innermost = GFC_OMP_SPLIT_TASKLOOP; + break; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD; + innermost = GFC_OMP_SPLIT_SIMD; + break; case EXEC_OMP_SIMD: innermost = GFC_OMP_SPLIT_SIMD; break; @@ -5427,9 +5435,11 @@ gfc_split_omp_clauses (gfc_code *code, | GFC_OMP_MASK_DISTRIBUTE | GFC_OMP_MASK_SIMD; innermost = GFC_OMP_SPLIT_SIMD; break; + case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_TASKLOOP: innermost = GFC_OMP_SPLIT_TASKLOOP; break; + case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_TASKLOOP_SIMD: mask = GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD; innermost = GFC_OMP_SPLIT_SIMD; @@ -5821,28 +5831,6 @@ gfc_trans_omp_parallel_do_simd (gfc_code *code, stmtblock_t *pblock, } static tree -gfc_trans_omp_parallel_master (gfc_code *code) -{ - stmtblock_t block; - tree stmt, omp_clauses; - - gfc_start_block (&block); - omp_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses, - code->loc); - pushlevel (); - stmt = gfc_trans_omp_master (code); - if (TREE_CODE (stmt) != BIND_EXPR) - stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); - else - poplevel (0, 0); - stmt = build2_loc (gfc_get_location (&code->loc), OMP_PARALLEL, - void_type_node, stmt, omp_clauses); - OMP_PARALLEL_COMBINED (stmt) = 1; - gfc_add_expr_to_block (&block, stmt); - return gfc_finish_block (&block); -} - -static tree gfc_trans_omp_parallel_sections (gfc_code *code) { stmtblock_t block; @@ -6217,7 +6205,7 @@ gfc_trans_omp_target (gfc_code *code) } static tree -gfc_trans_omp_taskloop (gfc_code *code) +gfc_trans_omp_taskloop (gfc_code *code, gfc_exec_op op) { stmtblock_t block; gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM]; @@ -6229,7 +6217,7 @@ gfc_trans_omp_taskloop (gfc_code *code) omp_clauses = gfc_trans_omp_clauses (&block, &clausesa[GFC_OMP_SPLIT_TASKLOOP], code->loc); - switch (code->op) + switch (op) { case EXEC_OMP_TASKLOOP: /* This is handled in gfc_trans_omp_do. */ @@ -6259,6 +6247,75 @@ gfc_trans_omp_taskloop (gfc_code *code) } static tree +gfc_trans_omp_master_taskloop (gfc_code *code, gfc_exec_op op) +{ + stmtblock_t block; + tree stmt; + + gfc_start_block (&block); + pushlevel (); + if (op == EXEC_OMP_MASTER_TASKLOOP_SIMD) + stmt = gfc_trans_omp_taskloop (code, EXEC_OMP_TASKLOOP_SIMD); + else + { + gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM]; + gcc_assert (op == EXEC_OMP_MASTER_TASKLOOP); + if (op != code->op) + gfc_split_omp_clauses (code, clausesa); + stmt = gfc_trans_omp_do (code, EXEC_OMP_TASKLOOP, NULL, + op != code->op + ? &clausesa[GFC_OMP_SPLIT_TASKLOOP] + : code->ext.omp_clauses, NULL); + } + if (TREE_CODE (stmt) != BIND_EXPR) + stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); + else + poplevel (0, 0); + stmt = build1_v (OMP_MASTER, stmt); + gfc_add_expr_to_block (&block, stmt); + return gfc_finish_block (&block); +} + +static tree +gfc_trans_omp_parallel_master (gfc_code *code) +{ + stmtblock_t block; + tree stmt, omp_clauses; + gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM]; + + if (code->op != EXEC_OMP_PARALLEL_MASTER) + gfc_split_omp_clauses (code, clausesa); + + gfc_start_block (&block); + omp_clauses = gfc_trans_omp_clauses (&block, + code->op == EXEC_OMP_PARALLEL_MASTER + ? code->ext.omp_clauses + : &clausesa[GFC_OMP_SPLIT_PARALLEL], + code->loc); + pushlevel (); + if (code->op == EXEC_OMP_PARALLEL_MASTER) + stmt = gfc_trans_omp_master (code); + else + { + gcc_assert (code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP + || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD); + gfc_exec_op op = (code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP + ? EXEC_OMP_MASTER_TASKLOOP + : EXEC_OMP_MASTER_TASKLOOP_SIMD); + stmt = gfc_trans_omp_master_taskloop (code, op); + } + if (TREE_CODE (stmt) != BIND_EXPR) + stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); + else + poplevel (0, 0); + stmt = build2_loc (gfc_get_location (&code->loc), OMP_PARALLEL, + void_type_node, stmt, omp_clauses); + OMP_PARALLEL_COMBINED (stmt) = 1; + gfc_add_expr_to_block (&block, stmt); + return gfc_finish_block (&block); +} + +static tree gfc_trans_omp_target_data (gfc_code *code) { stmtblock_t block; @@ -6568,6 +6625,9 @@ gfc_trans_omp_directive (gfc_code *code) return gfc_trans_omp_flush (code); case EXEC_OMP_MASTER: return gfc_trans_omp_master (code); + case EXEC_OMP_MASTER_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: + return gfc_trans_omp_master_taskloop (code, code->op); case EXEC_OMP_ORDERED: return gfc_trans_omp_ordered (code); case EXEC_OMP_PARALLEL: @@ -6577,6 +6637,8 @@ gfc_trans_omp_directive (gfc_code *code) case EXEC_OMP_PARALLEL_DO_SIMD: return gfc_trans_omp_parallel_do_simd (code, NULL, NULL); case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: return gfc_trans_omp_parallel_master (code); case EXEC_OMP_PARALLEL_SECTIONS: return gfc_trans_omp_parallel_sections (code); @@ -6610,7 +6672,7 @@ gfc_trans_omp_directive (gfc_code *code) case EXEC_OMP_TASKGROUP: return gfc_trans_omp_taskgroup (code); case EXEC_OMP_TASKLOOP_SIMD: - return gfc_trans_omp_taskloop (code); + return gfc_trans_omp_taskloop (code, code->op); case EXEC_OMP_TASKWAIT: return gfc_trans_omp_taskwait (code); case EXEC_OMP_TASKYIELD: diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index 9f296bd..cbbfcd9 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -2170,11 +2170,15 @@ trans_code (gfc_code * code, tree cond) case EXEC_OMP_DO_SIMD: case EXEC_OMP_FLUSH: case EXEC_OMP_MASTER: + case EXEC_OMP_MASTER_TASKLOOP: + case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_ORDERED: case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_MASTER: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SECTIONS: diff --git a/gcc/testsuite/gfortran.dg/gomp/pr99928-3.f90 b/gcc/testsuite/gfortran.dg/gomp/pr99928-3.f90 new file mode 100644 index 0000000..ce43dfb --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/pr99928-3.f90 @@ -0,0 +1,139 @@ +! PR middle-end/99928 +! { dg-do compile } +! { dg-options "-fopenmp -fdump-tree-gimple" } + +module m + implicit none + integer :: l00, l01, l02, l03, l04, l07, l08, l09 + integer :: l10, l11 + +contains + +subroutine bar () + integer :: l05, l06 + integer :: i + l05 = 0; l06 = 0 + ! { dg-final { scan-tree-dump "omp for\[^\n\r]*firstprivate\\(l00\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp for\[^\n\r]*lastprivate\\(l00\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp simd\[^\n\r]*firstprivate\\(l00\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp simd\[^\n\r]*lastprivate\\(l00\\)" "gimple" } } + !$omp do simd firstprivate (l00) lastprivate (l00) + do i = 1, 64 + l00 = i + end do + ! { dg-final { scan-tree-dump-not "omp master\[^\n\r]*firstprivate\\(l01\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp master\[^\n\r]*lastprivate\\(l01\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp taskloop\[^\n\r]*firstprivate\\(l01\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp taskloop\[^\n\r]*lastprivate\\(l01\\)" "gimple" } } + !$omp master taskloop firstprivate (l01) lastprivate (l01) + do i = 1, 64 + l01 = i + end do + ! { dg-final { scan-tree-dump-not "omp master\[^\n\r]*firstprivate\\(l02\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp master\[^\n\r]*lastprivate\\(l02\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp taskloop\[^\n\r]*firstprivate\\(l02\\)" "gimple" { xfail *-*-* } } } + ! { dg-final { scan-tree-dump "omp taskloop\[^\n\r]*lastprivate\\(l02\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp simd\[^\n\r]*firstprivate\\(l02\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp simd\[^\n\r]*lastprivate\\(l02\\)" "gimple" } } + !$omp master taskloop simd firstprivate (l02) lastprivate (l02) + do i = 1, 64 + l02 = i + end do + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*firstprivate\\(l03\\)" "gimple" } } ! FIXME: This should be on for instead. + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*lastprivate\\(l03\\)" "gimple" } } ! FIXME: This should be on for instead. + ! { dg-final { scan-tree-dump-not "omp for\[^\n\r]*firstprivate\\(l03\\)" "gimple" } } ! FIXME. + ! { dg-final { scan-tree-dump-not "omp for\[^\n\r]*lastprivate\\(l03\\)" "gimple" } } ! FIXME. + !$omp parallel do firstprivate (l03) lastprivate (l03) + do i = 1, 64 + l03 = i + end do + !$omp end parallel do + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*firstprivate\\(l04\\)" "gimple" } } ! FIXME: This should be on for instead. + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*lastprivate\\(l04\\)" "gimple" } } ! FIXME: This should be on for instead. + ! { dg-final { scan-tree-dump-not "omp for\[^\n\r]*firstprivate\\(l04\\)" "gimple" } } ! FIXME. + ! { dg-final { scan-tree-dump-not "omp for\[^\n\r]*lastprivate\\(l04\\)" "gimple" } } ! FIXME. + ! { dg-final { scan-tree-dump-not "omp simd\[^\n\r]*firstprivate\\(l04\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp simd\[^\n\r]*lastprivate\\(l04\\)" "gimple" } } + !$omp parallel do simd firstprivate (l04) lastprivate (l04) + do i = 1, 64 + l04 = i + end do + !$omp end parallel do simd + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*shared\\(l05\\)" "gimple" { xfail *-*-* } } } + ! { dg-final { scan-tree-dump-not "omp master\[^\n\r]*firstprivate\\(l05\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp master\[^\n\r]*lastprivate\\(l05\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp taskloop\[^\n\r]*firstprivate\\(l05\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp taskloop\[^\n\r]*lastprivate\\(l05\\)" "gimple" { xfail *-*-* } } } + !$omp parallel master taskloop firstprivate (l05) lastprivate (l05) + do i = 1, 64 + l05 = i + end do + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*shared\\(l06\\)" "gimple" { xfail *-*-* } } } + ! { dg-final { scan-tree-dump-not "omp master\[^\n\r]*firstprivate\\(l06\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp master\[^\n\r]*lastprivate\\(l06\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp taskloop\[^\n\r]*firstprivate\\(l06\\)" "gimple" { xfail *-*-* } } } + ! { dg-final { scan-tree-dump "omp taskloop\[^\n\r]*lastprivate\\(l06\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp simd\[^\n\r]*firstprivate\\(l06\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp simd\[^\n\r]*lastprivate\\(l06\\)" "gimple" } } + !$omp parallel master taskloop simd firstprivate (l06) lastprivate (l06) + do i = 1, 64 + l06 = i + end do + !$omp end parallel master taskloop simd + ! FIXME: OpenMP 5.0/5.1 broken here, conceptually it should be shared on parallel and + ! firstprivate+lastprivate on sections, in GCC implementation we put firstprivate+lastprivate + ! on parallel for historic reasons, but OpenMP 5.0/5.1 mistakenly say firstprivate + ! should be on parallel and lastprivate on sections. + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*firstprivate\\(l07\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*lastprivate\\(l07\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp sections\[^\n\r]*firstprivate\\(l07\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp sections\[^\n\r]*lastprivate\\(l07\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp section \[^\n\r]*firstprivate\\(l07\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp section \[^\n\r]*lastprivate\\(l07\\)" "gimple" } } + !$omp parallel sections firstprivate (l07) lastprivate (l07) + l07 = 1 + !$omp section + l07 = 2 + !$omp end parallel sections + ! { dg-final { scan-tree-dump "omp target\[^\n\r]*map\\(tofrom:l08" "gimple" { xfail *-*-* } } } + ! { dg-final { scan-tree-dump-not "omp target\[^\n\r]*firstprivate\\(l08\\)" "gimple" { xfail *-*-* } } } + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*firstprivate\\(l08\\)" "gimple" } } ! FIXME: This should be on for instead. + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*lastprivate\\(l08\\)" "gimple" } } ! FIXME: This should be on for instead. + ! { dg-final { scan-tree-dump-not "omp for\[^\n\r]*firstprivate\\(l08\\)" "gimple" } } ! FIXME. + ! { dg-final { scan-tree-dump-not "omp for\[^\n\r]*lastprivate\\(l08\\)" "gimple" } } ! FIXME. + !$omp target parallel do firstprivate (l08) lastprivate (l08) + do i = 1, 64 + l08 = i + end do + !$omp end target parallel do + ! { dg-final { scan-tree-dump "omp target\[^\n\r]*map\\(tofrom:l09" "gimple" { xfail *-*-* } } } + ! { dg-final { scan-tree-dump-not "omp target\[^\n\r]*firstprivate\\(l09\\)" "gimple" { xfail *-*-* } } } + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*firstprivate\\(l09\\)" "gimple" } } ! FIXME: This should be on for instead. + ! { dg-final { scan-tree-dump "omp parallel\[^\n\r]*lastprivate\\(l09\\)" "gimple" } } ! FIXME: This should be on for instead. + ! { dg-final { scan-tree-dump-not "omp for\[^\n\r]*firstprivate\\(l09\\)" "gimple" } } ! FIXME. + ! { dg-final { scan-tree-dump-not "omp for\[^\n\r]*lastprivate\\(l09\\)" "gimple" } } ! FIXME. + ! { dg-final { scan-tree-dump-not "omp simd\[^\n\r]*firstprivate\\(l09\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp simd\[^\n\r]*lastprivate\\(l09\\)" "gimple" } } + !$omp target parallel do simd firstprivate (l09) lastprivate (l09) + do i = 1, 64 + l09 = i + end do + ! { dg-final { scan-tree-dump "omp target\[^\n\r]*map\\(tofrom:l10" "gimple" { xfail *-*-* } } } + ! { dg-final { scan-tree-dump-not "omp target\[^\n\r]*firstprivate\\(l10\\)" "gimple" { xfail *-*-* } } } + ! { dg-final { scan-tree-dump-not "omp simd\[^\n\r]*firstprivate\\(l10\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp simd\[^\n\r]*lastprivate\\(l10\\)" "gimple" } } + !$omp target simd firstprivate (l10) lastprivate (l10) + do i = 1, 64 + l10 = i + end do + ! { dg-final { scan-tree-dump "omp taskloop\[^\n\r]*firstprivate\\(l11\\)" "gimple" { xfail *-*-* } } } + ! { dg-final { scan-tree-dump "omp taskloop\[^\n\r]*lastprivate\\(l11\\)" "gimple" } } + ! { dg-final { scan-tree-dump-not "omp simd\[^\n\r]*firstprivate\\(l11\\)" "gimple" } } + ! { dg-final { scan-tree-dump "omp simd\[^\n\r]*lastprivate\\(l11\\)" "gimple" } } + !$omp taskloop simd firstprivate (l11) lastprivate (l11) + do i = 1, 64 + l11 = i + end do + !$omp end taskloop simd +end +end module m diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction5.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction5.f90 index 032703d..44f89d8 100644 --- a/gcc/testsuite/gfortran.dg/gomp/reduction5.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/reduction5.f90 @@ -22,8 +22,7 @@ end do !$omp taskloop reduction(inscan,+:a) in_reduction(+:b) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" } ! { dg-error "34: With INSCAN at .1., expected loop body with ..OMP SCAN between two structured-block-sequences" "" { target *-*-* } .-1 } - ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" "" { target *-*-* } .-2 } - ! { dg-error "'inscan' and non-'inscan' 'reduction' clauses on the same construct" "" { target *-*-* } .-3 } + ! { dg-error "'inscan' and non-'inscan' 'reduction' clauses on the same construct" "" { target *-*-* } .-2 } do i=1,10 a = a + 1 end do @@ -34,7 +33,6 @@ do i=1,10 end do !$omp teams reduction(inscan,+:b) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" } - ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" "" { target *-*-* } .-1 } a = a + 1 !$omp end teams diff --git a/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 b/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 index 8c879fd..61d8925 100644 --- a/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 @@ -100,7 +100,7 @@ subroutine f3 (c, d) use m implicit none integer i, c(64), d(64) - !$omp teams reduction (inscan, +: a) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause at" } + !$omp teams reduction (inscan, +: a) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" "" { target *-*-* } .-1 } ! ... !$omp end teams @@ -135,7 +135,7 @@ subroutine f4 (c, d) use m implicit none integer i, c(64), d(64) - !$omp taskloop reduction (inscan, +: a) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } + !$omp taskloop reduction (inscan, +: a) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" "" { target *-*-* } .-1 } do i = 1, 64 d(i) = a diff --git a/gcc/testsuite/gfortran.dg/gomp/taskloop-1.f90 b/gcc/testsuite/gfortran.dg/gomp/taskloop-1.f90 new file mode 100644 index 0000000..7060a7a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/taskloop-1.f90 @@ -0,0 +1,126 @@ +module m + implicit none + integer :: t + !$omp threadprivate (t) + integer :: f, l, ll, r, r2 + !$omp declare target to(f, l, ll, r, r2) +end module m + +subroutine foo(fi, p, pp, g, s, nta, nth, ntm, i1, i2, i3, q) + use m + implicit none + integer, value :: p, pp, g, s, nta, nth, ntm + logical, value :: fi, i1, i2, i3 + integer, pointer :: q(:) + integer :: i + + !$omp taskgroup task_reduction(+:r2) !allocate (r2) + !$omp taskloop simd & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) & + !$omp& if(simd: i2) final(fi) mergeable priority (pp) & + !$omp& safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) & + !$omp& order(concurrent) !allocate (f) + do i = 1, 64 + ll = ll + 1 + end do + !$omp end taskgroup + + !$omp taskgroup task_reduction(+:r) !allocate (r) + !$omp taskloop simd & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) & + !$omp& collapse(1) untied if(i1) final(fi) mergeable nogroup priority (pp) & + !$omp& safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) in_reduction(+:r) nontemporal(ntm) & + !$omp& order(concurrent) !allocate (f) + do i = 1, 64 + ll = ll + 1 + end do + !$omp taskwait + + !$omp taskloop simd & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) & + !$omp& collapse(1) if(taskloop: i1) final(fi) priority (pp) & + !$omp& safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(+:r) if (simd: i3) nontemporal(ntm) & + !$omp& order(concurrent) !allocate (f) + do i = 1, 64 + ll = ll + 1 + end do + !$omp end taskgroup + + !$omp taskgroup task_reduction (+:r2) !allocate (r2) + !$omp master taskloop & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) & + !$omp& collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) & + !$omp& reduction(default, +:r) in_reduction(+:r2) !allocate (f) + do i = 1, 64 + ll = ll + 1 + end do + !$omp end taskgroup + + !$omp taskgroup task_reduction (+:r2) !allocate (r2) + !$omp master taskloop simd & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) & + !$omp& collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) & + !$omp& safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) & + !$omp& order(concurrent) !allocate (f) + do i = 1, 64 + ll = ll + 1 + end do + !$omp end taskgroup + + !$omp parallel master taskloop & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) & + !$omp& collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) & + !$omp& reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) !allocate (f) + do i = 1, 64 + ll = ll + 1 + end do + + !$omp parallel master taskloop simd & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) & + !$omp& untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) & + !$omp& safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) & + !$omp& if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) & + !$omp& order(concurrent) !allocate (f) + do i = 1, 64 + ll = ll + 1 + end do + + !$omp taskgroup task_reduction (+:r2) !allocate (r2) + !$omp master taskloop & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) & + !$omp& collapse(1) untied if(i1) final(fi) mergeable priority (pp) & + !$omp& reduction(default, +:r) in_reduction(+:r2) + do i = 1, 64 + ll = ll + 1 + end do + !$omp end taskgroup + + !$omp taskgroup task_reduction (+:r2) !allocate (r2) + !$omp master taskloop simd & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) & + !$omp& collapse(1) untied if(i1) final(fi) mergeable priority (pp) & + !$omp& safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) & + !$omp& order(concurrent) !allocate (f) + do i = 1, 64 + ll = ll + 1 + end do + !$omp end taskgroup + + !$omp parallel master taskloop & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) & + !$omp& collapse(1) untied if(i1) final(fi) mergeable priority (pp) & + !$omp& reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) !allocate (f) + do i = 1, 64 + ll = ll + 1 + end do + + !$omp parallel master taskloop simd & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) & + !$omp& collapse(1) untied if(i1) final(fi) mergeable priority (pp) & + !$omp& safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) & + !$omp& nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t) & + !$omp& order(concurrent) !allocate (f) + do i = 1, 64 + ll = ll + 1 + end do +end -- cgit v1.1 From fdbd0cb73af527f0630f0cbb26edb8584f593fea Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Tue, 1 Jun 2021 14:17:39 +0200 Subject: docs: Mention that -fgcse-after-reload is enabled with -O3. gcc/ChangeLog: PR other/100826 * doc/invoke.texi: Mention that -fgcse-after-reload is enabled with -O3. --- gcc/doc/invoke.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 5cd4e2d..08c3206 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10708,7 +10708,7 @@ When @option{-fgcse-after-reload} is enabled, a redundant load elimination pass is performed after reload. The purpose of this pass is to clean up redundant spilling. -Enabled by @option{-fprofile-use} and @option{-fauto-profile}. +Enabled by @option{-O3}, @option{-fprofile-use} and @option{-fauto-profile}. @item -faggressive-loop-optimizations @opindex faggressive-loop-optimizations -- cgit v1.1 From b195d84561a5c31108c7bbbd7c5b63fe3cebe35f Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Tue, 1 Jun 2021 10:41:04 +0200 Subject: Fix sanity checking of global_options. gcc/c-family/ChangeLog: PR other/100759 * c-attribs.c (handle_optimize_attribute): Limit sanity check to a situation where we are not in processing of an optimize pragma. * c-pragma.c (handle_pragma_pop_options): Restore target options. --- gcc/c-family/c-attribs.c | 6 +++++- gcc/c-family/c-pragma.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 804374d..156f7b3 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -5389,7 +5389,11 @@ handle_optimize_attribute (tree *node, tree name, tree args, /* If we previously had some optimization options, use them as the default. */ gcc_options *saved_global_options = NULL; - if (flag_checking) + + /* When #pragma GCC optimize pragma is used, it modifies global_options + without calling targetm.override_options_after_change. That can leave + target flags inconsistent for comparison. */ + if (flag_checking && optimization_current_node == optimization_default_node) { saved_global_options = XNEW (gcc_options); *saved_global_options = global_options; diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index 7f658ea..f46b5b9 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1088,6 +1088,8 @@ handle_pragma_pop_options (cpp_reader *ARG_UNUSED(dummy)) * overwritten by invoke_set_current_function_hook. */ cl_optimization_restore (&global_options, &global_options_set, TREE_OPTIMIZATION (p->optimize_binary)); + cl_target_option_restore (&global_options, &global_options_set, + TREE_TARGET_OPTION (p->target_binary)); if (p->optimize_binary != optimization_current_node) { -- cgit v1.1 From 18b88412069f51433e1b4f440d3c035bfc7b5cca Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 1 Jun 2021 05:26:02 -0400 Subject: Revert patch that disabled exporting of global ranges. Andrew's last set of changes fixes the bootstrap problem on i686 when global ranges are exported from evrp. The specific patch that fixes the problem is 715914d3: Author: Andrew MacLeod Date: Mon May 31 12:13:50 2021 -0400 Do not calculate new values when evaluating a debug statement. Add a flag to enable/disable immediately improving poor values found during cache propagation. Then disable it when processing debug statements. This patch reverts commit 2364b58 now that exporting of global ranges works. Tested on x86-64 Linux with default flags, and on i686 with the flags in the PR: --enable-clocale=gnu --with-system-zlib --with-demangler-in-ld --with-fpmath=sse --enable-languages=c,c++ --enable-cet i686-linux --enable-bootstrap --with-fpmath=sse --disable-libcc1 --disable-libcilkrts --disable-libsanitizer gcc/ChangeLog: * gimple-ssa-evrp.c: Enable exporting of global ranges. gcc/testsuite/ChangeLog: * gcc.dg/Wstringop-overflow-55.c: Adjust for global ranges changes. * gcc.dg/pr80776-1.c: Same. --- gcc/gimple-ssa-evrp.c | 6 ++---- gcc/testsuite/gcc.dg/Wstringop-overflow-55.c | 8 ++++---- gcc/testsuite/gcc.dg/pr80776-1.c | 4 +--- 3 files changed, 7 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c index f1eea20..118d103 100644 --- a/gcc/gimple-ssa-evrp.c +++ b/gcc/gimple-ssa-evrp.c @@ -127,8 +127,7 @@ public: if (dump_file && (dump_flags & TDF_DETAILS)) m_ranger->dump (dump_file); - // FIXME: Do not export ranges until PR100787 is fixed. - //m_ranger->export_global_ranges (); + m_ranger->export_global_ranges (); disable_ranger (cfun); } @@ -194,8 +193,7 @@ public: if (dump_file && (dump_flags & TDF_DETAILS)) m_ranger->dump (dump_file); - // FIXME: Do not export ranges until PR100787 is fixed. - //m_ranger->export_global_ranges (); + m_ranger->export_global_ranges (); disable_ranger (cfun); } diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c index 5f83af7..c3c2dbe 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c @@ -66,7 +66,7 @@ void warn_ptrdiff_anti_range_add (ptrdiff_t i) { i |= 1; - char ca5[5]; // { dg-message "at offset \\\[1, 5]" "pr?????" { xfail *-*-* } } + char ca5[5]; // { dg-message "at offset \\\[1, 5]" "pr?????" } char *p0 = ca5; // offset char *p1 = p0 + i; // 1-5 char *p2 = p1 + i; // 2-5 @@ -74,7 +74,7 @@ void warn_ptrdiff_anti_range_add (ptrdiff_t i) char *p4 = p3 + i; // 4-5 char *p5 = p4 + i; // 5 - memset (p5, 0, 5); // { dg-warning "writing 5 bytes into a region of size 0" "pr?????" { xfail *-*-* } } + memset (p5, 0, 5); // { dg-warning "writing 5 bytes into a region of size" "pr?????" } sink (p0, p1, p2, p3, p4, p5); } @@ -83,7 +83,7 @@ void warn_int_anti_range (int i) { i |= 1; - char ca5[5]; // { dg-message "at offset \\\[1, 5]" "pr?????" { xfail *-*-* } } + char ca5[5]; // { dg-message "at offset \\\[1, 5]" "pr?????" } char *p0 = ca5; // offset char *p1 = p0 + i; // 1-5 char *p2 = p1 + i; // 2-5 @@ -91,7 +91,7 @@ void warn_int_anti_range (int i) char *p4 = p3 + i; // 4-5 char *p5 = p4 + i; // 5 - memset (p5, 0, 5); // { dg-warning "writing 5 bytes into a region of size 0" "pr?????" { xfail *-*-* } } + memset (p5, 0, 5); // { dg-warning "writing 5 bytes into a region of size" "pr?????" } sink (p0, p1, p2, p3, p4, p5); } diff --git a/gcc/testsuite/gcc.dg/pr80776-1.c b/gcc/testsuite/gcc.dg/pr80776-1.c index af41c0c..f3a120b 100644 --- a/gcc/testsuite/gcc.dg/pr80776-1.c +++ b/gcc/testsuite/gcc.dg/pr80776-1.c @@ -17,7 +17,5 @@ Foo (void) __builtin_unreachable (); if (! (0 <= i && i <= 999999)) __builtin_unreachable (); - /* The correctness bits for [E]VRP cannot handle chained conditionals - when deciding to ignore a unreachable branch for setting SSA range info. */ - sprintf (number, "%d", i); /* { dg-bogus "writing" "" { xfail *-*-* } } */ + sprintf (number, "%d", i); /* { dg-bogus "writing" "" } */ } -- cgit v1.1 From 620cd7861e1266991c9c2a82e1e2d5f4d723ec88 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 27 Apr 2021 17:13:39 -0400 Subject: c++: -Wdeprecated-copy and #pragma diagnostic [PR94492] -Wdeprecated-copy was depending only on the state of the warning at the point where we call the function, making it hard to use #pragma diagnostic to suppress the warning for a particular implicitly declared function. But checking whether the warning is enabled at the location of the implicit declaration turned out to be a bit complicated; option_enabled only tests whether it was enabled at the start of compilation, the actual test only existed in the middle of diagnostic_report_diagnostic. So this patch factors it out and adds a new warning_enabled function to diagnostic.h. gcc/ChangeLog: PR c++/94492 * diagnostic.h (warning_enabled_at): Declare. * diagnostic.c (diagnostic_enabled): Factor out from... (diagnostic_report_diagnostic): ...here. (warning_enabled_at): New. gcc/cp/ChangeLog: PR c++/94492 * decl2.c (cp_warn_deprecated_use): Check warning_enabled_at. gcc/testsuite/ChangeLog: PR c++/94492 * g++.dg/cpp0x/depr-copy4.C: New test. --- gcc/cp/decl2.c | 8 ++-- gcc/diagnostic.c | 85 ++++++++++++++++++++++----------- gcc/diagnostic.h | 2 + gcc/testsuite/g++.dg/cpp0x/depr-copy4.C | 16 +++++++ 4 files changed, 80 insertions(+), 31 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/depr-copy4.C (limited to 'gcc') diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 89f874a..e46fded 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -5499,10 +5499,10 @@ cp_warn_deprecated_use (tree decl, tsubst_flags_t complain) && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl) && copy_fn_p (decl)) { - if (warn_deprecated_copy - /* Don't warn about system library classes (c++/86342). */ - && (!DECL_IN_SYSTEM_HEADER (decl) - || global_dc->dc_warn_system_headers)) + /* Don't warn if the flag was disabled around the class definition + (c++/94492). */ + if (warning_enabled_at (DECL_SOURCE_LOCATION (decl), + OPT_Wdeprecated_copy)) { auto_diagnostic_group d; tree ctx = DECL_CONTEXT (decl); diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index 246d752..d58586f 100644 --- a/gcc/diagnostic.c +++ b/gcc/diagnostic.c @@ -1122,6 +1122,62 @@ print_option_information (diagnostic_context *context, } } +/* Returns whether a DIAGNOSTIC should be printed, and adjusts diagnostic->kind + as appropriate for #pragma GCC diagnostic and -Werror=foo. */ + +static bool +diagnostic_enabled (diagnostic_context *context, + diagnostic_info *diagnostic) +{ + /* Diagnostics with no option or -fpermissive are always enabled. */ + if (!diagnostic->option_index + || diagnostic->option_index == permissive_error_option (context)) + return true; + + /* This tests if the user provided the appropriate -Wfoo or + -Wno-foo option. */ + if (! context->option_enabled (diagnostic->option_index, + context->lang_mask, + context->option_state)) + return false; + + /* This tests for #pragma diagnostic changes. */ + diagnostic_t diag_class + = update_effective_level_from_pragmas (context, diagnostic); + + /* This tests if the user provided the appropriate -Werror=foo + option. */ + if (diag_class == DK_UNSPECIFIED + && (context->classify_diagnostic[diagnostic->option_index] + != DK_UNSPECIFIED)) + diagnostic->kind + = context->classify_diagnostic[diagnostic->option_index]; + + /* This allows for future extensions, like temporarily disabling + warnings for ranges of source code. */ + if (diagnostic->kind == DK_IGNORED) + return false; + + return true; +} + +/* Returns whether warning OPT is enabled at LOC. */ + +bool +warning_enabled_at (location_t loc, int opt) +{ + if (!diagnostic_report_warnings_p (global_dc, loc)) + return false; + + rich_location richloc (line_table, loc); + diagnostic_info diagnostic = {}; + diagnostic.option_index = opt; + diagnostic.richloc = &richloc; + diagnostic.message.m_richloc = &richloc; + diagnostic.kind = DK_WARNING; + return diagnostic_enabled (global_dc, &diagnostic); +} + /* Report a diagnostic message (an error or a warning) as specified by DC. This function is *the* subroutine in terms of which front-ends should implement their specific diagnostic handling modules. The @@ -1172,33 +1228,8 @@ diagnostic_report_diagnostic (diagnostic_context *context, && diagnostic->kind == DK_WARNING) diagnostic->kind = DK_ERROR; - if (diagnostic->option_index - && diagnostic->option_index != permissive_error_option (context)) - { - /* This tests if the user provided the appropriate -Wfoo or - -Wno-foo option. */ - if (! context->option_enabled (diagnostic->option_index, - context->lang_mask, - context->option_state)) - return false; - - /* This tests for #pragma diagnostic changes. */ - diagnostic_t diag_class - = update_effective_level_from_pragmas (context, diagnostic); - - /* This tests if the user provided the appropriate -Werror=foo - option. */ - if (diag_class == DK_UNSPECIFIED - && (context->classify_diagnostic[diagnostic->option_index] - != DK_UNSPECIFIED)) - diagnostic->kind - = context->classify_diagnostic[diagnostic->option_index]; - - /* This allows for future extensions, like temporarily disabling - warnings for ranges of source code. */ - if (diagnostic->kind == DK_IGNORED) - return false; - } + if (!diagnostic_enabled (context, diagnostic)) + return false; if (diagnostic->kind != DK_NOTE && diagnostic->kind != DK_ICE) diagnostic_check_max_errors (context); diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index 9a6eefc..1b9d6b1 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -515,4 +515,6 @@ extern int num_digits (int); extern json::value *json_from_expanded_location (diagnostic_context *context, location_t loc); +extern bool warning_enabled_at (location_t, int); + #endif /* ! GCC_DIAGNOSTIC_H */ diff --git a/gcc/testsuite/g++.dg/cpp0x/depr-copy4.C b/gcc/testsuite/g++.dg/cpp0x/depr-copy4.C new file mode 100644 index 0000000..42852a7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/depr-copy4.C @@ -0,0 +1,16 @@ +// PR c++/94492 +// { dg-additional-options -Wdeprecated-copy } + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-copy" +struct expr +{ + int a, b; + expr& operator=(const expr&) { return *this; } +}; +#pragma GCC diagnostic pop + +expr foo(expr e) +{ + return e; +} -- cgit v1.1 From cf2b7020ee8e9745ede527b0a3b2e0ffbafd492b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 28 May 2021 17:05:23 -0400 Subject: c++: no clobber for C++20 destroying delete [PR91859] Before C++20 added destroying operator delete, by the time we called operator delete for a pointer, the object would already be gone. But that isn't true for destroying delete. Since the optimizers' assumptions about operator delete are based on either DECL_IS_REPLACEABLE_OPERATOR (which already is not set) or CALL_FROM_NEW_OR_DELETE_P, let's avoid setting the latter flag in this case. PR c++/91859 gcc/ChangeLog: * tree.h (CALL_FROM_NEW_OR_DELETE_P): Adjust comment. gcc/cp/ChangeLog: * call.c (build_op_delete_call): Don't set CALL_FROM_NEW_OR_DELETE_P for destroying delete. * init.c (build_delete): Don't clobber before destroying delete. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/destroying-delete5.C: New test. --- gcc/cp/call.c | 4 ++- gcc/cp/init.c | 5 +++- gcc/testsuite/g++.dg/cpp2a/destroying-delete5.C | 36 +++++++++++++++++++++++++ gcc/tree.h | 2 +- 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/destroying-delete5.C (limited to 'gcc') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index bf524b5..90192b1 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -7206,8 +7206,10 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, treat that as an implicit delete-expression. This is also called for the delete if the constructor throws in a new-expression, and for a deleting destructor (which implements a delete-expression). */ + /* But leave this flag off for destroying delete to avoid wrong + assumptions in the optimizers. */ tree call = extract_call_expr (ret); - if (TREE_CODE (call) == CALL_EXPR) + if (TREE_CODE (call) == CALL_EXPR && !destroying_delete_p (fn)) CALL_FROM_NEW_OR_DELETE_P (call) = 1; return ret; diff --git a/gcc/cp/init.c b/gcc/cp/init.c index a85f4d5..04d4958 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -4881,7 +4881,10 @@ build_delete (location_t loc, tree otype, tree addr, complain); } - if (!destroying_delete && type_build_dtor_call (type)) + if (destroying_delete) + /* The operator delete will call the destructor. */ + expr = addr; + else if (type_build_dtor_call (type)) expr = build_dtor_call (cp_build_fold_indirect_ref (addr), auto_delete, flags, complain); else diff --git a/gcc/testsuite/g++.dg/cpp2a/destroying-delete5.C b/gcc/testsuite/g++.dg/cpp2a/destroying-delete5.C new file mode 100644 index 0000000..553c964 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/destroying-delete5.C @@ -0,0 +1,36 @@ +// PR c++/91859 +// { dg-do run { target c++20 } } +// { dg-additional-options -O2 } + +#include +#include + +struct Expression { + int i = 0; + void *operator new(std::size_t); + void operator delete(Expression *, std::destroying_delete_t); +}; + +void * Expression::operator new(std::size_t sz) +{ + return std::malloc(sz); +} + +int i; + +void Expression::operator delete(Expression *p, std::destroying_delete_t) +{ + Expression * e = p; + ::i = e->i; + p->~Expression(); + std::free(p); +} + +int main() +{ + auto p = new Expression(); + p->i = 1; + delete p; + if (i != 1) + __builtin_abort(); +} diff --git a/gcc/tree.h b/gcc/tree.h index 260a3ae..62b2de4 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -937,7 +937,7 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, /* In a CALL_EXPR, if the function being called is DECL_IS_OPERATOR_NEW_P or DECL_IS_OPERATOR_DELETE_P, true for allocator calls from C++ new or delete - expressions. */ + expressions. Not set for C++20 destroying delete operators. */ #define CALL_FROM_NEW_OR_DELETE_P(NODE) \ (CALL_EXPR_CHECK (NODE)->base.protected_flag) -- cgit v1.1 From 250cf86735fc9e088cc2309c520adb655790eb99 Mon Sep 17 00:00:00 2001 From: Bill Schmidt Date: Tue, 1 Jun 2021 11:08:53 -0500 Subject: PR100750: Require ELFv2 ABI for ROP test 2021-06-01 Bill Schmidt gcc/testsuite/ PR testsuite/100750 * gcc.target/powerpc/rop-5.c: Require ELFv2 ABI. --- gcc/testsuite/gcc.target/powerpc/rop-5.c | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/powerpc/rop-5.c b/gcc/testsuite/gcc.target/powerpc/rop-5.c index cf04ea9..f2594df 100644 --- a/gcc/testsuite/gcc.target/powerpc/rop-5.c +++ b/gcc/testsuite/gcc.target/powerpc/rop-5.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target powerpc_elfv2 } */ /* { dg-options "-O2 -mdejagnu-cpu=power10 -mrop-protect" } */ /* Verify that __ROP_PROTECT__ is predefined for -mrop-protect. */ -- cgit v1.1 From 34aae6b561871d6d8b10c810f303cb6f18b5fdd0 Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Mon, 31 May 2021 12:25:28 +0000 Subject: Use is_empty_type instead of zero-sized type. Instead of only removing assignments of zero-sized types, assignments of all empty types should be removed during gimplification. This moves to use is_empty_type which will be used in other places too. OK? Bootstrapped and tested on aarch64-linux-gnu with no regressions. Thanks, Andrew Pinski gcc/ChangeLog: * gimplify.c (zero_sized_field_decl): Delete (zero_sized_type): Delete (gimplify_init_ctor_eval): Use is_empty_type instead of zero_sized_field_decl. (gimplify_modify_expr): Use is_empty_type instead of zero_sized_type. --- gcc/gimplify.c | 34 +++++++--------------------------- 1 file changed, 7 insertions(+), 27 deletions(-) (limited to 'gcc') diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 3ca29ce..39f5b97 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -4644,28 +4644,6 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper, gimplify_seq_add_stmt (pre_p, gimple_build_label (loop_exit_label)); } -/* Return true if FDECL is accessing a field that is zero sized. */ - -static bool -zero_sized_field_decl (const_tree fdecl) -{ - if (TREE_CODE (fdecl) == FIELD_DECL && DECL_SIZE (fdecl) - && integer_zerop (DECL_SIZE (fdecl))) - return true; - return false; -} - -/* Return true if TYPE is zero sized. */ - -static bool -zero_sized_type (const_tree type) -{ - if (AGGREGATE_TYPE_P (type) && TYPE_SIZE (type) - && integer_zerop (TYPE_SIZE (type))) - return true; - return false; -} - /* A subroutine of gimplify_init_constructor. Generate individual MODIFY_EXPRs for a CONSTRUCTOR. OBJECT is the LHS against which the assignments should happen. ELTS is the CONSTRUCTOR_ELTS of the @@ -4699,11 +4677,13 @@ gimplify_init_ctor_eval (tree object, vec *elts, gcc_assert (purpose); /* Skip zero-sized fields, unless value has side-effects. This can - happen with calls to functions returning a zero-sized type, which + happen with calls to functions returning a empty type, which we shouldn't discard. As a number of downstream passes don't - expect sets of zero-sized fields, we rely on the gimplification of + expect sets of empty type fields, we rely on the gimplification of the MODIFY_EXPR we make below to drop the assignment statement. */ - if (! TREE_SIDE_EFFECTS (value) && zero_sized_field_decl (purpose)) + if (!TREE_SIDE_EFFECTS (value) + && TREE_CODE (purpose) == FIELD_DECL + && is_empty_type (TREE_TYPE (purpose))) continue; /* If we have a RANGE_EXPR, we have to build a loop to assign the @@ -5781,11 +5761,11 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, if (ret != GS_UNHANDLED) return ret; - /* For zero sized types only gimplify the left hand side and right hand + /* For empty types only gimplify the left hand side and right hand side as statements and throw away the assignment. Do this after gimplify_modify_expr_rhs so we handle TARGET_EXPRs of addressable types properly. */ - if (zero_sized_type (TREE_TYPE (*from_p)) + if (is_empty_type (TREE_TYPE (*from_p)) && !want_value /* Don't do this for calls that return addressable types, expand_call relies on those having a lhs. */ -- cgit v1.1 From ea418485c700494c3efdc282854c5f5a08702416 Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Mon, 31 May 2021 00:17:22 +0000 Subject: Fix PR 95481: tail call fails with empty struct types The problem here is we don't have an assignment type any more for empty structs as they were removed during gimplifcation. This adds a special case where the assignment var does not exist and the return decl is empty typed. OK? Tested on aarch64-linux-gnu with no regressions. Thanks, Andrew Pinski changes since v1: v2: Use is_empty_type instead of zero-sized type. gcc/ChangeLog: PR tree-optimization/95481 * tree-tailcall.c (find_tail_calls): Handle empty typed return decls. gcc/testsuite/ChangeLog: PR tree-optimization/95481 * gcc.dg/tree-ssa/tailcall-10.c: New test. * gcc.dg/tree-ssa/tailcall-11.c: New test. * gcc.dg/tree-ssa/tailcall-12.c: New test. * gcc.dg/tree-ssa/tailcall-13.c: New test. * gcc.dg/tree-ssa/tailrecursion-8.c: New test. --- gcc/testsuite/gcc.dg/tree-ssa/tailcall-10.c | 12 ++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/tailcall-11.c | 12 ++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/tailcall-12.c | 12 ++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/tailcall-13.c | 15 +++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-8.c | 11 +++++++++++ gcc/tree-tailcall.c | 6 ++++-- 6 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailcall-10.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailcall-11.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailcall-12.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailcall-13.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-8.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-10.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-10.c new file mode 100644 index 0000000..484dcc1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-10.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-tailc-details" } */ + +struct A {}; + +struct A goo(void); +struct A foo(void) +{ + return goo(); +} + +/* { dg-final { scan-tree-dump-times "Found tail call" 1 "tailc"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-11.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-11.c new file mode 100644 index 0000000..36e4417 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-11.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-tailc-details" } */ + +struct A {}; + +void goo(void); +struct A foo(void) +{ + goo(); +} + +/* { dg-final { scan-tree-dump-times "Found tail call" 1 "tailc"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-12.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-12.c new file mode 100644 index 0000000..0eeb3ab --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-12.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-tailc-details" } */ + +struct A {}; + +struct A goo(void); +void foo(void) +{ + goo(); +} + +/* { dg-final { scan-tree-dump-times "Found tail call" 1 "tailc"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-13.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-13.c new file mode 100644 index 0000000..855b3312 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-13.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-tailc-details" } */ + +struct A {}; +struct B{}; + +struct B goo(void); +struct A foo(void) +{ + struct A a; + goo(); + return a; +} + +/* { dg-final { scan-tree-dump-times "Found tail call" 1 "tailc"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-8.c b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-8.c new file mode 100644 index 0000000..ecde499 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-8.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -foptimize-sibling-calls -fdump-tree-tailr1-details" } */ + +struct A {}; + +struct A foo() +{ + return foo(); +} + +/* { dg-final { scan-tree-dump-times "Eliminated tail recursion" 1 "tailr1"} } */ diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c index e866f72..a4d31c9 100644 --- a/gcc/tree-tailcall.c +++ b/gcc/tree-tailcall.c @@ -710,9 +710,11 @@ find_tail_calls (basic_block bb, struct tailcall **ret) ret_var = gimple_return_retval (as_a (stmt)); /* We may proceed if there either is no return value, or the return value - is identical to the call's return. */ + is identical to the call's return or if the return decl is an empty type + variable and the call's return was not assigned. */ if (ret_var - && (ret_var != ass_var)) + && (ret_var != ass_var + && !(is_empty_type (TREE_TYPE (ret_var)) && !ass_var))) return; /* If this is not a tail recursive call, we cannot handle addends or -- cgit v1.1 From 9f55df63154a39d67ef5b24def7044bf87300831 Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Tue, 1 Jun 2021 01:05:09 +0000 Subject: Replace conditional_replacement with match and simplify This is the first of series of patches to simplify phi-opt to use match and simplify in many cases. This simplification will more things to optimize. This is what Richard requested in https://gcc.gnu.org/pipermail/gcc-patches/2021-May/571197.html and I think it is the right thing to do too. OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. gcc/ChangeLog: PR tree-optimization/25290 * tree-ssa-phiopt.c (match_simplify_replacement): New function. (tree_ssa_phiopt_worker): Use match_simplify_replacement. (two_value_replacement): Change the comment about conditional_replacement. (conditional_replacement): Delete. --- gcc/tree-ssa-phiopt.c | 144 ++++++++++++++------------------------------------ 1 file changed, 39 insertions(+), 105 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index e3bd180..969b868 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -53,8 +53,8 @@ along with GCC; see the file COPYING3. If not see static unsigned int tree_ssa_phiopt_worker (bool, bool, bool); static bool two_value_replacement (basic_block, basic_block, edge, gphi *, tree, tree); -static bool conditional_replacement (basic_block, basic_block, - edge, edge, gphi *, tree, tree); +static bool match_simplify_replacement (basic_block, basic_block, + edge, edge, gphi *, tree, tree); static gphi *factor_out_conditional_conversion (edge, edge, gphi *, tree, tree, gimple *); static int value_replacement (basic_block, basic_block, @@ -347,8 +347,8 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) if (!early_p && two_value_replacement (bb, bb1, e2, phi, arg0, arg1)) cfgchanged = true; else if (!early_p - && conditional_replacement (bb, bb1, e1, e2, phi, - arg0, arg1)) + && match_simplify_replacement (bb, bb1, e1, e2, phi, + arg0, arg1)) cfgchanged = true; else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; @@ -675,7 +675,7 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb, } /* Defer boolean x ? 0 : {1,-1} or x ? {1,-1} : 0 to - conditional_replacement. */ + match_simplify_replacement. */ if (TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE && (integer_zerop (arg0) || integer_zerop (arg1) @@ -784,137 +784,71 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb, return true; } -/* The function conditional_replacement does the main work of doing the - conditional replacement. Return true if the replacement is done. +/* The function match_simplify_replacement does the main work of doing the + replacement using match and simplify. Return true if the replacement is done. Otherwise return false. BB is the basic block where the replacement is going to be done on. ARG0 is argument 0 from PHI. Likewise for ARG1. */ static bool -conditional_replacement (basic_block cond_bb, basic_block middle_bb, - edge e0, edge e1, gphi *phi, - tree arg0, tree arg1) +match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, + edge e0, edge e1, gphi *phi, + tree arg0, tree arg1) { - tree result; gimple *stmt; - gassign *new_stmt; tree cond; gimple_stmt_iterator gsi; edge true_edge, false_edge; - tree new_var, new_var2; - bool neg = false; - int shift = 0; - tree nonzero_arg; - - /* FIXME: Gimplification of complex type is too hard for now. */ - /* We aren't prepared to handle vectors either (and it is a question - if it would be worthwhile anyway). */ - if (!(INTEGRAL_TYPE_P (TREE_TYPE (arg0)) - || POINTER_TYPE_P (TREE_TYPE (arg0))) - || !(INTEGRAL_TYPE_P (TREE_TYPE (arg1)) - || POINTER_TYPE_P (TREE_TYPE (arg1)))) - return false; + gimple_seq seq = NULL; + tree result; - /* The PHI arguments have the constants 0 and 1, or 0 and -1 or - 0 and (1 << cst), then convert it to the conditional. */ - if (integer_zerop (arg0)) - nonzero_arg = arg1; - else if (integer_zerop (arg1)) - nonzero_arg = arg0; - else - return false; - if (integer_pow2p (nonzero_arg)) - { - shift = tree_log2 (nonzero_arg); - if (shift && POINTER_TYPE_P (TREE_TYPE (nonzero_arg))) - return false; - } - else if (integer_all_onesp (nonzero_arg)) - neg = true; - else + if (!empty_block_p (middle_bb)) return false; - if (!empty_block_p (middle_bb)) + /* Special case A ? B : B as this will always simplify to B. */ + if (operand_equal_for_phi_arg_p (arg0, arg1)) return false; - /* At this point we know we have a GIMPLE_COND with two successors. + /* At this point we know we have a GIMPLE_COND with two successors. One successor is BB, the other successor is an empty block which falls through into BB. - There is a single PHI node at the join point (BB) and its arguments - are constants (0, 1) or (0, -1) or (0, (1 << shift)). - - So, given the condition COND, and the two PHI arguments, we can - rewrite this PHI into non-branching code: - - dest = (COND) or dest = COND' or dest = (COND) << shift + There is a single PHI node at the join point (BB). - We use the condition as-is if the argument associated with the - true edge has the value one or the argument associated with the - false edge as the value zero. Note that those conditions are not - the same since only one of the outgoing edges from the GIMPLE_COND - will directly reach BB and thus be associated with an argument. */ + So, given the condition COND, and the two PHI arguments, match and simplify + can happen on (COND) ? arg0 : arg1. */ stmt = last_stmt (cond_bb); - result = PHI_RESULT (phi); /* To handle special cases like floating point comparison, it is easier and less error-prone to build a tree and gimplify it on the fly though it is - less efficient. */ - cond = fold_build2_loc (gimple_location (stmt), - gimple_cond_code (stmt), boolean_type_node, - gimple_cond_lhs (stmt), gimple_cond_rhs (stmt)); + less efficient. + Don't use fold_build2 here as that might create (bool)a instead of just + "a != 0". */ + cond = build2_loc (gimple_location (stmt), + gimple_cond_code (stmt), boolean_type_node, + gimple_cond_lhs (stmt), gimple_cond_rhs (stmt)); /* We need to know which is the true edge and which is the false edge so that we know when to invert the condition below. */ extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); - if ((e0 == true_edge && integer_zerop (arg0)) - || (e0 == false_edge && !integer_zerop (arg0)) - || (e1 == true_edge && integer_zerop (arg1)) - || (e1 == false_edge && !integer_zerop (arg1))) - cond = fold_build1_loc (gimple_location (stmt), - TRUTH_NOT_EXPR, TREE_TYPE (cond), cond); - - if (neg) - { - cond = fold_convert_loc (gimple_location (stmt), - TREE_TYPE (result), cond); - cond = fold_build1_loc (gimple_location (stmt), - NEGATE_EXPR, TREE_TYPE (cond), cond); - } - else if (shift) - { - cond = fold_convert_loc (gimple_location (stmt), - TREE_TYPE (result), cond); - cond = fold_build2_loc (gimple_location (stmt), - LSHIFT_EXPR, TREE_TYPE (cond), cond, - build_int_cst (integer_type_node, shift)); - } - - /* Insert our new statements at the end of conditional block before the - COND_STMT. */ - gsi = gsi_for_stmt (stmt); - new_var = force_gimple_operand_gsi (&gsi, cond, true, NULL, true, - GSI_SAME_STMT); + if (e1 == true_edge || e0 == false_edge) + std::swap (arg0, arg1); - if (!useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (new_var))) - { - location_t locus_0, locus_1; + tree type = TREE_TYPE (gimple_phi_result (phi)); + result = gimple_simplify (COND_EXPR, type, + cond, + arg0, arg1, + &seq, NULL); + if (!result) + return false; - new_var2 = make_ssa_name (TREE_TYPE (result)); - new_stmt = gimple_build_assign (new_var2, CONVERT_EXPR, new_var); - gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); - new_var = new_var2; + gsi = gsi_last_bb (cond_bb); - /* Set the locus to the first argument, unless is doesn't have one. */ - locus_0 = gimple_phi_arg_location (phi, 0); - locus_1 = gimple_phi_arg_location (phi, 1); - if (locus_0 == UNKNOWN_LOCATION) - locus_0 = locus_1; - gimple_set_location (new_stmt, locus_0); - } + if (seq) + gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT); - replace_phi_edge_with_variable (cond_bb, e1, phi, new_var); + replace_phi_edge_with_variable (cond_bb, e1, phi, result); /* Note that we optimized this PHI. */ return true; @@ -3627,7 +3561,7 @@ gate_hoist_loads (void) Conditional Replacement ----------------------- - This transformation, implemented in conditional_replacement, + This transformation, implemented in match_simplify_replacement, replaces bb0: -- cgit v1.1 From ac0bc21bd634a334ba8f323c39a11f01dfdc2aae Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 1 Jun 2021 12:23:49 -0400 Subject: c++: value-init vs zero-init in expand_aggr_init_1 [PR65816] In the case of value-initializing an object of class type T, [dcl.init.general]/8 says: - if T has either no default constructor ([class.default.ctor]) or a default constructor that is user-provided or deleted, then the object is default-initialized; - otherwise, the object is zero-initialized and ... if T has a non-trivial default constructor, the object is default-initialized; But when determining whether to first zero-initialize the object, expand_aggr_init_1 incorrectly considers the user-providedness of _all_ constructors rather than only that of the _default_ constructors. This causes us to skip the zero-initialization step when the class type has a defaulted default constructor alongside a user-defined constructor. It seems the predicate type_has_non_user_provided_default_constructor accurately captures the above rule for when to first perform a zero-initialization during value-initialization, so this patch adjusts expand_aggr_init_1 to use this predicate instead. PR c++/65816 gcc/cp/ChangeLog: * init.c (expand_aggr_init_1): Check type_has_non_user_provided_default_constructor instead of type_has_user_provided_constructor. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-delegating3.C: New test. * g++.dg/cpp0x/dc10.C: New test. * g++.dg/cpp0x/initlist-base4.C: New test. * g++.dg/cpp2a/constexpr-init22.C: New test. libstdc++-v3/ChangeLog: * testsuite/23_containers/deque/allocator/default_init.cc, testsuite/23_containers/forward_list/allocator/default_init.cc, testsuite/23_containers/list/allocator/default_init.cc, testsuite/23_containers/map/allocator/default_init.cc, testsuite/23_containers/set/allocator/default_init.cc, testsuite/23_containers/vector/allocator/default_init.cc, testsuite/23_containers/vector/bool/allocator/default_init.cc: Remove xfail. --- gcc/cp/init.c | 4 ++-- gcc/testsuite/g++.dg/cpp0x/constexpr-delegating3.C | 10 +++++++++ gcc/testsuite/g++.dg/cpp0x/dc10.C | 19 ++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/initlist-base4.C | 26 ++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp2a/constexpr-init22.C | 14 ++++++++++++ 5 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-delegating3.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/dc10.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-base4.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-init22.C (limited to 'gcc') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 04d4958..b112328 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2078,9 +2078,9 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, that's value-initialization. */ if (init == void_type_node) { - /* If the type has data but no user-provided ctor, we need to zero + /* If the type has data but no user-provided default ctor, we need to zero out the object. */ - if (!type_has_user_provided_constructor (type) + if (type_has_non_user_provided_default_constructor (type) && !is_really_empty_class (type, /*ignore_vptr*/true)) { tree field_size = NULL_TREE; diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-delegating3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-delegating3.C new file mode 100644 index 0000000..2263ec8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-delegating3.C @@ -0,0 +1,10 @@ +// PR c++/65816 +// { dg-do compile { target c++11 } } + +struct test { + int m; + test() = default; + constexpr test(int) : test() {} +}; + +static_assert(test(0).m == 0, ""); diff --git a/gcc/testsuite/g++.dg/cpp0x/dc10.C b/gcc/testsuite/g++.dg/cpp0x/dc10.C new file mode 100644 index 0000000..c008a17 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/dc10.C @@ -0,0 +1,19 @@ +// PR c++/65816 +// { dg-do run { target c++11 } } + +void* operator new(decltype(sizeof(int)), void* ptr) { return ptr; } + +struct test { + int i; + test() = default; + test(int) : test() {} +}; + +int main() { + alignas(test) unsigned char space[sizeof(test)]; + for (auto& c : space) c = 0xff; + + auto ptr = ::new(&space) test(42); + int& i = static_cast(*ptr).i; + if (i != 0) __builtin_abort(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-base4.C b/gcc/testsuite/g++.dg/cpp0x/initlist-base4.C new file mode 100644 index 0000000..4a02af9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-base4.C @@ -0,0 +1,26 @@ +// PR c++/65816 +// { dg-do run { target c++11 } } + +void* operator new(decltype(sizeof(int)), void* ptr) { return ptr; } + +struct item { int i; }; + +struct collector : item { + int j; + collector() = default; + collector(int) {} +}; + +struct tuple : collector { + tuple() : collector() {} +}; + +int main() { + alignas(tuple) unsigned char space[sizeof(tuple)]; + for (auto& c : space) c = 0xff; + + auto ptr = ::new(&space) tuple; + int& i = static_cast(*ptr).i; + int& j = static_cast(*ptr).j; + if (i != 0 || j != 0) __builtin_abort(); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-init22.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-init22.C new file mode 100644 index 0000000..50e4a95 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-init22.C @@ -0,0 +1,14 @@ +// PR c++/65816 +// { dg-do compile { target c++20 } } + +struct X { + int i; + X() = default; + constexpr X(int) { } +}; + +struct Y : X { + constexpr Y() : X() { } +}; + +static_assert(Y().i == 0); -- cgit v1.1 From b75978d14fc35981ffd8bf060ee52300db4dae50 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 2 Jun 2021 00:16:43 +0000 Subject: Daily bump. --- gcc/ChangeLog | 132 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c-family/ChangeLog | 9 ++++ gcc/cp/ChangeLog | 19 +++++++ gcc/fortran/ChangeLog | 38 ++++++++++++++ gcc/testsuite/ChangeLog | 61 ++++++++++++++++++++++ 6 files changed, 260 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e1ae7fa..ef69e6a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,135 @@ +2021-06-01 Andrew Pinski + + PR tree-optimization/25290 + * tree-ssa-phiopt.c (match_simplify_replacement): + New function. + (tree_ssa_phiopt_worker): Use match_simplify_replacement. + (two_value_replacement): Change the comment about + conditional_replacement. + (conditional_replacement): Delete. + +2021-06-01 Andrew Pinski + + PR tree-optimization/95481 + * tree-tailcall.c (find_tail_calls): Handle empty typed + return decls. + +2021-06-01 Andrew Pinski + + * gimplify.c (zero_sized_field_decl): Delete + (zero_sized_type): Delete + (gimplify_init_ctor_eval): Use is_empty_type instead + of zero_sized_field_decl. + (gimplify_modify_expr): Use is_empty_type instead of + zero_sized_type. + +2021-06-01 Jason Merrill + + PR c++/91859 + * tree.h (CALL_FROM_NEW_OR_DELETE_P): Adjust comment. + +2021-06-01 Jason Merrill + + PR c++/94492 + * diagnostic.h (warning_enabled_at): Declare. + * diagnostic.c (diagnostic_enabled): Factor out from... + (diagnostic_report_diagnostic): ...here. + (warning_enabled_at): New. + +2021-06-01 Aldy Hernandez + + * gimple-ssa-evrp.c: Enable exporting of global ranges. + +2021-06-01 Martin Liska + + PR other/100826 + * doc/invoke.texi: Mention that -fgcse-after-reload + is enabled with -O3. + +2021-06-01 liuhongt + + PR tree-optimization/98365 + * tree-if-conv.c (strip_nop_cond_scalar_reduction): New function. + (is_cond_scalar_reduction): Handle nop_expr in cond scalar reduction. + (convert_scalar_cond_reduction): Ditto. + (predicate_scalar_phi): Ditto. + +2021-06-01 Andrew MacLeod + + PR tree-optimization/100781 + * gimple-range-cache.cc (ranger_cache::ranger_cache): Enable new + value calculation by default. + (ranger_cache::enable_new_values): New. + (ranger_cache::disable_new_values): New. + (ranger_cache::push_poor_value): Check if new values are allowed. + * gimple-range-cache.h (class ranger_cache): New member/methods. + * gimple-range.cc (gimple_ranger::range_of_expr): Check for debug + statement, and disable/renable new value calculation. + +2021-06-01 Andrew MacLeod + + * gimple-range-cache.cc (ranger_cache::ssa_range_in_bb): Delete. + (ranger_cache::range_of_def): New. + (ranger_cache::entry_range): New. + (ranger_cache::exit_range): New. + (ranger_cache::range_of_expr): Adjust. + (ranger_cache::range_on_edge): Adjust. + (ranger_cache::propagate_cache): Call exit_range directly. + * gimple-range-cache.h (class ranger_cache): Adjust. + +2021-06-01 Andrew MacLeod + + * gimple-range-cache.cc (ranger_cache::ranger_cache): Adjust for + gori_compute being a member rather than base class. + dervied call to member call. + (ranger_cache::dump): No longer dump gori_map. + (ranger_cache::dump_bb): New. + (ranger_cache::get_non_stale_global_range): Adjust for gori_compute + being a member rather than base class. + (ranger_cache::set_global_range): Ditto. + (ranger_cache::ssa_range_in_bb): Ditto. + (ranger_cache::range_of_expr): New. + (ranger_cache::range_on_edge): New. + (ranger_cache::block_range): Adjust for gori_computes. Debug changes. + (ranger_cache::propagate_cache): Adjust debugging output. + (ranger_cache::fill_block_cache): Adjust for gori_computes. Debug + output changes. + * gimple-range-cache.h (class ranger_cache): Make gori_compute a + member, and inherit from range_query instead. + (ranger_cache::dump_bb): New. split from dump. + * gimple-range-gori.cc (gori_compute::ssa_range_in_bb): Delete. + (gori_compute::expr_range_at_stmt): Delete. + (gori_compute::compute_name_range_op): Delete. + (gori_compute::compute_operand_range_switch): Add fur_source. + (gori_compute::compute_operand_range): Add fur_source param, inline + old compute_name_range_op and optimize_logical_operands. + (struct tf_range): Delete. + (gori_compute::logical_combine): Adjust + (gori_compute::optimize_logical_operands): Delete. + (gori_compute::compute_logical_operands_in_chain): Delete. + (gori_compute::compute_logical_operands): Adjust. + (gori_compute::compute_operand1_range): Adjust to fur_source. + (gori_compute::compute_operand2_range): Ditto. + (gori_compute::compute_operand1_and_operand2_range): Ditto. + (gori_compute::outgoing_edge_range_p): Add range_query parameter, + and adjust to fur_source. + * gimple-range-gori.h (class gori_compute): Simplify and adjust to + range_query and fur_source. + * gimple-range.cc (gimple_ranger::range_on_edge): Query range_on_edge + from the ranger_cache.. + (gimple_ranger::fold_range_internal): Adjust to base class change of + ranger_cache. + (gimple_ranger::dump_bb): Adjust dump. + * gimple-range.h (gimple_ranger):export gori computes object. + +2021-06-01 Andrew MacLeod + + PR tree-optimization/100774 + * gimple-range-cache.cc (ranger_cache::get_non_stale_global_range): + Constant values are also not stale. + (ranger_cache::set_global_range): Range invariant values should also + have the correct timestamp. + 2021-05-31 Martin Liska * tree-streamer-in.c (unpack_ts_function_decl_value_fields): diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 6b43bb2..54b764a 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210601 +20210602 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index e85a6bf..cb2757c 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,12 @@ +2021-06-01 Martin Liska + + PR other/100759 + * c-attribs.c (handle_optimize_attribute): Limit sanity check + to a situation where we are not in processing of an optimize + pragma. + * c-pragma.c (handle_pragma_pop_options): Restore target + options. + 2021-05-31 Indu Bhagat PR testsuite/100749 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c764713..9a5fa79 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,22 @@ +2021-06-01 Patrick Palka + + PR c++/65816 + * init.c (expand_aggr_init_1): Check + type_has_non_user_provided_default_constructor instead of + type_has_user_provided_constructor. + +2021-06-01 Jason Merrill + + PR c++/91859 + * call.c (build_op_delete_call): Don't set CALL_FROM_NEW_OR_DELETE_P + for destroying delete. + * init.c (build_delete): Don't clobber before destroying delete. + +2021-06-01 Jason Merrill + + PR c++/94492 + * decl2.c (cp_warn_deprecated_use): Check warning_enabled_at. + 2021-05-31 Richard Biener PR c++/88601 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 95857cc..bab25eb 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,41 @@ +2021-06-01 Tobias Burnus + + PR middle-end/99928 + * dump-parse-tree.c (show_omp_node, show_code_node): Handle + (parallel) master taskloop (simd). + * frontend-passes.c (gfc_code_walker): Set in_omp_workshare + to false for parallel master taskloop (simd). + * gfortran.h (enum gfc_statement): + Add ST_OMP_(END_)(PARALLEL_)MASTER_TASKLOOP(_SIMD). + (enum gfc_exec_op): EXEC_OMP_(PARALLEL_)MASTER_TASKLOOP(_SIMD). + * match.h (gfc_match_omp_master_taskloop, + gfc_match_omp_master_taskloop_simd, + gfc_match_omp_parallel_master_taskloop, + gfc_match_omp_parallel_master_taskloop_simd): New prototype. + * openmp.c (gfc_match_omp_parallel_master_taskloop, + gfc_match_omp_parallel_master_taskloop_simd, + gfc_match_omp_master_taskloop, + gfc_match_omp_master_taskloop_simd): New. + (gfc_match_omp_taskloop_simd): Permit 'reduction' clause. + (resolve_omp_clauses): Handle new combined directives; remove + inscan-reduction check to reduce multiple errors; add + task-reduction error for 'taskloop simd'. + (gfc_resolve_omp_parallel_blocks, + resolve_omp_do, omp_code_to_statement, + gfc_resolve_omp_directive): Handle new combined constructs. + * parse.c (decode_omp_directive, next_statement, + gfc_ascii_statement, parse_omp_do, parse_omp_structured_block, + parse_executable): Likewise. + * resolve.c (gfc_resolve_blocks, gfc_resolve_code): Likewise. + * st.c (gfc_free_statement): Likewise. + * trans.c (trans_code): Likewise. + * trans-openmp.c (gfc_split_omp_clauses, + gfc_trans_omp_directive): Likewise. + (gfc_trans_omp_parallel_master): Move after gfc_trans_omp_master_taskloop; + handle parallel master taskloop (simd) as well. + (gfc_trans_omp_taskloop): Take gfc_exec_op as arg. + (gfc_trans_omp_master_taskloop): New. + 2021-05-30 Gerald Pfeifer * gfortran.texi (BOZ literal constants): Fix typo. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e55bbf2..46dc814 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,64 @@ +2021-06-01 Patrick Palka + + PR c++/65816 + * g++.dg/cpp0x/constexpr-delegating3.C: New test. + * g++.dg/cpp0x/dc10.C: New test. + * g++.dg/cpp0x/initlist-base4.C: New test. + * g++.dg/cpp2a/constexpr-init22.C: New test. + +2021-06-01 Andrew Pinski + + PR tree-optimization/95481 + * gcc.dg/tree-ssa/tailcall-10.c: New test. + * gcc.dg/tree-ssa/tailcall-11.c: New test. + * gcc.dg/tree-ssa/tailcall-12.c: New test. + * gcc.dg/tree-ssa/tailcall-13.c: New test. + * gcc.dg/tree-ssa/tailrecursion-8.c: New test. + +2021-06-01 Bill Schmidt + + PR testsuite/100750 + * gcc.target/powerpc/rop-5.c: Require ELFv2 ABI. + +2021-06-01 Jason Merrill + + PR c++/91859 + * g++.dg/cpp2a/destroying-delete5.C: New test. + +2021-06-01 Jason Merrill + + PR c++/94492 + * g++.dg/cpp0x/depr-copy4.C: New test. + +2021-06-01 Aldy Hernandez + + * gcc.dg/Wstringop-overflow-55.c: Adjust for global ranges changes. + * gcc.dg/pr80776-1.c: Same. + +2021-06-01 Tobias Burnus + + PR middle-end/99928 + * gfortran.dg/gomp/reduction5.f90: Remove dg-error; the issue is + now diagnosed with less error output. + * gfortran.dg/gomp/scan-1.f90: Likewise. + * gfortran.dg/gomp/pr99928-3.f90: New test. + * gfortran.dg/gomp/taskloop-1.f90: New test. + +2021-06-01 liuhongt + + PR tree-optimization/98365 + * gcc.target/i386/pr98365.c: New test. + +2021-06-01 Andrew MacLeod + + PR tree-optimization/100781 + * gcc.dg/pr100781.c: New. + +2021-06-01 Andrew MacLeod + + PR tree-optimization/100774 + * g++.dg/pr100774.C: New. + 2021-05-31 Tobias Burnus * gfortran.dg/gomp/depend-iterator-1.f90: Use dg-do compile. -- cgit v1.1 From 4ea5fe8b4002d15c8706749a3c43ed107c9a02f9 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Wed, 2 Jun 2021 00:56:38 -0400 Subject: Fix minor bugs in H8 port logical ops. Prepare for more compare/test removal gcc/ * config/h8300/h8300-protos.h (compute_a_shift_length): Drop unused argument from prototype. (output_logical_op): Add rtx_code argument. (compute_logical_op_length): Likewise. * config/h8300/h8300.c (h8300_and_costs): Pass additional argument to compute_a_shift_length. (output_logical_op); New argument with the rtx code rather than extracting it from an operand. Handle QImode too. (compute_logical_op_length): Similary. (compute_a_shift_length): Drop unused argument. * config/h8300/h8300.md (logicals): New code iterator. * config/h8300/logical.md (3 expander): Combine the "and" expander with the "ior"/"xor" expander. (bclrmsx): Combine the QI/HI mode patterns. (3 insns): Use code iterator rather than match_operator. Handle QImode as well. Update call to output_logical_op and compute_logical_op_length to pass in rtx_code Fix split condition on all define_insn_and_split patterns. (one_cmpl2): Use to support both clobbering the flags and setting ZN via existing define_subst. * config/h8300/shiftrotate.md: Drop unused argument from calls to compute_a_shift_length. Signed-off-by: Jeff Law --- gcc/config/h8300/h8300-protos.h | 7 ++-- gcc/config/h8300/h8300.c | 21 ++++++----- gcc/config/h8300/h8300.md | 2 ++ gcc/config/h8300/logical.md | 77 +++++++++++++++++------------------------ gcc/config/h8300/shiftrotate.md | 12 +++---- 5 files changed, 55 insertions(+), 64 deletions(-) (limited to 'gcc') diff --git a/gcc/config/h8300/h8300-protos.h b/gcc/config/h8300/h8300-protos.h index 45e7dec..af65329 100644 --- a/gcc/config/h8300/h8300-protos.h +++ b/gcc/config/h8300/h8300-protos.h @@ -29,16 +29,15 @@ extern unsigned int compute_mov_length (rtx *); extern const char *output_plussi (rtx *, bool); extern unsigned int compute_plussi_length (rtx *, bool); extern const char *output_a_shift (rtx *); -extern unsigned int compute_a_shift_length (rtx, rtx *); +extern unsigned int compute_a_shift_length (rtx *); extern const char *output_a_rotate (enum rtx_code, rtx *); extern unsigned int compute_a_rotate_length (rtx *); extern const char *output_simode_bld (int, rtx[]); extern void final_prescan_insn (rtx_insn *, rtx *, int); extern int h8300_expand_movsi (rtx[]); extern machine_mode h8300_select_cc_mode (RTX_CODE, rtx, rtx); -extern const char *output_logical_op (machine_mode, rtx *); -extern unsigned int compute_logical_op_length (machine_mode, - rtx *); +extern const char *output_logical_op (machine_mode, rtx_code code, rtx *); +extern unsigned int compute_logical_op_length (machine_mode, rtx_code, rtx *); extern int compute_logical_op_cc (machine_mode, rtx *); extern int compute_a_shift_cc (rtx, rtx *); diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c index ba2b9da..ef947aa 100644 --- a/gcc/config/h8300/h8300.c +++ b/gcc/config/h8300/h8300.c @@ -1100,7 +1100,7 @@ h8300_and_costs (rtx x) operands[1] = XEXP (x, 0); operands[2] = XEXP (x, 1); operands[3] = x; - return compute_logical_op_length (GET_MODE (x), operands) / 2; + return compute_logical_op_length (GET_MODE (x), AND, operands) / 2; } /* Compute the cost of a shift insn. */ @@ -1119,7 +1119,7 @@ h8300_shift_costs (rtx x) operands[1] = NULL; operands[2] = XEXP (x, 1); operands[3] = x; - return compute_a_shift_length (NULL, operands) / 2; + return compute_a_shift_length (operands) / 2; } /* Worker function for TARGET_RTX_COSTS. */ @@ -2879,10 +2879,8 @@ compute_plussi_cc (rtx *operands) /* Output a logical insn. */ const char * -output_logical_op (machine_mode mode, rtx *operands) +output_logical_op (machine_mode mode, rtx_code code, rtx *operands) { - /* Figure out the logical op that we need to perform. */ - enum rtx_code code = GET_CODE (operands[3]); /* Pretend that every byte is affected if both operands are registers. */ const unsigned HOST_WIDE_INT intval = (unsigned HOST_WIDE_INT) ((GET_CODE (operands[2]) == CONST_INT) @@ -2923,6 +2921,10 @@ output_logical_op (machine_mode mode, rtx *operands) switch (mode) { + case E_QImode: + sprintf (insn_buf, "%s.b\t%%X2,%%X0", opname); + output_asm_insn (insn_buf, operands); + break; case E_HImode: /* First, see if we can finish with one insn. */ if (b0 != 0 && b1 != 0) @@ -3033,10 +3035,8 @@ output_logical_op (machine_mode mode, rtx *operands) /* Compute the length of a logical insn. */ unsigned int -compute_logical_op_length (machine_mode mode, rtx *operands) +compute_logical_op_length (machine_mode mode, rtx_code code, rtx *operands) { - /* Figure out the logical op that we need to perform. */ - enum rtx_code code = GET_CODE (operands[3]); /* Pretend that every byte is affected if both operands are registers. */ const unsigned HOST_WIDE_INT intval = (unsigned HOST_WIDE_INT) ((GET_CODE (operands[2]) == CONST_INT) @@ -3061,6 +3061,9 @@ compute_logical_op_length (machine_mode mode, rtx *operands) switch (mode) { + case E_QImode: + return 2; + case E_HImode: /* First, see if we can finish with one insn. */ if (b0 != 0 && b1 != 0) @@ -4189,7 +4192,7 @@ h8300_asm_insn_count (const char *templ) /* Compute the length of a shift insn. */ unsigned int -compute_a_shift_length (rtx insn ATTRIBUTE_UNUSED, rtx *operands) +compute_a_shift_length (rtx *operands) { rtx shift = operands[3]; machine_mode mode = GET_MODE (shift); diff --git a/gcc/config/h8300/h8300.md b/gcc/config/h8300/h8300.md index 9a42547..e596987 100644 --- a/gcc/config/h8300/h8300.md +++ b/gcc/config/h8300/h8300.md @@ -229,6 +229,8 @@ (define_code_iterator shifts [ashift ashiftrt lshiftrt]) +(define_code_iterator logicals [ior xor and]) + (define_code_iterator ors [ior xor]) (include "movepush.md") diff --git a/gcc/config/h8300/logical.md b/gcc/config/h8300/logical.md index eb99c20..d778d24 100644 --- a/gcc/config/h8300/logical.md +++ b/gcc/config/h8300/logical.md @@ -1,11 +1,20 @@ +;; Generic for binary logicals across the supported integer modes +(define_expand "3" + [(set (match_operand:QHSI 0 "register_operand" "") + (logicals:QHSI (match_operand:QHSI 1 "register_operand" "") + (match_operand:QHSI 2 "h8300_src_operand" "")))] + "" + "") + +;; There's a ton of cleanup to do from here below. ;; ---------------------------------------------------------------------- ;; AND INSTRUCTIONS ;; ---------------------------------------------------------------------- -(define_insn "bclrqi_msx" - [(set (match_operand:QI 0 "bit_register_indirect_operand" "=WU") - (and:QI (match_operand:QI 1 "bit_register_indirect_operand" "%0") - (match_operand:QI 2 "single_zero_operand" "Y0")))] +(define_insn "bclr_msx" + [(set (match_operand:QHI 0 "bit_register_indirect_operand" "=WU") + (and:QHI (match_operand:QHI 1 "bit_register_indirect_operand" "%0") + (match_operand:QHI 2 "single_zero_operand" "Y0")))] "TARGET_H8300SX && rtx_equal_p (operands[0], operands[1])" "bclr\\t%W2,%0" [(set_attr "length" "8")]) @@ -24,21 +33,13 @@ operands[2] = GEN_INT ((INTVAL (operands[2])) >> 8); }) -(define_insn "bclrhi_msx" - [(set (match_operand:HI 0 "bit_register_indirect_operand" "=m") - (and:HI (match_operand:HI 1 "bit_register_indirect_operand" "%0") - (match_operand:HI 2 "single_zero_operand" "Y0")))] - "TARGET_H8300SX" - "bclr\\t%W2,%0" - [(set_attr "length" "8")]) - (define_insn_and_split "*andqi3_2" [(set (match_operand:QI 0 "bit_operand" "=U,rQ,r") (and:QI (match_operand:QI 1 "bit_operand" "%0,0,WU") (match_operand:QI 2 "h8300_src_operand" "Y0,rQi,IP1>X")))] "TARGET_H8300SX" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (and:QI (match_dup 1) (match_dup 2))) (clobber (reg:CC CC_REG))])]) @@ -62,7 +63,7 @@ "register_operand (operands[0], QImode) || single_zero_operand (operands[2], QImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (and:QI (match_dup 1) (match_dup 2))) (clobber (reg:CC CC_REG))])]) @@ -78,13 +79,6 @@ and %X2,%X0" [(set_attr "length" "2,8")]) -(define_expand "and3" - [(set (match_operand:QHSI 0 "register_operand" "") - (and:QHSI (match_operand:QHSI 1 "register_operand" "") - (match_operand:QHSI 2 "h8300_src_operand" "")))] - "" - "") - (define_insn_and_split "*andor3" [(set (match_operand:QHSI 0 "register_operand" "=r") (ior:QHSI (and:QHSI (match_operand:QHSI 2 "register_operand" "r") @@ -95,7 +89,7 @@ || (mode == SImode && (INTVAL (operands[3]) & 0xffff) != 0))" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (ior:QHSI (and:QHSI (match_dup 2) (match_dup 3)) (match_dup 1))) @@ -150,7 +144,7 @@ (match_operand:SI 1 "register_operand" "0")))] "" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (ior:SI (and:SI (ashift:SI (match_dup 2) (const_int 8)) (const_int 65280)) @@ -195,7 +189,7 @@ "TARGET_H8300SX || register_operand (operands[0], QImode) || single_one_operand (operands[2], QImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (ors:QI (match_dup 1) (match_dup 2))) (clobber (reg:CC CC_REG))])]) @@ -216,39 +210,32 @@ [(set_attr "length" "8,*") (set_attr "length_table" "*,logicb")]) -(define_expand "3" - [(set (match_operand:QHSI 0 "register_operand" "") - (ors:QHSI (match_operand:QHSI 1 "register_operand" "") - (match_operand:QHSI 2 "h8300_src_operand" "")))] - "" - "") - ;; ---------------------------------------------------------------------- ;; {AND,IOR,XOR}{HI3,SI3} PATTERNS ;; ---------------------------------------------------------------------- (define_insn_and_split "*logical3" - [(set (match_operand:HSI 0 "h8300_dst_operand" "=rQ") - (match_operator:HSI 3 "bit_operator" - [(match_operand:HSI 1 "h8300_dst_operand" "%0") - (match_operand:HSI 2 "h8300_src_operand" "rQi")]))] + [(set (match_operand:QHSI 0 "h8300_dst_operand" "=rQ") + (logicals:QHSI + (match_operand:QHSI 1 "h8300_dst_operand" "%0") + (match_operand:QHSI 2 "h8300_src_operand" "rQi")))] "h8300_operands_match_p (operands)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (match_op_dup 3 [(match_dup 1) (match_dup 2)])) (clobber (reg:CC CC_REG))])]) -(define_insn "*logical3_clobber_flags" - [(set (match_operand:HSI 0 "h8300_dst_operand" "=rQ") - (match_operator:HSI 3 "bit_operator" - [(match_operand:HSI 1 "h8300_dst_operand" "%0") - (match_operand:HSI 2 "h8300_src_operand" "rQi")])) +(define_insn "*3_clobber_flags" + [(set (match_operand:QHSI 0 "h8300_dst_operand" "=rQ") + (logicals:QHSI + (match_operand:QHSI 1 "h8300_dst_operand" "%0") + (match_operand:QHSI 2 "h8300_src_operand" "rQi"))) (clobber (reg:CC CC_REG))] "h8300_operands_match_p (operands)" - { return output_logical_op (mode, operands); } + { return output_logical_op (mode, , operands); } [(set (attr "length") - (symbol_ref "compute_logical_op_length (mode, operands)"))]) + (symbol_ref "compute_logical_op_length (mode, , operands)"))]) ;; ---------------------------------------------------------------------- @@ -260,11 +247,11 @@ (not:QHSI (match_operand:QHSI 1 "h8300_dst_operand" "0")))] "" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (not:QHSI (match_dup 1))) (clobber (reg:CC CC_REG))])]) -(define_insn "one_cmpl2_clobber_flags" +(define_insn "one_cmpl2_" [(set (match_operand:QHSI 0 "h8300_dst_operand" "=rQ") (not:QHSI (match_operand:QHSI 1 "h8300_dst_operand" "0"))) (clobber (reg:CC CC_REG))] diff --git a/gcc/config/h8300/shiftrotate.md b/gcc/config/h8300/shiftrotate.md index f1c86f7..4bf8fe1 100644 --- a/gcc/config/h8300/shiftrotate.md +++ b/gcc/config/h8300/shiftrotate.md @@ -175,7 +175,7 @@ return output_a_shift (operands); } [(set (attr "length") - (symbol_ref "compute_a_shift_length (insn, operands)"))]) + (symbol_ref "compute_a_shift_length (operands)"))]) (define_insn_and_split "*shiftqi_noscratch" [(set (match_operand:QI 0 "register_operand" "=r,r") @@ -203,7 +203,7 @@ return output_a_shift (operands); } [(set (attr "length") - (symbol_ref "compute_a_shift_length (insn, operands)"))]) + (symbol_ref "compute_a_shift_length (operands)"))]) (define_insn_and_split "*shifthi" [(set (match_operand:HI 0 "register_operand" "=r,r") @@ -230,7 +230,7 @@ return output_a_shift (operands); } [(set (attr "length") - (symbol_ref "compute_a_shift_length (insn, operands)"))]) + (symbol_ref "compute_a_shift_length (operands)"))]) (define_insn_and_split "*shifthi_noscratch" [(set (match_operand:HI 0 "register_operand" "=r,r") @@ -258,7 +258,7 @@ return output_a_shift (operands); } [(set (attr "length") - (symbol_ref "compute_a_shift_length (insn, operands)"))]) + (symbol_ref "compute_a_shift_length (operands)"))]) (define_insn_and_split "*shiftsi" [(set (match_operand:SI 0 "register_operand" "=r,r") @@ -285,7 +285,7 @@ return output_a_shift (operands); } [(set (attr "length") - (symbol_ref "compute_a_shift_length (insn, operands)"))]) + (symbol_ref "compute_a_shift_length (operands)"))]) (define_insn_and_split "*shiftsi_noscratch" [(set (match_operand:SI 0 "register_operand" "=r,r") @@ -313,7 +313,7 @@ return output_a_shift (operands); } [(set (attr "length") - (symbol_ref "compute_a_shift_length (insn, operands)"))]) + (symbol_ref "compute_a_shift_length (operands)"))]) ;; Split a variable shift into a loop. If the register containing ;; the shift count dies, then we just use that register. -- cgit v1.1 From 088264ea445efcee5f8f06150b5f9f508f21960b Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Tue, 1 Jun 2021 15:26:47 +0200 Subject: icf: Fix memory leak of a vector. gcc/ChangeLog: * ipa-icf.h: Use auto_vec for memory_access_types. --- gcc/ipa-icf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ipa-icf.h b/gcc/ipa-icf.h index 9f21a20..4b4d492 100644 --- a/gcc/ipa-icf.h +++ b/gcc/ipa-icf.h @@ -372,7 +372,7 @@ public: hashval_t gcode_hash; /* Vector of subpart of memory access types. */ - vec memory_access_types; + auto_vec memory_access_types; /* Total number of SSA names used in the function. */ unsigned ssa_names_size; -- cgit v1.1