diff options
author | Martin Liska <mliska@suse.cz> | 2021-06-02 08:59:18 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2021-06-02 08:59:18 +0200 |
commit | fa5b508acd3e217d75eaf000cdf2686d93b8c5c4 (patch) | |
tree | 6326ca887b1646391d66fc2a614e11d13bc7b4fe /gcc | |
parent | 520839b3244507adc4f3ad640e5cab46e2ccbf8f (diff) | |
parent | 088264ea445efcee5f8f06150b5f9f508f21960b (diff) | |
download | gcc-fa5b508acd3e217d75eaf000cdf2686d93b8c5c4.zip gcc-fa5b508acd3e217d75eaf000cdf2686d93b8c5c4.tar.gz gcc-fa5b508acd3e217d75eaf000cdf2686d93b8c5c4.tar.bz2 |
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc')
68 files changed, 1820 insertions, 637 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 05e1640..ef69e6a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,162 @@ +2021-06-01 Andrew Pinski <apinski@marvell.com> + + 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 <apinski@marvell.com> + + PR tree-optimization/95481 + * tree-tailcall.c (find_tail_calls): Handle empty typed + return decls. + +2021-06-01 Andrew Pinski <apinski@marvell.com> + + * 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 <jason@redhat.com> + + PR c++/91859 + * tree.h (CALL_FROM_NEW_OR_DELETE_P): Adjust comment. + +2021-06-01 Jason Merrill <jason@redhat.com> + + 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 <aldyh@redhat.com> + + * gimple-ssa-evrp.c: Enable exporting of global ranges. + +2021-06-01 Martin Liska <mliska@suse.cz> + + PR other/100826 + * doc/invoke.texi: Mention that -fgcse-after-reload + is enabled with -O3. + +2021-06-01 liuhongt <hongtao.liu@intel.com> + + 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 <amacleod@redhat.com> + + 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 <amacleod@redhat.com> + + * 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 <amacleod@redhat.com> + + * 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 <amacleod@redhat.com> + + 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 <mliska@suse.cz> + + * 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 <rguenther@suse.de> + + 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 <bergner@linux.ibm.com> + + PR target/99842 + * config/rs6000/predicates.md(mma_assemble_input_operand): Allow + indexed form addresses. + 2021-05-29 Jeff Law <jlaw@tachyum.com> * config/h8300/h8300.c (h8300_emit_stack_adjustment): Drop unused diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 9bfad84..54b764a 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210531 +20210602 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 2905179..cb2757c 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,27 @@ +2021-06-01 Martin Liska <mliska@suse.cz> + + 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 <indu.bhagat@oracle.com> + + PR testsuite/100749 + * c-pch.c (c_common_valid_pch): Use xstrdup for debug format set names. + +2021-05-31 Richard Biener <rguenther@suse.de> + + 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 <jakub@redhat.com> PR middle-end/99928 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-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; } 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) { 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 <rguenther@suse.de> + + 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 <rguenther@suse.de> PR c/100803 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 "<code><mode>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<mode>_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 "and<mode>3" - [(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 "*andor<mode>3" [(set (match_operand:QHSI 0 "register_operand" "=r") (ior:QHSI (and:QHSI (match_operand:QHSI 2 "register_operand" "r") @@ -95,7 +89,7 @@ || (<MODE>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 "<code><mode>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 "*logical<mode>3" - [(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 "*logical<mode>3_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 "*<code><mode>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>mode, operands); } + { return output_logical_op (<MODE>mode, <CODE>, operands); } [(set (attr "length") - (symbol_ref "compute_logical_op_length (<MODE>mode, operands)"))]) + (symbol_ref "compute_logical_op_length (<MODE>mode, <CODE>, 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_cmpl<mode>2_clobber_flags" +(define_insn "one_cmpl<mode>2_<cczn>" [(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. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 882c8eb..9a5fa79 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,35 @@ +2021-06-01 Patrick Palka <ppalka@redhat.com> + + 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 <jason@redhat.com> + + 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 <jason@redhat.com> + + PR c++/94492 + * decl2.c (cp_warn_deprecated_use): Check warning_enabled_at. + +2021-05-31 Richard Biener <rguenther@suse.de> + + 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 <jason@redhat.com> * constexpr.c (build_data_member_initialization): Use tsi_range. 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/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/cp/init.c b/gcc/cp/init.c index a85f4d5..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; @@ -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/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/doc/invoke.texi b/gcc/doc/invoke.texi index 4b4699f..9696c1b 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 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 <tobias@codesourcery.com> + + 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 <gerald@pfeifer.com> * gfortran.texi (BOZ literal constants): Fix typo. 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/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index 889cac1..cc27574 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. @@ -583,8 +584,9 @@ 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); } + enable_new_values (); } ranger_cache::~ranger_cache () @@ -599,22 +601,35 @@ 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"); } +// 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 -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); } @@ -639,7 +654,10 @@ 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, m_gori.depend1 (name), + m_gori.depend2 (name))) return true; } else @@ -674,15 +692,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); + m_gori.set_range_invariant (name); + m_temporal->set_timestamp (name); } // Push a request for a new lookup in block BB of name. Return true if @@ -691,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 @@ -711,41 +729,56 @@ 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, // 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 +792,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 +800,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 name, gimple *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 + entry_range (r, name, bb); + return true; +} + + +// 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. @@ -779,7 +876,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 +939,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 +955,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); + exit_range (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 +970,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 +979,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 +1139,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 +1154,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..4af461d 100644 --- a/gcc/gimple-range-cache.h +++ b/gcc/gimple-range-cache.h @@ -86,23 +86,27 @@ 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 name, gimple *stmt); + virtual bool range_on_edge (irange &r, edge e, tree expr); bool block_range (irange &r, basic_block bb, tree name, bool calc = true); bool get_global_range (irange &r, tree name) const; bool get_non_stale_global_range (irange &r, tree name); 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; - 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; @@ -111,6 +115,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<basic_block> m_workback; @@ -125,6 +133,7 @@ private: bool push_poor_value (basic_block bb, tree name); vec<update_record> 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-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<gswitch *> (stmt)) - return compute_operand_range_switch (r, as_a<gswitch *> (stmt), lhs, name); + return compute_operand_range_switch (r, as_a<gswitch *> (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..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); @@ -1051,7 +1060,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 +1072,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 +1173,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 +1202,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 +1245,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: 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/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<constructor_elt, va_gc> *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. */ 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<tree> memory_access_types; + auto_vec<tree> memory_access_types; /* Total number of SSA names used in the function. */ unsigned ssa_names_size; 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 <mliska@suse.cz> + + * lto-common.c (compare_tree_sccs_1): Compare + FUNCTION_DECL_DECL_TYPE. + 2021-05-24 Wang Liushuai <wangliushuai@bytedance.com> * 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..46dc814 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,82 @@ +2021-06-01 Patrick Palka <ppalka@redhat.com> + + 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 <apinski@marvell.com> + + 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 <wschmidt@linux.ibm.com> + + PR testsuite/100750 + * gcc.target/powerpc/rop-5.c: Require ELFv2 ABI. + +2021-06-01 Jason Merrill <jason@redhat.com> + + PR c++/91859 + * g++.dg/cpp2a/destroying-delete5.C: New test. + +2021-06-01 Jason Merrill <jason@redhat.com> + + PR c++/94492 + * g++.dg/cpp0x/depr-copy4.C: New test. + +2021-06-01 Aldy Hernandez <aldyh@redhat.com> + + * gcc.dg/Wstringop-overflow-55.c: Adjust for global ranges changes. + * gcc.dg/pr80776-1.c: Same. + +2021-06-01 Tobias Burnus <tobias@codesourcery.com> + + 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 <hongtao.liu@intel.com> + + PR tree-optimization/98365 + * gcc.target/i386/pr98365.c: New test. + +2021-06-01 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/100781 + * gcc.dg/pr100781.c: New. + +2021-06-01 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/100774 + * g++.dg/pr100774.C: New. + +2021-05-31 Tobias Burnus <tobias@codesourcery.com> + + * 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 <rguenther@suse.de> + + 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 <bergner@linux.ibm.com> + + PR target/99842 + * g++.target/powerpc/pr99842.C: New. + 2021-05-29 Bernd Edlinger <bernd.edlinger@hotmail.de> * gcc.dg/plugin/diagnostic_plugin_show_trees.c (plugin_init): Fix caret_max_with. 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<test&>(*ptr).i; + if (i != 0) __builtin_abort(); +} 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; +} 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<tuple&>(*ptr).i; + int& j = static_cast<tuple&>(*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); 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 <cstdlib> +#include <new> + +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/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(); + } +} 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/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() { } + 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" "" } */ } 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/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/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. */ 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) 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 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 <gassign *> (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 <reduc_1, reduc_3> + + 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); 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: 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 <greturn *> (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 @@ -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) |