diff options
author | Martin Liska <mliska@suse.cz> | 2022-10-19 15:25:12 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-10-19 15:25:12 +0200 |
commit | 4465e2a047c3b175bf6c4ca500547eb6b12df52f (patch) | |
tree | 3159c8256f9907538f186ce7c1087c83825b5519 /gcc | |
parent | 6c22519f33270a689fc8730ceff9212b376ed40d (diff) | |
parent | 09fed44cabd50f3d8e050f91cc2db02364ce9176 (diff) | |
download | gcc-4465e2a047c3b175bf6c4ca500547eb6b12df52f.zip gcc-4465e2a047c3b175bf6c4ca500547eb6b12df52f.tar.gz gcc-4465e2a047c3b175bf6c4ca500547eb6b12df52f.tar.bz2 |
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc')
150 files changed, 4704 insertions, 1686 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a687dc5..04c9dec 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,403 @@ +2022-10-18 Martin Jambor <mjambor@suse.cz> + + * ipa-prop.h (ipa_agg_value): Remove type. + (ipa_agg_value_set): Likewise. + (ipa_copy_agg_values): Remove function. + (ipa_release_agg_values): Likewise. + (ipa_auto_call_arg_values) Add a forward declaration. + (ipa_call_arg_values): Likewise. + (class ipa_argagg_value_list): New constructors, added member function + value_for_index_p. + (class ipa_auto_call_arg_values): Removed the destructor and member + function safe_aggval_at. Use ipa_argagg_values for m_known_aggs. + (class ipa_call_arg_values): Removed member function safe_aggval_at. + Use ipa_argagg_values for m_known_aggs. + (ipa_get_indirect_edge_target): Removed declaration. + (ipa_find_agg_cst_for_param): Likewise. + (ipa_find_agg_cst_from_init): New declaration. + (ipa_agg_value_from_jfunc): Likewise. + (ipa_agg_value_set_from_jfunc): Removed declaration. + (ipa_push_agg_values_from_jfunc): New declaration. + * ipa-cp.cc (ipa_agg_value_from_node): Renamed to + ipa_agg_value_from_jfunc, made public. + (ipa_agg_value_set_from_jfunc): Removed. + (ipa_push_agg_values_from_jfunc): New function. + (ipa_get_indirect_edge_target_1): Removed known_aggs parameter, use + avs for this purpose too. + (ipa_get_indirect_edge_target): Removed the overload working on + ipa_auto_call_arg_values, use ipa_argagg_value_list in the remaining + one. + (devirtualization_time_bonus): Use ipa_argagg_value_list and + ipa_get_indirect_edge_target_1 instead of + ipa_get_indirect_edge_target. + (context_independent_aggregate_values): Removed function. + (gather_context_independent_values): Work on ipa_argagg_value_list. + (estimate_local_effects): Likewise, define some iterator variables + only in the construct where necessary. + (ipcp_discover_new_direct_edges): Adjust the call to + ipa_get_indirect_edge_target_1. + (push_agg_values_for_index_from_edge): Adjust the call + ipa_agg_value_from_node which has been renamed to + ipa_agg_value_from_jfunc. + * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Work on + ipa_argagg_value_list. + (evaluate_properties_for_edge): Replace manual filling in aggregate + values with call to ipa_push_agg_values_from_jfunc. + (estimate_calls_size_and_time): Work on ipa_argagg_value_list. + (ipa_cached_call_context::duplicate_from): Likewise. + (ipa_cached_call_context::release): Likewise. + (ipa_call_context::equal_to): Likewise. + * ipa-prop.cc (ipa_find_agg_cst_from_init): Make public. + (ipa_find_agg_cst_for_param): Removed function. + (ipa_find_agg_cst_from_jfunc_items): New function. + (try_make_edge_direct_simple_call): Replace calls to + ipa_agg_value_set_from_jfunc and ipa_find_agg_cst_for_param with + ipa_find_agg_cst_from_init and ipa_find_agg_cst_from_jfunc_items. + (try_make_edge_direct_virtual_call): Replace calls to + ipa_agg_value_set_from_jfunc and ipa_find_agg_cst_for_param with + simple query of constant jump function and a call to + ipa_find_agg_cst_from_jfunc_items. + (ipa_auto_call_arg_values::~ipa_auto_call_arg_values): Removed. + +2022-10-18 Martin Jambor <mjambor@suse.cz> + + * ipa-prop.h (IPA_PROP_ARG_INDEX_LIMIT_BITS): New. + (ipcp_transformation): Added forward declaration. + (ipa_argagg_value): New type. + (ipa_argagg_value_list): New type. + (ipa_agg_replacement_value): Removed type. + (ipcp_transformation): Switch from using ipa_agg_replacement_value + to ipa_argagg_value_list. + (ipa_get_agg_replacements_for_node): Removed. + (ipa_dump_agg_replacement_values): Removed declaration. + * ipa-cp.cc: Define INCLUDE_ALGORITHM. + (values_equal_for_ipcp_p): Moved up in the file. + (ipa_argagg_value_list::dump): New function. + (ipa_argagg_value_list::debug): Likewise. + (ipa_argagg_value_list::get_elt): Likewise. + (ipa_argagg_value_list::get_elt_for_index): Likewise. + (ipa_argagg_value_list::get_value): New overloaded functions. + (ipa_argagg_value_list::superset_of_p): New function. + (new ipa_argagg_value_list::push_adjusted_values): Likewise. + (push_agg_values_from_plats): Likewise. + (intersect_argaggs_with): Likewise. + (get_clone_agg_value): Removed. + (ipa_agg_value_from_node): Make last parameter const, use + ipa_argagg_value_list to search values coming from clones. + (ipa_get_indirect_edge_target_1): Use ipa_argagg_value_list to search + values coming from clones. + (ipcp_discover_new_direct_edges): Pass around a vector of + ipa_argagg_values rather than a link list of replacement values. + (cgraph_edge_brings_value_p): Use ipa_argagg_value_list to search + values coming from clones. + (create_specialized_node): Work with a vector of ipa_argagg_values + rather than a link list of replacement values. + (self_recursive_agg_pass_through_p): Make the pointer parameters + const. + (copy_plats_to_inter): Removed. + (intersect_with_plats): Likewise. + (agg_replacements_to_vector): Likewise. + (intersect_with_agg_replacements): Likewise. + (intersect_aggregates_with_edge): Likewise. + (push_agg_values_for_index_from_edge): Likewise. + (push_agg_values_from_edge): Likewise. + (find_aggregate_values_for_callers_subset): Rewrite. + (cgraph_edge_brings_all_agg_vals_for_node): Likewise. + (ipcp_val_agg_replacement_ok_p): Use ipa_argagg_value_list to search + aggregate values. + (decide_about_value): Work with a vector of ipa_argagg_values rather + than a link list of replacement values. + (decide_whether_version_node): Likewise. + (ipa_analyze_node): Check number of parameters, assert that there + are no descriptors when bailing out. + * ipa-prop.cc (ipa_set_node_agg_value_chain): Switch to a vector of + ipa_argagg_value. + (ipa_node_params_t::duplicate): Removed superfluous handling of + ipa_agg_replacement_values. Name of src parameter removed because + it is no longer used. + (ipcp_transformation_t::duplicate): Replaced duplication of + ipa_agg_replacement_values with copying vector m_agg_values. + (ipa_dump_agg_replacement_values): Removed. + (write_ipcp_transformation_info): Stream the new data-structure + instead of the old. + (read_ipcp_transformation_info): Likewise. + (adjust_agg_replacement_values): Work with ipa_argagg_values instead + of linked lists of ipa_agg_replacement_values, copy the items and + truncate the vector as necessary to keep it sorted instead of marking + items as invalid. Return one bool if CFG should be updated. + (ipcp_modif_dom_walker): Store ipcp_transformation instead of + linked list of ipa_agg_replacement_values. + (ipcp_modif_dom_walker::before_dom_children): Use + ipa_argagg_value_list instead of walking a list of + ipa_agg_replacement_values. + (ipcp_transform_function): Switch to the new data structure, adjust + dumping. + +2022-10-18 Richard Biener <rguenther@suse.de> + + PR tree-optimization/107302 + * tree-vect-loop.cc (vectorizable_recurrence): Fix vec_perm + placement for a PHI latch def. + +2022-10-18 Andre Vieira <andre.simoesdiasvieira@arm.com> + + PR tree-optimization/107275 + * tree-if-conv.cc (if_convertible_loop_p_1): Move + find_data_references_in_loop call from here... + (if_convertible_loop_p): And move data-reference vector initialization + from here... + (tree_if_conversion):... to here. + +2022-10-18 Jakub Jelinek <jakub@redhat.com> + + PR c++/106654 + * gimple.def (GIMPLE_ASSUME): New statement kind. + * gimple.h (struct gimple_statement_assume): New type. + (is_a_helper <gimple_statement_assume *>::test, + is_a_helper <const gimple_statement_assume *>::test): New. + (gimple_build_assume): Declare. + (gimple_has_substatements): Return true for GIMPLE_ASSUME. + (gimple_assume_guard, gimple_assume_set_guard, + gimple_assume_guard_ptr, gimple_assume_body_ptr, gimple_assume_body): + New inline functions. + * gsstruct.def (GSS_ASSUME): New. + * gimple.cc (gimple_build_assume): New function. + (gimple_copy): Handle GIMPLE_ASSUME. + * gimple-pretty-print.cc (dump_gimple_assume): New function. + (pp_gimple_stmt_1): Handle GIMPLE_ASSUME. + * gimple-walk.cc (walk_gimple_op): Handle GIMPLE_ASSUME. + * omp-low.cc (WALK_SUBSTMTS): Likewise. + (lower_omp_1): Likewise. + * omp-oacc-kernels-decompose.cc (adjust_region_code_walk_stmt_fn): + Likewise. + * tree-cfg.cc (verify_gimple_stmt, verify_gimple_in_seq_2): Likewise. + * function.h (struct function): Add assume_function bitfield. + * gimplify.cc (gimplify_call_expr): If the assumption isn't + simple enough, expand it into GIMPLE_ASSUME wrapped block or + for -O0 drop it. + * gimple-low.cc: Include attribs.h. + (create_assumption_fn): New function. + (struct lower_assumption_data): New type. + (find_assumption_locals_r, assumption_copy_decl, + adjust_assumption_stmt_r, adjust_assumption_stmt_op, + lower_assumption): New functions. + (lower_stmt): Handle GIMPLE_ASSUME. + * tree-ssa-ccp.cc (pass_fold_builtins::execute): Remove + IFN_ASSUME calls. + * lto-streamer-out.cc (output_struct_function_base): Pack + assume_function bit. + * lto-streamer-in.cc (input_struct_function_base): And unpack it. + * cgraphunit.cc (cgraph_node::expand): Don't verify assume_function + has TREE_ASM_WRITTEN set and don't release its body. + (symbol_table::compile): Allow assume functions not to have released + body. + * internal-fn.cc (expand_ASSUME): Remove gcc_unreachable. + * passes.cc (execute_one_pass): For TODO_discard_function don't + release body of assume functions. + * cgraph.cc (cgraph_node::verify_node): Don't verify cgraph nodes + of PROP_assumptions_done functions. + * tree-pass.h (PROP_assumptions_done): Define. + (TODO_discard_function): Adjust comment. + (make_pass_assumptions): Declare. + * passes.def (pass_assumptions): Add. + * timevar.def (TV_TREE_ASSUMPTIONS): New. + * tree-inline.cc (remap_gimple_stmt): Handle GIMPLE_ASSUME. + * tree-vrp.cc (pass_data_assumptions): New variable. + (pass_assumptions): New class. + (make_pass_assumptions): New function. + +2022-10-18 Richard Biener <rguenther@suse.de> + + PR tree-optimization/107301 + * gimple-ssa-isolate-paths.cc (handle_return_addr_local_phi_arg): + Check whether we can duplicate the block. + (find_implicit_erroneous_behavior): Likewise. + +2022-10-18 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/107273 + * value-relation.cc (equiv_oracle::add_partial_equiv): Merge + instead of copying precison of each member. + +2022-10-17 Jeff Law <jeffreyalaw@gmail.com> + + PR target/101697 + * config/h8300/combiner.md: Replace '<' preincment constraint with + ZA/Z1..ZH/Z7 combinations. + * config/h8300/movepush.md: Similarly + +2022-10-17 Jeff Law <jeffreyalaw@gmail.com> + + * config/h8300/constraints.md (Za..Zh): New constraints for + autoinc addresses using a specific register. + * config/h8300/h8300.cc (pre_incdec_with_reg): New function. + * config/h8300/h8300-protos.h (pre_incdec_with_reg): Add prototype. + +2022-10-17 Jeff Law <jlaw@ventanamicro.com> + + * config/i386/cet.c: Remove accidental commit. + * config/i386/driver-mingw32.c: Likewise. + * config/i386/i386-builtins.c: Likewise. + * config/i386/i386-d.c: Likewise. + * config/i386/i386-expand.c: Likewise. + * config/i386/i386-features.c: Likewise. + * config/i386/i386-options.c: Likewise. + * config/i386/t-cet: Likewise. + * config/i386/x86-tune-sched-atom.c: Likewise. + * config/i386/x86-tune-sched-bd.c: Likewise. + * config/i386/x86-tune-sched-core.c: Likewise. + * config/i386/x86-tune-sched.c: Likewise. + +2022-10-17 Jeff Law <jeffreyalaw@gmail.com> + + * common/config/h8300/h8300-common.cc (h8300_option_optimization_table): + Enable redundant extension elimination at -O2 and above. + * config/i386/cet.c: New file. + * config/i386/driver-mingw32.c: New file. + * config/i386/i386-builtins.c: New file. + * config/i386/i386-d.c: New file. + * config/i386/i386-expand.c: New file. + * config/i386/i386-features.c: New file. + * config/i386/i386-options.c: New file. + * config/i386/t-cet: New file. + * config/i386/x86-tune-sched-atom.c: New file. + * config/i386/x86-tune-sched-bd.c: New file. + * config/i386/x86-tune-sched-core.c: New file. + * config/i386/x86-tune-sched.c: New file. + +2022-10-17 Jeff Law <jeffreyalaw@gmail.com> + + * config/h8300/extensions.md (CCZN setting zero extended load): Add + missing splitter. + +2022-10-17 Aldy Hernandez <aldyh@redhat.com> + + PR tree-optimization/107293 + * tree-ssa-dom.cc + (dom_opt_dom_walker::set_global_ranges_from_unreachable_edges): + Check that condition post-dominates the definition point. + +2022-10-17 Aldy Hernandez <aldyh@redhat.com> + + PR tree-optimization/107286 + * value-range.cc (range_tests_floats): Do not test for -Inf when + flag_finite_math_only. + +2022-10-17 Andrew MacLeod <amacleod@redhat.com> + + * gimple-range-fold.cc (fold_using_range::range_of_range_op): + Provide relation_trio class. + * gimple-range-gori.cc (gori_compute::refine_using_relation): + Provide relation_trio class. + (gori_compute::refine_using_relation): Ditto. + (gori_compute::compute_operand1_range): Provide lhs_op2 and + op1_op2 relations via relation_trio class. + (gori_compute::compute_operand2_range): Ditto. + * gimple-range-op.cc (gimple_range_op_handler::calc_op1): Use + relation_trio instead of relation_kind. + (gimple_range_op_handler::calc_op2): Ditto. + (*::fold_range): Ditto. + * gimple-range-op.h (gimple_range_op::calc_op1): Adjust prototypes. + (gimple_range_op::calc_op2): Adjust prototypes. + * range-op-float.cc (*::fold_range): Use relation_trio instead of + relation_kind. + (*::op1_range): Ditto. + (*::op2_range): Ditto. + * range-op.cc (*::fold_range): Use relation_trio instead of + relation_kind. + (*::op1_range): Ditto. + (*::op2_range): Ditto. + * range-op.h (class range_operator): Adjust prototypes. + (class range_operator_float): Ditto. + (class range_op_handler): Adjust prototypes. + (relop_early_resolve): Pickup op1_op2 relation from relation_trio. + * value-relation.cc (VREL_LAST): Adjust use to be one past the end of + the enum. + (relation_oracle::validate_relation): Use relation_trio in call + to fold_range. + * value-relation.h (enum relation_kind_t): Add VREL_LAST as + final element. + (class relation_trio): New. + (TRIO_VARYING, TRIO_SHIFT, TRIO_MASK): New. + +2022-10-17 Andrew MacLeod <amacleod@redhat.com> + + * range-op-float.cc (foperator_not_equal::op1_range): Check for + VREL_EQ after singleton. + (foperator_unordered::op1_range): Set VARYING before calling + clear_nan(). + (foperator_ordered::op1_range): Set rather than clear NAN if both + operands are the same. + +2022-10-17 Andrew MacLeod <amacleod@redhat.com> + + * value-relation.cc (value_relation::dump): Change message. + * value-relation.h (value_relation::set_relation): If op1 is the + same as op2 do not create a relation. + +2022-10-17 Thomas Schwinge <thomas@codesourcery.com> + + * config/gcn/gcn.cc (VnMODE): Use 'case E_QImode:' instead of + 'case QImode:', etc. + +2022-10-17 Thomas Schwinge <thomas@codesourcery.com> + + * gimple-expr.cc (mark_addressable_2): Tag as 'static'. + +2022-10-17 Richard Biener <rguenther@suse.de> + Ju-Zhe Zhong <juzhe.zhong@rivai.ai> + + PR tree-optimization/99409 + PR tree-optimization/99394 + * tree-vectorizer.h (vect_def_type::vect_first_order_recurrence): Add. + (stmt_vec_info_type::recurr_info_type): Likewise. + (vectorizable_recurr): New function. + * tree-vect-loop.cc (vect_phi_first_order_recurrence_p): New + function. + (vect_analyze_scalar_cycles_1): Look for first order + recurrences. + (vect_analyze_loop_operations): Handle them. + (vect_transform_loop): Likewise. + (vectorizable_recurr): New function. + (maybe_set_vectorized_backedge_value): Handle the backedge value + setting in the first order recurrence PHI and the permutes. + * tree-vect-stmts.cc (vect_analyze_stmt): Handle first order + recurrences. + (vect_transform_stmt): Likewise. + (vect_is_simple_use): Likewise. + (vect_is_simple_use): Likewise. + * tree-vect-slp.cc (vect_get_and_check_slp_defs): Likewise. + (vect_build_slp_tree_2): Likewise. + (vect_schedule_scc): Handle the backedge value setting in the + first order recurrence PHI and the permutes. + +2022-10-17 Ju-Zhe Zhong <juzhe.zhong@rivai.ai> + + * config/riscv/t-riscv: Change Tab into 2 space. + +2022-10-17 Ju-Zhe Zhong <juzhe.zhong@rivai.ai> + + * config/riscv/riscv-vector-builtins.cc (mangle_builtin_type): Move down the function. + +2022-10-17 Arsen Arsenovic <arsen@aarsen.me> + + * config.gcc: --target=*-elf --without-{newlib,headers} should + provide stdint.h. + +2022-10-17 Hu, Lin1 <lin1.hu@intel.com> + + * common/config/i386/cpuinfo.h: + (get_intel_cpu): Handle Meteorlake. + * common/config/i386/i386-common.cc: + (processor_alias_table): Add Meteorlake. + +2022-10-17 Haochen Jiang <haochen.jiang@intel.com> + + * common/config/i386/cpuinfo.h: + (get_intel_cpu): Handle Raptorlake. + * common/config/i386/i386-common.cc: + (processor_alias_table): Add Raptorlake. + 2022-10-16 Jeff Law <jeffreyalaw@gmail.com> * config/h8300/constraints.md (Z0..Z7): New register diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 856b00b..268d1b4 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20221017 +20221019 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 2047e2e..63076ed 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,11 @@ +2022-10-18 Joseph Myers <joseph@codesourcery.com> + + PR c/36113 + * c-common.cc (c_common_type_for_size): Add fallback to + widest_unsigned_literal_type_node or + widest_integer_literal_type_node for precision that may not + exactly match the precision of those types. + 2022-10-14 Jakub Jelinek <jakub@redhat.com> * c-cppbuiltin.cc (c_cpp_builtins): If bfloat16_type_node, diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 9ec9100..cd54c51 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -2298,6 +2298,10 @@ c_common_type_for_size (unsigned int bits, int unsignedp) if (bits <= TYPE_PRECISION (intDI_type_node)) return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + if (bits <= TYPE_PRECISION (widest_integer_literal_type_node)) + return (unsignedp ? widest_unsigned_literal_type_node + : widest_integer_literal_type_node); + return NULL_TREE; } diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index d28585b..7cb2e9c 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,24 @@ +2022-10-18 Joseph Myers <joseph@codesourcery.com> + + PR c/107164 + * c-decl.cc (shadow_tag_warned): If pedantic, diagnose "enum tag;" + with previous declaration visible. + +2022-10-18 Joseph Myers <joseph@codesourcery.com> + + PR c/36113 + * c-decl.cc (finish_enum): If any enumerators do not fit in int, + convert all to the type of the enumeration. pedwarn if no integer + type fits all enumerators and default to + widest_integer_literal_type_node in that case. Otherwise pedwarn + for type wider than intmax_t. + (build_enumerator): pedwarn for enumerators outside the range of + uintmax_t or intmax_t, and otherwise use pedwarn_c11 for + enumerators outside the range of int. On overflow, attempt to + find a wider type that can hold the value of the next enumerator. + Do not convert value to type determined with + c_common_type_for_size. + 2022-10-14 Jakub Jelinek <jakub@redhat.com> * c-typeck.cc (convert_arguments): Don't promote __bf16 to diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index a7571cc..80f6e91 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -4814,6 +4814,20 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) warned = 1; pending_xref_error (); } + else if (declspecs->typespec_kind != ctsk_tagdef + && declspecs->typespec_kind != ctsk_tagfirstref + && declspecs->typespec_kind != ctsk_tagfirstref_attrs + && code == ENUMERAL_TYPE) + { + bool warned_enum = false; + if (warned != 1) + warned_enum = pedwarn (input_location, OPT_Wpedantic, + "empty declaration of %<enum%> type " + "does not redeclare tag"); + if (warned_enum) + warned = 1; + pending_xref_error (); + } else { pending_invalid_xref = NULL_TREE; @@ -9385,6 +9399,10 @@ finish_enum (tree enumtype, tree values, tree attributes) precision = MAX (tree_int_cst_min_precision (minnode, sign), tree_int_cst_min_precision (maxnode, sign)); + bool wider_than_int = + (tree_int_cst_lt (minnode, TYPE_MIN_VALUE (integer_type_node)) + || tree_int_cst_lt (TYPE_MAX_VALUE (integer_type_node), maxnode)); + /* If the precision of the type was specified with an attribute and it was too small, give an error. Otherwise, use it. */ if (TYPE_PRECISION (enumtype) && lookup_attribute ("mode", attributes)) @@ -9407,9 +9425,20 @@ finish_enum (tree enumtype, tree values, tree attributes) tem = c_common_type_for_size (precision, sign == UNSIGNED ? 1 : 0); if (tem == NULL) { - warning (0, "enumeration values exceed range of largest integer"); - tem = long_long_integer_type_node; - } + /* This should only occur when both signed and unsigned + values of maximum precision occur among the + enumerators. */ + pedwarn (input_location, 0, + "enumeration values exceed range of largest integer"); + tem = widest_integer_literal_type_node; + } + else if (precision > TYPE_PRECISION (intmax_type_node) + && !tree_int_cst_lt (minnode, TYPE_MIN_VALUE (intmax_type_node)) + && !tree_int_cst_lt (TYPE_MAX_VALUE (uintmax_type_node), + maxnode)) + pedwarn (input_location, OPT_Wpedantic, + "enumeration values exceed range of %qs", + sign == UNSIGNED ? "uintmax_t" : "intmax_t"); } else tem = sign == UNSIGNED ? unsigned_type_node : integer_type_node; @@ -9439,17 +9468,17 @@ finish_enum (tree enumtype, tree values, tree attributes) TREE_TYPE (enu) = enumtype; - /* The ISO C Standard mandates enumerators to have type int, - even though the underlying type of an enum type is - unspecified. However, GCC allows enumerators of any - integer type as an extensions. build_enumerator() - converts any enumerators that fit in an int to type int, - to avoid promotions to unsigned types when comparing - integers with enumerators that fit in the int range. - When -pedantic is given, build_enumerator() would have - already warned about those that don't fit. Here we - convert the rest to the enumerator type. */ - if (TREE_TYPE (ini) != integer_type_node) + /* Before C2X, the ISO C Standard mandates enumerators to + have type int, even though the underlying type of an enum + type is unspecified. However, C2X allows enumerators of + any integer type, and if an enumeration has any + enumerators wider than int, all enumerators have the + enumerated type after it is parsed. Any enumerators that + fit in int are given type int in build_enumerator (which + is the correct type while the enumeration is being + parsed), so no conversions are needed here if all + enumerators fit in int. */ + if (wider_than_int) ini = convert (enumtype, ini); DECL_INITIAL (enu) = ini; @@ -9517,7 +9546,7 @@ tree build_enumerator (location_t decl_loc, location_t loc, struct c_enum_contents *the_enum, tree name, tree value) { - tree decl, type; + tree decl; /* Validate and default VALUE. */ @@ -9568,21 +9597,45 @@ build_enumerator (location_t decl_loc, location_t loc, } /* Even though the underlying type of an enum is unspecified, the type of enumeration constants is explicitly defined as int - (6.4.4.3/2 in the C99 Standard). GCC allows any integer type as - an extension. */ - else if (!int_fits_type_p (value, integer_type_node)) - pedwarn (loc, OPT_Wpedantic, - "ISO C restricts enumerator values to range of %<int%>"); - - /* The ISO C Standard mandates enumerators to have type int, even - though the underlying type of an enum type is unspecified. - However, GCC allows enumerators of any integer type as an - extensions. Here we convert any enumerators that fit in an int - to type int, to avoid promotions to unsigned types when comparing - integers with enumerators that fit in the int range. When - -pedantic is given, we would have already warned about those that - don't fit. We have to do this here rather than in finish_enum - because this value may be used to define more enumerators. */ + (6.4.4.3/2 in the C99 Standard). C2X allows any integer type, and + GCC allows such types for older standards as an extension. */ + bool warned_range = false; + if (!int_fits_type_p (value, + (TYPE_UNSIGNED (TREE_TYPE (value)) + ? uintmax_type_node + : intmax_type_node))) + /* GCC does not consider its types larger than intmax_t to be + extended integer types (although C2X would permit such types to + be considered extended integer types if all the features + required by <stdint.h> and <inttypes.h> macros, such as support + for integer constants and I/O, were present), so diagnose if + such a wider type is used. (If the wider type arose from a + constant of such a type, that will also have been diagnosed, + but this is the only diagnostic in the case where it arises + from choosing a wider type automatically when adding 1 + overflows.) */ + warned_range = pedwarn (loc, OPT_Wpedantic, + "enumerator value outside the range of %qs", + (TYPE_UNSIGNED (TREE_TYPE (value)) + ? "uintmax_t" + : "intmax_t")); + if (!warned_range && !int_fits_type_p (value, integer_type_node)) + pedwarn_c11 (loc, OPT_Wpedantic, + "ISO C restricts enumerator values to range of %<int%> " + "before C2X"); + + /* The ISO C Standard mandates enumerators to have type int before + C2X, even though the underlying type of an enum type is + unspecified. C2X allows enumerators of any integer type. During + the parsing of the enumeration, C2X specifies that constants + representable in int have type int, constants not representable + in int have the type of the given expression if any, and + constants not representable in int and derived by adding 1 to the + previous constant have the type of that constant unless the + addition would overflow or wraparound, in which case a wider type + of the same signedness is chosen automatically; after the + enumeration is parsed, all the constants have the type of the + enumeration if any do not fit in int. */ if (int_fits_type_p (value, integer_type_node)) value = convert (integer_type_node, value); @@ -9591,18 +9644,38 @@ build_enumerator (location_t decl_loc, location_t loc, = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), PLUS_EXPR, value, integer_one_node, false); the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value); + if (the_enum->enum_overflow) + { + /* Choose a wider type with the same signedness if + available. */ + int prec = TYPE_PRECISION (TREE_TYPE (value)) + 1; + bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (value)); + tree new_type = (unsignedp + ? long_unsigned_type_node + : long_integer_type_node); + if (prec > TYPE_PRECISION (new_type)) + new_type = (unsignedp + ? long_long_unsigned_type_node + : long_long_integer_type_node); + if (prec > TYPE_PRECISION (new_type)) + new_type = (unsignedp + ? widest_unsigned_literal_type_node + : widest_integer_literal_type_node); + if (prec <= TYPE_PRECISION (new_type)) + { + the_enum->enum_overflow = false; + the_enum->enum_next_value + = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), + PLUS_EXPR, convert (new_type, value), + integer_one_node, false); + gcc_assert (!tree_int_cst_lt (the_enum->enum_next_value, value)); + } + } /* Now create a declaration for the enum value name. */ - type = TREE_TYPE (value); - type = c_common_type_for_size (MAX (TYPE_PRECISION (type), - TYPE_PRECISION (integer_type_node)), - (TYPE_PRECISION (type) - >= TYPE_PRECISION (integer_type_node) - && TYPE_UNSIGNED (type))); - - decl = build_decl (decl_loc, CONST_DECL, name, type); - DECL_INITIAL (decl) = convert (type, value); + decl = build_decl (decl_loc, CONST_DECL, name, TREE_TYPE (value)); + DECL_INITIAL (decl) = value; pushdecl (decl); return tree_cons (decl, value, NULL_TREE); diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc index 8d6ed38..5851b2f 100644 --- a/gcc/cgraph.cc +++ b/gcc/cgraph.cc @@ -1411,7 +1411,6 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge *e) { tree decl = gimple_call_fndecl (e->call_stmt); gcall *new_stmt; - gimple_stmt_iterator gsi; if (e->speculative) { @@ -1572,18 +1571,17 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge *e) && (VOID_TYPE_P (TREE_TYPE (gimple_call_fntype (new_stmt))) || should_remove_lhs_p (lhs))) { + gimple_call_set_lhs (new_stmt, NULL_TREE); + /* We need to fix up the SSA name to avoid checking errors. */ if (TREE_CODE (lhs) == SSA_NAME) { tree var = create_tmp_reg_fn (DECL_STRUCT_FUNCTION (e->caller->decl), TREE_TYPE (lhs), NULL); - var = get_or_create_ssa_default_def - (DECL_STRUCT_FUNCTION (e->caller->decl), var); - gimple *set_stmt = gimple_build_assign (lhs, var); - gsi = gsi_for_stmt (new_stmt); - gsi_insert_before_without_update (&gsi, set_stmt, GSI_SAME_STMT); - update_stmt_fn (DECL_STRUCT_FUNCTION (e->caller->decl), set_stmt); + SET_SSA_NAME_VAR_OR_IDENTIFIER (lhs, var); + SSA_NAME_DEF_STMT (lhs) = gimple_build_nop (); + set_ssa_default_def (DECL_STRUCT_FUNCTION (e->caller->decl), + var, lhs); } - gimple_call_set_lhs (new_stmt, NULL_TREE); update_stmt_fn (DECL_STRUCT_FUNCTION (e->caller->decl), new_stmt); } @@ -3751,7 +3749,9 @@ cgraph_node::verify_node (void) && (!DECL_EXTERNAL (decl) || inlined_to) && !flag_wpa) { - if (this_cfun->cfg) + if ((this_cfun->curr_properties & PROP_assumptions_done) != 0) + ; + else if (this_cfun->cfg) { hash_set<gimple *> stmts; diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc index 7b5be0f..b05d790 100644 --- a/gcc/cgraphunit.cc +++ b/gcc/cgraphunit.cc @@ -1882,6 +1882,16 @@ cgraph_node::expand (void) ggc_collect (); timevar_pop (TV_REST_OF_COMPILATION); + if (DECL_STRUCT_FUNCTION (decl) + && DECL_STRUCT_FUNCTION (decl)->assume_function) + { + /* Assume functions aren't expanded into RTL, on the other side + we don't want to release their body. */ + if (cfun) + pop_cfun (); + return; + } + /* Make sure that BE didn't give up on compiling. */ gcc_assert (TREE_ASM_WRITTEN (decl)); if (cfun) @@ -2373,6 +2383,10 @@ symbol_table::compile (void) if (node->inlined_to || gimple_has_body_p (node->decl)) { + if (DECL_STRUCT_FUNCTION (node->decl) + && (DECL_STRUCT_FUNCTION (node->decl)->curr_properties + & PROP_assumptions_done) != 0) + continue; error_found = true; node->debug (); } diff --git a/gcc/common/config/h8300/h8300-common.cc b/gcc/common/config/h8300/h8300-common.cc index bfbda22..22e2cfc 100644 --- a/gcc/common/config/h8300/h8300-common.cc +++ b/gcc/common/config/h8300/h8300-common.cc @@ -32,6 +32,8 @@ static const struct default_options h8300_option_optimization_table[] = and/or variable-cycle branches where (cycle count taken != cycle count not taken). */ { OPT_LEVELS_ALL, OPT_freorder_blocks, NULL, 0 }, + /* Enable redundant extension instructions removal at -O2 and higher. */ + { OPT_LEVELS_2_PLUS, OPT_free, NULL, 1 }, { OPT_LEVELS_NONE, 0, NULL, 0 } }; diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc index 3dc294c..8777255 100644 --- a/gcc/config/gcn/gcn.cc +++ b/gcc/config/gcn/gcn.cc @@ -402,7 +402,7 @@ VnMODE (int n, machine_mode mode) { switch (mode) { - case QImode: + case E_QImode: switch (n) { case 2: return V2QImode; @@ -413,7 +413,7 @@ VnMODE (int n, machine_mode mode) case 64: return V64QImode; } break; - case HImode: + case E_HImode: switch (n) { case 2: return V2HImode; @@ -424,7 +424,7 @@ VnMODE (int n, machine_mode mode) case 64: return V64HImode; } break; - case HFmode: + case E_HFmode: switch (n) { case 2: return V2HFmode; @@ -435,7 +435,7 @@ VnMODE (int n, machine_mode mode) case 64: return V64HFmode; } break; - case SImode: + case E_SImode: switch (n) { case 2: return V2SImode; @@ -446,7 +446,7 @@ VnMODE (int n, machine_mode mode) case 64: return V64SImode; } break; - case SFmode: + case E_SFmode: switch (n) { case 2: return V2SFmode; @@ -457,7 +457,7 @@ VnMODE (int n, machine_mode mode) case 64: return V64SFmode; } break; - case DImode: + case E_DImode: switch (n) { case 2: return V2DImode; @@ -468,7 +468,7 @@ VnMODE (int n, machine_mode mode) case 64: return V64DImode; } break; - case DFmode: + case E_DFmode: switch (n) { case 2: return V2DFmode; diff --git a/gcc/config/h8300/combiner.md b/gcc/config/h8300/combiner.md index 067f266..fd5cf2f 100644 --- a/gcc/config/h8300/combiner.md +++ b/gcc/config/h8300/combiner.md @@ -1142,8 +1142,8 @@ ;; Storing a part of HImode to QImode. (define_insn_and_split "" - [(set (match_operand:QI 0 "general_operand_dst" "=rm<") - (subreg:QI (lshiftrt:HI (match_operand:HI 1 "register_operand" "r") + [(set (match_operand:QI 0 "general_operand_dst" "=rm,Za,Zb,Zc,Zd,Ze,Zf,Zg,Zh") + (subreg:QI (lshiftrt:HI (match_operand:HI 1 "register_operand" "r,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7") (const_int 8)) 1))] "" "#" @@ -1153,8 +1153,8 @@ (clobber (reg:CC CC_REG))])]) (define_insn "" - [(set (match_operand:QI 0 "general_operand_dst" "=rm<") - (subreg:QI (lshiftrt:HI (match_operand:HI 1 "register_operand" "r") + [(set (match_operand:QI 0 "general_operand_dst" "=rm,Za,Zb,Zc,Zd,Ze,Zf,Zh,Zg") + (subreg:QI (lshiftrt:HI (match_operand:HI 1 "register_operand" "r,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7") (const_int 8)) 1)) (clobber (reg:CC CC_REG))] "" @@ -1164,8 +1164,8 @@ ;; Storing a part of SImode to QImode. (define_insn_and_split "" - [(set (match_operand:QI 0 "general_operand_dst" "=rm<") - (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + [(set (match_operand:QI 0 "general_operand_dst" "=rm,Za,Zb,Zc,Zd,Ze,Zf,Zh,Zg") + (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7") (const_int 8)) 3))] "" "#" @@ -1175,8 +1175,8 @@ (clobber (reg:CC CC_REG))])]) (define_insn "" - [(set (match_operand:QI 0 "general_operand_dst" "=rm<") - (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + [(set (match_operand:QI 0 "general_operand_dst" "=rm,Za,Zb,Zc,Zd,Ze,Zf,Zh,Zg") + (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7") (const_int 8)) 3)) (clobber (reg:CC CC_REG))] "" @@ -1184,10 +1184,10 @@ [(set_attr "length" "8")]) (define_insn_and_split "" - [(set (match_operand:QI 0 "general_operand_dst" "=rm<") - (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + [(set (match_operand:QI 0 "general_operand_dst" "=rm,Za,Zb,Zc,Zd,Ze,Zf,Zh,Zg") + (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7") (const_int 16)) 3)) - (clobber (match_scratch:SI 2 "=&r"))] + (clobber (match_scratch:SI 2 "=&r,&r,&r,&r,&r,&r,&r,&r,&r"))] "" "#" "&& reload_completed" @@ -1197,20 +1197,20 @@ (clobber (reg:CC CC_REG))])]) (define_insn "" - [(set (match_operand:QI 0 "general_operand_dst" "=rm<") - (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + [(set (match_operand:QI 0 "general_operand_dst" "=rm,Za,Zb,Zc,Zd,Ze,Zf,Zh,Zg") + (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7") (const_int 16)) 3)) - (clobber (match_scratch:SI 2 "=&r")) + (clobber (match_scratch:SI 2 "=&r,&r,&r,&r,&r,&r,&r,&r,&r")) (clobber (reg:CC CC_REG))] "" "mov.w\\t%e1,%f2\;mov.b\\t%w2,%R0" [(set_attr "length" "10")]) (define_insn_and_split "" - [(set (match_operand:QI 0 "general_operand_dst" "=rm<") - (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + [(set (match_operand:QI 0 "general_operand_dst" "=rm,Za,Zb,Zc,Zd,Ze,Zf,Zh,Zg") + (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7") (const_int 24)) 3)) - (clobber (match_scratch:SI 2 "=&r"))] + (clobber (match_scratch:SI 2 "=&r,&r,&r,&r,&r,&r,&r,&r,&r"))] "" "#" "&& reload_completed" @@ -1220,10 +1220,10 @@ (clobber (reg:CC CC_REG))])]) (define_insn "" - [(set (match_operand:QI 0 "general_operand_dst" "=rm<") - (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r") + [(set (match_operand:QI 0 "general_operand_dst" "=rm,Za,Zb,Zc,Zd,Ze,Zf,Zh,Zg") + (subreg:QI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7") (const_int 24)) 3)) - (clobber (match_scratch:SI 2 "=&r")) + (clobber (match_scratch:SI 2 "=&r,&r,&r,&r,&r,&r,&r,&r,&r")) (clobber (reg:CC CC_REG))] "" "mov.w\\t%e1,%f2\;mov.b\\t%x2,%R0" diff --git a/gcc/config/h8300/constraints.md b/gcc/config/h8300/constraints.md index 6eaffc1..7e6681c 100644 --- a/gcc/config/h8300/constraints.md +++ b/gcc/config/h8300/constraints.md @@ -241,3 +241,11 @@ (define_register_constraint "Z7" "NOT_SP_REGS" "@internal") +(define_constraint "Za" "@internal" (match_test "pre_incdec_with_reg (op, 0)")) +(define_constraint "Zb" "@internal" (match_test "pre_incdec_with_reg (op, 1)")) +(define_constraint "Zc" "@internal" (match_test "pre_incdec_with_reg (op, 2)")) +(define_constraint "Zd" "@internal" (match_test "pre_incdec_with_reg (op, 3)")) +(define_constraint "Ze" "@internal" (match_test "pre_incdec_with_reg (op, 4)")) +(define_constraint "Zf" "@internal" (match_test "pre_incdec_with_reg (op, 5)")) +(define_constraint "Zg" "@internal" (match_test "pre_incdec_with_reg (op, 6)")) +(define_constraint "Zh" "@internal" (match_test "pre_incdec_with_reg (op, 7)")) diff --git a/gcc/config/h8300/extensions.md b/gcc/config/h8300/extensions.md index 74647c7..7149dc0 100644 --- a/gcc/config/h8300/extensions.md +++ b/gcc/config/h8300/extensions.md @@ -47,6 +47,24 @@ operands[2] = gen_rtx_REG (QImode, REGNO (operands[0])); }) +;; Similarly, but setting cczn. +(define_split + [(set (reg:CCZN CC_REG) + (compare:CCZN + (zero_extend:HI (match_operand:QI 1 "general_operand_src" "")) + (const_int 0))) + (set (match_operand:HI 0 "register_operand" "") + (zero_extend:HI (match_dup 1)))] + "!REG_P (operands[1]) && reload_completed" + [(parallel [(set (match_dup 2) (match_dup 1)) + (clobber (reg:CC CC_REG))]) + (parallel [(set (reg:CCZN CC_REG) + (compare:CCZN (zero_extend:HI (match_dup 2)) (const_int 0))) + (set (match_dup 0) (zero_extend:HI (match_dup 2)))])] + { + operands[2] = gen_rtx_REG (QImode, REGNO (operands[0])); + }) + (define_insn "*zero_extendqisi2" [(set (match_operand:SI 0 "register_operand" "=r,r") (zero_extend:SI (match_operand:QI 1 "general_operand_src" "0,g>")))] diff --git a/gcc/config/h8300/h8300-protos.h b/gcc/config/h8300/h8300-protos.h index e9d434c..8c98949 100644 --- a/gcc/config/h8300/h8300-protos.h +++ b/gcc/config/h8300/h8300-protos.h @@ -100,6 +100,7 @@ extern int h8300_initial_elimination_offset (int, int); extern int h8300_regs_ok_for_stm (int, rtx[]); extern int h8300_hard_regno_rename_ok (unsigned int, unsigned int); extern bool h8300_move_ok (rtx, rtx); +extern bool pre_incdec_with_reg (rtx, int); struct cpp_reader; extern void h8300_pr_interrupt (struct cpp_reader *); diff --git a/gcc/config/h8300/h8300.cc b/gcc/config/h8300/h8300.cc index be3e385..ce0702e 100644 --- a/gcc/config/h8300/h8300.cc +++ b/gcc/config/h8300/h8300.cc @@ -5531,6 +5531,32 @@ h8300_ok_for_sibcall_p (tree fndecl, tree) return 1; } + +/* Return TRUE if OP is a PRE_INC or PRE_DEC + instruction using REG, FALSE otherwise. */ + +bool +pre_incdec_with_reg (rtx op, int reg) +{ + /* OP must be a MEM. */ + if (GET_CODE (op) != MEM) + return false; + + /* The address must be a PRE_INC or PRE_DEC. */ + op = XEXP (op, 0); + if (GET_CODE (op) != PRE_DEC && GET_CODE (op) != PRE_INC) + return false; + + /* It must be a register that is being incremented + or decremented. */ + op = XEXP (op, 0); + if (!REG_P (op)) + return false; + + /* Finally, check that the register number matches. */ + return REGNO (op) == reg; +} + /* Initialize the GCC target structure. */ #undef TARGET_ATTRIBUTE_TABLE diff --git a/gcc/config/h8300/movepush.md b/gcc/config/h8300/movepush.md index e895de8..e536602 100644 --- a/gcc/config/h8300/movepush.md +++ b/gcc/config/h8300/movepush.md @@ -5,8 +5,8 @@ ;; movqi (define_insn_and_split "*movqi" - [(set (match_operand:QI 0 "general_operand_dst" "=r,r ,<,r,r,m") - (match_operand:QI 1 "general_operand_src" " I,r>,r,n,m,r"))] + [(set (match_operand:QI 0 "general_operand_dst" "=r,r ,Za,Zb,Zc,Zd,Ze,Zf,Zg,Zh,r,r,m") + (match_operand:QI 1 "general_operand_src" " I,r>,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7,n,m,r"))] "!TARGET_H8300SX && h8300_move_ok (operands[0], operands[1])" "#" "&& reload_completed" @@ -14,14 +14,21 @@ (clobber (reg:CC CC_REG))])]) (define_insn "*movqi<cczn>" - [(set (match_operand:QI 0 "general_operand_dst" "=r,r ,<,r,r,m") - (match_operand:QI 1 "general_operand_src" " I,r>,r,n,m,r")) + [(set (match_operand:QI 0 "general_operand_dst" "=r,r ,Za,Zb,Zc,Zd,Ze,Zf,Zg,Zh,r,r,m") + (match_operand:QI 1 "general_operand_src" " I,r>,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7,n,m,r")) (clobber (reg:CC CC_REG))] "!TARGET_H8300SX && h8300_move_ok (operands[0], operands[1])" "@ sub.b %X0,%X0 mov.b %R1,%X0 mov.b %X1,%R0 + mov.b %X1,%R0 + mov.b %X1,%R0 + mov.b %X1,%R0 + mov.b %X1,%R0 + mov.b %X1,%R0 + mov.b %X1,%R0 + mov.b %X1,%R0 mov.b %R1,%X0 mov.b %R1,%X0 mov.b %X1,%R0" @@ -88,8 +95,8 @@ ;; movhi (define_insn_and_split "*movhi" - [(set (match_operand:HI 0 "general_operand_dst" "=r,r,<,r,r,m") - (match_operand:HI 1 "general_operand_src" "I,r>,r,i,m,r"))] + [(set (match_operand:HI 0 "general_operand_dst" "=r,r,Za,Zb,Zc,Zd,Ze,Zf,Zg,Zh,r,r,m") + (match_operand:HI 1 "general_operand_src" "I,r>,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7,i,m,r"))] "!TARGET_H8300SX && h8300_move_ok (operands[0], operands[1])" "#" @@ -98,8 +105,8 @@ (clobber (reg:CC CC_REG))])]) (define_insn "*movhi<cczn>" - [(set (match_operand:HI 0 "general_operand_dst" "=r,r,<,r,r,m") - (match_operand:HI 1 "general_operand_src" "I,r>,r,i,m,r")) + [(set (match_operand:HI 0 "general_operand_dst" "=r,r,Za,Zb,Zc,Zd,Ze,Zf,Zg,Zh,r,r,m") + (match_operand:HI 1 "general_operand_src" "I,r>,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7,i,m,r")) (clobber (reg:CC CC_REG))] "!TARGET_H8300SX && h8300_move_ok (operands[0], operands[1])" @@ -109,6 +116,13 @@ mov.w %T1,%T0 mov.w %T1,%T0 mov.w %T1,%T0 + mov.w %T1,%T0 + mov.w %T1,%T0 + mov.w %T1,%T0 + mov.w %T1,%T0 + mov.w %T1,%T0 + mov.w %T1,%T0 + mov.w %T1,%T0 mov.w %T1,%T0" [(set (attr "length") (symbol_ref "compute_mov_length (operands)"))]) @@ -158,8 +172,8 @@ ;; movsi (define_insn_and_split "*movsi" - [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,<,r,r,m,*a,*a,r") - (match_operand:SI 1 "general_operand_src" "I,r,i,r,>,m,r,I,r,*a"))] + [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,Za,Zb,Zc,Zd,Ze,Zf,Zg,Zh,r,r,m,*a,*a,r") + (match_operand:SI 1 "general_operand_src" "I,r,i,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7,>,m,r,I,r,*a"))] "(TARGET_H8300S || TARGET_H8300H) && !TARGET_H8300SX && h8300_move_ok (operands[0], operands[1])" "#" @@ -168,8 +182,8 @@ (clobber (reg:CC CC_REG))])]) (define_insn "*movsi_clobber_flags" - [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,<,r,r,m,*a,*a, r") - (match_operand:SI 1 "general_operand_src" " I,r,i,r,>,m,r, I, r,*a")) + [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,Za,Zb,Zc,Zd,Ze,Zf,Zg,Zh,r,r,m,*a,*a, r") + (match_operand:SI 1 "general_operand_src" " I,r,i,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7,>,m,r, I, r,*a")) (clobber (reg:CC CC_REG))] "(TARGET_H8300S || TARGET_H8300H) && !TARGET_H8300SX && h8300_move_ok (operands[0], operands[1])" @@ -178,11 +192,11 @@ { case 0: return "sub.l %S0,%S0"; - case 7: + case 14: return "clrmac"; - case 8: + case 15: return "clrmac\;ldmac %1,macl"; - case 9: + case 16: return "stmac macl,%0"; default: if (GET_CODE (operands[1]) == CONST_INT) @@ -238,9 +252,9 @@ (define_insn "*movsi_cczn" [(set (reg:CCZN CC_REG) (compare:CCZN - (match_operand:SI 1 "general_operand_src" " I,r,i,r,>,m,r") + (match_operand:SI 1 "general_operand_src" " I,r,i,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7,>,m,r") (const_int 0))) - (set (match_operand:SI 0 "general_operand_dst" "=r,r,r,<,r,r,m") + (set (match_operand:SI 0 "general_operand_dst" "=r,r,r,Za,Zb,Zc,Zd,Ze,Zf,Zg,Zh,r,r,m") (match_dup 1))] "(TARGET_H8300S || TARGET_H8300H) && !TARGET_H8300SX && h8300_move_ok (operands[0], operands[1])" @@ -251,6 +265,13 @@ mov.l %S1,%S0 mov.l %S1,%S0 mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 mov.l %S1,%S0" [(set (attr "length") (symbol_ref "compute_mov_length (operands)"))]) @@ -316,8 +337,8 @@ (set_attr "length_table" "*,movl")]) (define_insn_and_split "*movsf" - [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,m,<,r") - (match_operand:SF 1 "general_operand_src" "G,r,im,r,r,>"))] + [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,m,Za,Zb,Zc,Zd,Ze,Zf,Zg,Zh,r") + (match_operand:SF 1 "general_operand_src" "G,r,im,r,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7,>"))] "!TARGET_H8300SX && (register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode))" @@ -327,8 +348,8 @@ (clobber (reg:CC CC_REG))])]) (define_insn "*movsf_clobber_flags" - [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,m,<,r") - (match_operand:SF 1 "general_operand_src" "G,r,im,r,r,>")) + [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,m,Za,Zb,Zc,Zd,Ze,Zf,Zg,Zh,r") + (match_operand:SF 1 "general_operand_src" "G,r,im,r,Z0,Z1,Z2,Z3,Z4,Z5,Z6,Z7,>")) (clobber (reg:CC CC_REG))] "!TARGET_H8300SX && (register_operand (operands[0], SFmode) @@ -339,6 +360,13 @@ mov.l %S1,%S0 mov.l %S1,%S0 mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 + mov.l %S1,%S0 mov.l %S1,%S0" [(set (attr "length") (symbol_ref "compute_mov_length (operands)"))]) diff --git a/gcc/config/i386/i386-builtin-types.def b/gcc/config/i386/i386-builtin-types.def index 2c27a4e..63a360b 100644 --- a/gcc/config/i386/i386-builtin-types.def +++ b/gcc/config/i386/i386-builtin-types.def @@ -69,7 +69,7 @@ DEF_PRIMITIVE_TYPE (UINT16, short_unsigned_type_node) DEF_PRIMITIVE_TYPE (INT64, long_long_integer_type_node) DEF_PRIMITIVE_TYPE (UINT64, long_long_unsigned_type_node) DEF_PRIMITIVE_TYPE (FLOAT16, ix86_float16_type_node) -DEF_PRIMITIVE_TYPE (BFLOAT16, bfloat16_type_node) +DEF_PRIMITIVE_TYPE (BFLOAT16, ix86_bf16_type_node) DEF_PRIMITIVE_TYPE (FLOAT, float_type_node) DEF_PRIMITIVE_TYPE (DOUBLE, double_type_node) DEF_PRIMITIVE_TYPE (FLOAT80, float80_type_node) diff --git a/gcc/config/i386/i386-builtins.cc b/gcc/config/i386/i386-builtins.cc index b5c651a..76668cc 100644 --- a/gcc/config/i386/i386-builtins.cc +++ b/gcc/config/i386/i386-builtins.cc @@ -126,7 +126,7 @@ BDESC_VERIFYS (IX86_BUILTIN_MAX, static GTY(()) tree ix86_builtin_type_tab[(int) IX86_BT_LAST_CPTR + 1]; tree ix86_float16_type_node = NULL_TREE; -tree ix86_bf16_ptr_type_node = NULL_TREE; +tree ix86_bf16_type_node = NULL_TREE; /* Retrieve an element from the above table, building some of the types lazily. */ @@ -1373,17 +1373,16 @@ ix86_register_bf16_builtin_type (void) { if (bfloat16_type_node == NULL_TREE) { - bfloat16_type_node = make_node (REAL_TYPE); - TYPE_PRECISION (bfloat16_type_node) = 16; - SET_TYPE_MODE (bfloat16_type_node, BFmode); - layout_type (bfloat16_type_node); + ix86_bf16_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (ix86_bf16_type_node) = 16; + SET_TYPE_MODE (ix86_bf16_type_node, BFmode); + layout_type (ix86_bf16_type_node); } + else + ix86_bf16_type_node = bfloat16_type_node; if (!maybe_get_identifier ("__bf16") && TARGET_SSE2) - { - lang_hooks.types.register_builtin_type (bfloat16_type_node, "__bf16"); - ix86_bf16_ptr_type_node = build_pointer_type (bfloat16_type_node); - } + lang_hooks.types.register_builtin_type (ix86_bf16_type_node, "__bf16"); } static void diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index a0f8a98..70fd82b 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -19604,6 +19604,22 @@ expand_vec_perm_1 (struct expand_vec_perm_d *d) return false; } +/* Canonicalize vec_perm index to make the first index + always comes from the first vector. */ +static void +ix86_vec_perm_index_canon (struct expand_vec_perm_d *d) +{ + unsigned nelt = d->nelt; + if (d->perm[0] < nelt) + return; + + for (unsigned i = 0; i != nelt; i++) + d->perm[i] = (d->perm[i] + nelt) % (2 * nelt); + + std::swap (d->op0, d->op1); + return; +} + /* A subroutine of ix86_expand_vec_perm_const_1. Try to implement D in terms of a pair of shufps+ shufps/pshufd instructions. */ static bool @@ -19621,6 +19637,7 @@ expand_vec_perm_shufps_shufps (struct expand_vec_perm_d *d) if (d->testing_p) return true; + ix86_vec_perm_index_canon (d); for (i = 0; i < 4; ++i) count += d->perm[i] > 3 ? 1 : 0; diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc index 99c4825..55d4565 100644 --- a/gcc/config/riscv/riscv-vector-builtins.cc +++ b/gcc/config/riscv/riscv-vector-builtins.cc @@ -155,19 +155,6 @@ lookup_vector_type_attribute (const_tree type) return lookup_attribute ("RVV type", TYPE_ATTRIBUTES (type)); } -/* If TYPE is a built-in type defined by the RVV ABI, return the mangled name, - otherwise return NULL. */ -const char * -mangle_builtin_type (const_tree type) -{ - if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) - type = TREE_TYPE (TYPE_NAME (type)); - if (tree attr = lookup_vector_type_attribute (type)) - if (tree id = TREE_VALUE (chain_index (0, TREE_VALUE (attr)))) - return IDENTIFIER_POINTER (id); - return NULL; -} - /* Return a representation of "const T *". */ static tree build_const_pointer (tree t) @@ -250,6 +237,19 @@ register_vector_type (vector_type_index type) builtin_types[type].vector_ptr = build_pointer_type (vectype); } +/* If TYPE is a built-in type defined by the RVV ABI, return the mangled name, + otherwise return NULL. */ +const char * +mangle_builtin_type (const_tree type) +{ + if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) + type = TREE_TYPE (TYPE_NAME (type)); + if (tree attr = lookup_vector_type_attribute (type)) + if (tree id = TREE_VALUE (chain_index (0, TREE_VALUE (attr)))) + return IDENTIFIER_POINTER (id); + return NULL; +} + /* Initialize all compiler built-ins related to RVV that should be defined at start-up. */ void diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv index 2f06043..15b9e7c 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -11,7 +11,7 @@ riscv-vector-builtins.o: $(srcdir)/config/riscv/riscv-vector-builtins.cc \ $(FUNCTION_H) fold-const.h gimplify.h explow.h stor-layout.h $(REGS_H) \ alias.h langhooks.h attribs.h stringpool.h \ $(srcdir)/config/riscv/riscv-vector-builtins.h \ - $(srcdir)/config/riscv/riscv-vector-builtins.def + $(srcdir)/config/riscv/riscv-vector-builtins.def $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/riscv/riscv-vector-builtins.cc diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index ae30947..f5c7539 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -13792,36 +13792,37 @@ s390_call_saved_register_used (tree call_expr) function_arg_info arg (TREE_TYPE (parameter), /*named=*/true); apply_pass_by_reference_rules (&cum_v, arg); - parm_rtx = s390_function_arg (cum, arg); + parm_rtx = s390_function_arg (cum, arg); - s390_function_arg_advance (cum, arg); + s390_function_arg_advance (cum, arg); - if (!parm_rtx) - continue; - - if (REG_P (parm_rtx)) - { - for (reg = 0; reg < REG_NREGS (parm_rtx); reg++) - if (!call_used_or_fixed_reg_p (reg + REGNO (parm_rtx))) - return true; - } + if (!parm_rtx) + continue; - if (GET_CODE (parm_rtx) == PARALLEL) - { - int i; + if (REG_P (parm_rtx)) + { + int size = s390_function_arg_size (arg.mode, arg.type); + int nregs = (size + UNITS_PER_LONG - 1) / UNITS_PER_LONG; - for (i = 0; i < XVECLEN (parm_rtx, 0); i++) - { - rtx r = XEXP (XVECEXP (parm_rtx, 0, i), 0); + for (reg = 0; reg < nregs; reg++) + if (!call_used_or_fixed_reg_p (reg + REGNO (parm_rtx))) + return true; + } + else if (GET_CODE (parm_rtx) == PARALLEL) + { + int i; - gcc_assert (REG_P (r)); + for (i = 0; i < XVECLEN (parm_rtx, 0); i++) + { + rtx r = XEXP (XVECEXP (parm_rtx, 0, i), 0); - for (reg = 0; reg < REG_NREGS (r); reg++) - if (!call_used_or_fixed_reg_p (reg + REGNO (r))) - return true; - } - } + gcc_assert (REG_P (r)); + gcc_assert (REG_NREGS (r) == 1); + if (!call_used_or_fixed_reg_p (REGNO (r))) + return true; + } + } } return false; } diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index 962927c..c89b15c 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -8797,9 +8797,10 @@ (neg:DI (match_operand:DI 1 "register_operand" ""))) (clobber (reg:CC CC_REGNUM))] "!TARGET_ZARCH - && (REGNO (operands[0]) == REGNO (operands[1]) - || s390_split_ok_p (operands[0], operands[1], DImode, 0)) - && reload_completed" + && reload_completed + && ((REG_P (operands[0]) && REG_P (operands[1]) + && REGNO (operands[0]) == REGNO (operands[1])) + || s390_split_ok_p (operands[0], operands[1], DImode, 0))" [(parallel [(set (match_dup 2) (neg:SI (match_dup 3))) (clobber (reg:CC CC_REGNUM))]) diff --git a/gcc/config/xtensa/constraints.md b/gcc/config/xtensa/constraints.md index e4c314b..cd200d6 100644 --- a/gcc/config/xtensa/constraints.md +++ b/gcc/config/xtensa/constraints.md @@ -121,7 +121,7 @@ (ior (and (match_code "const_int,const_double,const,symbol_ref,label_ref") (match_test "TARGET_AUTO_LITPOOLS")) (and (match_code "const_int") - (match_test "can_create_pseudo_p ()")))) + (match_test "! xtensa_split1_finished_p ()")))) ;; Memory constraints. Do not use define_memory_constraint here. Doing so ;; causes reload to force some constants into the constant pool, but since diff --git a/gcc/config/xtensa/predicates.md b/gcc/config/xtensa/predicates.md index 0590c0f..c11e863 100644 --- a/gcc/config/xtensa/predicates.md +++ b/gcc/config/xtensa/predicates.md @@ -149,7 +149,7 @@ (ior (and (match_code "const_int") (match_test "(GET_MODE_CLASS (mode) == MODE_INT && xtensa_simm12b (INTVAL (op))) - || can_create_pseudo_p ()")) + || ! xtensa_split1_finished_p ()")) (and (match_code "const_int,const_double,const,symbol_ref,label_ref") (match_test "(TARGET_CONST16 || TARGET_AUTO_LITPOOLS) && CONSTANT_P (op) diff --git a/gcc/config/xtensa/xtensa-protos.h b/gcc/config/xtensa/xtensa-protos.h index 459e2aa..bc75ad9 100644 --- a/gcc/config/xtensa/xtensa-protos.h +++ b/gcc/config/xtensa/xtensa-protos.h @@ -58,6 +58,8 @@ extern char *xtensa_emit_call (int, rtx *); extern char *xtensa_emit_sibcall (int, rtx *); extern bool xtensa_tls_referenced_p (rtx); extern enum rtx_code xtensa_shlrd_which_direction (rtx, rtx); +extern bool xtensa_split1_finished_p (void); +extern void xtensa_split_DI_reg_imm (rtx *); #ifdef TREE_CODE extern void init_cumulative_args (CUMULATIVE_ARGS *, int); diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index 828c764..950eb5a 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see #include "hw-doloop.h" #include "rtl-iter.h" #include "insn-attr.h" +#include "tree-pass.h" /* This file should be included last. */ #include "target-def.h" @@ -199,6 +200,7 @@ static void xtensa_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, tree function); +static bool xtensa_lra_p (void); static rtx xtensa_delegitimize_address (rtx); @@ -295,7 +297,7 @@ static rtx xtensa_delegitimize_address (rtx); #define TARGET_CANNOT_FORCE_CONST_MEM xtensa_cannot_force_const_mem #undef TARGET_LRA_P -#define TARGET_LRA_P hook_bool_void_false +#define TARGET_LRA_P xtensa_lra_p #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P xtensa_legitimate_address_p @@ -492,21 +494,30 @@ xtensa_mask_immediate (HOST_WIDE_INT v) int xt_true_regnum (rtx x) { - if (GET_CODE (x) == REG) + if (REG_P (x)) { - if (reg_renumber - && REGNO (x) >= FIRST_PSEUDO_REGISTER - && reg_renumber[REGNO (x)] >= 0) + if (! HARD_REGISTER_P (x) + && reg_renumber + && (lra_in_progress || reg_renumber[REGNO (x)] >= 0)) return reg_renumber[REGNO (x)]; return REGNO (x); } - if (GET_CODE (x) == SUBREG) + if (SUBREG_P (x)) { int base = xt_true_regnum (SUBREG_REG (x)); - if (base >= 0 && base < FIRST_PSEUDO_REGISTER) - return base + subreg_regno_offset (REGNO (SUBREG_REG (x)), - GET_MODE (SUBREG_REG (x)), - SUBREG_BYTE (x), GET_MODE (x)); + + if (base >= 0 + && HARD_REGISTER_NUM_P (base)) + { + struct subreg_info info; + + subreg_get_info (lra_in_progress + ? (unsigned) base : REGNO (SUBREG_REG (x)), + GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x), GET_MODE (x), &info); + if (info.representable_p) + return base + info.offset; + } } return -1; } @@ -2477,6 +2488,36 @@ xtensa_shlrd_which_direction (rtx op0, rtx op1) } +/* Return true after "split1" pass has been finished. */ + +bool +xtensa_split1_finished_p (void) +{ + return cfun && (cfun->curr_properties & PROP_rtl_split_insns); +} + + +/* Split a DImode pair of reg (operand[0]) and const_int (operand[1]) into + two SImode pairs, the low-part (operands[0] and [1]) and the high-part + (operands[2] and [3]). */ + +void +xtensa_split_DI_reg_imm (rtx *operands) +{ + rtx lowpart, highpart; + + if (WORDS_BIG_ENDIAN) + split_double (operands[1], &highpart, &lowpart); + else + split_double (operands[1], &lowpart, &highpart); + + operands[3] = highpart; + operands[2] = gen_highpart (SImode, operands[0]); + operands[1] = lowpart; + operands[0] = gen_lowpart (SImode, operands[0]); +} + + /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */ static bool @@ -5119,4 +5160,12 @@ xtensa_delegitimize_address (rtx op) return op; } +/* Implement TARGET_LRA_P. */ + +static bool +xtensa_lra_p (void) +{ + return TARGET_LRA; +} + #include "gt-xtensa.h" diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h index 16e3d55..2275fe6 100644 --- a/gcc/config/xtensa/xtensa.h +++ b/gcc/config/xtensa/xtensa.h @@ -229,7 +229,7 @@ along with GCC; see the file COPYING3. If not see } /* 1 for registers not available across function calls. - These must include the FIXED_REGISTERS and also any + These need not include the FIXED_REGISTERS but must any registers that can be used without being saved. The latter must include the registers where values are returned and the register where structure-value addresses are passed. @@ -242,10 +242,10 @@ along with GCC; see the file COPYING3. If not see Proper values are computed in TARGET_CONDITIONAL_REGISTER_USAGE. */ -#define CALL_USED_REGISTERS \ +#define CALL_REALLY_USED_REGISTERS \ { \ - 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 2, 2, 2, 2, \ - 1, 1, 1, \ + 1, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 2, 2, 2, 2, \ + 0, 0, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 1, \ } diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index 608110c..2e7f76a 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -940,14 +940,9 @@ because of offering further optimization opportunities. */ if (register_operand (operands[0], DImode)) { - rtx lowpart, highpart; - - if (TARGET_BIG_ENDIAN) - split_double (operands[1], &highpart, &lowpart); - else - split_double (operands[1], &lowpart, &highpart); - emit_insn (gen_movsi (gen_lowpart (SImode, operands[0]), lowpart)); - emit_insn (gen_movsi (gen_highpart (SImode, operands[0]), highpart)); + xtensa_split_DI_reg_imm (operands); + emit_move_insn (operands[0], operands[1]); + emit_move_insn (operands[2], operands[3]); DONE; } @@ -981,6 +976,19 @@ } }) +(define_split + [(set (match_operand:DI 0 "register_operand") + (match_operand:DI 1 "const_int_operand"))] + "!TARGET_CONST16 && !TARGET_AUTO_LITPOOLS + && ! xtensa_split1_finished_p ()" + [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 2) + (match_dup 3))] +{ + xtensa_split_DI_reg_imm (operands); +}) + ;; 32-bit Integer moves (define_expand "movsi" @@ -1019,6 +1027,18 @@ (define_split [(set (match_operand:SI 0 "register_operand") + (match_operand:SI 1 "const_int_operand"))] + "!TARGET_CONST16 && !TARGET_AUTO_LITPOOLS + && ! xtensa_split1_finished_p () + && ! xtensa_simm12b (INTVAL (operands[1]))" + [(set (match_dup 0) + (match_dup 1))] +{ + operands[1] = force_const_mem (SImode, operands[1]); +}) + +(define_split + [(set (match_operand:SI 0 "register_operand") (match_operand:SI 1 "constantpool_operand"))] "! optimize_debug && reload_completed" [(const_int 0)] diff --git a/gcc/config/xtensa/xtensa.opt b/gcc/config/xtensa/xtensa.opt index 08338e3..00d2db4 100644 --- a/gcc/config/xtensa/xtensa.opt +++ b/gcc/config/xtensa/xtensa.opt @@ -34,6 +34,10 @@ mextra-l32r-costs= Target RejectNegative Joined UInteger Var(xtensa_extra_l32r_costs) Init(0) Set extra memory access cost for L32R instruction, in clock-cycle units. +mlra +Target Mask(LRA) +Use LRA instead of reload (transitional). + mtarget-align Target Automatically align branch targets to reduce branch penalties. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a9983c1..1fe2b1f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2022-10-18 Patrick Palka <ppalka@redhat.com> + + PR c++/105045 + * module.cc (trees_out::tpl_parms_fini): Don't assume default + template arguments must be trailing. + (trees_in::tpl_parms_fini): Likewise. + +2022-10-18 Jakub Jelinek <jakub@redhat.com> + + PR c++/106654 + * cp-tree.h (build_assume_call): Declare. + * parser.cc (cp_parser_omp_assumption_clauses): Use build_assume_call. + * cp-gimplify.cc (build_assume_call): New function. + (process_stmt_assume_attribute): Use build_assume_call. + * pt.cc (tsubst_copy_and_build): Likewise. + +2022-10-17 Patrick Palka <ppalka@redhat.com> + + PR c++/101449 + * module.cc (trees_out::write_function_def): Stream the + parms and result of the constexpr_fundef entry. + (trees_in::read_function_def): Likewise. + 2022-10-14 Patrick Palka <ppalka@redhat.com> PR c++/106304 diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index 2608475..28c3398 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -3101,6 +3101,17 @@ process_stmt_hotness_attribute (tree std_attrs, location_t attrs_loc) return std_attrs; } +/* Build IFN_ASSUME internal call for assume condition ARG. */ + +tree +build_assume_call (location_t loc, tree arg) +{ + if (!processing_template_decl) + arg = fold_build_cleanup_point_expr (TREE_TYPE (arg), arg); + return build_call_expr_internal_loc (loc, IFN_ASSUME, void_type_node, + 1, arg); +} + /* If [[assume (cond)]] appears on this statement, handle it. */ tree @@ -3137,9 +3148,7 @@ process_stmt_assume_attribute (tree std_attrs, tree statement, arg = contextual_conv_bool (arg, tf_warning_or_error); if (error_operand_p (arg)) continue; - statement = build_call_expr_internal_loc (attrs_loc, IFN_ASSUME, - void_type_node, 1, arg); - finish_expr_stmt (statement); + finish_expr_stmt (build_assume_call (attrs_loc, arg)); } } return remove_attribute ("gnu", "assume", std_attrs); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e2607f0..60a2510 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8280,6 +8280,7 @@ extern tree predeclare_vla (tree); extern void clear_fold_cache (void); extern tree lookup_hotness_attribute (tree); extern tree process_stmt_hotness_attribute (tree, location_t); +extern tree build_assume_call (location_t, tree); extern tree process_stmt_assume_attribute (tree, tree, location_t); extern bool simple_empty_class_p (tree, tree, tree_code); extern tree fold_builtin_source_location (location_t); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 7ffeefa..2c2f9a9 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -10034,15 +10034,11 @@ trees_out::tpl_parms_fini (tree tmpl, unsigned tpl_levels) tree vec = TREE_VALUE (parms); tree_node (TREE_TYPE (vec)); - tree dflt = error_mark_node; for (unsigned ix = TREE_VEC_LENGTH (vec); ix--;) { tree parm = TREE_VEC_ELT (vec, ix); - if (dflt) - { - dflt = TREE_PURPOSE (parm); - tree_node (dflt); - } + tree dflt = TREE_PURPOSE (parm); + tree_node (dflt); if (streaming_p ()) { @@ -10072,19 +10068,15 @@ trees_in::tpl_parms_fini (tree tmpl, unsigned tpl_levels) tpl_levels--; parms = TREE_CHAIN (parms)) { tree vec = TREE_VALUE (parms); - tree dflt = error_mark_node; TREE_TYPE (vec) = tree_node (); for (unsigned ix = TREE_VEC_LENGTH (vec); ix--;) { tree parm = TREE_VEC_ELT (vec, ix); - if (dflt) - { - dflt = tree_node (); - if (get_overrun ()) - return false; - TREE_PURPOSE (parm) = dflt; - } + tree dflt = tree_node (); + if (get_overrun ()) + return false; + TREE_PURPOSE (parm) = dflt; tree decl = TREE_VALUE (parm); if (TREE_CODE (decl) == TEMPLATE_DECL) @@ -11553,34 +11545,13 @@ trees_out::write_function_def (tree decl) tree_node (DECL_FRIEND_CONTEXT (decl)); constexpr_fundef *cexpr = retrieve_constexpr_fundef (decl); - int tag = 0; - if (cexpr) - { - if (cexpr->result == error_mark_node) - /* We'll stream the RESULT_DECL naturally during the - serialization. We never need to fish it back again, so - that's ok. */ - tag = 0; - else - tag = insert (cexpr->result); - } + if (streaming_p ()) + u (cexpr != nullptr); + if (cexpr) { - i (tag); - if (tag) - dump (dumper::TREE) - && dump ("Constexpr:%d result %N", tag, cexpr->result); - } - if (tag) - { - unsigned ix = 0; - for (tree parm = cexpr->parms; parm; parm = DECL_CHAIN (parm), ix++) - { - tag = insert (parm); - if (streaming_p ()) - dump (dumper::TREE) - && dump ("Constexpr:%d parm:%u %N", tag, ix, parm); - } + chained_decls (cexpr->parms); + tree_node (cexpr->result); tree_node (cexpr->body); } @@ -11613,32 +11584,10 @@ trees_in::read_function_def (tree decl, tree maybe_template) tree maybe_dup = odr_duplicate (maybe_template, DECL_SAVED_TREE (decl)); bool installing = maybe_dup && !DECL_SAVED_TREE (decl); - if (int wtag = i ()) + if (u ()) { - int tag = 1; - cexpr.result = error_mark_node; - - cexpr.result = copy_decl (result); - tag = insert (cexpr.result); - - if (wtag != tag) - set_overrun (); - dump (dumper::TREE) - && dump ("Constexpr:%d result %N", tag, cexpr.result); - - cexpr.parms = NULL_TREE; - tree *chain = &cexpr.parms; - unsigned ix = 0; - for (tree parm = DECL_ARGUMENTS (maybe_dup ? maybe_dup : decl); - parm; parm = DECL_CHAIN (parm), ix++) - { - tree p = copy_decl (parm); - tag = insert (p); - dump (dumper::TREE) - && dump ("Constexpr:%d parm:%u %N", tag, ix, p); - *chain = p; - chain = &DECL_CHAIN (p); - } + cexpr.parms = chained_decls (); + cexpr.result = tree_node (); cexpr.body = tree_node (); cexpr.decl = decl; } diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 9ddfb02..a39c5f0 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -46012,11 +46012,7 @@ cp_parser_omp_assumption_clauses (cp_parser *parser, cp_token *pragma_tok, if (!type_dependent_expression_p (t)) t = contextual_conv_bool (t, tf_warning_or_error); if (is_assume && !error_operand_p (t)) - { - t = build_call_expr_internal_loc (eloc, IFN_ASSUME, - void_type_node, 1, t); - finish_expr_stmt (t); - } + finish_expr_stmt (build_assume_call (eloc, t)); if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index e4dca9d..5eddad9 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -21140,10 +21140,7 @@ tsubst_copy_and_build (tree t, ret = error_mark_node; break; } - ret = build_call_expr_internal_loc (EXPR_LOCATION (t), - IFN_ASSUME, - void_type_node, 1, - arg); + ret = build_assume_call (EXPR_LOCATION (t), arg); RETURN (ret); } break; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 71a4c1b..6cba2a8 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -7895,7 +7895,7 @@ This attribute works similar to the @code{section} attribute but adds additional checking. @table @asis -@item @bullet{}@tie{} Ordinary AVR cores with 32 general purpose registers: +@item @bullet{} Ordinary AVR cores with 32 general purpose registers: @code{progmem} affects the location of the data but not how this data is accessed. In order to read data located with the @code{progmem} attribute @@ -7920,7 +7920,7 @@ normally resides in the data memory (RAM). See also the @ref{AVR Named Address Spaces} section for an alternate way to locate and access data in flash memory. -@item @bullet{}@tie{} AVR cores with flash memory visible in the RAM address range: +@item @bullet{} AVR cores with flash memory visible in the RAM address range: On such devices, there is no need for attribute @code{progmem} or @ref{AVR Named Address Spaces,,@code{__flash}} qualifier at all. Just use standard C / C++. The compiler will generate @code{LD*} @@ -7933,7 +7933,7 @@ avoiding @code{progmem} and @code{__flash}. This applies to devices from families @code{avrtiny} and @code{avrxmega3}, see @ref{AVR Options} for an overview. -@item @bullet{}@tie{}Reduced AVR Tiny cores like ATtiny40: +@item @bullet{} Reduced AVR Tiny cores like ATtiny40: The compiler adds @code{0x4000} to the addresses of objects and declarations in @code{progmem} and locates the objects in flash memory, namely in section @code{.progmem.data}. diff --git a/gcc/expr.cc b/gcc/expr.cc index 4c892d6..efe387e 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -416,8 +416,15 @@ convert_mode_scalar (rtx to, rtx from, int unsignedp) rtx tof = NULL_RTX; if (fromi) { - rtx toi = gen_reg_rtx (toi_mode); - convert_mode_scalar (toi, fromi, 1); + rtx toi; + if (GET_MODE (fromi) == VOIDmode) + toi = simplify_unary_operation (ZERO_EXTEND, toi_mode, + fromi, fromi_mode); + else + { + toi = gen_reg_rtx (toi_mode); + convert_mode_scalar (toi, fromi, 1); + } toi = maybe_expand_shift (LSHIFT_EXPR, toi_mode, toi, GET_MODE_PRECISION (to_mode) diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 8b80242..80f12c6e 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,51 @@ +2022-10-17 Steve Kargl <kargl@gcc.gnu.org> + + PR fortran/104330 + * simplify.cc (gfc_simplify_image_index): Do not dereference NULL + pointer. + +2022-10-17 Harald Anlauf <anlauf@gmx.de> + Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/93483 + PR fortran/107216 + PR fortran/107219 + * arith.cc (reduce_unary): Handled expressions are EXP_CONSTANT and + EXPR_ARRAY. Do not attempt to reduce otherwise. + (reduce_binary_ac): Likewise. + (reduce_binary_ca): Likewise. + (reduce_binary_aa): Moved check for EXP_CONSTANT and EXPR_ARRAY + from here ... + (reduce_binary): ... to here. + (eval_intrinsic): Catch failed reductions. + * gfortran.h (GFC_INTRINSIC_OPS): New enum ARITH_NOT_REDUCED to keep + track of expressions that were not reduced by the arithmetic evaluation + code. + +2022-10-17 Harald Anlauf <anlauf@gmx.de> + + PR fortran/107272 + * arith.cc (gfc_arith_not): Operand must be of type BT_LOGICAL. + (gfc_arith_and): Likewise. + (gfc_arith_or): Likewise. + (gfc_arith_eqv): Likewise. + (gfc_arith_neqv): Likewise. + (gfc_arith_eq): Compare consistency of types of operands. + (gfc_arith_ne): Likewise. + (gfc_arith_gt): Likewise. + (gfc_arith_ge): Likewise. + (gfc_arith_lt): Likewise. + (gfc_arith_le): Likewise. + +2022-10-17 Tobias Burnus <tobias@codesourcery.com> + + PR fortran/107266 + * trans-expr.cc (gfc_conv_string_parameter): Use passed + type to honor character kind. + * trans-types.cc (gfc_sym_type): Honor character kind. + * trans-decl.cc (gfc_conv_cfi_to_gfc): Fix handling kind=4 + character strings. + 2022-10-14 Harald Anlauf <anlauf@gmx.de> PR fortran/100971 diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc index 14ba931..fc9224eb 100644 --- a/gcc/fortran/arith.cc +++ b/gcc/fortran/arith.cc @@ -422,6 +422,9 @@ gfc_arith_not (gfc_expr *op1, gfc_expr **resultp) { gfc_expr *result; + if (op1->ts.type != BT_LOGICAL) + return ARITH_INVALID_TYPE; + result = gfc_get_constant_expr (BT_LOGICAL, op1->ts.kind, &op1->where); result->value.logical = !op1->value.logical; *resultp = result; @@ -435,6 +438,9 @@ gfc_arith_and (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp) { gfc_expr *result; + if (op1->ts.type != BT_LOGICAL || op2->ts.type != BT_LOGICAL) + return ARITH_INVALID_TYPE; + result = gfc_get_constant_expr (BT_LOGICAL, gfc_kind_max (op1, op2), &op1->where); result->value.logical = op1->value.logical && op2->value.logical; @@ -449,6 +455,9 @@ gfc_arith_or (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp) { gfc_expr *result; + if (op1->ts.type != BT_LOGICAL || op2->ts.type != BT_LOGICAL) + return ARITH_INVALID_TYPE; + result = gfc_get_constant_expr (BT_LOGICAL, gfc_kind_max (op1, op2), &op1->where); result->value.logical = op1->value.logical || op2->value.logical; @@ -463,6 +472,9 @@ gfc_arith_eqv (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp) { gfc_expr *result; + if (op1->ts.type != BT_LOGICAL || op2->ts.type != BT_LOGICAL) + return ARITH_INVALID_TYPE; + result = gfc_get_constant_expr (BT_LOGICAL, gfc_kind_max (op1, op2), &op1->where); result->value.logical = op1->value.logical == op2->value.logical; @@ -477,6 +489,9 @@ gfc_arith_neqv (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp) { gfc_expr *result; + if (op1->ts.type != BT_LOGICAL || op2->ts.type != BT_LOGICAL) + return ARITH_INVALID_TYPE; + result = gfc_get_constant_expr (BT_LOGICAL, gfc_kind_max (op1, op2), &op1->where); result->value.logical = op1->value.logical != op2->value.logical; @@ -1187,6 +1202,9 @@ gfc_arith_eq (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp) { gfc_expr *result; + if (op1->ts.type != op2->ts.type) + return ARITH_INVALID_TYPE; + result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind, &op1->where); result->value.logical = (op1->ts.type == BT_COMPLEX) @@ -1203,6 +1221,9 @@ gfc_arith_ne (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp) { gfc_expr *result; + if (op1->ts.type != op2->ts.type) + return ARITH_INVALID_TYPE; + result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind, &op1->where); result->value.logical = (op1->ts.type == BT_COMPLEX) @@ -1219,6 +1240,9 @@ gfc_arith_gt (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp) { gfc_expr *result; + if (op1->ts.type != op2->ts.type) + return ARITH_INVALID_TYPE; + result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind, &op1->where); result->value.logical = (gfc_compare_expr (op1, op2, INTRINSIC_GT) > 0); @@ -1233,6 +1257,9 @@ gfc_arith_ge (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp) { gfc_expr *result; + if (op1->ts.type != op2->ts.type) + return ARITH_INVALID_TYPE; + result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind, &op1->where); result->value.logical = (gfc_compare_expr (op1, op2, INTRINSIC_GE) >= 0); @@ -1247,6 +1274,9 @@ gfc_arith_lt (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp) { gfc_expr *result; + if (op1->ts.type != op2->ts.type) + return ARITH_INVALID_TYPE; + result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind, &op1->where); result->value.logical = (gfc_compare_expr (op1, op2, INTRINSIC_LT) < 0); @@ -1261,6 +1291,9 @@ gfc_arith_le (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp) { gfc_expr *result; + if (op1->ts.type != op2->ts.type) + return ARITH_INVALID_TYPE; + result = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind, &op1->where); result->value.logical = (gfc_compare_expr (op1, op2, INTRINSIC_LE) <= 0); @@ -1282,14 +1315,14 @@ reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), gfc_expr *op, if (op->expr_type == EXPR_CONSTANT) return eval (op, result); + if (op->expr_type != EXPR_ARRAY) + return ARITH_NOT_REDUCED; + rc = ARITH_OK; head = gfc_constructor_copy (op->value.constructor); for (c = gfc_constructor_first (head); c; c = gfc_constructor_next (c)) { - if (c->expr->expr_type == EXPR_OP && c->expr->ts.type == BT_UNKNOWN) - rc = ARITH_INVALID_TYPE; - else - rc = reduce_unary (eval, c->expr, &r); + rc = reduce_unary (eval, c->expr, &r); if (rc != ARITH_OK) break; @@ -1330,8 +1363,8 @@ reduce_binary_ac (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), if (c->expr->expr_type == EXPR_CONSTANT) rc = eval (c->expr, op2, &r); - else if (c->expr->expr_type == EXPR_OP && c->expr->ts.type == BT_UNKNOWN) - rc = ARITH_INVALID_TYPE; + else if (c->expr->expr_type != EXPR_ARRAY) + rc = ARITH_NOT_REDUCED; else rc = reduce_binary_ac (eval, c->expr, op2, &r); @@ -1384,8 +1417,8 @@ reduce_binary_ca (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), if (c->expr->expr_type == EXPR_CONSTANT) rc = eval (op1, c->expr, &r); - else if (c->expr->expr_type == EXPR_OP && c->expr->ts.type == BT_UNKNOWN) - rc = ARITH_INVALID_TYPE; + else if (c->expr->expr_type != EXPR_ARRAY) + rc = ARITH_NOT_REDUCED; else rc = reduce_binary_ca (eval, op1, c->expr, &r); @@ -1445,11 +1478,7 @@ reduce_binary_aa (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), c && d; c = gfc_constructor_next (c), d = gfc_constructor_next (d)) { - if ((c->expr->expr_type == EXPR_OP && c->expr->ts.type == BT_UNKNOWN) - || (d->expr->expr_type == EXPR_OP && d->expr->ts.type == BT_UNKNOWN)) - rc = ARITH_INVALID_TYPE; - else - rc = reduce_binary (eval, c->expr, d->expr, &r); + rc = reduce_binary (eval, c->expr, d->expr, &r); if (rc != ARITH_OK) break; @@ -1490,6 +1519,9 @@ reduce_binary (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), if (op1->expr_type == EXPR_ARRAY && op2->expr_type == EXPR_CONSTANT) return reduce_binary_ac (eval, op1, op2, result); + if (op1->expr_type != EXPR_ARRAY || op2->expr_type != EXPR_ARRAY) + return ARITH_NOT_REDUCED; + return reduce_binary_aa (eval, op1, op2, result); } @@ -1668,7 +1700,7 @@ eval_intrinsic (gfc_intrinsic_op op, else rc = reduce_binary (eval.f3, op1, op2, &result); - if (rc == ARITH_INVALID_TYPE) + if (rc == ARITH_INVALID_TYPE || rc == ARITH_NOT_REDUCED) goto runtime; /* Something went wrong. */ diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 10bb098..6bd8800 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -222,11 +222,12 @@ enum gfc_intrinsic_op Assumptions are made about the numbering of the interface_op enums. */ #define GFC_INTRINSIC_OPS GFC_INTRINSIC_END -/* Arithmetic results. */ +/* Arithmetic results. ARITH_NOT_REDUCED is used to keep track of expressions + that were not reduced by the arithmetic evaluation code. */ enum arith { ARITH_OK = 1, ARITH_OVERFLOW, ARITH_UNDERFLOW, ARITH_NAN, ARITH_DIV0, ARITH_INCOMMENSURATE, ARITH_ASYMMETRIC, ARITH_PROHIBIT, - ARITH_WRONGCONCAT, ARITH_INVALID_TYPE + ARITH_WRONGCONCAT, ARITH_INVALID_TYPE, ARITH_NOT_REDUCED }; /* Statements. */ diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc index 6ac92cf..9c2fea8 100644 --- a/gcc/fortran/simplify.cc +++ b/gcc/fortran/simplify.cc @@ -8266,7 +8266,7 @@ gfc_simplify_image_index (gfc_expr *coarray, gfc_expr *sub) if (ref->type == REF_COMPONENT) as = ref->u.ar.as; - if (as->type == AS_DEFERRED) + if (!as || as->type == AS_DEFERRED) return NULL; /* "valid sequence of cosubscripts" are required; thus, return 0 unless diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc index 5d16d64..4b570c3 100644 --- a/gcc/fortran/trans-decl.cc +++ b/gcc/fortran/trans-decl.cc @@ -7378,13 +7378,13 @@ done: /* Set string length for len=:, only. */ if (sym->ts.type == BT_CHARACTER && !sym->ts.u.cl->length) { - tmp = sym->ts.u.cl->backend_decl; + tmp2 = gfc_get_cfi_desc_elem_len (cfi); + tmp = fold_convert (TREE_TYPE (tmp2), sym->ts.u.cl->backend_decl); if (sym->ts.kind != 1) tmp = fold_build2_loc (input_location, MULT_EXPR, - gfc_array_index_type, - sym->ts.u.cl->backend_decl, tmp); - tmp2 = gfc_get_cfi_desc_elem_len (cfi); - gfc_add_modify (&block, tmp2, fold_convert (TREE_TYPE (tmp2), tmp)); + TREE_TYPE (tmp2), tmp, + build_int_cst (TREE_TYPE (tmp2), sym->ts.kind)); + gfc_add_modify (&block, tmp2, tmp); } if (!sym->attr.dimension) diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 1551a2e..e7b9211 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -10374,15 +10374,15 @@ gfc_conv_string_parameter (gfc_se * se) || TREE_CODE (TREE_TYPE (se->expr)) == INTEGER_TYPE) && TYPE_STRING_FLAG (TREE_TYPE (se->expr))) { + type = TREE_TYPE (se->expr); if (TREE_CODE (se->expr) != INDIRECT_REF) - { - type = TREE_TYPE (se->expr); - se->expr = gfc_build_addr_expr (build_pointer_type (type), se->expr); - } + se->expr = gfc_build_addr_expr (build_pointer_type (type), se->expr); else { - type = gfc_get_character_type_len (gfc_default_character_kind, - se->string_length); + if (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + type = gfc_get_character_type_len_for_eltype (type, + se->string_length); type = build_pointer_type (type); se->expr = gfc_build_addr_expr (type, se->expr); } diff --git a/gcc/fortran/trans-types.cc b/gcc/fortran/trans-types.cc index c062a5b..fdce56d 100644 --- a/gcc/fortran/trans-types.cc +++ b/gcc/fortran/trans-types.cc @@ -2314,7 +2314,7 @@ gfc_sym_type (gfc_symbol * sym, bool is_bind_c) && sym->ns->proc_name->attr.is_bind_c) || (sym->ts.deferred && (!sym->ts.u.cl || !sym->ts.u.cl->backend_decl)))) - type = gfc_character1_type_node; + type = gfc_get_char_type (sym->ts.kind); else type = gfc_typenode_for_spec (&sym->ts, sym->attr.codimension); diff --git a/gcc/function.h b/gcc/function.h index 0986137..d7deaeb 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -438,6 +438,10 @@ struct GTY(()) function { /* Set if there are any OMP_TARGET regions in the function. */ unsigned int has_omp_target : 1; + + /* Set for artificial function created for [[assume (cond)]]. + These should be GIMPLE optimized, but not expanded to RTL. */ + unsigned int assume_function : 1; }; /* Add the decl D to the local_decls list of FUN. */ diff --git a/gcc/gimple-expr.cc b/gcc/gimple-expr.cc index c9c7285..4fbce93 100644 --- a/gcc/gimple-expr.cc +++ b/gcc/gimple-expr.cc @@ -912,7 +912,7 @@ mark_addressable_1 (tree x) /* Adaptor for mark_addressable_1 for use in hash_set traversal. */ -bool +static bool mark_addressable_2 (tree const &x, void * ATTRIBUTE_UNUSED = NULL) { mark_addressable_1 (x); diff --git a/gcc/gimple-low.cc b/gcc/gimple-low.cc index 4cd27dd..512aa9f 100644 --- a/gcc/gimple-low.cc +++ b/gcc/gimple-low.cc @@ -33,6 +33,14 @@ along with GCC; see the file COPYING3. If not see #include "predict.h" #include "gimple-predict.h" #include "gimple-fold.h" +#include "cgraph.h" +#include "tree-ssa.h" +#include "value-range.h" +#include "stringpool.h" +#include "tree-ssanames.h" +#include "tree-inline.h" +#include "gimple-walk.h" +#include "attribs.h" /* The differences between High GIMPLE and Low GIMPLE are the following: @@ -237,6 +245,389 @@ lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data) gsi_next (gsi); } +/* Create an artificial FUNCTION_DECL for assumption at LOC. */ + +static tree +create_assumption_fn (location_t loc) +{ + tree name = clone_function_name_numbered (current_function_decl, "_assume"); + /* Temporarily, until we determine all the arguments. */ + tree type = build_varargs_function_type_list (boolean_type_node, NULL_TREE); + tree decl = build_decl (loc, FUNCTION_DECL, name, type); + TREE_STATIC (decl) = 1; + TREE_USED (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + DECL_NAMELESS (decl) = 1; + TREE_PUBLIC (decl) = 0; + DECL_UNINLINABLE (decl) = 1; + DECL_EXTERNAL (decl) = 0; + DECL_CONTEXT (decl) = NULL_TREE; + DECL_INITIAL (decl) = make_node (BLOCK); + tree attributes = DECL_ATTRIBUTES (current_function_decl); + if (lookup_attribute ("noipa", attributes) == NULL) + { + attributes = tree_cons (get_identifier ("noipa"), NULL, attributes); + if (lookup_attribute ("noinline", attributes) == NULL) + attributes = tree_cons (get_identifier ("noinline"), NULL, attributes); + if (lookup_attribute ("noclone", attributes) == NULL) + attributes = tree_cons (get_identifier ("noclone"), NULL, attributes); + if (lookup_attribute ("no_icf", attributes) == NULL) + attributes = tree_cons (get_identifier ("no_icf"), NULL, attributes); + } + DECL_ATTRIBUTES (decl) = attributes; + BLOCK_SUPERCONTEXT (DECL_INITIAL (decl)) = decl; + DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl) + = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (current_function_decl); + DECL_FUNCTION_SPECIFIC_TARGET (decl) + = DECL_FUNCTION_SPECIFIC_TARGET (current_function_decl); + tree t = build_decl (DECL_SOURCE_LOCATION (decl), + RESULT_DECL, NULL_TREE, boolean_type_node); + DECL_ARTIFICIAL (t) = 1; + DECL_IGNORED_P (t) = 1; + DECL_CONTEXT (t) = decl; + DECL_RESULT (decl) = t; + push_struct_function (decl); + cfun->function_end_locus = loc; + init_tree_ssa (cfun); + return decl; +} + +struct lower_assumption_data +{ + copy_body_data id; + tree return_false_label; + tree guard_copy; + auto_vec<tree> decls; +}; + +/* Helper function for lower_assumptions. Find local vars and labels + in the assumption sequence and remove debug stmts. */ + +static tree +find_assumption_locals_r (gimple_stmt_iterator *gsi_p, bool *, + struct walk_stmt_info *wi) +{ + lower_assumption_data *data = (lower_assumption_data *) wi->info; + gimple *stmt = gsi_stmt (*gsi_p); + tree lhs = gimple_get_lhs (stmt); + if (lhs && TREE_CODE (lhs) == SSA_NAME) + { + gcc_assert (SSA_NAME_VAR (lhs) == NULL_TREE); + data->id.decl_map->put (lhs, NULL_TREE); + data->decls.safe_push (lhs); + } + switch (gimple_code (stmt)) + { + case GIMPLE_BIND: + for (tree var = gimple_bind_vars (as_a <gbind *> (stmt)); + var; var = DECL_CHAIN (var)) + if (VAR_P (var) + && !DECL_EXTERNAL (var) + && DECL_CONTEXT (var) == data->id.src_fn) + { + data->id.decl_map->put (var, var); + data->decls.safe_push (var); + } + break; + case GIMPLE_LABEL: + { + tree label = gimple_label_label (as_a <glabel *> (stmt)); + data->id.decl_map->put (label, label); + break; + } + case GIMPLE_RETURN: + /* If something in assumption tries to return from parent function, + if it would be reached in hypothetical evaluation, it would be UB, + so transform such returns into return false; */ + { + gimple *g = gimple_build_assign (data->guard_copy, boolean_false_node); + gsi_insert_before (gsi_p, g, GSI_SAME_STMT); + gimple_return_set_retval (as_a <greturn *> (stmt), data->guard_copy); + break; + } + case GIMPLE_DEBUG: + /* As assumptions won't be emitted, debug info stmts in them + are useless. */ + gsi_remove (gsi_p, true); + wi->removed_stmt = true; + break; + default: + break; + } + return NULL_TREE; +} + +/* Create a new PARM_DECL that is indentical in all respect to DECL except that + DECL can be either a VAR_DECL, a PARM_DECL or RESULT_DECL. The original + DECL must come from ID->src_fn and the copy will be part of ID->dst_fn. */ + +static tree +assumption_copy_decl (tree decl, copy_body_data *id) +{ + tree type = TREE_TYPE (decl); + + if (is_global_var (decl)) + return decl; + + gcc_assert (VAR_P (decl) + || TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == RESULT_DECL); + tree copy = build_decl (DECL_SOURCE_LOCATION (decl), + PARM_DECL, DECL_NAME (decl), type); + if (DECL_PT_UID_SET_P (decl)) + SET_DECL_PT_UID (copy, DECL_PT_UID (decl)); + TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl); + TREE_READONLY (copy) = TREE_READONLY (decl); + TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl); + DECL_NOT_GIMPLE_REG_P (copy) = DECL_NOT_GIMPLE_REG_P (decl); + DECL_BY_REFERENCE (copy) = DECL_BY_REFERENCE (decl); + DECL_ARG_TYPE (copy) = type; + ((lower_assumption_data *) id)->decls.safe_push (decl); + return copy_decl_for_dup_finish (id, decl, copy); +} + +/* Transform gotos out of the assumption into return false. */ + +static tree +adjust_assumption_stmt_r (gimple_stmt_iterator *gsi_p, bool *, + struct walk_stmt_info *wi) +{ + lower_assumption_data *data = (lower_assumption_data *) wi->info; + gimple *stmt = gsi_stmt (*gsi_p); + tree lab = NULL_TREE; + unsigned int idx = 0; + if (gimple_code (stmt) == GIMPLE_GOTO) + lab = gimple_goto_dest (stmt); + else if (gimple_code (stmt) == GIMPLE_COND) + { + repeat: + if (idx == 0) + lab = gimple_cond_true_label (as_a <gcond *> (stmt)); + else + lab = gimple_cond_false_label (as_a <gcond *> (stmt)); + } + else if (gimple_code (stmt) == GIMPLE_LABEL) + { + tree label = gimple_label_label (as_a <glabel *> (stmt)); + DECL_CONTEXT (label) = current_function_decl; + } + if (lab) + { + if (!data->id.decl_map->get (lab)) + { + if (!data->return_false_label) + data->return_false_label + = create_artificial_label (UNKNOWN_LOCATION); + if (gimple_code (stmt) == GIMPLE_GOTO) + gimple_goto_set_dest (as_a <ggoto *> (stmt), + data->return_false_label); + else if (idx == 0) + gimple_cond_set_true_label (as_a <gcond *> (stmt), + data->return_false_label); + else + gimple_cond_set_false_label (as_a <gcond *> (stmt), + data->return_false_label); + } + if (gimple_code (stmt) == GIMPLE_COND && idx == 0) + { + idx = 1; + goto repeat; + } + } + return NULL_TREE; +} + +/* Adjust trees in the assumption body. Called through walk_tree. */ + +static tree +adjust_assumption_stmt_op (tree *tp, int *, void *datap) +{ + struct walk_stmt_info *wi = (struct walk_stmt_info *) datap; + lower_assumption_data *data = (lower_assumption_data *) wi->info; + tree t = *tp; + tree *newt; + switch (TREE_CODE (t)) + { + case SSA_NAME: + newt = data->id.decl_map->get (t); + /* There shouldn't be SSA_NAMEs other than ones defined in the + assumption's body. */ + gcc_assert (newt); + *tp = *newt; + break; + case LABEL_DECL: + newt = data->id.decl_map->get (t); + if (newt) + *tp = *newt; + break; + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + *tp = remap_decl (t, &data->id); + break; + default: + break; + } + return NULL_TREE; +} + +/* Lower assumption. + The gimplifier transformed: + .ASSUME (cond); + into: + [[assume (guard)]] + { + guard = cond; + } + which we should transform into: + .ASSUME (&artificial_fn, args...); + where artificial_fn will look like: + bool artificial_fn (args...) + { + guard = cond; + return guard; + } + with any debug stmts in the block removed and jumps out of + the block or return stmts replaced with return false; */ + +static void +lower_assumption (gimple_stmt_iterator *gsi, struct lower_data *data) +{ + gimple *stmt = gsi_stmt (*gsi); + tree guard = gimple_assume_guard (stmt); + gimple *bind = gimple_assume_body (stmt); + location_t loc = gimple_location (stmt); + gcc_assert (gimple_code (bind) == GIMPLE_BIND); + + lower_assumption_data lad; + hash_map<tree, tree> decl_map; + memset (&lad.id, 0, sizeof (lad.id)); + lad.return_false_label = NULL_TREE; + lad.id.src_fn = current_function_decl; + lad.id.dst_fn = create_assumption_fn (loc); + lad.id.src_cfun = DECL_STRUCT_FUNCTION (lad.id.src_fn); + lad.id.decl_map = &decl_map; + lad.id.copy_decl = assumption_copy_decl; + lad.id.transform_call_graph_edges = CB_CGE_DUPLICATE; + lad.id.transform_parameter = true; + lad.id.do_not_unshare = true; + lad.id.do_not_fold = true; + cfun->curr_properties = lad.id.src_cfun->curr_properties; + lad.guard_copy = create_tmp_var (boolean_type_node); + decl_map.put (lad.guard_copy, lad.guard_copy); + decl_map.put (guard, lad.guard_copy); + cfun->assume_function = 1; + + /* Find variables, labels and SSA_NAMEs local to the assume GIMPLE_BIND. */ + gimple_stmt_iterator gsi2 = gsi_start (*gimple_assume_body_ptr (stmt)); + struct walk_stmt_info wi; + memset (&wi, 0, sizeof (wi)); + wi.info = (void *) &lad; + walk_gimple_stmt (&gsi2, find_assumption_locals_r, NULL, &wi); + unsigned int sz = lad.decls.length (); + for (unsigned i = 0; i < sz; ++i) + { + tree v = lad.decls[i]; + tree newv; + /* SSA_NAMEs defined in the assume condition should be replaced + by new SSA_NAMEs in the artificial function. */ + if (TREE_CODE (v) == SSA_NAME) + { + newv = make_ssa_name (remap_type (TREE_TYPE (v), &lad.id)); + decl_map.put (v, newv); + } + /* Local vars should have context and type adjusted to the + new artificial function. */ + else if (VAR_P (v)) + { + if (is_global_var (v) && !DECL_ASSEMBLER_NAME_SET_P (v)) + DECL_ASSEMBLER_NAME (v); + TREE_TYPE (v) = remap_type (TREE_TYPE (v), &lad.id); + DECL_CONTEXT (v) = current_function_decl; + } + } + /* References to other automatic vars should be replaced by + PARM_DECLs to the artificial function. */ + memset (&wi, 0, sizeof (wi)); + wi.info = (void *) &lad; + walk_gimple_stmt (&gsi2, adjust_assumption_stmt_r, + adjust_assumption_stmt_op, &wi); + + /* At the start prepend guard = false; */ + gimple_seq body = NULL; + gimple *g = gimple_build_assign (lad.guard_copy, boolean_false_node); + gimple_seq_add_stmt (&body, g); + gimple_seq_add_stmt (&body, bind); + /* At the end add return guard; */ + greturn *gr = gimple_build_return (lad.guard_copy); + gimple_seq_add_stmt (&body, gr); + /* If there were any jumps to labels outside of the condition, + replace them with a jump to + return_false_label: + guard = false; + return guard; */ + if (lad.return_false_label) + { + g = gimple_build_label (lad.return_false_label); + gimple_seq_add_stmt (&body, g); + g = gimple_build_assign (lad.guard_copy, boolean_false_node); + gimple_seq_add_stmt (&body, g); + gr = gimple_build_return (lad.guard_copy); + gimple_seq_add_stmt (&body, gr); + } + bind = gimple_build_bind (NULL_TREE, body, NULL_TREE); + body = NULL; + gimple_seq_add_stmt (&body, bind); + gimple_set_body (current_function_decl, body); + pop_cfun (); + + tree parms = NULL_TREE; + tree parmt = void_list_node; + auto_vec<tree, 8> vargs; + vargs.safe_grow (1 + (lad.decls.length () - sz), true); + /* First argument to IFN_ASSUME will be address of the + artificial function. */ + vargs[0] = build_fold_addr_expr (lad.id.dst_fn); + for (unsigned i = lad.decls.length (); i > sz; --i) + { + tree *v = decl_map.get (lad.decls[i - 1]); + gcc_assert (v && TREE_CODE (*v) == PARM_DECL); + DECL_CHAIN (*v) = parms; + parms = *v; + parmt = tree_cons (NULL_TREE, TREE_TYPE (*v), parmt); + /* Remaining arguments will be the variables/parameters + mentioned in the condition. */ + vargs[i - sz] = lad.decls[i - 1]; + /* If they have gimple types, we might need to regimplify + them to make the IFN_ASSUME call valid. */ + if (is_gimple_reg_type (TREE_TYPE (vargs[i - sz])) + && !is_gimple_val (vargs[i - sz])) + { + tree t = make_ssa_name (TREE_TYPE (vargs[i - sz])); + g = gimple_build_assign (t, vargs[i - sz]); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + vargs[i - sz] = t; + } + } + DECL_ARGUMENTS (lad.id.dst_fn) = parms; + TREE_TYPE (lad.id.dst_fn) = build_function_type (boolean_type_node, parmt); + + cgraph_node::add_new_function (lad.id.dst_fn, false); + + for (unsigned i = 0; i < sz; ++i) + { + tree v = lad.decls[i]; + if (TREE_CODE (v) == SSA_NAME) + release_ssa_name (v); + } + + data->cannot_fallthru = false; + /* Replace GIMPLE_ASSUME statement with IFN_ASSUME call. */ + gcall *call = gimple_build_call_internal_vec (IFN_ASSUME, vargs); + gimple_set_location (call, loc); + gsi_replace (gsi, call, true); +} /* Lower statement GSI. DATA is passed through the recursion. We try to track the fallthruness of statements and get rid of unreachable return @@ -403,6 +794,10 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) data->cannot_fallthru = false; return; + case GIMPLE_ASSUME: + lower_assumption (gsi, data); + return; + case GIMPLE_TRANSACTION: lower_sequence (gimple_transaction_body_ptr ( as_a <gtransaction *> (stmt)), diff --git a/gcc/gimple-pretty-print.cc b/gcc/gimple-pretty-print.cc index a87e2ae..7ec079f 100644 --- a/gcc/gimple-pretty-print.cc +++ b/gcc/gimple-pretty-print.cc @@ -2052,6 +2052,31 @@ dump_gimple_omp_return (pretty_printer *buffer, const gimple *gs, int spc, } } +/* Dump a GIMPLE_ASSUME tuple on the pretty_printer BUFFER. */ + +static void +dump_gimple_assume (pretty_printer *buffer, const gimple *gs, + int spc, dump_flags_t flags) +{ + if (flags & TDF_RAW) + dump_gimple_fmt (buffer, spc, flags, + "%G [GUARD=%T] <%+BODY <%S> >", + gs, gimple_assume_guard (gs), + gimple_assume_body (gs)); + else + { + pp_string (buffer, "[[assume ("); + dump_generic_node (buffer, gimple_assume_guard (gs), spc, flags, false); + pp_string (buffer, ")]]"); + newline_and_indent (buffer, spc + 2); + pp_left_brace (buffer); + pp_newline (buffer); + dump_gimple_seq (buffer, gimple_assume_body (gs), spc + 4, flags); + newline_and_indent (buffer, spc + 2); + pp_right_brace (buffer); + } +} + /* Dump a GIMPLE_TRANSACTION tuple on the pretty_printer BUFFER. */ static void @@ -2841,6 +2866,10 @@ pp_gimple_stmt_1 (pretty_printer *buffer, const gimple *gs, int spc, pp_string (buffer, " predictor."); break; + case GIMPLE_ASSUME: + dump_gimple_assume (buffer, gs, spc, flags); + break; + case GIMPLE_TRANSACTION: dump_gimple_transaction (buffer, as_a <const gtransaction *> (gs), spc, flags); diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index c381ef9..f919237 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -578,7 +578,8 @@ fold_using_range::range_of_range_op (vrange &r, fputc ('\n', dump_file); } // Fold range, and register any dependency if available. - if (!handler.fold_range (r, type, range1, range2, rel)) + if (!handler.fold_range (r, type, range1, range2, + relation_trio::op1_op2 (rel))) r.set_varying (type); if (irange::supports_p (type)) relation_fold_and_or (as_a <irange> (r), s, src); @@ -597,7 +598,7 @@ fold_using_range::range_of_range_op (vrange &r, } if (gimple_range_ssa_p (op2)) { - rel= handler.lhs_op2_relation (r, range1, range2, rel); + rel = handler.lhs_op2_relation (r, range1, range2, rel); if (rel != VREL_VARYING) src.register_relation (s, rel, lhs, op2); } diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index 5ff067c..610a529 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -991,7 +991,7 @@ gori_compute::refine_using_relation (tree op1, vrange &op1_range, Value_Range new_result (type); if (!op_handler.op1_range (new_result, type, op1_def_p ? op1_range : op2_range, - other_op, k)) + other_op, relation_trio::lhs_op2 (k))) return false; if (op1_def_p) { @@ -1023,7 +1023,7 @@ gori_compute::refine_using_relation (tree op1, vrange &op1_range, Value_Range new_result (type); if (!op_handler.op2_range (new_result, type, op1_def_p ? op1_range : op2_range, - other_op, k)) + other_op, relation_trio::lhs_op1 (k))) return false; if (op1_def_p) { @@ -1074,6 +1074,7 @@ gori_compute::compute_operand1_range (vrange &r, { src.get_operand (op2_range, op2); relation_kind k = VREL_VARYING; + relation_kind op_op = (op1 == op2) ? VREL_EQ : VREL_VARYING; if (rel) { if (lhs_name == rel->op1 () && op1 == rel->op2 ()) @@ -1081,13 +1082,18 @@ gori_compute::compute_operand1_range (vrange &r, else if (lhs_name == rel->op2 () && op1 == rel->op1 ()) k = relation_swap (rel->kind ()); else if (op1 == rel->op1 () && op2 == rel->op2 ()) - refine_using_relation (op1, op1_range, op2, op2_range, src, - rel->kind ()); + { + op_op = rel->kind (); + refine_using_relation (op1, op1_range, op2, op2_range, src, op_op); + } else if (op1 == rel->op2 () && op2 == rel->op1 ()) - refine_using_relation (op1, op1_range, op2, op2_range, src, - relation_swap (rel->kind ())); + { + op_op = relation_swap (rel->kind ()); + refine_using_relation (op1, op1_range, op2, op2_range, src, op_op); + } } - if (!handler.calc_op1 (tmp, lhs, op2_range, k)) + if (!handler.calc_op1 (tmp, lhs, op2_range, relation_trio (VREL_VARYING, + k, op_op))) return false; } else @@ -1095,7 +1101,7 @@ gori_compute::compute_operand1_range (vrange &r, // We pass op1_range to the unary operation. Nomally it's a // hidden range_for_type parameter, but sometimes having the // actual range can result in better information. - if (!handler.calc_op1 (tmp, lhs, op1_range, VREL_VARYING)) + if (!handler.calc_op1 (tmp, lhs, op1_range, TRIO_VARYING)) return false; } @@ -1167,23 +1173,28 @@ gori_compute::compute_operand2_range (vrange &r, src.get_operand (op1_range, op1); src.get_operand (op2_range, op2); relation_kind k = VREL_VARYING; + relation_kind op_op = (op1 == op2) ? VREL_EQ : VREL_VARYING; if (rel) { if (lhs_name == rel->op1 () && op2 == rel->op2 ()) - k = rel->kind (); + k = rel->kind (); else if (lhs_name == rel->op2 () && op2 == rel->op1 ()) - k = relation_swap (rel->kind ()); + k = relation_swap (rel->kind ()); else if (op1 == rel->op1 () && op2 == rel->op2 ()) - refine_using_relation (op1, op1_range, op2, op2_range, src, - rel->kind ()); + { + op_op = rel->kind (); + refine_using_relation (op1, op1_range, op2, op2_range, src, op_op); + } else if (op1 == rel->op2 () && op2 == rel->op1 ()) - refine_using_relation (op1, op1_range, op2, op2_range, src, - relation_swap (rel->kind ())); + { + op_op = relation_swap (rel->kind ()); + refine_using_relation (op1, op1_range, op2, op2_range, src, op_op); + } } - // Intersect with range for op2 based on lhs and op1. - if (!handler.calc_op2 (tmp, lhs, op1_range, k)) + if (!handler.calc_op2 (tmp, lhs, op1_range, relation_trio (k, VREL_VARYING, + op_op))) return false; unsigned idx; diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc index 2662319..7764166 100644 --- a/gcc/gimple-range-op.cc +++ b/gcc/gimple-range-op.cc @@ -202,7 +202,7 @@ gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range) bool gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range, - const vrange &op2_range, relation_kind k) + const vrange &op2_range, relation_trio k) { // Give up on empty ranges. if (lhs_range.undefined_p ()) @@ -237,7 +237,7 @@ gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range, bool gimple_range_op_handler::calc_op2 (vrange &r, const vrange &lhs_range, - const vrange &op1_range, relation_kind k) + const vrange &op1_range, relation_trio k) { // Give up on empty ranges. if (lhs_range.undefined_p ()) @@ -263,7 +263,7 @@ class cfn_constant_float_p : public range_operator_float public: using range_operator_float::fold_range; virtual bool fold_range (irange &r, tree type, const frange &lh, - const irange &, relation_kind) const + const irange &, relation_trio) const { if (lh.singleton_p ()) { @@ -285,7 +285,7 @@ class cfn_constant_p : public range_operator public: using range_operator::fold_range; virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &, relation_kind) const + const irange &, relation_trio) const { if (lh.singleton_p ()) { @@ -308,7 +308,7 @@ public: using range_operator_float::fold_range; using range_operator_float::op1_range; virtual bool fold_range (irange &r, tree type, const frange &lh, - const irange &, relation_kind) const override + const irange &, relation_trio) const override { bool signbit; if (lh.signbit_p (signbit)) @@ -322,7 +322,7 @@ public: return false; } virtual bool op1_range (frange &r, tree type, const irange &lhs, - const frange &, relation_kind) const override + const frange &, relation_trio) const override { if (lhs.zero_p ()) { @@ -348,7 +348,7 @@ class cfn_copysign : public range_operator_float public: using range_operator_float::fold_range; virtual bool fold_range (frange &r, tree type, const frange &lh, - const frange &rh, relation_kind) const override + const frange &rh, relation_trio) const override { frange neg; range_op_handler abs_op (ABS_EXPR, type); @@ -381,7 +381,7 @@ public: using range_operator::fold_range; cfn_toupper_tolower (bool toupper) { m_toupper = toupper; } virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &, relation_kind) const; + const irange &, relation_trio) const; private: bool get_letter_range (tree type, irange &lowers, irange &uppers) const; bool m_toupper; @@ -412,7 +412,7 @@ cfn_toupper_tolower::get_letter_range (tree type, irange &lowers, bool cfn_toupper_tolower::fold_range (irange &r, tree type, const irange &lh, - const irange &, relation_kind) const + const irange &, relation_trio) const { int_range<3> lowers; int_range<3> uppers; @@ -445,7 +445,7 @@ class cfn_ffs : public range_operator public: using range_operator::fold_range; virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &, relation_kind) const + const irange &, relation_trio) const { if (lh.undefined_p ()) return false; @@ -472,7 +472,7 @@ class cfn_popcount : public cfn_ffs public: using range_operator::fold_range; virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh, relation_kind rel) const + const irange &rh, relation_trio rel) const { if (lh.undefined_p ()) return false; @@ -502,14 +502,14 @@ public: cfn_clz (bool internal) { m_gimple_call_internal_p = internal; } using range_operator::fold_range; virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &, relation_kind) const; + const irange &, relation_trio) const; private: bool m_gimple_call_internal_p; } op_cfn_clz (false), op_cfn_clz_internal (true); bool cfn_clz::fold_range (irange &r, tree type, const irange &lh, - const irange &, relation_kind) const + const irange &, relation_trio) const { // __builtin_c[lt]z* return [0, prec-1], except when the // argument is 0, but that is undefined behavior. @@ -577,14 +577,14 @@ public: cfn_ctz (bool internal) { m_gimple_call_internal_p = internal; } using range_operator::fold_range; virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &, relation_kind) const; + const irange &, relation_trio) const; private: bool m_gimple_call_internal_p; } op_cfn_ctz (false), op_cfn_ctz_internal (true); bool cfn_ctz::fold_range (irange &r, tree type, const irange &lh, - const irange &, relation_kind) const + const irange &, relation_trio) const { if (lh.undefined_p ()) return false; @@ -647,7 +647,7 @@ class cfn_clrsb : public range_operator public: using range_operator::fold_range; virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &, relation_kind) const + const irange &, relation_trio) const { if (lh.undefined_p ()) return false; @@ -665,7 +665,7 @@ public: cfn_ubsan (enum tree_code code) { m_code = code; } using range_operator::fold_range; virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh, relation_kind rel) const + const irange &rh, relation_trio rel) const { range_op_handler handler (m_code, type); gcc_checking_assert (handler); @@ -699,7 +699,7 @@ class cfn_strlen : public range_operator public: using range_operator::fold_range; virtual bool fold_range (irange &r, tree type, const irange &, - const irange &, relation_kind) const + const irange &, relation_trio) const { tree max = vrp_val_max (ptrdiff_type_node); wide_int wmax @@ -724,7 +724,7 @@ public: cfn_goacc_dim (bool is_pos) { m_is_pos = is_pos; } using range_operator::fold_range; virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &, relation_kind) const + const irange &, relation_trio) const { tree axis_tree; if (!lh.singleton_p (&axis_tree)) @@ -751,7 +751,7 @@ class cfn_parity : public range_operator public: using range_operator::fold_range; virtual bool fold_range (irange &r, tree type, const irange &, - const irange &, relation_kind) const + const irange &, relation_trio) const { r.set (build_zero_cst (type), build_one_cst (type)); return true; diff --git a/gcc/gimple-range-op.h b/gcc/gimple-range-op.h index 3a555f2..be1305c 100644 --- a/gcc/gimple-range-op.h +++ b/gcc/gimple-range-op.h @@ -36,9 +36,9 @@ public: tree operand2 () const { gcc_checking_assert (m_valid); return m_op2; } bool calc_op1 (vrange &r, const vrange &lhs_range); bool calc_op1 (vrange &r, const vrange &lhs_range, const vrange &op2_range, - relation_kind k = VREL_VARYING); + relation_trio = TRIO_VARYING); bool calc_op2 (vrange &r, const vrange &lhs_range, const vrange &op1_range, - relation_kind k = VREL_VARYING); + relation_trio = TRIO_VARYING); private: void maybe_builtin_call (); gimple *m_stmt; diff --git a/gcc/gimple-ssa-isolate-paths.cc b/gcc/gimple-ssa-isolate-paths.cc index 87ecd19..e4a4e08 100644 --- a/gcc/gimple-ssa-isolate-paths.cc +++ b/gcc/gimple-ssa-isolate-paths.cc @@ -647,7 +647,8 @@ handle_return_addr_local_phi_arg (basic_block bb, basic_block duplicate, if (!maybe && (flag_isolate_erroneous_paths_dereference || flag_isolate_erroneous_paths_attribute) - && gimple_bb (use_stmt) == bb) + && gimple_bb (use_stmt) == bb + && (duplicate || can_duplicate_block_p (bb))) { duplicate = isolate_path (bb, duplicate, e, use_stmt, lhs, true); @@ -765,7 +766,8 @@ find_implicit_erroneous_behavior (void) ? gimple_location (use_stmt) : phi_arg_loc; - if (stmt_uses_name_in_undefined_way (use_stmt, lhs, loc)) + if (stmt_uses_name_in_undefined_way (use_stmt, lhs, loc) + && (duplicate || can_duplicate_block_p (bb))) { duplicate = isolate_path (bb, duplicate, e, use_stmt, lhs, false); diff --git a/gcc/gimple-walk.cc b/gcc/gimple-walk.cc index c40f280..cad36f7 100644 --- a/gcc/gimple-walk.cc +++ b/gcc/gimple-walk.cc @@ -485,6 +485,12 @@ walk_gimple_op (gimple *stmt, walk_tree_fn callback_op, } break; + case GIMPLE_ASSUME: + ret = walk_tree (gimple_assume_guard_ptr (stmt), callback_op, wi, pset); + if (ret) + return ret; + break; + case GIMPLE_TRANSACTION: { gtransaction *txn = as_a <gtransaction *> (stmt); @@ -707,6 +713,13 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt, return wi->callback_result; break; + case GIMPLE_ASSUME: + ret = walk_gimple_seq_mod (gimple_assume_body_ptr (stmt), + callback_stmt, callback_op, wi); + if (ret) + return wi->callback_result; + break; + case GIMPLE_TRANSACTION: ret = walk_gimple_seq_mod (gimple_transaction_body_ptr ( as_a <gtransaction *> (stmt)), diff --git a/gcc/gimple.cc b/gcc/gimple.cc index 4d45311..6c23dd7 100644 --- a/gcc/gimple.cc +++ b/gcc/gimple.cc @@ -1290,6 +1290,18 @@ gimple_build_omp_atomic_store (tree val, enum omp_memory_order mo) return p; } +/* Build a GIMPLE_ASSUME statement. */ + +gimple * +gimple_build_assume (tree guard, gimple_seq body) +{ + gimple_statement_assume *p + = as_a <gimple_statement_assume *> (gimple_alloc (GIMPLE_ASSUME, 0)); + gimple_assume_set_guard (p, guard); + *gimple_assume_body_ptr (p) = body; + return p; +} + /* Build a GIMPLE_TRANSACTION statement. */ gtransaction * @@ -2135,6 +2147,13 @@ gimple_copy (gimple *stmt) gimple_omp_masked_set_clauses (copy, t); goto copy_omp_body; + case GIMPLE_ASSUME: + new_seq = gimple_seq_copy (gimple_assume_body (stmt)); + *gimple_assume_body_ptr (copy) = new_seq; + gimple_assume_set_guard (copy, + unshare_expr (gimple_assume_guard (stmt))); + break; + case GIMPLE_TRANSACTION: new_seq = gimple_seq_copy (gimple_transaction_body ( as_a <gtransaction *> (stmt))); diff --git a/gcc/gimple.def b/gcc/gimple.def index 296c73c..7c617cd 100644 --- a/gcc/gimple.def +++ b/gcc/gimple.def @@ -406,3 +406,8 @@ DEFGSCODE(GIMPLE_PREDICT, "gimple_predict", GSS_BASE) This tuple should not exist outside of the gimplifier proper. */ DEFGSCODE(GIMPLE_WITH_CLEANUP_EXPR, "gimple_with_cleanup_expr", GSS_WCE) + +/* GIMPLE_ASSUME <GUARD, BODY> represents [[assume(cond)]]. + BODY is the GIMPLE_BIND with the condition which sets GUARD to true + (otherwise UB). */ +DEFGSCODE(GIMPLE_ASSUME, "gimple_assume", GSS_ASSUME) diff --git a/gcc/gimple.h b/gcc/gimple.h index 77ac149..adbeb06 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -825,6 +825,20 @@ struct GTY((tag("GSS_OMP_ATOMIC_STORE_LAYOUT"))) stmt->code == GIMPLE_OMP_RETURN. */ }; +/* Assumptions. */ + +struct GTY((tag("GSS_ASSUME"))) + gimple_statement_assume : public gimple +{ + /* [ WORD 1-6 ] : base class */ + + /* [ WORD 7 ] */ + tree guard; + + /* [ WORD 8 ] */ + gimple_seq body; +}; + /* GIMPLE_TRANSACTION. */ /* Bits to be stored in the GIMPLE_TRANSACTION subcode. */ @@ -1271,6 +1285,14 @@ is_a_helper <const gswitch *>::test (const gimple *gs) template <> template <> inline bool +is_a_helper <gimple_statement_assume *>::test (gimple *gs) +{ + return gs->code == GIMPLE_ASSUME; +} + +template <> +template <> +inline bool is_a_helper <gtransaction *>::test (gimple *gs) { return gs->code == GIMPLE_TRANSACTION; @@ -1497,6 +1519,14 @@ is_a_helper <const greturn *>::test (const gimple *gs) template <> template <> inline bool +is_a_helper <const gimple_statement_assume *>::test (const gimple *gs) +{ + return gs->code == GIMPLE_ASSUME; +} + +template <> +template <> +inline bool is_a_helper <const gtransaction *>::test (const gimple *gs) { return gs->code == GIMPLE_TRANSACTION; @@ -1577,6 +1607,7 @@ gomp_teams *gimple_build_omp_teams (gimple_seq, tree); gomp_atomic_load *gimple_build_omp_atomic_load (tree, tree, enum omp_memory_order); gomp_atomic_store *gimple_build_omp_atomic_store (tree, enum omp_memory_order); +gimple *gimple_build_assume (tree, gimple_seq); gtransaction *gimple_build_transaction (gimple_seq); extern void gimple_seq_add_stmt (gimple_seq *, gimple *); extern void gimple_seq_add_stmt_without_update (gimple_seq *, gimple *); @@ -1835,6 +1866,7 @@ gimple_has_substatements (gimple *g) { switch (gimple_code (g)) { + case GIMPLE_ASSUME: case GIMPLE_BIND: case GIMPLE_CATCH: case GIMPLE_EH_FILTER: @@ -6520,6 +6552,52 @@ gimple_omp_continue_set_control_use (gomp_continue *cont_stmt, tree use) cont_stmt->control_use = use; } +/* Return the guard associated with the GIMPLE_ASSUME statement GS. */ + +static inline tree +gimple_assume_guard (const gimple *gs) +{ + const gimple_statement_assume *assume_stmt + = as_a <const gimple_statement_assume *> (gs); + return assume_stmt->guard; +} + +/* Set the guard associated with the GIMPLE_ASSUME statement GS. */ + +static inline void +gimple_assume_set_guard (gimple *gs, tree guard) +{ + gimple_statement_assume *assume_stmt = as_a <gimple_statement_assume *> (gs); + assume_stmt->guard = guard; +} + +static inline tree * +gimple_assume_guard_ptr (gimple *gs) +{ + gimple_statement_assume *assume_stmt = as_a <gimple_statement_assume *> (gs); + return &assume_stmt->guard; +} + +/* Return the address of the GIMPLE sequence contained in the GIMPLE_ASSUME + statement GS. */ + +static inline gimple_seq * +gimple_assume_body_ptr (gimple *gs) +{ + gimple_statement_assume *assume_stmt = as_a <gimple_statement_assume *> (gs); + return &assume_stmt->body; +} + +/* Return the GIMPLE sequence contained in the GIMPLE_ASSUME statement GS. */ + +static inline gimple_seq +gimple_assume_body (const gimple *gs) +{ + const gimple_statement_assume *assume_stmt + = as_a <const gimple_statement_assume *> (gs); + return assume_stmt->body; +} + /* Return a pointer to the body for the GIMPLE_TRANSACTION statement TRANSACTION_STMT. */ diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index d4209ea..42a996d 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -3569,7 +3569,33 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) fndecl, 0)); return GS_OK; } - /* FIXME: Otherwise expand it specially. */ + /* If not optimizing, ignore the assumptions. */ + if (!optimize) + { + *expr_p = NULL_TREE; + return GS_ALL_DONE; + } + /* Temporarily, until gimple lowering, transform + .ASSUME (cond); + into: + [[assume (guard)]] + { + guard = cond; + } + such that gimple lowering can outline the condition into + a separate function easily. */ + tree guard = create_tmp_var (boolean_type_node); + *expr_p = build2 (MODIFY_EXPR, void_type_node, guard, + CALL_EXPR_ARG (*expr_p, 0)); + *expr_p = build3 (BIND_EXPR, void_type_node, NULL, *expr_p, NULL); + push_gimplify_context (); + gimple_seq body = NULL; + gimple *g = gimplify_and_return_first (*expr_p, &body); + pop_gimplify_context (g); + g = gimple_build_assume (guard, body); + gimple_set_location (g, loc); + gimplify_seq_add_stmt (pre_p, g); + *expr_p = NULL_TREE; return GS_ALL_DONE; } diff --git a/gcc/gsstruct.def b/gcc/gsstruct.def index 19e1088..c3f64ef 100644 --- a/gcc/gsstruct.def +++ b/gcc/gsstruct.def @@ -50,4 +50,5 @@ DEFGSSTRUCT(GSS_OMP_SINGLE_LAYOUT, gimple_statement_omp_single_layout, false) DEFGSSTRUCT(GSS_OMP_CONTINUE, gomp_continue, false) DEFGSSTRUCT(GSS_OMP_ATOMIC_LOAD, gomp_atomic_load, false) DEFGSSTRUCT(GSS_OMP_ATOMIC_STORE_LAYOUT, gomp_atomic_store, false) +DEFGSSTRUCT(GSS_ASSUME, gimple_statement_assume, false) DEFGSSTRUCT(GSS_TRANSACTION, gtransaction, false) diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc index de608bd4..9471f54 100644 --- a/gcc/internal-fn.cc +++ b/gcc/internal-fn.cc @@ -4526,5 +4526,4 @@ expand_TRAP (internal_fn, gcall *) void expand_ASSUME (internal_fn, gcall *) { - gcc_unreachable (); } diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index 66bba71..d2bcd5e 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -100,6 +100,7 @@ along with GCC; see the file COPYING3. If not see and tree-inline.cc) according to instructions inserted to the call graph by the second stage. */ +#define INCLUDE_ALGORITHM #include "config.h" #include "system.h" #include "coretypes.h" @@ -455,6 +456,26 @@ ipcp_lattice<valtype>::is_single_const () return true; } +/* Return true iff X and Y should be considered equal values by IPA-CP. */ + +static bool +values_equal_for_ipcp_p (tree x, tree y) +{ + gcc_checking_assert (x != NULL_TREE && y != NULL_TREE); + + if (x == y) + return true; + + if (TREE_CODE (x) == ADDR_EXPR + && TREE_CODE (y) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (x, 0)) == CONST_DECL + && TREE_CODE (TREE_OPERAND (y, 0)) == CONST_DECL) + return operand_equal_p (DECL_INITIAL (TREE_OPERAND (x, 0)), + DECL_INITIAL (TREE_OPERAND (y, 0)), 0); + else + return operand_equal_p (x, y, 0); +} + /* Print V which is extracted from a value in a lattice to F. */ static void @@ -1217,6 +1238,274 @@ ipcp_bits_lattice::meet_with (ipcp_bits_lattice& other, unsigned precision, drop_all_ones); } +/* Dump the contents of the list to FILE. */ + +void +ipa_argagg_value_list::dump (FILE *f) +{ + bool comma = false; + for (const ipa_argagg_value &av : m_elts) + { + fprintf (f, "%s %i[%u]=", comma ? "," : "", + av.index, av.unit_offset); + print_generic_expr (f, av.value); + if (av.by_ref) + fprintf (f, "(by_ref)"); + comma = true; + } + fprintf (f, "\n"); +} + +/* Dump the contents of the list to stderr. */ + +void +ipa_argagg_value_list::debug () +{ + dump (stderr); +} + +/* Return the item describing a constant stored for INDEX at UNIT_OFFSET or + NULL if there is no such constant. */ + +const ipa_argagg_value * +ipa_argagg_value_list::get_elt (int index, unsigned unit_offset) const +{ + ipa_argagg_value key; + key.index = index; + key.unit_offset = unit_offset; + const ipa_argagg_value *res + = std::lower_bound (m_elts.begin (), m_elts.end (), key, + [] (const ipa_argagg_value &elt, + const ipa_argagg_value &val) + { + if (elt.index < val.index) + return true; + if (elt.index > val.index) + return false; + if (elt.unit_offset < val.unit_offset) + return true; + return false; + }); + + if (res == m_elts.end () + || res->index != index + || res->unit_offset != unit_offset) + res = nullptr; + + /* TODO: perhaps remove the check (that the underlying array is indeed + sorted) if it turns out it can be too slow? */ + if (!flag_checking) + return res; + + const ipa_argagg_value *slow_res = NULL; + int prev_index = -1; + unsigned prev_unit_offset = 0; + for (const ipa_argagg_value &av : m_elts) + { + gcc_assert (prev_index < 0 + || prev_index < av.index + || prev_unit_offset < av.unit_offset); + prev_index = av.index; + prev_unit_offset = av.unit_offset; + if (av.index == index + && av.unit_offset == unit_offset) + slow_res = &av; + } + gcc_assert (res == slow_res); + + return res; +} + +/* Return the first item describing a constant stored for parameter with INDEX, + regardless of offset or reference, or NULL if there is no such constant. */ + +const ipa_argagg_value * +ipa_argagg_value_list::get_elt_for_index (int index) const +{ + const ipa_argagg_value *res + = std::lower_bound (m_elts.begin (), m_elts.end (), index, + [] (const ipa_argagg_value &elt, unsigned idx) + { + return elt.index < idx; + }); + if (res == m_elts.end () + || res->index != index) + res = nullptr; + return res; +} + +/* Return the aggregate constant stored for INDEX at UNIT_OFFSET, not + performing any check of whether value is passed by reference, or NULL_TREE + if there is no such constant. */ + +tree +ipa_argagg_value_list::get_value (int index, unsigned unit_offset) const +{ + const ipa_argagg_value *av = get_elt (index, unit_offset); + return av ? av->value : NULL_TREE; +} + +/* Return the aggregate constant stored for INDEX at UNIT_OFFSET, if it is + passed by reference or not according to BY_REF, or NULL_TREE if there is + no such constant. */ + +tree +ipa_argagg_value_list::get_value (int index, unsigned unit_offset, + bool by_ref) const +{ + const ipa_argagg_value *av = get_elt (index, unit_offset); + if (av && av->by_ref == by_ref) + return av->value; + return NULL_TREE; +} + +/* Return true if all elements present in OTHER are also present in this + list. */ + +bool +ipa_argagg_value_list::superset_of_p (const ipa_argagg_value_list &other) const +{ + unsigned j = 0; + for (unsigned i = 0; i < other.m_elts.size (); i++) + { + unsigned other_index = other.m_elts[i].index; + unsigned other_offset = other.m_elts[i].unit_offset; + + while (j < m_elts.size () + && (m_elts[j].index < other_index + || (m_elts[j].index == other_index + && m_elts[j].unit_offset < other_offset))) + j++; + + if (j >= m_elts.size () + || m_elts[j].index != other_index + || m_elts[j].unit_offset != other_offset + || m_elts[j].by_ref != other.m_elts[i].by_ref + || !m_elts[j].value + || !values_equal_for_ipcp_p (m_elts[j].value, other.m_elts[i].value)) + return false; + } + return true; +} + +/* Push all items in this list that describe parameter SRC_INDEX into RES as + ones describing DST_INDEX while subtracting UNIT_DELTA from their unit + offsets but skip those which would end up with a negative offset. */ + +void +ipa_argagg_value_list::push_adjusted_values (unsigned src_index, + unsigned dest_index, + unsigned unit_delta, + vec<ipa_argagg_value> *res) const +{ + const ipa_argagg_value *av = get_elt_for_index (src_index); + if (!av) + return; + unsigned prev_unit_offset = 0; + bool first = true; + for (; av < m_elts.end (); ++av) + { + if (av->index > src_index) + return; + if (av->index == src_index + && (av->unit_offset >= unit_delta) + && av->value) + { + ipa_argagg_value new_av; + gcc_checking_assert (av->value); + new_av.value = av->value; + new_av.unit_offset = av->unit_offset - unit_delta; + new_av.index = dest_index; + new_av.by_ref = av->by_ref; + + /* Quick check that the offsets we push are indeed increasing. */ + gcc_assert (first + || new_av.unit_offset > prev_unit_offset); + prev_unit_offset = new_av.unit_offset; + first = false; + + res->safe_push (new_av); + } + } +} + +/* Push to RES information about single lattices describing aggregate values in + PLATS as those describing parameter DEST_INDEX and the original offset minus + UNIT_DELTA. Return true if any item has been pushed to RES. */ + +static bool +push_agg_values_from_plats (ipcp_param_lattices *plats, int dest_index, + unsigned unit_delta, + vec<ipa_argagg_value> *res) +{ + if (plats->aggs_contain_variable) + return false; + + bool pushed_sth = false; + bool first = true; + unsigned prev_unit_offset = 0; + for (struct ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next) + if (aglat->is_single_const () + && (aglat->offset / BITS_PER_UNIT - unit_delta) >= 0) + { + ipa_argagg_value iav; + iav.value = aglat->values->value; + iav.unit_offset = aglat->offset / BITS_PER_UNIT - unit_delta; + iav.index = dest_index; + iav.by_ref = plats->aggs_by_ref; + + gcc_assert (first + || iav.unit_offset > prev_unit_offset); + prev_unit_offset = iav.unit_offset; + first = false; + + pushed_sth = true; + res->safe_push (iav); + } + return pushed_sth; +} + +/* Turn all values in LIST that are not present in OTHER into NULL_TREEs. + Return the number of remaining valid entries. */ + +static unsigned +intersect_argaggs_with (vec<ipa_argagg_value> &elts, + const vec<ipa_argagg_value> &other) +{ + unsigned valid_entries = 0; + unsigned j = 0; + for (unsigned i = 0; i < elts.length (); i++) + { + if (!elts[i].value) + continue; + + unsigned this_index = elts[i].index; + unsigned this_offset = elts[i].unit_offset; + + while (j < other.length () + && (other[j].index < this_index + || (other[j].index == this_index + && other[j].unit_offset < this_offset))) + j++; + + if (j >= other.length ()) + { + elts[i].value = NULL_TREE; + continue; + } + + if (other[j].index == this_index + && other[j].unit_offset == this_offset + && other[j].by_ref == elts[i].by_ref + && other[j].value + && values_equal_for_ipcp_p (other[j].value, elts[i].value)) + valid_entries++; + else + elts[i].value = NULL_TREE; + } + return valid_entries; +} + /* Mark bot aggregate and scalar lattices as containing an unknown variable, return true is any of them has not been marked as such so far. */ @@ -1401,26 +1690,6 @@ ipacp_value_safe_for_type (tree param_type, tree value) return false; } -/* Return true iff X and Y should be considered equal values by IPA-CP. */ - -static bool -values_equal_for_ipcp_p (tree x, tree y) -{ - gcc_checking_assert (x != NULL_TREE && y != NULL_TREE); - - if (x == y) - return true; - - if (TREE_CODE (x) == ADDR_EXPR - && TREE_CODE (y) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (x, 0)) == CONST_DECL - && TREE_CODE (TREE_OPERAND (y, 0)) == CONST_DECL) - return operand_equal_p (DECL_INITIAL (TREE_OPERAND (x, 0)), - DECL_INITIAL (TREE_OPERAND (y, 0)), 0); - else - return operand_equal_p (x, y, 0); -} - /* Return the result of a (possibly arithmetic) operation on the constant value INPUT. OPERAND is 2nd operand for binary operation. RES_TYPE is the type of the parameter to which the result is passed. Return @@ -1701,35 +1970,14 @@ ipa_value_range_from_jfunc (ipa_node_params *info, cgraph_edge *cs, return vr; } -/* See if NODE is a clone with a known aggregate value at a given OFFSET of a - parameter with the given INDEX. */ - -static tree -get_clone_agg_value (struct cgraph_node *node, HOST_WIDE_INT offset, - int index) -{ - struct ipa_agg_replacement_value *aggval; - - aggval = ipa_get_agg_replacements_for_node (node); - while (aggval) - { - if (aggval->offset == offset - && aggval->index == index) - return aggval->value; - aggval = aggval->next; - } - return NULL_TREE; -} - /* Determine whether ITEM, jump function for an aggregate part, evaluates to a single known constant value and if so, return it. Otherwise return NULL. NODE and INFO describes the caller node or the one it is inlined to, and its related info. */ -static tree -ipa_agg_value_from_node (class ipa_node_params *info, - struct cgraph_node *node, - struct ipa_agg_jf_item *item) +tree +ipa_agg_value_from_jfunc (ipa_node_params *info, cgraph_node *node, + const ipa_agg_jf_item *item) { tree value = NULL_TREE; int src_idx; @@ -1749,9 +1997,13 @@ ipa_agg_value_from_node (class ipa_node_params *info, { if (item->jftype == IPA_JF_PASS_THROUGH) value = info->known_csts[src_idx]; - else - value = get_clone_agg_value (node, item->value.load_agg.offset, - src_idx); + else if (ipcp_transformation *ts = ipcp_get_transformation_summary (node)) + { + ipa_argagg_value_list avl (ts); + value = avl.get_value (src_idx, + item->value.load_agg.offset / BITS_PER_UNIT, + item->value.load_agg.by_ref); + } } else if (info->lattices) { @@ -1808,37 +2060,38 @@ ipa_agg_value_from_node (class ipa_node_params *info, item->type); } -/* Determine whether AGG_JFUNC evaluates to a set of known constant value for - an aggregate and if so, return it. Otherwise return an empty set. NODE - and INFO describes the caller node or the one it is inlined to, and its - related info. */ +/* Process all items in AGG_JFUNC relative to caller (or the node the original + caller is inlined to) NODE which described by INFO and push the results to + RES as describing values passed in parameter DST_INDEX. */ -struct ipa_agg_value_set -ipa_agg_value_set_from_jfunc (class ipa_node_params *info, cgraph_node *node, - struct ipa_agg_jump_function *agg_jfunc) +void +ipa_push_agg_values_from_jfunc (ipa_node_params *info, cgraph_node *node, + ipa_agg_jump_function *agg_jfunc, + unsigned dst_index, + vec<ipa_argagg_value> *res) { - struct ipa_agg_value_set agg; - struct ipa_agg_jf_item *item; - int i; - - agg.items = vNULL; - agg.by_ref = agg_jfunc->by_ref; + unsigned prev_unit_offset = 0; + bool first = true; - FOR_EACH_VEC_SAFE_ELT (agg_jfunc->items, i, item) + for (const ipa_agg_jf_item &item : agg_jfunc->items) { - tree value = ipa_agg_value_from_node (info, node, item); + tree value = ipa_agg_value_from_jfunc (info, node, &item); + if (!value) + continue; - if (value) - { - struct ipa_agg_value value_item; + ipa_argagg_value iav; + iav.value = value; + iav.unit_offset = item.offset / BITS_PER_UNIT; + iav.index = dst_index; + iav.by_ref = agg_jfunc->by_ref; - value_item.offset = item->offset; - value_item.value = value; + gcc_assert (first + || iav.unit_offset > prev_unit_offset); + prev_unit_offset = iav.unit_offset; + first = false; - agg.items.safe_push (value_item); - } + res->safe_push (iav); } - return agg; } /* If checking is enabled, verify that no lattice is in the TOP state, i.e. not @@ -2979,15 +3232,15 @@ propagate_constants_across_call (struct cgraph_edge *cs) } /* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS - KNOWN_CONTEXTS, KNOWN_AGGS or AGG_REPS return the destination. The latter - three can be NULL. If AGG_REPS is not NULL, KNOWN_AGGS is ignored. */ + KNOWN_CONTEXTS, and known aggregates either in AVS or KNOWN_AGGS return + the destination. The latter three can be NULL. If AGG_REPS is not NULL, + KNOWN_AGGS is ignored. */ static tree ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, const vec<tree> &known_csts, const vec<ipa_polymorphic_call_context> &known_contexts, - const vec<ipa_agg_value_set> &known_aggs, - struct ipa_agg_replacement_value *agg_reps, + const ipa_argagg_value_list &avs, bool *speculative) { int param_index = ie->indirect_info->param_index; @@ -3007,41 +3260,16 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, if (ie->indirect_info->agg_contents) { t = NULL; - if (agg_reps && ie->indirect_info->guaranteed_unmodified) - { - while (agg_reps) - { - if (agg_reps->index == param_index - && agg_reps->offset == ie->indirect_info->offset - && agg_reps->by_ref == ie->indirect_info->by_ref) - { - t = agg_reps->value; - break; - } - agg_reps = agg_reps->next; - } - } - if (!t) - { - const ipa_agg_value_set *agg; - if (known_aggs.length () > (unsigned int) param_index) - agg = &known_aggs[param_index]; - else - agg = NULL; - bool from_global_constant; - t = ipa_find_agg_cst_for_param (agg, - (unsigned) param_index - < known_csts.length () - ? known_csts[param_index] - : NULL, - ie->indirect_info->offset, - ie->indirect_info->by_ref, - &from_global_constant); - if (t - && !from_global_constant - && !ie->indirect_info->guaranteed_unmodified) - t = NULL_TREE; - } + if ((unsigned) param_index < known_csts.length () + && known_csts[param_index]) + t = ipa_find_agg_cst_from_init (known_csts[param_index], + ie->indirect_info->offset, + ie->indirect_info->by_ref); + + if (!t && ie->indirect_info->guaranteed_unmodified) + t = avs.get_value (param_index, + ie->indirect_info->offset / BITS_PER_UNIT, + ie->indirect_info->by_ref); } else if ((unsigned) param_index < known_csts.length ()) t = known_csts[param_index]; @@ -3058,38 +3286,22 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, return NULL_TREE; gcc_assert (!ie->indirect_info->agg_contents); + gcc_assert (!ie->indirect_info->by_ref); anc_offset = ie->indirect_info->offset; t = NULL; - /* Try to work out value of virtual table pointer value in replacements. */ - if (!t && agg_reps && !ie->indirect_info->by_ref) - { - while (agg_reps) - { - if (agg_reps->index == param_index - && agg_reps->offset == ie->indirect_info->offset - && agg_reps->by_ref) - { - t = agg_reps->value; - break; - } - agg_reps = agg_reps->next; - } - } + if ((unsigned) param_index < known_csts.length () + && known_csts[param_index]) + t = ipa_find_agg_cst_from_init (known_csts[param_index], + ie->indirect_info->offset, true); - /* Try to work out value of virtual table pointer value in known - aggregate values. */ - if (!t && known_aggs.length () > (unsigned int) param_index - && !ie->indirect_info->by_ref) - { - const ipa_agg_value_set *agg = &known_aggs[param_index]; - t = ipa_find_agg_cst_for_param (agg, - (unsigned) param_index - < known_csts.length () - ? known_csts[param_index] : NULL, - ie->indirect_info->offset, true); - } + /* Try to work out value of virtual table pointer value in replacements. */ + /* or known aggregate values. */ + if (!t) + t = avs.get_value (param_index, + ie->indirect_info->offset / BITS_PER_UNIT, + true); /* If we found the virtual table pointer, lookup the target. */ if (t) @@ -3208,23 +3420,10 @@ ipa_get_indirect_edge_target (struct cgraph_edge *ie, ipa_call_arg_values *avals, bool *speculative) { + ipa_argagg_value_list avl (avals); return ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals, avals->m_known_contexts, - avals->m_known_aggs, - NULL, speculative); -} - -/* The same functionality as above overloaded for ipa_auto_call_arg_values. */ - -tree -ipa_get_indirect_edge_target (struct cgraph_edge *ie, - ipa_auto_call_arg_values *avals, - bool *speculative) -{ - return ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals, - avals->m_known_contexts, - avals->m_known_aggs, - NULL, speculative); + avl, speculative); } /* Calculate devirtualization time bonus for NODE, assuming we know information @@ -3245,7 +3444,10 @@ devirtualization_time_bonus (struct cgraph_node *node, tree target; bool speculative; - target = ipa_get_indirect_edge_target (ie, avals, &speculative); + ipa_argagg_value_list avl (avals); + target = ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals, + avals->m_known_contexts, + avl, &speculative); if (!target) continue; @@ -3381,32 +3583,6 @@ good_cloning_opportunity_p (struct cgraph_node *node, sreal time_benefit, } } -/* Return all context independent values from aggregate lattices in PLATS in a - vector. Return NULL if there are none. */ - -static vec<ipa_agg_value> -context_independent_aggregate_values (class ipcp_param_lattices *plats) -{ - vec<ipa_agg_value> res = vNULL; - - if (plats->aggs_bottom - || plats->aggs_contain_variable - || plats->aggs_count == 0) - return vNULL; - - for (struct ipcp_agg_lattice *aglat = plats->aggs; - aglat; - aglat = aglat->next) - if (aglat->is_single_const ()) - { - struct ipa_agg_value item; - item.offset = aglat->offset; - item.value = aglat->values->value; - res.safe_push (item); - } - return res; -} - /* Grow vectors in AVALS and fill them with information about values of parameters that are known to be independent of the context. Only calculate m_known_aggs if CALCULATE_AGGS is true. INFO describes the function. If @@ -3426,8 +3602,6 @@ gather_context_independent_values (class ipa_node_params *info, avals->m_known_vals.safe_grow_cleared (count, true); avals->m_known_contexts.safe_grow_cleared (count, true); - if (calculate_aggs) - avals->m_known_aggs.safe_grow_cleared (count, true); if (removable_params_cost) *removable_params_cost = 0; @@ -3462,16 +3636,7 @@ gather_context_independent_values (class ipa_node_params *info, avals->m_known_contexts[i] = ctxlat->values->value; if (calculate_aggs) - { - vec<ipa_agg_value> agg_items; - struct ipa_agg_value_set *agg; - - agg_items = context_independent_aggregate_values (plats); - agg = &avals->m_known_aggs[i]; - agg->items = agg_items; - agg->by_ref = plats->aggs_by_ref; - ret |= !agg_items.is_empty (); - } + ret |= push_agg_values_from_plats (plats, i, 0, &avals->m_known_aggs); } return ret; @@ -3542,7 +3707,7 @@ static void estimate_local_effects (struct cgraph_node *node) { ipa_node_params *info = ipa_node_params_sum->get (node); - int i, count = ipa_get_param_count (info); + int count = ipa_get_param_count (info); bool always_const; int removable_params_cost; @@ -3608,7 +3773,7 @@ estimate_local_effects (struct cgraph_node *node) } - for (i = 0; i < count; i++) + for (int i = 0; i < count; i++) { class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); ipcp_lattice<tree> *lat = &plats->itself; @@ -3642,7 +3807,7 @@ estimate_local_effects (struct cgraph_node *node) avals.m_known_vals[i] = NULL_TREE; } - for (i = 0; i < count; i++) + for (int i = 0; i < count; i++) { class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); @@ -3677,30 +3842,49 @@ estimate_local_effects (struct cgraph_node *node) avals.m_known_contexts[i] = ipa_polymorphic_call_context (); } - for (i = 0; i < count; i++) + unsigned all_ctx_len = avals.m_known_aggs.length (); + auto_vec<ipa_argagg_value, 32> all_ctx; + all_ctx.reserve_exact (all_ctx_len); + all_ctx.splice (avals.m_known_aggs); + avals.m_known_aggs.safe_grow_cleared (all_ctx_len + 1); + + unsigned j = 0; + for (int index = 0; index < count; index++) { - class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); + class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, index); if (plats->aggs_bottom || !plats->aggs) continue; - ipa_agg_value_set *agg = &avals.m_known_aggs[i]; for (ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next) { ipcp_value<tree> *val; if (aglat->bottom || !aglat->values - /* If the following is true, the one value is in known_aggs. */ + /* If the following is true, the one value is already part of all + context estimations. */ || (!plats->aggs_contain_variable && aglat->is_single_const ())) continue; - for (val = aglat->values; val; val = val->next) + unsigned unit_offset = aglat->offset / BITS_PER_UNIT; + while (j < all_ctx_len + && (all_ctx[j].index < index + || (all_ctx[j].index == index + && all_ctx[j].unit_offset < unit_offset))) { - struct ipa_agg_value item; + avals.m_known_aggs[j] = all_ctx[j]; + j++; + } + + for (unsigned k = j; k < all_ctx_len; k++) + avals.m_known_aggs[k+1] = all_ctx[k]; - item.offset = aglat->offset; - item.value = val->value; - agg->items.safe_push (item); + for (val = aglat->values; val; val = val->next) + { + avals.m_known_aggs[j].value = val->value; + avals.m_known_aggs[j].unit_offset = unit_offset; + avals.m_known_aggs[j].index = index; + avals.m_known_aggs[j].by_ref = plats->aggs_by_ref; perform_estimation_of_a_value (node, &avals, removable_params_cost, 0, val); @@ -3710,7 +3894,7 @@ estimate_local_effects (struct cgraph_node *node) fprintf (dump_file, " - estimates for value "); print_ipcp_constant_value (dump_file, val->value); fprintf (dump_file, " for "); - ipa_dump_param (dump_file, info, i); + ipa_dump_param (dump_file, info, index); fprintf (dump_file, "[%soffset: " HOST_WIDE_INT_PRINT_DEC "]: time_benefit: %g, size: %i\n", plats->aggs_by_ref ? "ref " : "", @@ -3718,8 +3902,6 @@ estimate_local_effects (struct cgraph_node *node) val->local_time_benefit.to_double (), val->local_size_cost); } - - agg->items.pop (); } } } @@ -4103,7 +4285,7 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node, vec<tree> known_csts, vec<ipa_polymorphic_call_context> known_contexts, - struct ipa_agg_replacement_value *aggvals) + vec<ipa_argagg_value, va_gc> *aggvals) { struct cgraph_edge *ie, *next_ie; bool found = false; @@ -4114,8 +4296,9 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node, bool speculative; next_ie = ie->next_callee; + ipa_argagg_value_list avs (aggvals); target = ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts, - vNULL, aggvals, &speculative); + avs, &speculative); if (target) { bool agg_contents = ie->indirect_info->agg_contents; @@ -4249,11 +4432,15 @@ cgraph_edge_brings_value_p (cgraph_edge *cs, ipcp_value_source<tree> *src, if (caller_info->ipcp_orig_node) { - tree t; + tree t = NULL_TREE; if (src->offset == -1) t = caller_info->known_csts[src->index]; - else - t = get_clone_agg_value (cs->caller, src->offset, src->index); + else if (ipcp_transformation *ts + = ipcp_get_transformation_summary (cs->caller)) + { + ipa_argagg_value_list avl (ts); + t = avl.get_value (src->index, src->offset / BITS_PER_UNIT); + } return (t != NULL_TREE && values_equal_for_ipcp_p (src->val->value, t)); } @@ -5060,13 +5247,12 @@ static struct cgraph_node * create_specialized_node (struct cgraph_node *node, vec<tree> known_csts, vec<ipa_polymorphic_call_context> known_contexts, - struct ipa_agg_replacement_value *aggvals, + vec<ipa_argagg_value, va_gc> *aggvals, vec<cgraph_edge *> &callers) { ipa_node_params *new_info, *info = ipa_node_params_sum->get (node); vec<ipa_replace_map *, va_gc> *replace_trees = NULL; vec<ipa_adjusted_param, va_gc> *new_params = NULL; - struct ipa_agg_replacement_value *av; struct cgraph_node *new_node; int i, count = ipa_get_param_count (info); clone_info *cinfo = clone_info::get (node); @@ -5194,8 +5380,8 @@ create_specialized_node (struct cgraph_node *node, new_node->expand_all_artificial_thunks (); ipa_set_node_agg_value_chain (new_node, aggvals); - for (av = aggvals; av; av = av->next) - new_node->maybe_create_reference (av->value, NULL); + for (const ipa_argagg_value &av : aggvals) + new_node->maybe_create_reference (av.value, NULL); if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -5210,7 +5396,11 @@ create_specialized_node (struct cgraph_node *node, } } if (aggvals) - ipa_dump_agg_replacement_values (dump_file, aggvals); + { + fprintf (dump_file, " Aggregate replacements:"); + ipa_argagg_value_list avs (aggvals); + avs.dump (dump_file); + } } new_info = ipa_node_params_sum->get (new_node); @@ -5219,7 +5409,8 @@ create_specialized_node (struct cgraph_node *node, new_info->known_csts = known_csts; new_info->known_contexts = known_contexts; - ipcp_discover_new_direct_edges (new_node, known_csts, known_contexts, aggvals); + ipcp_discover_new_direct_edges (new_node, known_csts, known_contexts, + aggvals); return new_node; } @@ -5252,7 +5443,8 @@ self_recursive_pass_through_p (cgraph_edge *cs, ipa_jump_func *jfunc, int i, pass-through. */ static bool -self_recursive_agg_pass_through_p (cgraph_edge *cs, ipa_agg_jf_item *jfunc, +self_recursive_agg_pass_through_p (const cgraph_edge *cs, + const ipa_agg_jf_item *jfunc, int i, bool simple = true) { enum availability availability; @@ -5427,376 +5619,215 @@ find_more_contexts_for_caller_subset (cgraph_node *node, } } -/* Go through PLATS and create a vector of values consisting of values and - offsets (minus OFFSET) of lattices that contain only a single value. */ - -static vec<ipa_agg_value> -copy_plats_to_inter (class ipcp_param_lattices *plats, HOST_WIDE_INT offset) -{ - vec<ipa_agg_value> res = vNULL; - - if (!plats->aggs || plats->aggs_contain_variable || plats->aggs_bottom) - return vNULL; - - for (struct ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next) - if (aglat->is_single_const ()) - { - struct ipa_agg_value ti; - ti.offset = aglat->offset - offset; - ti.value = aglat->values->value; - res.safe_push (ti); - } - return res; -} - -/* Intersect all values in INTER with single value lattices in PLATS (while - subtracting OFFSET). */ - -static void -intersect_with_plats (class ipcp_param_lattices *plats, - vec<ipa_agg_value> *inter, - HOST_WIDE_INT offset) -{ - struct ipcp_agg_lattice *aglat; - struct ipa_agg_value *item; - int k; - - if (!plats->aggs || plats->aggs_contain_variable || plats->aggs_bottom) - { - inter->release (); - return; - } - - aglat = plats->aggs; - FOR_EACH_VEC_ELT (*inter, k, item) - { - bool found = false; - if (!item->value) - continue; - while (aglat) - { - if (aglat->offset - offset > item->offset) - break; - if (aglat->offset - offset == item->offset) - { - if (aglat->is_single_const ()) - { - tree value = aglat->values->value; - - if (values_equal_for_ipcp_p (item->value, value)) - found = true; - } - break; - } - aglat = aglat->next; - } - if (!found) - item->value = NULL_TREE; - } -} - -/* Copy aggregate replacement values of NODE (which is an IPA-CP clone) to the - vector result while subtracting OFFSET from the individual value offsets. */ - -static vec<ipa_agg_value> -agg_replacements_to_vector (struct cgraph_node *node, int index, - HOST_WIDE_INT offset) -{ - struct ipa_agg_replacement_value *av; - vec<ipa_agg_value> res = vNULL; - - for (av = ipa_get_agg_replacements_for_node (node); av; av = av->next) - if (av->index == index - && (av->offset - offset) >= 0) - { - struct ipa_agg_value item; - gcc_checking_assert (av->value); - item.offset = av->offset - offset; - item.value = av->value; - res.safe_push (item); - } - - return res; -} +/* Push all aggregate values coming along edge CS for parameter number INDEX to + RES. If INTERIM is non-NULL, it contains the current interim state of + collected aggregate values which can be used to compute values passed over + self-recursive edges. -/* Intersect all values in INTER with those that we have already scheduled to - be replaced in parameter number INDEX of NODE, which is an IPA-CP clone - (while subtracting OFFSET). */ + This basically one iteration of push_agg_values_from_edge over one + parameter, which allows for simpler early returns. */ static void -intersect_with_agg_replacements (struct cgraph_node *node, int index, - vec<ipa_agg_value> *inter, - HOST_WIDE_INT offset) +push_agg_values_for_index_from_edge (struct cgraph_edge *cs, int index, + vec<ipa_argagg_value> *res, + const ipa_argagg_value_list *interim) { - struct ipa_agg_replacement_value *srcvals; - struct ipa_agg_value *item; - int i; + bool agg_values_from_caller = false; + bool agg_jf_preserved = false; + unsigned unit_delta = UINT_MAX; + int src_idx = -1; + ipa_jump_func *jfunc = ipa_get_ith_jump_func (ipa_edge_args_sum->get (cs), + index); - srcvals = ipa_get_agg_replacements_for_node (node); - if (!srcvals) + if (jfunc->type == IPA_JF_PASS_THROUGH + && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) { - inter->release (); - return; + agg_values_from_caller = true; + agg_jf_preserved = ipa_get_jf_pass_through_agg_preserved (jfunc); + src_idx = ipa_get_jf_pass_through_formal_id (jfunc); + unit_delta = 0; } - - FOR_EACH_VEC_ELT (*inter, i, item) + else if (jfunc->type == IPA_JF_ANCESTOR + && ipa_get_jf_ancestor_agg_preserved (jfunc)) { - struct ipa_agg_replacement_value *av; - bool found = false; - if (!item->value) - continue; - for (av = srcvals; av; av = av->next) - { - gcc_checking_assert (av->value); - if (av->index == index - && av->offset - offset == item->offset) - { - if (values_equal_for_ipcp_p (item->value, av->value)) - found = true; - break; - } - } - if (!found) - item->value = NULL_TREE; + agg_values_from_caller = true; + agg_jf_preserved = true; + src_idx = ipa_get_jf_ancestor_formal_id (jfunc); + unit_delta = ipa_get_jf_ancestor_offset (jfunc) / BITS_PER_UNIT; } -} -/* Intersect values in INTER with aggregate values that come along edge CS to - parameter number INDEX and return it. If INTER does not actually exist yet, - copy all incoming values to it. If we determine we ended up with no values - whatsoever, return a released vector. */ - -static vec<ipa_agg_value> -intersect_aggregates_with_edge (struct cgraph_edge *cs, int index, - vec<ipa_agg_value> inter) -{ - struct ipa_jump_func *jfunc; - jfunc = ipa_get_ith_jump_func (ipa_edge_args_sum->get (cs), index); - if (jfunc->type == IPA_JF_PASS_THROUGH - && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) + ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); + if (agg_values_from_caller) { - ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); - int src_idx = ipa_get_jf_pass_through_formal_id (jfunc); - if (caller_info->ipcp_orig_node) { struct cgraph_node *orig_node = caller_info->ipcp_orig_node; - class ipcp_param_lattices *orig_plats; + ipcp_transformation *ts + = ipcp_get_transformation_summary (cs->caller); ipa_node_params *orig_info = ipa_node_params_sum->get (orig_node); - orig_plats = ipa_get_parm_lattices (orig_info, src_idx); - if (agg_pass_through_permissible_p (orig_plats, jfunc)) + ipcp_param_lattices *orig_plats + = ipa_get_parm_lattices (orig_info, src_idx); + if (ts + && orig_plats->aggs + && (agg_jf_preserved || !orig_plats->aggs_by_ref)) { - if (!inter.exists ()) - inter = agg_replacements_to_vector (cs->caller, src_idx, 0); - else - intersect_with_agg_replacements (cs->caller, src_idx, - &inter, 0); - return inter; + ipa_argagg_value_list src (ts); + src.push_adjusted_values (src_idx, index, unit_delta, res); + return; } } else { - class ipcp_param_lattices *src_plats; - src_plats = ipa_get_parm_lattices (caller_info, src_idx); - if (agg_pass_through_permissible_p (src_plats, jfunc)) + ipcp_param_lattices *src_plats + = ipa_get_parm_lattices (caller_info, src_idx); + if (src_plats->aggs + && !src_plats->aggs_bottom + && (agg_jf_preserved || !src_plats->aggs_by_ref)) { - /* Currently we do not produce clobber aggregate jump - functions, adjust when we do. */ - gcc_checking_assert (!jfunc->agg.items); - if (!inter.exists ()) - inter = copy_plats_to_inter (src_plats, 0); - else - intersect_with_plats (src_plats, &inter, 0); - return inter; + if (interim && self_recursive_pass_through_p (cs, jfunc, index)) + { + interim->push_adjusted_values (src_idx, index, unit_delta, + res); + return; + } + if (!src_plats->aggs_contain_variable) + { + push_agg_values_from_plats (src_plats, index, unit_delta, + res); + return; + } } } } - else if (jfunc->type == IPA_JF_ANCESTOR - && ipa_get_jf_ancestor_agg_preserved (jfunc)) - { - ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); - int src_idx = ipa_get_jf_ancestor_formal_id (jfunc); - class ipcp_param_lattices *src_plats; - HOST_WIDE_INT delta = ipa_get_jf_ancestor_offset (jfunc); - - if (caller_info->ipcp_orig_node) - { - if (!inter.exists ()) - inter = agg_replacements_to_vector (cs->caller, src_idx, delta); - else - intersect_with_agg_replacements (cs->caller, src_idx, &inter, - delta); - } - else - { - src_plats = ipa_get_parm_lattices (caller_info, src_idx); - /* Currently we do not produce clobber aggregate jump - functions, adjust when we do. */ - gcc_checking_assert (!src_plats->aggs || !jfunc->agg.items); - if (!inter.exists ()) - inter = copy_plats_to_inter (src_plats, delta); - else - intersect_with_plats (src_plats, &inter, delta); - } - return inter; - } - if (jfunc->agg.items) + if (!jfunc->agg.items) + return; + bool first = true; + unsigned prev_unit_offset = 0; + for (const ipa_agg_jf_item &agg_jf : *jfunc->agg.items) { - ipa_node_params *caller_info = ipa_node_params_sum->get (cs->caller); - struct ipa_agg_value *item; - int k; + tree value, srcvalue; + /* Besides simple pass-through aggregate jump function, arithmetic + aggregate jump function could also bring same aggregate value as + parameter passed-in for self-feeding recursive call. For example, - if (!inter.exists ()) - for (unsigned i = 0; i < jfunc->agg.items->length (); i++) - { - struct ipa_agg_jf_item *agg_item = &(*jfunc->agg.items)[i]; - tree value = ipa_agg_value_from_node (caller_info, cs->caller, - agg_item); - if (value) - { - struct ipa_agg_value agg_value; + fn (int *i) + { + int j = *i & 1; + fn (&j); + } - agg_value.value = value; - agg_value.offset = agg_item->offset; - inter.safe_push (agg_value); - } - } + Given that *i is 0, recursive propagation via (*i & 1) also gets 0. */ + if (interim + && self_recursive_agg_pass_through_p (cs, &agg_jf, index, false) + && (srcvalue = interim->get_value(index, + agg_jf.offset / BITS_PER_UNIT))) + value = ipa_get_jf_arith_result (agg_jf.value.pass_through.operation, + srcvalue, + agg_jf.value.pass_through.operand, + agg_jf.type); else - FOR_EACH_VEC_ELT (inter, k, item) - { - int l = 0; - bool found = false; - - if (!item->value) - continue; - - while ((unsigned) l < jfunc->agg.items->length ()) - { - struct ipa_agg_jf_item *ti; - ti = &(*jfunc->agg.items)[l]; - if (ti->offset > item->offset) - break; - if (ti->offset == item->offset) - { - tree value; - - /* Besides simple pass-through aggregate jump function, - arithmetic aggregate jump function could also bring - same aggregate value as parameter passed-in for - self-feeding recursive call. For example, - - fn (int *i) - { - int j = *i & 1; - fn (&j); - } - - Given that *i is 0, recursive propagation via (*i & 1) - also gets 0. */ - if (self_recursive_agg_pass_through_p (cs, ti, index, - false)) - value = ipa_get_jf_arith_result ( - ti->value.pass_through.operation, - item->value, - ti->value.pass_through.operand, - ti->type); - else - value = ipa_agg_value_from_node (caller_info, - cs->caller, ti); + value = ipa_agg_value_from_jfunc (caller_info, cs->caller, + &agg_jf); + if (value) + { + struct ipa_argagg_value iav; + iav.value = value; + iav.unit_offset = agg_jf.offset / BITS_PER_UNIT; + iav.index = index; + iav.by_ref = jfunc->agg.by_ref; + + gcc_assert (first + || iav.unit_offset > prev_unit_offset); + prev_unit_offset = iav.unit_offset; + first = false; - if (value && values_equal_for_ipcp_p (item->value, value)) - found = true; - break; - } - l++; - } - if (!found) - item->value = NULL; - } - } - else - { - inter.release (); - return vNULL; + res->safe_push (iav); + } } - return inter; + return; } -/* Look at edges in CALLERS and collect all known aggregate values that arrive - from all of them. */ +/* Push all aggregate values coming along edge CS to RES. DEST_INFO is the + description of ultimate callee of CS or the one it was cloned from (the + summary where lattices are). If INTERIM is non-NULL, it contains the + current interim state of collected aggregate values which can be used to + compute values passed over self-recursive edges and to skip values which + clearly will not be part of intersection with INTERIM. */ -static struct ipa_agg_replacement_value * -find_aggregate_values_for_callers_subset (struct cgraph_node *node, - const vec<cgraph_edge *> &callers) +static void +push_agg_values_from_edge (struct cgraph_edge *cs, + ipa_node_params *dest_info, + vec<ipa_argagg_value> *res, + const ipa_argagg_value_list *interim) { - ipa_node_params *dest_info = ipa_node_params_sum->get (node); - struct ipa_agg_replacement_value *res; - struct ipa_agg_replacement_value **tail = &res; - struct cgraph_edge *cs; - int i, j, count = ipa_get_param_count (dest_info); + ipa_edge_args *args = ipa_edge_args_sum->get (cs); + if (!args) + return; - FOR_EACH_VEC_ELT (callers, j, cs) + int count = MIN (ipa_get_param_count (dest_info), + ipa_get_cs_argument_count (args)); + + unsigned interim_index = 0; + for (int index = 0; index < count; index++) { - ipa_edge_args *args = ipa_edge_args_sum->get (cs); - if (!args) + if (interim) { - count = 0; - break; + while (interim_index < interim->m_elts.size () + && interim->m_elts[interim_index].value + && interim->m_elts[interim_index].index < index) + interim_index++; + if (interim_index >= interim->m_elts.size () + || interim->m_elts[interim_index].index > index) + continue; } - int c = ipa_get_cs_argument_count (args); - if (c < count) - count = c; - } - for (i = 0; i < count; i++) - { - struct cgraph_edge *cs; - vec<ipa_agg_value> inter = vNULL; - struct ipa_agg_value *item; - class ipcp_param_lattices *plats = ipa_get_parm_lattices (dest_info, i); - int j; - - /* Among other things, the following check should deal with all by_ref - mismatches. */ + ipcp_param_lattices *plats = ipa_get_parm_lattices (dest_info, index); if (plats->aggs_bottom) continue; + push_agg_values_for_index_from_edge (cs, index, res, interim); + } +} - FOR_EACH_VEC_ELT (callers, j, cs) - { - struct ipa_jump_func *jfunc - = ipa_get_ith_jump_func (ipa_edge_args_sum->get (cs), i); - if (self_recursive_pass_through_p (cs, jfunc, i) - && (!plats->aggs_by_ref - || ipa_get_jf_pass_through_agg_preserved (jfunc))) - continue; - inter = intersect_aggregates_with_edge (cs, i, inter); - if (!inter.exists ()) - goto next_param; - } +/* Look at edges in CALLERS and collect all known aggregate values that arrive + from all of them. Return nullptr if there are none. */ - FOR_EACH_VEC_ELT (inter, j, item) - { - struct ipa_agg_replacement_value *v; +static struct vec<ipa_argagg_value, va_gc> * +find_aggregate_values_for_callers_subset (struct cgraph_node *node, + const vec<cgraph_edge *> &callers) +{ + ipa_node_params *dest_info = ipa_node_params_sum->get (node); + if (dest_info->ipcp_orig_node) + dest_info = ipa_node_params_sum->get (dest_info->ipcp_orig_node); - if (!item->value) - continue; + /* gather_edges_for_value puts a non-recursive call into the first element of + callers if it can. */ + auto_vec<ipa_argagg_value, 32> interim; + push_agg_values_from_edge (callers[0], dest_info, &interim, NULL); - v = ggc_alloc<ipa_agg_replacement_value> (); - v->index = i; - v->offset = item->offset; - v->value = item->value; - v->by_ref = plats->aggs_by_ref; - *tail = v; - tail = &v->next; - } + unsigned valid_entries = interim.length (); + if (!valid_entries) + return nullptr; - next_param: - if (inter.exists ()) - inter.release (); + unsigned caller_count = callers.length(); + for (unsigned i = 1; i < caller_count; i++) + { + auto_vec<ipa_argagg_value, 32> last; + ipa_argagg_value_list avs (&interim); + push_agg_values_from_edge (callers[i], dest_info, &last, &avs); + + valid_entries = intersect_argaggs_with (interim, last); + if (!valid_entries) + return nullptr; } - *tail = NULL; + + vec<ipa_argagg_value, va_gc> *res = NULL; + vec_safe_reserve_exact (res, valid_entries); + for (const ipa_argagg_value &av : interim) + if (av.value) + res->quick_push(av); + gcc_checking_assert (res->length () == valid_entries); return res; } @@ -5837,72 +5868,23 @@ cgraph_edge_brings_all_scalars_for_node (struct cgraph_edge *cs, /* Determine whether CS also brings all aggregate values that NODE is specialized for. */ + static bool cgraph_edge_brings_all_agg_vals_for_node (struct cgraph_edge *cs, struct cgraph_node *node) { - struct ipa_agg_replacement_value *aggval; - int i, ec, count; - - aggval = ipa_get_agg_replacements_for_node (node); - if (!aggval) + ipcp_transformation *ts = ipcp_get_transformation_summary (node); + if (!ts || vec_safe_is_empty (ts->m_agg_values)) return true; - ipa_node_params *clone_node_info = ipa_node_params_sum->get (node); - count = ipa_get_param_count (clone_node_info); - ec = ipa_get_cs_argument_count (ipa_edge_args_sum->get (cs)); - if (ec < count) - for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next) - if (aggval->index >= ec) - return false; - - ipa_node_params *orig_node_info - = ipa_node_params_sum->get (clone_node_info->ipcp_orig_node); - - for (i = 0; i < count; i++) - { - class ipcp_param_lattices *plats; - bool interesting = false; - for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next) - if (aggval->index == i) - { - interesting = true; - break; - } - if (!interesting) - continue; - - plats = ipa_get_parm_lattices (orig_node_info, aggval->index); - if (plats->aggs_bottom) - return false; - - vec<ipa_agg_value> values = intersect_aggregates_with_edge (cs, i, vNULL); - if (!values.exists ()) - return false; - - for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next) - if (aggval->index == i) - { - struct ipa_agg_value *item; - int j; - bool found = false; - FOR_EACH_VEC_ELT (values, j, item) - if (item->value - && item->offset == av->offset - && values_equal_for_ipcp_p (item->value, av->value)) - { - found = true; - break; - } - if (!found) - { - values.release (); - return false; - } - } - values.release (); - } - return true; + const ipa_argagg_value_list existing (ts->m_agg_values); + auto_vec<ipa_argagg_value, 32> edge_values; + ipa_node_params *dest_info = ipa_node_params_sum->get (node); + gcc_checking_assert (dest_info->ipcp_orig_node); + dest_info = ipa_node_params_sum->get (dest_info->ipcp_orig_node); + push_agg_values_from_edge (cs, dest_info, &edge_values, &existing); + const ipa_argagg_value_list avl (&edge_values); + return avl.superset_of_p (existing); } /* Given an original NODE and a VAL for which we have already created a @@ -6006,28 +5988,22 @@ copy_known_vectors_add_val (ipa_auto_call_arg_values *avals, AGGVALS list. */ DEBUG_FUNCTION bool -ipcp_val_agg_replacement_ok_p (ipa_agg_replacement_value *aggvals, +ipcp_val_agg_replacement_ok_p (vec<ipa_argagg_value, va_gc> *aggvals, int index, HOST_WIDE_INT offset, tree value) { if (offset == -1) return true; - while (aggvals) - { - if (aggvals->index == index - && aggvals->offset == offset - && values_equal_for_ipcp_p (aggvals->value, value)) - return true; - aggvals = aggvals->next; - } - return false; + const ipa_argagg_value_list avl (aggvals); + tree v = avl.get_value (index, offset / BITS_PER_UNIT); + return v && values_equal_for_ipcp_p (v, value); } /* Return true if offset is minus one because source of a polymorphic context cannot be an aggregate value. */ DEBUG_FUNCTION bool -ipcp_val_agg_replacement_ok_p (ipa_agg_replacement_value *, +ipcp_val_agg_replacement_ok_p (vec<ipa_argagg_value, va_gc> *, int , HOST_WIDE_INT offset, ipa_polymorphic_call_context) { @@ -6047,7 +6023,6 @@ decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset, ipcp_value<valtype> *val, ipa_auto_call_arg_values *avals, vec<cgraph_node *> *self_gen_clones) { - struct ipa_agg_replacement_value *aggvals; int caller_count; sreal freq_sum; profile_count count_sum, rec_count_sum; @@ -6126,7 +6101,8 @@ decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset, } find_more_scalar_values_for_callers_subset (node, known_csts, callers); find_more_contexts_for_caller_subset (node, &known_contexts, callers); - aggvals = find_aggregate_values_for_callers_subset (node, callers); + vec<ipa_argagg_value, va_gc> *aggvals + = find_aggregate_values_for_callers_subset (node, callers); gcc_checking_assert (ipcp_val_agg_replacement_ok_p (aggvals, index, offset, val->value)); val->spec_node = create_specialized_node (node, known_csts, known_contexts, @@ -6277,7 +6253,7 @@ decide_whether_version_node (struct cgraph_node *node) = copy_useful_known_contexts (avals.m_known_contexts); find_more_scalar_values_for_callers_subset (node, known_csts, callers); find_more_contexts_for_caller_subset (node, &known_contexts, callers); - ipa_agg_replacement_value *aggvals + vec<ipa_argagg_value, va_gc> *aggvals = find_aggregate_values_for_callers_subset (node, callers); if (!known_contexts_useful_p (known_contexts)) diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc index e2a8668..fd3d7d6 100644 --- a/gcc/ipa-fnsummary.cc +++ b/gcc/ipa-fnsummary.cc @@ -386,15 +386,6 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, int j; struct expr_eval_op *op; - /* We allow call stmt to have fewer arguments than the callee function - (especially for K&R style programs). So bound check here (we assume - m_known_aggs vector is either empty or has the same length as - m_known_vals). */ - gcc_checking_assert (!avals->m_known_aggs.length () - || !avals->m_known_vals.length () - || (avals->m_known_vals.length () - == avals->m_known_aggs.length ())); - if (c->agg_contents) { if (c->code == ipa_predicate::changed @@ -402,14 +393,14 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, && (avals->safe_sval_at(c->operand_num) == error_mark_node)) continue; - if (ipa_agg_value_set *agg = avals->safe_aggval_at (c->operand_num)) + if (tree sval = avals->safe_sval_at (c->operand_num)) + val = ipa_find_agg_cst_from_init (sval, c->offset, c->by_ref); + if (!val) { - tree sval = avals->safe_sval_at (c->operand_num); - val = ipa_find_agg_cst_for_param (agg, sval, c->offset, - c->by_ref); + ipa_argagg_value_list avs (avals); + val = avs.get_value (c->operand_num, c->offset / BITS_PER_UNIT, + c->by_ref); } - else - val = NULL_TREE; } else { @@ -674,17 +665,9 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, /* Determine known aggregate values. */ if (fre_will_run_p (caller)) - { - ipa_agg_value_set agg - = ipa_agg_value_set_from_jfunc (caller_parms_info, - caller, &jf->agg); - if (agg.items.length ()) - { - if (!avals->m_known_aggs.length ()) - avals->m_known_aggs.safe_grow_cleared (count, true); - avals->m_known_aggs[i] = agg; - } - } + ipa_push_agg_values_from_jfunc (caller_parms_info, + caller, &jf->agg, i, + &avals->m_known_aggs); } /* For calls used in polymorphic calls we further determine @@ -3446,8 +3429,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, { if (ipa_is_param_used_by_indirect_call (params_summary, i) && (avals->safe_sval_at (i) - || (avals->m_known_aggs.length () > i - && avals->m_known_aggs[i].items.length ()))) + || (ipa_argagg_value_list (avals).value_for_index_p (i)))) use_table = false; else if (ipa_is_param_used_by_polymorphic_call (params_summary, i) && (avals->m_known_contexts.length () > i @@ -3583,14 +3565,12 @@ ipa_cached_call_context::duplicate_from (const ipa_call_context &ctx) m_avals.m_known_aggs = vNULL; if (ctx.m_avals.m_known_aggs.exists ()) { - unsigned int n = MIN (ctx.m_avals.m_known_aggs.length (), nargs); - - for (unsigned int i = 0; i < n; i++) + const ipa_argagg_value_list avl (&ctx.m_avals); + for (unsigned int i = 0; i < nargs; i++) if (ipa_is_param_used_by_indirect_call (params_summary, i) - && !ctx.m_avals.m_known_aggs[i].is_empty ()) + && avl.value_for_index_p (i)) { - m_avals.m_known_aggs - = ipa_copy_agg_values (ctx.m_avals.m_known_aggs); + m_avals.m_known_aggs = ctx.m_avals.m_known_aggs.copy (); break; } } @@ -3607,7 +3587,7 @@ ipa_cached_call_context::release () /* See if context is initialized at first place. */ if (!m_node) return; - ipa_release_agg_values (m_avals.m_known_aggs, true); + m_avals.m_known_aggs.release (); m_avals.m_known_vals.release (); m_avals.m_known_contexts.release (); m_inline_param_summary.release (); @@ -3708,28 +3688,59 @@ ipa_call_context::equal_to (const ipa_call_context &ctx) } if (m_avals.m_known_aggs.exists () || ctx.m_avals.m_known_aggs.exists ()) { - for (unsigned int i = 0; i < nargs; i++) + unsigned i = 0, j = 0; + while (i < m_avals.m_known_aggs.length () + || j < ctx.m_avals.m_known_aggs.length ()) { - if (!ipa_is_param_used_by_indirect_call (params_summary, i)) - continue; - if (i >= m_avals.m_known_aggs.length () - || m_avals.m_known_aggs[i].is_empty ()) + if (i >= m_avals.m_known_aggs.length ()) { - if (i < ctx.m_avals.m_known_aggs.length () - && !ctx.m_avals.m_known_aggs[i].is_empty ()) + int idx2 = ctx.m_avals.m_known_aggs[j].index; + if (ipa_is_param_used_by_indirect_call (params_summary, idx2)) return false; + j++; continue; } - if (i >= ctx.m_avals.m_known_aggs.length () - || ctx.m_avals.m_known_aggs[i].is_empty ()) + if (j >= ctx.m_avals.m_known_aggs.length ()) { - if (i < m_avals.m_known_aggs.length () - && !m_avals.m_known_aggs[i].is_empty ()) + int idx1 = m_avals.m_known_aggs[i].index; + if (ipa_is_param_used_by_indirect_call (params_summary, idx1)) return false; + i++; continue; } - if (!m_avals.m_known_aggs[i].equal_to (ctx.m_avals.m_known_aggs[i])) + + int idx1 = m_avals.m_known_aggs[i].index; + int idx2 = ctx.m_avals.m_known_aggs[j].index; + if (idx1 < idx2) + { + if (ipa_is_param_used_by_indirect_call (params_summary, idx1)) + return false; + i++; + continue; + } + if (idx1 > idx2) + { + if (ipa_is_param_used_by_indirect_call (params_summary, idx2)) + return false; + j++; + continue; + } + if (!ipa_is_param_used_by_indirect_call (params_summary, idx1)) + { + i++; + j++; + continue; + } + + if ((m_avals.m_known_aggs[i].unit_offset + != ctx.m_avals.m_known_aggs[j].unit_offset) + || (m_avals.m_known_aggs[i].by_ref + != ctx.m_avals.m_known_aggs[j].by_ref) + || !operand_equal_p (m_avals.m_known_aggs[i].value, + ctx.m_avals.m_known_aggs[j].value)) return false; + i++; + j++; } } return true; diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc index 724c945..e6cf255 100644 --- a/gcc/ipa-prop.cc +++ b/gcc/ipa-prop.cc @@ -1095,7 +1095,10 @@ parm_ref_data_pass_through_p (struct ipa_func_body_info *fbi, int index, latter can be NULL), STMT is the load statement. If function returns true, *INDEX_P, *OFFSET_P and *BY_REF is filled with the parameter index, offset within the aggregate and whether it is a load from a value passed by - reference respectively. */ + reference respectively. + + Return false if the offset divided by BITS_PER_UNIT would not fit into an + unsigned int. */ bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi, @@ -1109,7 +1112,8 @@ ipa_load_from_parm_agg (struct ipa_func_body_info *fbi, bool reverse; tree base = get_ref_base_and_extent_hwi (op, offset_p, &size, &reverse); - if (!base) + if (!base + || (*offset_p / BITS_PER_UNIT) > UINT_MAX) return false; /* We can not propagate across volatile loads. */ @@ -3057,13 +3061,11 @@ ipa_analyze_node (struct cgraph_node *node) return; info->analysis_done = 1; - if (ipa_func_spec_opts_forbid_analysis_p (node)) + if (ipa_func_spec_opts_forbid_analysis_p (node) + || (count_formal_params (node->decl) + >= (1 << IPA_PROP_ARG_INDEX_LIMIT_BITS))) { - for (int i = 0; i < ipa_get_param_count (info); i++) - { - ipa_set_param_used (info, i, true); - ipa_set_controlled_uses (info, i, IPA_UNDESCRIBED_USE); - } + gcc_assert (!ipa_get_param_count (info)); return; } @@ -3610,7 +3612,7 @@ find_constructor_constant_at_offset (tree constructor, HOST_WIDE_INT req_offset) invariant from a static constructor and if so, return it. Otherwise return NULL. */ -static tree +tree ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset, bool by_ref) { if (by_ref) @@ -3630,47 +3632,24 @@ ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset, bool by_ref) return find_constructor_constant_at_offset (DECL_INITIAL (scalar), offset); } -/* Retrieve value from AGG, a set of known offset/value for an aggregate or - static initializer of SCALAR (which can be NULL) for the given OFFSET or - return NULL if there is none. BY_REF specifies whether the value has to be - passed by reference or by value. If FROM_GLOBAL_CONSTANT is non-NULL, then - the boolean it points to is set to true if the value comes from an - initializer of a constant. */ +/* Retrieve value from AGG_JFUNC for the given OFFSET or return NULL if there + is none. BY_REF specifies whether the value has to be passed by reference + or by value. */ -tree -ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar, - HOST_WIDE_INT offset, bool by_ref, - bool *from_global_constant) +static tree +ipa_find_agg_cst_from_jfunc_items (struct ipa_agg_jump_function *agg_jfunc, + ipa_node_params *src_info, + cgraph_node *src_node, + HOST_WIDE_INT offset, bool by_ref) { - struct ipa_agg_value *item; - int i; - - if (scalar) - { - tree res = ipa_find_agg_cst_from_init (scalar, offset, by_ref); - if (res) - { - if (from_global_constant) - *from_global_constant = true; - return res; - } - } + if (by_ref != agg_jfunc->by_ref) + return NULL_TREE; - if (!agg - || by_ref != agg->by_ref) - return NULL; + for (const ipa_agg_jf_item &item : agg_jfunc->items) + if (item.offset == offset) + return ipa_agg_value_from_jfunc (src_info, src_node, &item); - FOR_EACH_VEC_ELT (agg->items, i, item) - if (item->offset == offset) - { - /* Currently we do not have clobber values, return NULL for them once - we do. */ - gcc_checking_assert (is_gimple_ip_invariant (item->value)); - if (from_global_constant) - *from_global_constant = false; - return item->value; - } - return NULL; + return NULL_TREE; } /* Remove a reference to SYMBOL from the list of references of a node given by @@ -3767,24 +3746,19 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie, class ipa_node_params *new_root_info) { struct cgraph_edge *cs; - tree target; + tree target = NULL_TREE; bool agg_contents = ie->indirect_info->agg_contents; tree scalar = ipa_value_from_jfunc (new_root_info, jfunc, target_type); if (agg_contents) { - bool from_global_constant; - ipa_agg_value_set agg = ipa_agg_value_set_from_jfunc (new_root_info, - new_root, - &jfunc->agg); - target = ipa_find_agg_cst_for_param (&agg, scalar, - ie->indirect_info->offset, - ie->indirect_info->by_ref, - &from_global_constant); - agg.release (); - if (target - && !from_global_constant - && !ie->indirect_info->guaranteed_unmodified) - return NULL; + if (scalar) + target = ipa_find_agg_cst_from_init (scalar, ie->indirect_info->offset, + ie->indirect_info->by_ref); + if (!target && ie->indirect_info->guaranteed_unmodified) + target = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info, + new_root, + ie->indirect_info->offset, + ie->indirect_info->by_ref); } else target = scalar; @@ -3859,15 +3833,14 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie, { tree vtable; unsigned HOST_WIDE_INT offset; - tree scalar = (jfunc->type == IPA_JF_CONST) ? ipa_get_jf_constant (jfunc) - : NULL; - ipa_agg_value_set agg = ipa_agg_value_set_from_jfunc (new_root_info, - new_root, - &jfunc->agg); - tree t = ipa_find_agg_cst_for_param (&agg, scalar, - ie->indirect_info->offset, - true); - agg.release (); + tree t = NULL_TREE; + if (jfunc->type == IPA_JF_CONST) + t = ipa_find_agg_cst_from_init (ipa_get_jf_constant (jfunc), + ie->indirect_info->offset, true); + if (!t) + t = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info, + new_root, + ie->indirect_info->offset, true); if (t && vtable_pointer_value_to_vtable (t, &vtable, &offset)) { bool can_refer; @@ -4383,11 +4356,11 @@ ipcp_free_transformation_sum (void) void ipa_set_node_agg_value_chain (struct cgraph_node *node, - struct ipa_agg_replacement_value *aggvals) + vec<ipa_argagg_value, va_gc> *aggs) { ipcp_transformation_initialize (); ipcp_transformation *s = ipcp_transformation_sum->get_create (node); - s->agg_values = aggvals; + s->m_agg_values = aggs; } /* Hook that is called by cgraph.cc when an edge is removed. Adjust reference @@ -4532,12 +4505,10 @@ ipa_add_new_function (cgraph_node *node, void *data ATTRIBUTE_UNUSED) /* Hook that is called by summary when a node is duplicated. */ void -ipa_node_params_t::duplicate(cgraph_node *src, cgraph_node *dst, +ipa_node_params_t::duplicate(cgraph_node *, cgraph_node *, ipa_node_params *old_info, ipa_node_params *new_info) { - ipa_agg_replacement_value *old_av, *new_av; - new_info->descriptors = vec_safe_copy (old_info->descriptors); new_info->lattices = NULL; new_info->ipcp_orig_node = old_info->ipcp_orig_node; @@ -4547,23 +4518,6 @@ ipa_node_params_t::duplicate(cgraph_node *src, cgraph_node *dst, new_info->analysis_done = old_info->analysis_done; new_info->node_enqueued = old_info->node_enqueued; new_info->versionable = old_info->versionable; - - old_av = ipa_get_agg_replacements_for_node (src); - if (old_av) - { - new_av = NULL; - while (old_av) - { - struct ipa_agg_replacement_value *v; - - v = ggc_alloc<ipa_agg_replacement_value> (); - memcpy (v, old_av, sizeof (*v)); - v->next = new_av; - new_av = v; - old_av = old_av->next; - } - ipa_set_node_agg_value_chain (dst, new_av); - } } /* Duplication of ipcp transformation summaries. */ @@ -4576,17 +4530,9 @@ ipcp_transformation_t::duplicate(cgraph_node *, cgraph_node *dst, /* Avoid redundant work of duplicating vectors we will never use. */ if (dst->inlined_to) return; + dst_trans->m_agg_values = vec_safe_copy (src_trans->m_agg_values); dst_trans->bits = vec_safe_copy (src_trans->bits); dst_trans->m_vr = vec_safe_copy (src_trans->m_vr); - ipa_agg_replacement_value *agg = src_trans->agg_values, - **aggptr = &dst_trans->agg_values; - while (agg) - { - *aggptr = ggc_alloc<ipa_agg_replacement_value> (); - **aggptr = *agg; - agg = agg->next; - aggptr = &(*aggptr)->next; - } } /* Register our cgraph hooks if they are not already there. */ @@ -4703,23 +4649,6 @@ ipa_print_all_params (FILE * f) ipa_print_node_params (f, node); } -/* Dump the AV linked list. */ - -void -ipa_dump_agg_replacement_values (FILE *f, struct ipa_agg_replacement_value *av) -{ - bool comma = false; - fprintf (f, " Aggregate replacements:"); - for (; av; av = av->next) - { - fprintf (f, "%s %i[" HOST_WIDE_INT_PRINT_DEC "]=", comma ? "," : "", - av->index, av->offset); - print_generic_expr (f, av->value); - comma = true; - } - fprintf (f, "\n"); -} - /* Stream out jump function JUMP_FUNC to OB. */ static void @@ -5356,31 +5285,31 @@ write_ipcp_transformation_info (output_block *ob, cgraph_node *node) int node_ref; unsigned int count = 0; lto_symtab_encoder_t encoder; - struct ipa_agg_replacement_value *aggvals, *av; - aggvals = ipa_get_agg_replacements_for_node (node); encoder = ob->decl_state->symtab_node_encoder; node_ref = lto_symtab_encoder_encode (encoder, node); streamer_write_uhwi (ob, node_ref); - for (av = aggvals; av; av = av->next) - count++; - streamer_write_uhwi (ob, count); - - for (av = aggvals; av; av = av->next) + ipcp_transformation *ts = ipcp_get_transformation_summary (node); + if (ts && !vec_safe_is_empty (ts->m_agg_values)) { - struct bitpack_d bp; + streamer_write_uhwi (ob, ts->m_agg_values->length ()); + for (const ipa_argagg_value &av : ts->m_agg_values) + { + struct bitpack_d bp; - streamer_write_uhwi (ob, av->offset); - streamer_write_uhwi (ob, av->index); - stream_write_tree (ob, av->value, true); + stream_write_tree (ob, av.value, true); + streamer_write_uhwi (ob, av.unit_offset); + streamer_write_uhwi (ob, av.index); - bp = bitpack_create (ob->main_stream); - bp_pack_value (&bp, av->by_ref, 1); - streamer_write_bitpack (&bp); + bp = bitpack_create (ob->main_stream); + bp_pack_value (&bp, av.by_ref, 1); + streamer_write_bitpack (&bp); + } } + else + streamer_write_uhwi (ob, 0); - ipcp_transformation *ts = ipcp_get_transformation_summary (node); if (ts && vec_safe_length (ts->m_vr) > 0) { count = ts->m_vr->length (); @@ -5432,26 +5361,27 @@ static void read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node, data_in *data_in) { - struct ipa_agg_replacement_value *aggvals = NULL; unsigned int count, i; count = streamer_read_uhwi (ib); - for (i = 0; i <count; i++) - { - struct ipa_agg_replacement_value *av; - struct bitpack_d bp; - - av = ggc_alloc<ipa_agg_replacement_value> (); - av->offset = streamer_read_uhwi (ib); - av->index = streamer_read_uhwi (ib); - av->value = stream_read_tree (ib, data_in); - bp = streamer_read_bitpack (ib); - av->by_ref = bp_unpack_value (&bp, 1); - av->next = aggvals; - aggvals = av; - } - ipa_set_node_agg_value_chain (node, aggvals); - + if (count > 0) + { + ipcp_transformation_initialize (); + ipcp_transformation *ts = ipcp_transformation_sum->get_create (node); + vec_safe_grow_cleared (ts->m_agg_values, count, true); + for (i = 0; i <count; i++) + { + ipa_argagg_value *av = &(*ts->m_agg_values)[i];; + + av->value = stream_read_tree (ib, data_in); + av->unit_offset = streamer_read_uhwi (ib); + av->index = streamer_read_uhwi (ib); + + bitpack_d bp = streamer_read_bitpack (ib); + av->by_ref = bp_unpack_value (&bp, 1); + } + } + count = streamer_read_uhwi (ib); if (count > 0) { @@ -5595,56 +5525,75 @@ ipcp_read_transformation_summaries (void) } } -/* Adjust the aggregate replacements in AGGVAL to reflect parameters skipped in +/* Adjust the aggregate replacements in TS to reflect parameters skipped in NODE but also if any parameter was IPA-SRAed into a scalar go ahead with substitution of the default_definitions of that new param with the appropriate constant. - Return two bools. the first it true if at least one item in AGGVAL still - exists and function body walk should go ahead. The second is true if any - values were already substituted for scalarized parameters and update_cfg - shuld be run after replace_uses_by. */ + If after adjustments there are no aggregate replacements left, the + m_agg_values will be set to NULL. In other cases, it may be shrunk. + + Return true if any values were already substituted for scalarized parameters + and update_cfg shuld be run after replace_uses_by. */ -static std::pair<bool, bool> +static bool adjust_agg_replacement_values (cgraph_node *node, - ipa_agg_replacement_value *aggval, + ipcp_transformation *ts, const vec<ipa_param_descriptor, va_gc> &descriptors) { - struct ipa_agg_replacement_value *v; clone_info *cinfo = clone_info::get (node); if (!cinfo || !cinfo->param_adjustments) - return std::pair<bool, bool> (true, false); + return false; - bool anything_left = false; + bool removed_item = false; bool done_replacement = false; - for (v = aggval; v; v = v->next) + unsigned dst_index = 0; + unsigned count = ts->m_agg_values->length (); + for (unsigned i = 0; i < count; i++) { + ipa_argagg_value *v = &(*ts->m_agg_values)[i]; gcc_checking_assert (v->index >= 0); - unsigned unit_offset = v->offset / BITS_PER_UNIT; tree cst_type = TREE_TYPE (v->value); int split_idx; int new_idx = cinfo->param_adjustments->get_updated_index_or_split (v->index, - unit_offset, + v->unit_offset, cst_type, &split_idx); - v->index = new_idx; if (new_idx >= 0) - anything_left = true; - else if (split_idx >= 0) { - tree parm = ipa_get_param (descriptors, split_idx); - tree ddef = ssa_default_def (cfun, parm); - if (ddef) + v->index = new_idx; + if (removed_item) + (*ts->m_agg_values)[dst_index] = *v; + dst_index++; + } + else + { + removed_item = true; + if (split_idx >= 0) { - replace_uses_by (ddef, v->value); - done_replacement = true; + tree parm = ipa_get_param (descriptors, split_idx); + tree ddef = ssa_default_def (cfun, parm); + if (ddef) + { + replace_uses_by (ddef, v->value); + done_replacement = true; + } } } } - return std::pair<bool, bool> (anything_left, done_replacement); + + if (dst_index == 0) + { + ggc_free (ts->m_agg_values); + ts->m_agg_values = NULL; + } + else if (removed_item) + ts->m_agg_values->truncate (dst_index); + + return done_replacement; } /* Dominator walker driving the ipcp modification phase. */ @@ -5654,10 +5603,9 @@ class ipcp_modif_dom_walker : public dom_walker public: ipcp_modif_dom_walker (struct ipa_func_body_info *fbi, vec<ipa_param_descriptor, va_gc> *descs, - struct ipa_agg_replacement_value *av, - bool *sc) + ipcp_transformation *ts, bool *sc) : dom_walker (CDI_DOMINATORS), m_fbi (fbi), m_descriptors (descs), - m_aggval (av), m_something_changed (sc) {} + m_ts (ts), m_something_changed (sc) {} edge before_dom_children (basic_block) final override; bool cleanup_eh () @@ -5666,7 +5614,7 @@ public: private: struct ipa_func_body_info *m_fbi; vec<ipa_param_descriptor, va_gc> *m_descriptors; - struct ipa_agg_replacement_value *m_aggval; + ipcp_transformation *m_ts; bool *m_something_changed; auto_bitmap m_need_eh_cleanup; }; @@ -5677,10 +5625,9 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb) gimple_stmt_iterator gsi; for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { - struct ipa_agg_replacement_value *v; gimple *stmt = gsi_stmt (gsi); tree rhs, val, t; - HOST_WIDE_INT offset; + HOST_WIDE_INT bit_offset; poly_int64 size; int index; bool by_ref, vce; @@ -5708,32 +5655,30 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb) continue; if (!ipa_load_from_parm_agg (m_fbi, m_descriptors, stmt, rhs, &index, - &offset, &size, &by_ref)) + &bit_offset, &size, &by_ref)) continue; - for (v = m_aggval; v; v = v->next) - if (v->index == index - && v->offset == offset) - break; + unsigned unit_offset = bit_offset / BITS_PER_UNIT; + ipa_argagg_value_list avl (m_ts); + tree v = avl.get_value (index, unit_offset, by_ref); + if (!v - || v->by_ref != by_ref - || maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (v->value))), - size)) + || maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (v))), size)) continue; - gcc_checking_assert (is_gimple_ip_invariant (v->value)); - if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v->value))) + gcc_checking_assert (is_gimple_ip_invariant (v)); + if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v))) { - if (fold_convertible_p (TREE_TYPE (rhs), v->value)) - val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v->value); + if (fold_convertible_p (TREE_TYPE (rhs), v)) + val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v); else if (TYPE_SIZE (TREE_TYPE (rhs)) - == TYPE_SIZE (TREE_TYPE (v->value))) - val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v->value); + == TYPE_SIZE (TREE_TYPE (v))) + val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v); else { if (dump_file) { fprintf (dump_file, " const "); - print_generic_expr (dump_file, v->value); + print_generic_expr (dump_file, v); fprintf (dump_file, " can't be converted to type of "); print_generic_expr (dump_file, rhs); fprintf (dump_file, "\n"); @@ -5742,7 +5687,7 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb) } } else - val = v->value; + val = v; if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -6019,7 +5964,6 @@ ipcp_transform_function (struct cgraph_node *node) { vec<ipa_param_descriptor, va_gc> *descriptors = NULL; struct ipa_func_body_info fbi; - struct ipa_agg_replacement_value *aggval; int param_count; gcc_checking_assert (cfun); @@ -6031,18 +5975,17 @@ ipcp_transform_function (struct cgraph_node *node) ipcp_update_bits (node); ipcp_update_vr (node); - aggval = ipa_get_agg_replacements_for_node (node); - if (!aggval) + ipcp_transformation *ts = ipcp_get_transformation_summary (node); + if (!ts || vec_safe_is_empty (ts->m_agg_values)) return 0; param_count = count_formal_params (node->decl); if (param_count == 0) return 0; vec_safe_grow_cleared (descriptors, param_count, true); ipa_populate_param_decls (node, *descriptors); - std::pair<bool, bool> rr - = adjust_agg_replacement_values (node, aggval, *descriptors); - bool cfg_changed = rr.second; - if (!rr.first) + + bool cfg_changed = adjust_agg_replacement_values (node, ts, *descriptors); + if (vec_safe_is_empty (ts->m_agg_values)) { vec_free (descriptors); if (dump_file) @@ -6053,7 +5996,11 @@ ipcp_transform_function (struct cgraph_node *node) return 0; } if (dump_file) - ipa_dump_agg_replacement_values (dump_file, aggval); + { + fprintf (dump_file, " Aggregate replacements:"); + ipa_argagg_value_list avs (ts); + avs.dump (dump_file); + } fbi.node = node; fbi.info = NULL; @@ -6064,7 +6011,7 @@ ipcp_transform_function (struct cgraph_node *node) bool modified_mem_access = false; calculate_dominance_info (CDI_DOMINATORS); - ipcp_modif_dom_walker walker (&fbi, descriptors, aggval, &modified_mem_access); + ipcp_modif_dom_walker walker (&fbi, descriptors, ts, &modified_mem_access); walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun)); free_dominance_info (CDI_DOMINATORS); cfg_changed |= walker.cleanup_eh (); @@ -6076,7 +6023,7 @@ ipcp_transform_function (struct cgraph_node *node) fbi.bb_infos.release (); ipcp_transformation *s = ipcp_transformation_sum->get (node); - s->agg_values = NULL; + s->m_agg_values = NULL; s->bits = NULL; s->m_vr = NULL; @@ -6088,21 +6035,4 @@ ipcp_transform_function (struct cgraph_node *node) } -/* Return true if OTHER describes same agg value. */ -bool -ipa_agg_value::equal_to (const ipa_agg_value &other) -{ - return offset == other.offset - && operand_equal_p (value, other.value, 0); -} - -/* Destructor also removing individual aggregate values. */ - -ipa_auto_call_arg_values::~ipa_auto_call_arg_values () -{ - ipa_release_agg_values (m_known_aggs, false); -} - - - #include "gt-ipa-prop.h" diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index e54842d..0ba6ded 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -25,6 +25,11 @@ along with GCC; see the file COPYING3. If not see #define IPA_UNDESCRIBED_USE -1 +/* Index identifying an actualargument or a formal parameter may have only this + many bits. */ + +#define IPA_PROP_ARG_INDEX_LIMIT_BITS 16 + /* ipa-prop.cc stuff (ipa-cp, indirect inlining): */ /* A jump function for a callsite represents the values passed as actual @@ -184,104 +189,105 @@ struct GTY(()) ipa_agg_jump_function bool by_ref; }; -/* An element in an aggregate part describing a known value at a given offset. - All unlisted positions are assumed to be unknown and all listed values must - fulfill is_gimple_ip_invariant. */ +class ipcp_transformation; +class ipa_auto_call_arg_values; +class ipa_call_arg_values; -struct ipa_agg_value -{ - /* The offset at which the known value is located within the aggregate. */ - HOST_WIDE_INT offset; +/* Element of a vector describing aggregate values for a number of arguments in + a particular context, be it a call or the aggregate constants that a node is + specialized for. */ - /* The known constant. */ +struct GTY(()) ipa_argagg_value +{ + /* The constant value. In the contexts where the list of known values is + being pruned, NULL means a variable value. */ tree value; - - /* Return true if OTHER describes same agg value. */ - bool equal_to (const ipa_agg_value &other); + /* Unit offset within the aggregate. */ + unsigned unit_offset; + /* Index of the parameter, as it was in the original function (i.e. needs + remapping after parameter modification is carried out as part of clone + materialization). */ + unsigned index : IPA_PROP_ARG_INDEX_LIMIT_BITS; + /* Whether the value was passed by reference. */ + unsigned by_ref : 1; }; -/* Structure describing a set of known offset/value for aggregate. */ +/* A view into a sorted list of aggregate values in a particular context, be it + a call or the aggregate constants that a node is specialized for. The + actual data is stored in the vector this has been constructed from. */ -struct ipa_agg_value_set +class ipa_argagg_value_list { - /* Description of the individual item. */ - vec<ipa_agg_value> items; - /* True if the data was passed by reference (as opposed to by value). */ - bool by_ref; +public: + ipa_argagg_value_list () = delete; + ipa_argagg_value_list (const vec<ipa_argagg_value, va_gc> *values) + : m_elts (values) + {} + ipa_argagg_value_list (const vec<ipa_argagg_value> *values) + : m_elts (*values) + {} + ipa_argagg_value_list (const ipa_auto_call_arg_values *aavals); + ipa_argagg_value_list (const ipa_call_arg_values *gavals); + ipa_argagg_value_list (const ipcp_transformation *tinfo); - /* Return true if OTHER describes same agg values. */ - bool equal_to (const ipa_agg_value_set &other) - { - if (by_ref != other.by_ref) - return false; - if (items.length () != other.items.length ()) - return false; - for (unsigned int i = 0; i < items.length (); i++) - if (!items[i].equal_to (other.items[i])) - return false; - return true; - } + /* Return the aggregate constant stored for INDEX at UNIT_OFFSET, if it is + passed by reference or not according to BY_REF, or NULL_TREE + otherwise. */ - /* Return true if there is any value for aggregate. */ - bool is_empty () const - { - return items.is_empty (); - } + tree get_value (int index, unsigned unit_offset, bool by_ref) const; - ipa_agg_value_set copy () const - { - ipa_agg_value_set new_copy; + /* Return the aggregate constant stored for INDEX at UNIT_OFFSET, not + performing any check of whether value is passed by reference. Return + NULL_TREE if there is no such constant. */ - new_copy.items = items.copy (); - new_copy.by_ref = by_ref; + tree get_value (int index, unsigned unit_offset) const; - return new_copy; - } + /* Return the item describing a constant stored for INDEX at UNIT_OFFSET or + NULL if there is no such constant. */ + + const ipa_argagg_value *get_elt (int index, unsigned unit_offset) const; + + + /* Return the first item describing a constant stored for parameter with + INDEX, regardless of offset or reference, or NULL if there is no such + constant. */ + + const ipa_argagg_value *get_elt_for_index (int index) const; + + /* Return true if there is an aggregate constant referring to a value passed + in or by parameter with INDEX (at any offset, whether by reference or + not). */ - void release () + bool value_for_index_p (int index) const { - items.release (); + return !!get_elt_for_index (index); } -}; -/* Return copy of a vec<ipa_agg_value_set>. */ + /* Return true if all elements present in OTHER are also present in this + list. */ -static inline vec<ipa_agg_value_set> -ipa_copy_agg_values (const vec<ipa_agg_value_set> &aggs) -{ - vec<ipa_agg_value_set> aggs_copy = vNULL; + bool superset_of_p (const ipa_argagg_value_list &other) const; - if (!aggs.is_empty ()) - { - ipa_agg_value_set *agg; - int i; + /* Push all items in this list that describe parameter SRC_INDEX into RES as + ones describing DST_INDEX while subtracting UNIT_DELTA from their unit + offsets but skip those which would end up with a negative offset. */ - aggs_copy.reserve_exact (aggs.length ()); + void push_adjusted_values (unsigned src_index, unsigned dest_index, + unsigned unit_delta, + vec<ipa_argagg_value> *res) const; - FOR_EACH_VEC_ELT (aggs, i, agg) - aggs_copy.quick_push (agg->copy ()); - } + /* Dump aggregate constants to FILE. */ - return aggs_copy; -} + void dump (FILE *f); -/* For vec<ipa_agg_value_set>, DO NOT call release(), use below function - instead. Because ipa_agg_value_set contains a field of vector type, we - should release this child vector in each element before reclaiming the - whole vector. */ + /* Dump aggregate constants to stderr. */ -static inline void -ipa_release_agg_values (vec<ipa_agg_value_set> &aggs, - bool release_vector = true) -{ - ipa_agg_value_set *agg; - int i; + void DEBUG_FUNCTION debug (); - FOR_EACH_VEC_ELT (aggs, i, agg) - agg->release (); - if (release_vector) - aggs.release (); -} + /* Array slice pointing to the actual storage. */ + + array_slice<const ipa_argagg_value> m_elts; +}; /* Information about zero/non-zero bits. */ class GTY(()) ipa_bits @@ -460,28 +466,15 @@ ipa_get_jf_ancestor_keep_null (struct ipa_jump_func *jfunc) class ipa_auto_call_arg_values { public: - ~ipa_auto_call_arg_values (); - /* If m_known_vals (vector of known "scalar" values) is sufficiantly long, return its element at INDEX, otherwise return NULL. */ tree safe_sval_at (int index) { - /* TODO: Assert non-negative index here and test. */ if ((unsigned) index < m_known_vals.length ()) return m_known_vals[index]; return NULL; } - /* If m_known_aggs is sufficiantly long, return the pointer rto its element - at INDEX, otherwise return NULL. */ - ipa_agg_value_set *safe_aggval_at (int index) - { - /* TODO: Assert non-negative index here and test. */ - if ((unsigned) index < m_known_aggs.length ()) - return &m_known_aggs[index]; - return NULL; - } - /* Vector describing known values of parameters. */ auto_vec<tree, 32> m_known_vals; @@ -489,15 +482,22 @@ public: auto_vec<ipa_polymorphic_call_context, 32> m_known_contexts; /* Vector describing known aggregate values. */ - auto_vec<ipa_agg_value_set, 32> m_known_aggs; + auto_vec<ipa_argagg_value, 32> m_known_aggs; /* Vector describing known value ranges of arguments. */ auto_vec<value_range, 32> m_known_value_ranges; }; +inline +ipa_argagg_value_list +::ipa_argagg_value_list (const ipa_auto_call_arg_values *aavals) + : m_elts (aavals->m_known_aggs) +{} + /* Class bundling the various potentially known properties about actual arguments of a particular call. This variant does not deallocate the - bundled data in any way. */ + bundled data in any way as the vectors can either be pointing to vectors in + ipa_auto_call_arg_values or be allocated independently. */ class ipa_call_arg_values { @@ -522,22 +522,11 @@ public: return its element at INDEX, otherwise return NULL. */ tree safe_sval_at (int index) { - /* TODO: Assert non-negative index here and test. */ if ((unsigned) index < m_known_vals.length ()) return m_known_vals[index]; return NULL; } - /* If m_known_aggs is sufficiantly long, return the pointer rto its element - at INDEX, otherwise return NULL. */ - ipa_agg_value_set *safe_aggval_at (int index) - { - /* TODO: Assert non-negative index here and test. */ - if ((unsigned) index < m_known_aggs.length ()) - return &m_known_aggs[index]; - return NULL; - } - /* Vector describing known values of parameters. */ vec<tree> m_known_vals = vNULL; @@ -545,12 +534,17 @@ public: vec<ipa_polymorphic_call_context> m_known_contexts = vNULL; /* Vector describing known aggregate values. */ - vec<ipa_agg_value_set> m_known_aggs = vNULL; + vec<ipa_argagg_value> m_known_aggs = vNULL; /* Vector describing known value ranges of arguments. */ vec<value_range> m_known_value_ranges = vNULL; }; +inline +ipa_argagg_value_list +::ipa_argagg_value_list (const ipa_call_arg_values *gavals) + : m_elts (gavals->m_known_aggs) +{} /* Summary describing a single formal parameter. */ @@ -882,28 +876,12 @@ ipa_is_param_used_by_polymorphic_call (class ipa_node_params *info, int i) return (*info->descriptors)[i].used_by_polymorphic_call; } -/* Information about replacements done in aggregates for a given node (each - node has its linked list). */ -struct GTY(()) ipa_agg_replacement_value -{ - /* Next item in the linked list. */ - struct ipa_agg_replacement_value *next; - /* Offset within the aggregate. */ - HOST_WIDE_INT offset; - /* The constant value. */ - tree value; - /* The parameter index. */ - int index; - /* Whether the value was passed by reference. */ - bool by_ref; -}; - /* Structure holding information for the transformation phase of IPA-CP. */ struct GTY(()) ipcp_transformation { - /* Linked list of known aggregate values. */ - ipa_agg_replacement_value *agg_values; + /* Known aggregate values. */ + vec<ipa_argagg_value, va_gc> *m_agg_values; /* Known bits information. */ vec<ipa_bits *, va_gc> *bits; /* Value range information. */ @@ -911,26 +889,25 @@ struct GTY(()) ipcp_transformation /* Default constructor. */ ipcp_transformation () - : agg_values (NULL), bits (NULL), m_vr (NULL) + : m_agg_values (NULL), bits (NULL), m_vr (NULL) { } /* Default destructor. */ ~ipcp_transformation () { - ipa_agg_replacement_value *agg = agg_values; - while (agg) - { - ipa_agg_replacement_value *next = agg->next; - ggc_free (agg); - agg = next; - } + vec_free (m_agg_values); vec_free (bits); vec_free (m_vr); } }; +inline +ipa_argagg_value_list::ipa_argagg_value_list (const ipcp_transformation *tinfo) + : m_elts (tinfo->m_agg_values) +{} + void ipa_set_node_agg_value_chain (struct cgraph_node *node, - struct ipa_agg_replacement_value *aggvals); + vec<ipa_argagg_value, va_gc> *aggs); void ipcp_transformation_initialize (void); void ipcp_free_transformation_sum (void); @@ -1107,15 +1084,6 @@ ipcp_get_transformation_summary (cgraph_node *node) return ipcp_transformation_sum->get (node); } -/* Return the aggregate replacements for NODE, if there are any. */ - -static inline struct ipa_agg_replacement_value * -ipa_get_agg_replacements_for_node (cgraph_node *node) -{ - ipcp_transformation *ts = ipcp_get_transformation_summary (node); - return ts ? ts->agg_values : NULL; -} - /* Function formal parameters related computations. */ void ipa_initialize_node_params (struct cgraph_node *node); bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs, @@ -1125,9 +1093,6 @@ bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs, tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, ipa_call_arg_values *avals, bool *speculative); -tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, - ipa_auto_call_arg_values *avals, - bool *speculative); struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree, bool speculative = false); tree ipa_impossible_devirt_target (struct cgraph_edge *, tree); @@ -1139,9 +1104,8 @@ ipa_bits *ipa_get_ipa_bits_for_value (const widest_int &value, void ipa_analyze_node (struct cgraph_node *); /* Aggregate jump function related functions. */ -tree ipa_find_agg_cst_for_param (const ipa_agg_value_set *agg, tree scalar, - HOST_WIDE_INT offset, bool by_ref, - bool *from_global_constant = NULL); +tree ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset, + bool by_ref); bool ipa_load_from_parm_agg (struct ipa_func_body_info *fbi, vec<ipa_param_descriptor, va_gc> *descriptors, gimple *stmt, tree op, int *index_p, @@ -1171,8 +1135,6 @@ struct ipcp_agg_lattice; extern object_allocator<ipcp_agg_lattice> ipcp_agg_lattice_pool; -void ipa_dump_agg_replacement_values (FILE *f, - struct ipa_agg_replacement_value *av); void ipa_prop_write_jump_functions (void); void ipa_prop_read_jump_functions (void); void ipcp_write_transformation_summaries (void); @@ -1180,6 +1142,8 @@ void ipcp_read_transformation_summaries (void); int ipa_get_param_decl_index (class ipa_node_params *, tree); tree ipa_value_from_jfunc (class ipa_node_params *info, struct ipa_jump_func *jfunc, tree type); +tree ipa_agg_value_from_jfunc (ipa_node_params *info, cgraph_node *node, + const ipa_agg_jf_item *item); unsigned int ipcp_transform_function (struct cgraph_node *node); ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *, cgraph_edge *, @@ -1187,9 +1151,10 @@ ipa_polymorphic_call_context ipa_context_from_jfunc (ipa_node_params *, ipa_jump_func *); value_range ipa_value_range_from_jfunc (ipa_node_params *, cgraph_edge *, ipa_jump_func *, tree); -ipa_agg_value_set ipa_agg_value_set_from_jfunc (ipa_node_params *, - cgraph_node *, - ipa_agg_jump_function *); +void ipa_push_agg_values_from_jfunc (ipa_node_params *info, cgraph_node *node, + ipa_agg_jump_function *agg_jfunc, + unsigned dst_index, + vec<ipa_argagg_value> *res); void ipa_dump_param (FILE *, class ipa_node_params *info, int i); void ipa_release_body_info (struct ipa_func_body_info *); tree ipa_get_callee_param_type (struct cgraph_edge *e, int i); diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc index fa89634..5439651 100644 --- a/gcc/lto-streamer-in.cc +++ b/gcc/lto-streamer-in.cc @@ -1318,6 +1318,7 @@ input_struct_function_base (struct function *fn, class data_in *data_in, fn->calls_eh_return = bp_unpack_value (&bp, 1); fn->has_force_vectorize_loops = bp_unpack_value (&bp, 1); fn->has_simduid_loops = bp_unpack_value (&bp, 1); + fn->assume_function = bp_unpack_value (&bp, 1); fn->va_list_fpr_size = bp_unpack_value (&bp, 8); fn->va_list_gpr_size = bp_unpack_value (&bp, 8); fn->last_clique = bp_unpack_value (&bp, sizeof (short) * 8); diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc index 2e7af03..1e38904 100644 --- a/gcc/lto-streamer-out.cc +++ b/gcc/lto-streamer-out.cc @@ -2278,6 +2278,7 @@ output_struct_function_base (struct output_block *ob, struct function *fn) bp_pack_value (&bp, fn->calls_eh_return, 1); bp_pack_value (&bp, fn->has_force_vectorize_loops, 1); bp_pack_value (&bp, fn->has_simduid_loops, 1); + bp_pack_value (&bp, fn->assume_function, 1); bp_pack_value (&bp, fn->va_list_fpr_size, 8); bp_pack_value (&bp, fn->va_list_gpr_size, 8); bp_pack_value (&bp, fn->last_clique, sizeof (short) * 8); diff --git a/gcc/match.pd b/gcc/match.pd index fd64ad7..d07c0e4 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1331,8 +1331,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* (~X - ~Y) -> Y - X. */ (simplify (minus (bit_not @0) (bit_not @1)) - (with { tree utype = unsigned_type_for (type); } - (convert (minus (convert:utype @1) (convert:utype @0))))) + (if (!TYPE_OVERFLOW_SANITIZED (type)) + (with { tree utype = unsigned_type_for (type); } + (convert (minus (convert:utype @1) (convert:utype @0)))))) /* ~(X - Y) -> ~X + Y. */ (simplify @@ -8176,5 +8177,6 @@ and, /* -x & 1 -> x & 1. */ (simplify - (bit_and (negate @0) integer_onep@1) - (bit_and @0 @1)) + (bit_and (negate @0) integer_onep@1) + (if (!TYPE_OVERFLOW_SANITIZED (type)) + (bit_and @0 @1))) diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc index dc42c75..a880973 100644 --- a/gcc/omp-low.cc +++ b/gcc/omp-low.cc @@ -202,6 +202,7 @@ static bool omp_maybe_offloaded_ctx (omp_context *ctx); case GIMPLE_TRY: \ case GIMPLE_CATCH: \ case GIMPLE_EH_FILTER: \ + case GIMPLE_ASSUME: \ case GIMPLE_TRANSACTION: \ /* The sub-statements for these should be walked. */ \ *handled_ops_p = false; \ @@ -14413,6 +14414,9 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) lower_omp (gimple_try_eval_ptr (stmt), ctx); lower_omp (gimple_try_cleanup_ptr (stmt), ctx); break; + case GIMPLE_ASSUME: + lower_omp (gimple_assume_body_ptr (stmt), ctx); + break; case GIMPLE_TRANSACTION: lower_omp (gimple_transaction_body_ptr (as_a <gtransaction *> (stmt)), ctx); diff --git a/gcc/omp-oacc-kernels-decompose.cc b/gcc/omp-oacc-kernels-decompose.cc index 524060e..df333ba 100644 --- a/gcc/omp-oacc-kernels-decompose.cc +++ b/gcc/omp-oacc-kernels-decompose.cc @@ -189,6 +189,7 @@ adjust_region_code_walk_stmt_fn (gimple_stmt_iterator *gsi_p, case GIMPLE_GOTO: case GIMPLE_SWITCH: case GIMPLE_ASM: + case GIMPLE_ASSUME: case GIMPLE_TRANSACTION: case GIMPLE_RETURN: /* Statement that might constitute some looping/control flow pattern. */ diff --git a/gcc/passes.cc b/gcc/passes.cc index 78a07f8..3bbf525 100644 --- a/gcc/passes.cc +++ b/gcc/passes.cc @@ -2660,6 +2660,15 @@ execute_one_pass (opt_pass *pass) if (dom_info_available_p (CDI_POST_DOMINATORS)) free_dominance_info (CDI_POST_DOMINATORS); + if (cfun->assume_function) + { + /* For assume functions, don't release body, keep it around. */ + cfun->curr_properties |= PROP_assumptions_done; + pop_cfun (); + current_pass = NULL; + return true; + } + tree fn = cfun->decl; pop_cfun (); gcc_assert (!cfun); diff --git a/gcc/passes.def b/gcc/passes.def index 939ec3e..193b579 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -407,6 +407,7 @@ along with GCC; see the file COPYING3. If not see and thus it should be run last. */ NEXT_PASS (pass_uncprop); POP_INSERT_PASSES () + NEXT_PASS (pass_assumptions); NEXT_PASS (pass_tm_init); PUSH_INSERT_PASSES_WITHIN (pass_tm_init) NEXT_PASS (pass_tm_mark); diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 23e0f5e..e733479 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -53,7 +53,7 @@ range_operator_float::fold_range (frange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const frange &lh ATTRIBUTE_UNUSED, const frange &rh ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return false; } @@ -63,7 +63,7 @@ range_operator_float::fold_range (irange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const frange &lh ATTRIBUTE_UNUSED, const irange &rh ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return false; } @@ -73,7 +73,7 @@ range_operator_float::fold_range (irange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const frange &lh ATTRIBUTE_UNUSED, const frange &rh ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return false; } @@ -83,7 +83,7 @@ range_operator_float::op1_range (frange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const frange &lhs ATTRIBUTE_UNUSED, const frange &op2 ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return false; } @@ -93,7 +93,7 @@ range_operator_float::op1_range (frange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const irange &lhs ATTRIBUTE_UNUSED, const frange &op2 ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return false; } @@ -103,7 +103,7 @@ range_operator_float::op2_range (frange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const frange &lhs ATTRIBUTE_UNUSED, const frange &op1 ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return false; } @@ -113,7 +113,7 @@ range_operator_float::op2_range (frange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const irange &lhs ATTRIBUTE_UNUSED, const frange &op1 ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return false; } @@ -188,7 +188,7 @@ finite_operands_p (const frange &op1, const frange &op2) inline bool frelop_early_resolve (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel, relation_kind my_rel) + relation_trio rel, relation_kind my_rel) { // If either operand is undefined, return VARYING. if (empty_range_varying (r, type, op1, op2)) @@ -324,14 +324,14 @@ class foperator_identity : public range_operator_float public: bool fold_range (frange &r, tree type ATTRIBUTE_UNUSED, const frange &op1, const frange &op2 ATTRIBUTE_UNUSED, - relation_kind = VREL_VARYING) const final override + relation_trio = TRIO_VARYING) const final override { r = op1; return true; } bool op1_range (frange &r, tree type ATTRIBUTE_UNUSED, const frange &lhs, const frange &op2 ATTRIBUTE_UNUSED, - relation_kind = VREL_VARYING) const final override + relation_trio = TRIO_VARYING) const final override { r = lhs; return true; @@ -348,26 +348,26 @@ class foperator_equal : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange &lhs) const final override { return equal_op1_op2_relation (lhs); } bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind rel = VREL_VARYING) const final override + relation_trio rel = TRIO_VARYING) const final override { - return op1_range (r, type, lhs, op1, rel); + return op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); } } fop_equal; bool foperator_equal::fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel) const + relation_trio rel) const { if (frelop_early_resolve (r, type, op1, op2, rel, VREL_EQ)) return true; @@ -403,8 +403,9 @@ bool foperator_equal::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind rel) const + relation_trio trio) const { + relation_kind rel = trio.op1_op2 (); switch (get_bool_state (r, lhs, type)) { case BRS_TRUE: @@ -455,20 +456,20 @@ class foperator_not_equal : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel = VREL_VARYING) const final override; + relation_trio rel = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange &lhs) const final override { return not_equal_op1_op2_relation (lhs); } bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; } fop_not_equal; bool foperator_not_equal::fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel) const + relation_trio rel) const { if (frelop_early_resolve (r, type, op1, op2, rel, VREL_NE)) return true; @@ -505,17 +506,15 @@ bool foperator_not_equal::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind rel) const + relation_trio trio) const { + relation_kind rel = trio.op1_op2 (); switch (get_bool_state (r, lhs, type)) { case BRS_TRUE: - // The TRUE side of op1 != op1 implies op1 is NAN. - if (rel == VREL_EQ) - r.set_nan (type); // If the result is true, the only time we know anything is if // OP2 is a constant. - else if (op2.singleton_p ()) + if (op2.singleton_p ()) { // This is correct even if op1 is NAN, because the following // range would be ~[tmp, tmp] with the NAN property set to @@ -523,6 +522,9 @@ foperator_not_equal::op1_range (frange &r, tree type, REAL_VALUE_TYPE tmp = op2.lower_bound (); r.set (type, tmp, tmp, VR_ANTI_RANGE); } + // The TRUE side of op1 != op1 implies op1 is NAN. + else if (rel == VREL_EQ) + r.set_nan (type); else r.set_varying (type); break; @@ -557,23 +559,23 @@ class foperator_lt : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange &lhs) const final override { return lt_op1_op2_relation (lhs); } bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; } fop_lt; bool foperator_lt::fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel) const + relation_trio rel) const { if (frelop_early_resolve (r, type, op1, op2, rel, VREL_LT)) return true; @@ -599,7 +601,7 @@ foperator_lt::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -634,7 +636,7 @@ foperator_lt::op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -673,23 +675,23 @@ class foperator_le : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel = VREL_VARYING) const final override; + relation_trio rel = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange &lhs) const final override { return le_op1_op2_relation (lhs); } bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind rel = VREL_VARYING) const final override; + relation_trio rel = TRIO_VARYING) const final override; bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind rel = VREL_VARYING) const final override; + relation_trio rel = TRIO_VARYING) const final override; } fop_le; bool foperator_le::fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel) const + relation_trio rel) const { if (frelop_early_resolve (r, type, op1, op2, rel, VREL_LE)) return true; @@ -715,7 +717,7 @@ foperator_le::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -746,7 +748,7 @@ foperator_le::op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -781,23 +783,23 @@ class foperator_gt : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange &lhs) const final override { return gt_op1_op2_relation (lhs); } bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; } fop_gt; bool foperator_gt::fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel) const + relation_trio rel) const { if (frelop_early_resolve (r, type, op1, op2, rel, VREL_GT)) return true; @@ -823,7 +825,7 @@ foperator_gt::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -858,7 +860,7 @@ foperator_gt::op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -897,23 +899,23 @@ class foperator_ge : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; relation_kind op1_op2_relation (const irange &lhs) const final override { return ge_op1_op2_relation (lhs); } bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; } fop_ge; bool foperator_ge::fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel) const + relation_trio rel) const { if (frelop_early_resolve (r, type, op1, op2, rel, VREL_GE)) return true; @@ -939,7 +941,7 @@ foperator_ge::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -969,7 +971,7 @@ bool foperator_ge::op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -1008,22 +1010,22 @@ class foperator_unordered : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind rel = VREL_VARYING) const final override + relation_trio rel = TRIO_VARYING) const final override { - return op1_range (r, type, lhs, op1, rel); + return op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); } } fop_unordered; bool foperator_unordered::fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind) const + relation_trio) const { // UNORDERED is TRUE if either operand is a NAN. if (op1.known_isnan () || op2.known_isnan ()) @@ -1040,27 +1042,24 @@ bool foperator_unordered::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind rel) const + relation_trio trio) const { + relation_kind rel = trio.op1_op2 (); switch (get_bool_state (r, lhs, type)) { case BRS_TRUE: - if (rel == VREL_EQ) - r.set_nan (type); // Since at least one operand must be NAN, if one of them is // not, the other must be. - else if (!op2.maybe_isnan ()) + if (rel == VREL_EQ || !op2.maybe_isnan ()) r.set_nan (type); else r.set_varying (type); break; case BRS_FALSE: - if (rel == VREL_EQ) - r.clear_nan (); // A false UNORDERED means both operands are !NAN, so it's // impossible for op2 to be a NAN. - else if (op2.known_isnan ()) + if (op2.known_isnan ()) r.set_undefined (); else { @@ -1085,22 +1084,22 @@ class foperator_ordered : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind rel = VREL_VARYING) const final override + relation_trio rel = TRIO_VARYING) const final override { - return op1_range (r, type, lhs, op1, rel); + return op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); } } fop_ordered; bool foperator_ordered::fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind) const + relation_trio) const { if (op1.known_isnan () || op2.known_isnan ()) r = range_false (type); @@ -1115,8 +1114,9 @@ bool foperator_ordered::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind rel) const + relation_trio trio) const { + relation_kind rel = trio.op1_op2 (); switch (get_bool_state (r, lhs, type)) { case BRS_TRUE: @@ -1132,10 +1132,11 @@ foperator_ordered::op1_range (frange &r, tree type, break; case BRS_FALSE: - r.set_varying (type); - // The FALSE side of op1 ORDERED op1 implies op1 is !NAN. + // The FALSE side of op1 ORDERED op1 implies op1 is NAN. if (rel == VREL_EQ) - r.clear_nan (); + r.set_nan (type); + else + r.set_varying (type); break; default: @@ -1151,7 +1152,7 @@ class foperator_negate : public range_operator_float public: bool fold_range (frange &r, tree type, const frange &op1, const frange &op2, - relation_kind = VREL_VARYING) const final override + relation_trio = TRIO_VARYING) const final override { if (empty_range_varying (r, type, op1, op2)) return true; @@ -1184,7 +1185,7 @@ public: } bool op1_range (frange &r, tree type, const frange &lhs, const frange &op2, - relation_kind rel = VREL_VARYING) const final override + relation_trio rel = TRIO_VARYING) const final override { return fold_range (r, type, lhs, op2, rel); } @@ -1197,16 +1198,16 @@ class foperator_abs : public range_operator_float public: bool fold_range (frange &r, tree type, const frange &op1, const frange &, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op1_range (frange &r, tree type, const frange &lhs, const frange &op2, - relation_kind rel = VREL_VARYING) const final override; + relation_trio rel = TRIO_VARYING) const final override; } fop_abs; bool foperator_abs::fold_range (frange &r, tree type, const frange &op1, const frange &op2, - relation_kind) const + relation_trio) const { if (empty_range_varying (r, type, op1, op2)) return true; @@ -1256,7 +1257,7 @@ foperator_abs::fold_range (frange &r, tree type, bool foperator_abs::op1_range (frange &r, tree type, const frange &lhs, const frange &op2, - relation_kind) const + relation_trio) const { if (empty_range_varying (r, type, lhs, op2)) return true; @@ -1285,7 +1286,7 @@ class foperator_unordered_lt : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel = VREL_VARYING) const final override + relation_trio rel = TRIO_VARYING) const final override { if (op1.known_isnan () || op2.known_isnan ()) { @@ -1314,7 +1315,7 @@ class foperator_unordered_le : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel = VREL_VARYING) const final override + relation_trio rel = TRIO_VARYING) const final override { if (op1.known_isnan () || op2.known_isnan ()) { @@ -1335,16 +1336,16 @@ public: } bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; } fop_unordered_le; bool foperator_unordered_le::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -1368,7 +1369,7 @@ foperator_unordered_le::op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -1395,7 +1396,7 @@ class foperator_unordered_gt : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel = VREL_VARYING) const final override + relation_trio rel = TRIO_VARYING) const final override { if (op1.known_isnan () || op2.known_isnan ()) { @@ -1416,10 +1417,10 @@ public: } bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; } fop_unordered_gt; bool @@ -1427,7 +1428,7 @@ foperator_unordered_gt::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -1451,7 +1452,7 @@ foperator_unordered_gt::op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -1478,7 +1479,7 @@ class foperator_unordered_ge : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel = VREL_VARYING) const final override + relation_trio rel = TRIO_VARYING) const final override { if (op1.known_isnan () || op2.known_isnan ()) { @@ -1499,10 +1500,10 @@ public: } bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; } fop_unordered_ge; bool @@ -1510,7 +1511,7 @@ foperator_unordered_ge::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -1533,7 +1534,7 @@ bool foperator_unordered_ge::op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -1560,7 +1561,7 @@ class foperator_unordered_equal : public range_operator_float public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind rel = VREL_VARYING) const final override + relation_trio rel = TRIO_VARYING) const final override { if (op1.known_isnan () || op2.known_isnan ()) { @@ -1581,12 +1582,12 @@ public: } bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind = VREL_VARYING) const final override; + relation_trio = TRIO_VARYING) const final override; bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind rel = VREL_VARYING) const final override + relation_trio rel = TRIO_VARYING) const final override { - return op1_range (r, type, lhs, op1, rel); + return op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); } } fop_unordered_equal; @@ -1594,7 +1595,7 @@ bool foperator_unordered_equal::op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { diff --git a/gcc/range-op.cc b/gcc/range-op.cc index cf7f0dc..49ee7be 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -179,12 +179,13 @@ bool range_operator::fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel) const + relation_trio trio) const { gcc_checking_assert (r.supports_type_p (type)); if (empty_range_varying (r, type, lh, rh)) return true; + relation_kind rel = trio.op1_op2 (); unsigned num_lh = lh.num_pairs (); unsigned num_rh = rh.num_pairs (); @@ -227,7 +228,7 @@ range_operator::op1_range (irange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const irange &lhs ATTRIBUTE_UNUSED, const irange &op2 ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return false; } @@ -239,7 +240,7 @@ range_operator::op2_range (irange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const irange &lhs ATTRIBUTE_UNUSED, const irange &op1 ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return false; } @@ -453,15 +454,15 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &val, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &val, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual relation_kind op1_op2_relation (const irange &lhs) const; } op_equal; @@ -494,7 +495,7 @@ bool operator_equal::fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel) const + relation_trio rel) const { if (relop_early_resolve (r, type, op1, op2, rel, VREL_EQ)) return true; @@ -527,7 +528,7 @@ bool operator_equal::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -558,9 +559,9 @@ bool operator_equal::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel) const + relation_trio rel) const { - return operator_equal::op1_range (r, type, lhs, op1, rel); + return operator_equal::op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); } class operator_not_equal : public range_operator @@ -572,15 +573,15 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual relation_kind op1_op2_relation (const irange &lhs) const; } op_not_equal; @@ -612,7 +613,7 @@ bool operator_not_equal::fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel) const + relation_trio rel) const { if (relop_early_resolve (r, type, op1, op2, rel, VREL_NE)) return true; @@ -645,7 +646,7 @@ bool operator_not_equal::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -677,9 +678,9 @@ bool operator_not_equal::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel) const + relation_trio rel) const { - return operator_not_equal::op1_range (r, type, lhs, op1, rel); + return operator_not_equal::op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); } // (X < VAL) produces the range of [MIN, VAL - 1]. @@ -751,15 +752,15 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual relation_kind op1_op2_relation (const irange &lhs) const; } op_lt; @@ -791,7 +792,7 @@ bool operator_lt::fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel) const + relation_trio rel) const { if (relop_early_resolve (r, type, op1, op2, rel, VREL_LT)) return true; @@ -815,7 +816,7 @@ bool operator_lt::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -837,7 +838,7 @@ bool operator_lt::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -865,15 +866,15 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual relation_kind op1_op2_relation (const irange &lhs) const; } op_le; @@ -905,7 +906,7 @@ bool operator_le::fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel) const + relation_trio rel) const { if (relop_early_resolve (r, type, op1, op2, rel, VREL_LE)) return true; @@ -926,7 +927,7 @@ bool operator_le::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -948,7 +949,7 @@ bool operator_le::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -976,15 +977,15 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual relation_kind op1_op2_relation (const irange &lhs) const; } op_gt; @@ -1016,7 +1017,7 @@ operator_gt::op1_op2_relation (const irange &lhs) const bool operator_gt::fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel) const + relation_trio rel) const { if (relop_early_resolve (r, type, op1, op2, rel, VREL_GT)) return true; @@ -1036,7 +1037,7 @@ operator_gt::fold_range (irange &r, tree type, bool operator_gt::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -1058,7 +1059,7 @@ bool operator_gt::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -1086,15 +1087,15 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual relation_kind op1_op2_relation (const irange &lhs) const; } op_ge; @@ -1126,7 +1127,7 @@ bool operator_ge::fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel) const + relation_trio rel) const { if (relop_early_resolve (r, type, op1, op2, rel, VREL_GE)) return true; @@ -1147,7 +1148,7 @@ bool operator_ge::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -1169,7 +1170,7 @@ bool operator_ge::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -1198,11 +1199,11 @@ public: virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const; + relation_trio) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const; + relation_trio) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -1402,7 +1403,7 @@ bool operator_plus::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel) const + relation_trio trio) const { if (lhs.undefined_p ()) return false; @@ -1411,6 +1412,7 @@ operator_plus::op1_range (irange &r, tree type, if (!minus) return false; bool res = minus.fold_range (r, type, lhs, op2); + relation_kind rel = trio.lhs_op2 (); // Check for a relation refinement. if (res) adjust_op1_for_overflow (r, op2, rel, true /* PLUS_EXPR */); @@ -1421,9 +1423,9 @@ bool operator_plus::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel) const + relation_trio rel) const { - return op1_range (r, type, lhs, op1, rel); + return op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); } @@ -1436,11 +1438,11 @@ public: virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const; + relation_trio) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const; + relation_trio) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -1573,7 +1575,7 @@ bool operator_minus::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio trio) const { if (lhs.undefined_p ()) return false; @@ -1582,6 +1584,7 @@ operator_minus::op1_range (irange &r, tree type, if (!minus) return false; bool res = minus.fold_range (r, type, lhs, op2); + relation_kind rel = trio.lhs_op2 (); if (res) adjust_op1_for_overflow (r, op2, rel, false /* PLUS_EXPR */); return res; @@ -1592,7 +1595,7 @@ bool operator_minus::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (lhs.undefined_p ()) return false; @@ -1752,17 +1755,17 @@ public: virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const; + relation_trio) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const; + relation_trio) const; } op_mult; bool operator_mult::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { tree offset; if (lhs.undefined_p ()) @@ -1783,9 +1786,9 @@ operator_mult::op1_range (irange &r, tree type, bool operator_mult::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel) const + relation_trio rel) const { - return operator_mult::op1_range (r, type, lhs, op1, rel); + return operator_mult::op1_range (r, type, lhs, op1, rel.swap_op1_op2 ()); } bool @@ -2009,7 +2012,7 @@ public: virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const; + relation_trio) const; } op_exact_div; @@ -2017,7 +2020,7 @@ bool operator_exact_divide::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (lhs.undefined_p ()) return false; @@ -2043,11 +2046,11 @@ public: virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -2067,7 +2070,7 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -2080,7 +2083,7 @@ public: virtual bool op1_range (irange &, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual relation_kind lhs_op1_relation (const irange &lhs, const irange &op1, const irange &op2, @@ -2106,7 +2109,7 @@ bool operator_lshift::fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel) const + relation_trio rel) const { int_range_max shift_range; if (!get_shift_range (shift_range, type, op2)) @@ -2228,7 +2231,7 @@ operator_lshift::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (lhs.undefined_p ()) return false; @@ -2301,7 +2304,7 @@ operator_rshift::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { tree shift; if (lhs.undefined_p ()) @@ -2380,7 +2383,7 @@ bool operator_rshift::fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel) const + relation_trio rel) const { int_range_max shift; if (!get_shift_range (shift, type, op2)) @@ -2412,11 +2415,11 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual relation_kind lhs_op1_relation (const irange &lhs, const irange &op1, const irange &op2, @@ -2528,7 +2531,7 @@ bool operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &inner, const irange &outer, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (empty_range_varying (r, type, inner, outer)) return true; @@ -2567,7 +2570,7 @@ bool operator_cast::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (lhs.undefined_p ()) return false; @@ -2682,15 +2685,15 @@ public: virtual bool fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; } op_logical_and; @@ -2698,7 +2701,7 @@ bool operator_logical_and::fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -2721,7 +2724,7 @@ bool operator_logical_and::op1_range (irange &r, tree type, const irange &lhs, const irange &op2 ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -2743,7 +2746,7 @@ bool operator_logical_and::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return operator_logical_and::op1_range (r, type, lhs, op1); } @@ -2758,15 +2761,15 @@ public: virtual bool fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -2786,7 +2789,7 @@ bool operator_bitwise_and::fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (range_operator::fold_range (r, type, lh, rh)) { @@ -3136,7 +3139,7 @@ bool operator_bitwise_and::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (lhs.undefined_p ()) return false; @@ -3171,7 +3174,7 @@ bool operator_bitwise_and::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return operator_bitwise_and::op1_range (r, type, lhs, op1); } @@ -3186,22 +3189,22 @@ public: virtual bool fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; } op_logical_or; bool operator_logical_or::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lh, const irange &rh, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -3215,7 +3218,7 @@ bool operator_logical_or::op1_range (irange &r, tree type, const irange &lhs, const irange &op2 ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { switch (get_bool_state (r, lhs, type)) { @@ -3237,7 +3240,7 @@ bool operator_logical_or::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return operator_logical_or::op1_range (r, type, lhs, op1); } @@ -3251,11 +3254,11 @@ public: virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel= VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -3323,7 +3326,7 @@ bool operator_bitwise_or::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (lhs.undefined_p ()) return false; @@ -3345,7 +3348,7 @@ bool operator_bitwise_or::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return operator_bitwise_or::op1_range (r, type, lhs, op1); } @@ -3364,11 +3367,11 @@ public: virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op1_op2_relation_effect (irange &lhs_range, tree type, const irange &op1_range, @@ -3454,7 +3457,7 @@ bool operator_bitwise_xor::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (lhs.undefined_p () || lhs.varying_p ()) { @@ -3489,7 +3492,7 @@ bool operator_bitwise_xor::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return operator_bitwise_xor::op1_range (r, type, lhs, op1); } @@ -3507,11 +3510,11 @@ public: virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const; + relation_trio) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const; + relation_trio) const; } op_trunc_mod; void @@ -3574,7 +3577,7 @@ bool operator_trunc_mod::op1_range (irange &r, tree type, const irange &lhs, const irange &, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (lhs.undefined_p ()) return false; @@ -3600,7 +3603,7 @@ bool operator_trunc_mod::op2_range (irange &r, tree type, const irange &lhs, const irange &, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (lhs.undefined_p ()) return false; @@ -3644,11 +3647,11 @@ public: virtual bool fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; } op_logical_not; // Folding a logical NOT, oddly enough, involves doing nothing on the @@ -3669,7 +3672,7 @@ bool operator_logical_not::fold_range (irange &r, tree type, const irange &lh, const irange &rh ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -3686,7 +3689,7 @@ operator_logical_not::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { // Logical NOT is involutary...do it again. return fold_range (r, type, lhs, op2); @@ -3701,18 +3704,18 @@ public: virtual bool fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; } op_bitwise_not; bool operator_bitwise_not::fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -3730,7 +3733,7 @@ bool operator_bitwise_not::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (lhs.undefined_p ()) return false; @@ -3749,14 +3752,14 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; } op_integer_cst; bool operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lh, const irange &rh ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { r = lh; return true; @@ -3772,11 +3775,11 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual relation_kind lhs_op1_relation (const irange &lhs, const irange &op1, const irange &op2, @@ -3801,7 +3804,7 @@ bool operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lh, const irange &rh ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { r = lh; return true; @@ -3811,7 +3814,7 @@ bool operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lhs, const irange &op2 ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { r = lhs; return true; @@ -3825,14 +3828,14 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; } op_unknown; bool operator_unknown::fold_range (irange &r, tree type, const irange &lh ATTRIBUTE_UNUSED, const irange &rh ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { r.set_varying (type); return true; @@ -3851,7 +3854,7 @@ class operator_abs : public range_operator virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const; + relation_trio) const; } op_abs; void @@ -3932,7 +3935,7 @@ bool operator_abs::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (empty_range_varying (r, type, lhs, op2)) return true; @@ -4013,18 +4016,18 @@ class operator_negate : public range_operator virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; } op_negate; bool operator_negate::fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -4037,7 +4040,7 @@ bool operator_negate::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { // NEGATE is involutory. return fold_range (r, type, lhs, op2); @@ -4052,18 +4055,18 @@ public: virtual bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; } op_addr; bool operator_addr_expr::fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -4082,7 +4085,7 @@ bool operator_addr_expr::op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return operator_addr_expr::fold_range (r, type, lhs, op2); } @@ -4204,11 +4207,11 @@ public: virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio rel = TRIO_VARYING) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const; @@ -4218,7 +4221,7 @@ bool pointer_or_operator::op1_range (irange &r, tree type, const irange &lhs, const irange &op2 ATTRIBUTE_UNUSED, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { if (lhs.undefined_p ()) return false; @@ -4236,7 +4239,7 @@ bool pointer_or_operator::op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel ATTRIBUTE_UNUSED) const + relation_trio) const { return pointer_or_operator::op1_range (r, type, lhs, op1); } @@ -4422,7 +4425,7 @@ bool range_op_handler::fold_range (vrange &r, tree type, const vrange &lh, const vrange &rh, - relation_kind rel) const + relation_trio rel) const { gcc_checking_assert (m_valid); if (m_int) @@ -4450,7 +4453,7 @@ bool range_op_handler::op1_range (vrange &r, tree type, const vrange &lhs, const vrange &op2, - relation_kind rel) const + relation_trio rel) const { gcc_checking_assert (m_valid); @@ -4474,7 +4477,7 @@ bool range_op_handler::op2_range (vrange &r, tree type, const vrange &lhs, const vrange &op1, - relation_kind rel) const + relation_trio rel) const { gcc_checking_assert (m_valid); if (lhs.undefined_p ()) diff --git a/gcc/range-op.h b/gcc/range-op.h index 48adcec..c724989 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -53,7 +53,7 @@ public: virtual bool fold_range (irange &r, tree type, const irange &lh, const irange &rh, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; // Return the range for op[12] in the general case. LHS is the range for // the LHS of the expression, OP[12]is the range for the other @@ -69,11 +69,11 @@ public: virtual bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; // The following routines are used to represent relations between the // various operations. If the caller knows where the symbolics are, @@ -116,32 +116,32 @@ public: virtual bool fold_range (frange &r, tree type, const frange &lh, const frange &rh, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; // Unary operations have the range of the LHS as op2. virtual bool fold_range (irange &r, tree type, const frange &lh, const irange &rh, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool fold_range (irange &r, tree type, const frange &lh, const frange &rh, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op1_range (frange &r, tree type, const frange &lhs, const frange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op2_range (frange &r, tree type, const frange &lhs, const frange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; virtual relation_kind lhs_op1_relation (const frange &lhs, const frange &op1, @@ -173,15 +173,15 @@ public: bool fold_range (vrange &r, tree type, const vrange &lh, const vrange &rh, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; bool op1_range (vrange &r, tree type, const vrange &lhs, const vrange &op2, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; bool op2_range (vrange &r, tree type, const vrange &lhs, const vrange &op1, - relation_kind rel = VREL_VARYING) const; + relation_trio = TRIO_VARYING) const; relation_kind lhs_op1_relation (const vrange &lhs, const vrange &op1, const vrange &op2, @@ -240,9 +240,10 @@ empty_range_varying (vrange &r, tree type, inline bool relop_early_resolve (irange &r, tree type, const vrange &op1, - const vrange &op2, relation_kind rel, + const vrange &op2, relation_trio trio, relation_kind my_rel) { + relation_kind rel = trio.op1_op2 (); // If known relation is a complete subset of this relation, always true. if (relation_union (rel, my_rel) == my_rel) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f717614..763e88a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,130 @@ +2022-10-18 Joseph Myers <joseph@codesourcery.com> + + PR c/107164 + * gcc.dg/c99-tag-4.c, gcc.dg/c99-tag-5.c, gcc.dg/c99-tag-6.c: New + tests. + +2022-10-18 Marek Polacek <polacek@redhat.com> + + PR testsuite/107213 + * c-c++-common/pointer-to-fn1.c: Only run on i?86/x86_64. + +2022-10-18 Patrick Palka <ppalka@redhat.com> + + PR c++/105045 + * g++.dg/modules/pr105045_a.C: New test. + * g++.dg/modules/pr105045_b.C: New test. + +2022-10-18 Joseph Myers <joseph@codesourcery.com> + + PR c/36113 + * gcc.dg/c11-enum-1.c, gcc.dg/c11-enum-2.c, gcc.dg/c11-enum-3.c, + gcc.dg/c2x-enum-1.c, gcc.dg/c2x-enum-2.c, gcc.dg/c2x-enum-3.c, + gcc.dg/c2x-enum-4.c, gcc.dg/c2x-enum-5.c: New tests. + * gcc.dg/pr30260.c: Explicitly use -std=gnu11. Update expected + diagnostics. + * gcc.dg/torture/pr25183.c: Update expected diagnostics. + +2022-10-18 Martin Jambor <mjambor@suse.cz> + + * gcc.dg/ipa/ipcp-agg-11.c: Adjust dumps. + * gcc.dg/ipa/ipcp-agg-8.c: Likewise. + +2022-10-18 Richard Biener <rguenther@suse.de> + + PR tree-optimization/107302 + * gcc.dg/vect/pr107302.c: New testcase. + +2022-10-18 Andre Vieira <andre.simoesdiasvieira@arm.com> + + * gcc.dg/vect/pr107275.c: New test. + +2022-10-18 Jakub Jelinek <jakub@redhat.com> + + PR c++/106654 + * g++.dg/cpp23/attr-assume5.C: New test. + * g++.dg/cpp23/attr-assume6.C: New test. + * g++.dg/cpp23/attr-assume7.C: New test. + +2022-10-18 Richard Biener <rguenther@suse.de> + + PR tree-optimization/107301 + * gcc.dg/torture/pr107301.c: New testcase. + +2022-10-18 Liwei Xu <liwei.xu@intel.com> + + PR testsuite/107220 + * gcc.dg/tree-ssa/forwprop-19.c: Move scanning pass from + forwprop1 to dse1, This fixs the test case fail. + +2022-10-18 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/107273 + * gcc.dg/tree-ssa/pr107273-1.c: New. + * gcc.dg/tree-ssa/pr107273-2.c: New. + +2022-10-17 Steve Kargl <kargl@gcc.gnu.org> + + PR fortran/104330 + * gfortran.dg/pr104330.f90: New test. + +2022-10-17 Aldy Hernandez <aldyh@redhat.com> + + PR tree-optimization/107293 + * gcc.dg/tree-ssa/pr107293.c: New test. + +2022-10-17 Harald Anlauf <anlauf@gmx.de> + Mikael Morin <mikael@gcc.gnu.org> + + PR fortran/93483 + PR fortran/107216 + PR fortran/107219 + * gfortran.dg/array_constructor_56.f90: New test. + * gfortran.dg/array_constructor_57.f90: New test. + +2022-10-17 Harald Anlauf <anlauf@gmx.de> + + PR fortran/107272 + * gfortran.dg/pr107272.f90: New test. + +2022-10-17 Tobias Burnus <tobias@codesourcery.com> + + PR fortran/107266 + * gfortran.dg/char4_decl.f90: New test. + * gfortran.dg/char4_decl-2.f90: New test. + +2022-10-17 Patrick Palka <ppalka@redhat.com> + + PR c++/101449 + * g++.dg/modules/cexpr-3_a.C: New test. + * g++.dg/modules/cexpr-3_b.C: New test. + +2022-10-17 Aldy Hernandez <aldyh@redhat.com> + + PR tree-optimization/105820 + * g++.dg/tree-ssa/pr105820.c: New test. + +2022-10-17 Aldy Hernandez <aldyh@redhat.com> + + * gcc.dg/tree-ssa/vrp-float-3a.c: New. + * gcc.dg/tree-ssa/vrp-float-4a.c: New. + * gcc.dg/tree-ssa/vrp-float-5a.c: New. + +2022-10-17 Richard Biener <rguenther@suse.de> + Ju-Zhe Zhong <juzhe.zhong@rivai.ai> + + PR tree-optimization/99409 + PR tree-optimization/99394 + * gcc.dg/vect/vect-recurr-1.c: New testcase. + * gcc.dg/vect/vect-recurr-2.c: Likewise. + * gcc.dg/vect/vect-recurr-3.c: Likewise. + * gcc.dg/vect/vect-recurr-4.c: Likewise. + * gcc.dg/vect/vect-recurr-5.c: Likewise. + * gcc.dg/vect/vect-recurr-6.c: Likewise. + * gcc.dg/vect/tsvc/vect-tsvc-s252.c: Un-XFAIL. + * gcc.dg/vect/tsvc/vect-tsvc-s254.c: Likewise. + * gcc.dg/vect/tsvc/vect-tsvc-s291.c: Likewise. + 2022-10-14 Joseph Myers <joseph@codesourcery.com> * gcc.dg/cpp/c2x-ucnid-1-utf8.c, gcc.dg/cpp/c2x-ucnid-1.c: New diff --git a/gcc/testsuite/c-c++-common/pointer-to-fn1.c b/gcc/testsuite/c-c++-common/pointer-to-fn1.c index 9758854..e2f948d 100644 --- a/gcc/testsuite/c-c++-common/pointer-to-fn1.c +++ b/gcc/testsuite/c-c++-common/pointer-to-fn1.c @@ -1,4 +1,5 @@ /* PR c++/106937 */ +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */ /* { dg-options "-fcf-protection" } */ /* { dg-additional-options "-std=c++11 -fpermissive" { target c++ } } */ /* Test printing a pointer to function with attribute. */ diff --git a/gcc/testsuite/c-c++-common/ubsan/pr106990.c b/gcc/testsuite/c-c++-common/ubsan/pr106990.c new file mode 100644 index 0000000..5bd46af --- /dev/null +++ b/gcc/testsuite/c-c++-common/ubsan/pr106990.c @@ -0,0 +1,29 @@ +/* PR tree-optimization/106990 */ +/* { dg-do run { target int32 } } */ +/* { dg-options "-fsanitize=signed-integer-overflow" } */ + +__attribute__((noipa)) int +foo (void) +{ + int x = -1956816001; + int y = 1999200512; + return ~x - ~y; +} + +__attribute__((noipa)) int +bar (void) +{ + int x = -__INT_MAX__ - 1; + return -x & 1; +} + +int +main () +{ + foo (); + bar (); + return 0; +} + +/* { dg-output "signed integer overflow: 1956816000 - -1999200513 cannot be represented in type 'int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself" } */ diff --git a/gcc/testsuite/g++.dg/cpp23/attr-assume5.C b/gcc/testsuite/g++.dg/cpp23/attr-assume5.C new file mode 100644 index 0000000..fec2209 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/attr-assume5.C @@ -0,0 +1,5 @@ +// P1774R8 - Portable assumptions +// { dg-do run { target c++11 } } +// { dg-options "-O2" } + +#include "attr-assume1.C" diff --git a/gcc/testsuite/g++.dg/cpp23/attr-assume6.C b/gcc/testsuite/g++.dg/cpp23/attr-assume6.C new file mode 100644 index 0000000..4a81df1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/attr-assume6.C @@ -0,0 +1,5 @@ +// P1774R8 - Portable assumptions +// { dg-do run { target c++11 } } +// { dg-options "-O2" } + +#include "attr-assume3.C" diff --git a/gcc/testsuite/g++.dg/cpp23/attr-assume7.C b/gcc/testsuite/g++.dg/cpp23/attr-assume7.C new file mode 100644 index 0000000..441242c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/attr-assume7.C @@ -0,0 +1,56 @@ +// P1774R8 - Portable assumptions +// { dg-do compile { target c++11 } } +// { dg-options "-O2" } + +int +foo (int x) +{ + [[assume (x == 42)]]; + return x; +} + +int +bar (int x) +{ + [[assume (++x == 43)]]; + return x; +} + +int +baz (int x) +{ + [[assume (({ int z = ++x; static int w; ++w; if (z == 51) return -1; if (z == 53) goto lab1; if (z == 64) throw 1; z == 43; }))]]; +lab1: + return x; +} + +struct S { S (); S (const S &); ~S (); int a, b; int foo (); }; + +int +qux () +{ + S s; + [[assume (s.a == 42 && s.b == 43)]]; + return s.a + s.b; +} + +int +S::foo () +{ + [[assume (a == 42 && b == 43)]]; + return a + b; +} + +int +corge (int x) +{ + [[assume (({ [[assume (x < 42)]]; x > -42; }))]]; + return x < 42; +} + +int +garply (int x) +{ + [[assume (({ [[assume (++x < 43)]]; x > -42; }))]]; + return x < 42; +} diff --git a/gcc/testsuite/g++.dg/modules/cexpr-3_a.C b/gcc/testsuite/g++.dg/modules/cexpr-3_a.C new file mode 100644 index 0000000..be24bb4 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cexpr-3_a.C @@ -0,0 +1,14 @@ +// PR c++/101449 +// { dg-additional-options -fmodules-ts } +// { dg-module-cmi pr101449 } + +export module pr101449; + +struct X { + bool b = true; + constexpr X() { } + constexpr X(const X&) { } +}; + +export constexpr X f() { return {}; } +export constexpr bool g(X x) { return x.b; } diff --git a/gcc/testsuite/g++.dg/modules/cexpr-3_b.C b/gcc/testsuite/g++.dg/modules/cexpr-3_b.C new file mode 100644 index 0000000..cbf3be4 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cexpr-3_b.C @@ -0,0 +1,7 @@ +// PR c++/101449 +// { dg-additional-options -fmodules-ts } + +import pr101449; + +static_assert(f().b); +static_assert(g(f())); diff --git a/gcc/testsuite/g++.dg/modules/pr105045_a.C b/gcc/testsuite/g++.dg/modules/pr105045_a.C new file mode 100644 index 0000000..597f929 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr105045_a.C @@ -0,0 +1,7 @@ +// PR c++/105045 +// { dg-additional-options -fmodules-ts } +// { dg-module-cmi pr105045 } + +export module pr105045; + +export template<int T=0, class U> void f(U) { } diff --git a/gcc/testsuite/g++.dg/modules/pr105045_b.C b/gcc/testsuite/g++.dg/modules/pr105045_b.C new file mode 100644 index 0000000..77c94d4 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr105045_b.C @@ -0,0 +1,6 @@ +// PR c++/105045 +// { dg-additional-options -fmodules-ts } + +import pr105045; + +int main() { f(0); } diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr105820.c b/gcc/testsuite/g++.dg/tree-ssa/pr105820.c new file mode 100644 index 0000000..507950f --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr105820.c @@ -0,0 +1,26 @@ +// { dg-do compile } +// { dg-options "-O2 -fstrict-enums --param case-values-threshold=1"} + +typedef int basic_block; + +enum gimple_code {}; + +struct omp_region { + omp_region *outer; + basic_block cont; +}; + +void +oof (void); + +void +build_omp_regions_1 (omp_region *parent, basic_block bb, gimple_code code) +{ + if (code == 2) + parent = parent->outer; + else if (code != 0) + parent->cont = bb; + + if (parent) + oof (); +} diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr107206.C b/gcc/testsuite/g++.dg/tree-ssa/pr107206.C new file mode 100644 index 0000000..34810ad --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr107206.C @@ -0,0 +1,27 @@ +// { dg-do compile } +// { dg-require-effective-target c++17 } +// { dg-options "-O -Wuninitialized" } + +#include <optional> +struct X { + X() = default; + X(X const& r) : i(r.i) {} + int i; +}; +struct Y { + Y() : x() {} + X x; + std::optional<int> o; +}; +struct Z { + Y y; + explicit Z(Y y) : y(y) {} +}; +void f(Y const&); +void test() { + Y const y; + Z z(y); + z.y.o = 1; + auto const w = z; + f(w.y); +} diff --git a/gcc/testsuite/gcc.dg/c11-enum-1.c b/gcc/testsuite/gcc.dg/c11-enum-1.c new file mode 100644 index 0000000..571041d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-enum-1.c @@ -0,0 +1,14 @@ +/* Test C2x enumerations with values not representable in int are diagnosed for + C11. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ + +enum e1 { e1a = -__LONG_LONG_MAX__ - 1 }; /* { dg-error "ISO C restricts enumerator values" } */ + +enum e2 { e2a = __LONG_LONG_MAX__ }; /* { dg-error "ISO C restricts enumerator values" } */ + +enum e3 { e3a = (unsigned int) -1 }; /* { dg-error "ISO C restricts enumerator values" } */ + +enum e4 { e4a = (long long) -__INT_MAX__ - 1, e4b = (unsigned int) __INT_MAX__ }; + +enum e5 { e5a = __INT_MAX__, e5b }; /* { dg-error "ISO C restricts enumerator values" } */ diff --git a/gcc/testsuite/gcc.dg/c11-enum-2.c b/gcc/testsuite/gcc.dg/c11-enum-2.c new file mode 100644 index 0000000..5b07c8d --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-enum-2.c @@ -0,0 +1,14 @@ +/* Test C2x enumerations with values not representable in int are diagnosed for + C11. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic" } */ + +enum e1 { e1a = -__LONG_LONG_MAX__ - 1 }; /* { dg-warning "ISO C restricts enumerator values" } */ + +enum e2 { e2a = __LONG_LONG_MAX__ }; /* { dg-warning "ISO C restricts enumerator values" } */ + +enum e3 { e3a = (unsigned int) -1 }; /* { dg-warning "ISO C restricts enumerator values" } */ + +enum e4 { e4a = (long long) -__INT_MAX__ - 1, e4b = (unsigned int) __INT_MAX__ }; + +enum e5 { e5a = __INT_MAX__, e5b }; /* { dg-warning "ISO C restricts enumerator values" } */ diff --git a/gcc/testsuite/gcc.dg/c11-enum-3.c b/gcc/testsuite/gcc.dg/c11-enum-3.c new file mode 100644 index 0000000..8266d4e --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-enum-3.c @@ -0,0 +1,14 @@ +/* Test C2x enumerations with values not representable in int are not diagnosed + for C11 with -pedantic-errors -Wno-c11-c2x-compat. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic-errors -Wno-c11-c2x-compat" } */ + +enum e1 { e1a = -__LONG_LONG_MAX__ - 1 }; + +enum e2 { e2a = __LONG_LONG_MAX__ }; + +enum e3 { e3a = (unsigned int) -1 }; + +enum e4 { e4a = (long long) -__INT_MAX__ - 1, e4b = (unsigned int) __INT_MAX__ }; + +enum e5 { e5a = __INT_MAX__, e5b }; diff --git a/gcc/testsuite/gcc.dg/c2x-enum-1.c b/gcc/testsuite/gcc.dg/c2x-enum-1.c new file mode 100644 index 0000000..c4371fa --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-enum-1.c @@ -0,0 +1,104 @@ +/* Test C2x enumerations with values not representable in int. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +/* Check a type while defining an enum (via a diagnostic for incompatible + pointer types if the wrong type was chosen). */ +#define TYPE_CHECK(cst, type) \ + cst ## _type_check = sizeof (1 ? (type *) 0 : (typeof (cst) *) 0) + +/* Test various explicit values not representable in int. */ + +enum e1 { e1a = -__LONG_LONG_MAX__ - 1, TYPE_CHECK (e1a, long long), + e1b = 0, TYPE_CHECK (e1b, int), + e1c = __LONG_LONG_MAX__, TYPE_CHECK (e1c, long long), + e1d = 1, TYPE_CHECK (e1d, int) }; +extern enum e1 e1v; +extern typeof (e1a) e1v; +extern typeof (e1b) e1v; +extern typeof (e1c) e1v; +extern typeof (e1d) e1v; +static_assert (sizeof (enum e1) >= sizeof (long long)); +static_assert (e1a == -__LONG_LONG_MAX__ - 1); +static_assert (e1b == 0); +static_assert (e1c == __LONG_LONG_MAX__); +static_assert (e1d == 1); +static_assert (e1a < 0); +static_assert (e1c > 0); + +/* This is a test where values are representable in int. */ +enum e2 { e2a = (long long) -__INT_MAX__ - 1, TYPE_CHECK (e2a, int), + e2b = (unsigned int) __INT_MAX__, TYPE_CHECK (e2b, int), + e2c = 2, TYPE_CHECK (e2c, int) }; +extern int e2v; +extern typeof (e2a) e2v; +extern typeof (e2b) e2v; +extern typeof (e2c) e2v; +static_assert (e2a == -__INT_MAX__ - 1); +static_assert (e2b == __INT_MAX__); +static_assert (e2c == 2); +static_assert (e2a < 0); +static_assert (e2b > 0); + +enum e3 { e3a = 0, TYPE_CHECK (e3a, int), + e3b = (unsigned int) -1, TYPE_CHECK (e3b, unsigned int) }; +extern enum e3 e3v; +extern typeof (e3a) e3v; +extern typeof (e3b) e3v; +static_assert (e3a == 0u); +static_assert (e3b == (unsigned int) -1); +static_assert (e3b > 0); + +/* Test handling of overflow and wraparound (choosing a wider type). */ +#if __LONG_LONG_MAX__ > __INT_MAX__ +enum e4 { e4a = __INT_MAX__, + e4b, e4c, e4d = ((typeof (e4b)) -1) < 0, + e4e = (unsigned int) -1, + e4f, e4g = ((typeof (e4e)) -1) > 0, + TYPE_CHECK (e4a, int), TYPE_CHECK (e4e, unsigned int) }; +extern enum e4 e4v; +extern typeof (e4a) e4v; +extern typeof (e4b) e4v; +extern typeof (e4c) e4v; +extern typeof (e4d) e4v; +extern typeof (e4e) e4v; +extern typeof (e4f) e4v; +extern typeof (e4g) e4v; +static_assert (e4a == __INT_MAX__); +static_assert (e4b == (long long) __INT_MAX__ + 1); +static_assert (e4c == (long long) __INT_MAX__ + 2); +static_assert (e4f == (unsigned long long) (unsigned int) -1 + 1); +/* Verify the type chosen on overflow of a signed type while parsing was + signed. */ +static_assert (e4d == 1); +/* Verify the type chosen on wraparound of an unsigned type while parsing was + unsigned. */ +static_assert (e4g == 1); +#endif + +/* Likewise, for overflow from long to long long. */ +#if __LONG_LONG_MAX__ > __LONG_MAX__ +enum e5 { e5a = __LONG_MAX__, + e5b, e5c, e5d = ((typeof (e5b)) -1) < 0, + e5e = (unsigned long) -1, + e5f, e5g = ((typeof (e5e)) -1) > 0, + TYPE_CHECK (e5a, long), TYPE_CHECK (e5e, unsigned long) }; +extern enum e5 e5v; +extern typeof (e5a) e5v; +extern typeof (e5b) e5v; +extern typeof (e5c) e5v; +extern typeof (e5d) e5v; +extern typeof (e5e) e5v; +extern typeof (e5f) e5v; +extern typeof (e5g) e5v; +static_assert (e5a == __LONG_MAX__); +static_assert (e5b == (long long) __LONG_MAX__ + 1); +static_assert (e5c == (long long) __LONG_MAX__ + 2); +static_assert (e5f == (unsigned long long) (unsigned long) -1 + 1); +/* Verify the type chosen on overflow of a signed type while parsing was + signed. */ +static_assert (e5d == 1); +/* Verify the type chosen on wraparound of an unsigned type while parsing was + unsigned. */ +static_assert (e5g == 1); +#endif diff --git a/gcc/testsuite/gcc.dg/c2x-enum-2.c b/gcc/testsuite/gcc.dg/c2x-enum-2.c new file mode 100644 index 0000000..15dcf9a --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-enum-2.c @@ -0,0 +1,14 @@ +/* Test C2x enumerations with values not representable in int. Test values + outside the range of standard or extended integer types are diagnosed, even + when they can be represented in __int128. */ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +enum e1 { e1a = __LONG_LONG_MAX__, e1b }; /* { dg-error "enumerator value outside the range" } */ + +enum e2 { e2a = __LONG_LONG_MAX__ * 2ULL + 1ULL, e2b }; /* { dg-error "enumerator value outside the range" } */ + +/* Likewise, when it's the enum as a whole that can't fit in any standard or + extended type, but the individual enumerators fit (some fitting a signed + type and some fitting an unsigned type). */ +enum e3 { e3a = -__LONG_LONG_MAX__ - 1, e3b = __LONG_LONG_MAX__ * 2ULL + 1ULL }; /* { dg-error "enumeration values exceed range of 'intmax_t'" } */ diff --git a/gcc/testsuite/gcc.dg/c2x-enum-3.c b/gcc/testsuite/gcc.dg/c2x-enum-3.c new file mode 100644 index 0000000..532d977 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-enum-3.c @@ -0,0 +1,14 @@ +/* Test C2x enumerations with values not representable in int. Test values + outside the range of standard or extended integer types are diagnosed, + when __int128 is unsupported. */ +/* { dg-do compile { target { ! int128 } } } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +enum e1 { e1a = __LONG_LONG_MAX__, e1b }; /* { dg-error "overflow in enumeration values" } */ + +enum e2 { e2a = __LONG_LONG_MAX__ * 2ULL + 1ULL, e2b }; /* { dg-error "overflow in enumeration values" } */ + +/* Likewise, when it's the enum as a whole that can't fit in any standard or + extended type, but the individual enumerators fit (some fitting a signed + type and some fitting an unsigned type). */ +enum e3 { e3a = -__LONG_LONG_MAX__ - 1, e3b = __LONG_LONG_MAX__ * 2ULL + 1ULL }; /* { dg-error "enumeration values exceed range of largest integer" } */ diff --git a/gcc/testsuite/gcc.dg/c2x-enum-4.c b/gcc/testsuite/gcc.dg/c2x-enum-4.c new file mode 100644 index 0000000..c2e58bf --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-enum-4.c @@ -0,0 +1,14 @@ +/* Test C2x enumerations with values not representable in int. Test overflow + of __int128 is diagnosed. */ +/* { dg-do compile { target { int128 } } } */ +/* { dg-options "-std=c2x" } */ + +enum e1 { e1a = (__int128) (((unsigned __int128) -1) >> 1), e1b }; /* { dg-error "overflow in enumeration values" } */ + +enum e2 { e2a = (unsigned __int128) -1, e2b }; /* { dg-error "overflow in enumeration values" } */ + +/* Likewise, when it's the enum as a whole that can't fit in __int128 or + unsigned __int128, but the individual enumerators fit (some fitting __int128 + and some fitting unsigned __int128). */ +enum e3 { e3a = -(__int128) (((unsigned __int128) -1) >> 1) - 1, + e3b = (unsigned __int128) -1 }; /* { dg-warning "enumeration values exceed range of largest integer" } */ diff --git a/gcc/testsuite/gcc.dg/c2x-enum-5.c b/gcc/testsuite/gcc.dg/c2x-enum-5.c new file mode 100644 index 0000000..a4290f0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-enum-5.c @@ -0,0 +1,12 @@ +/* Test C2x enumerations with values not representable in int. Test + -Wc11-c2x-compat warnings. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x -pedantic-errors -Wc11-c2x-compat" } */ + +enum e1 { e1a = -__LONG_LONG_MAX__ - 1 }; /* { dg-warning "ISO C restricts enumerator values" } */ + +enum e2 { e2a = __LONG_LONG_MAX__ }; /* { dg-warning "ISO C restricts enumerator values" } */ + +enum e3 { e3a = (unsigned int) -1 }; /* { dg-warning "ISO C restricts enumerator values" } */ + +enum e4 { e4a = (long long) -__INT_MAX__ - 1, e4b = (unsigned int) __INT_MAX__ }; diff --git a/gcc/testsuite/gcc.dg/c99-tag-4.c b/gcc/testsuite/gcc.dg/c99-tag-4.c new file mode 100644 index 0000000..9ff3ccb --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-tag-4.c @@ -0,0 +1,8 @@ +/* Test for handling of tags. "enum foo;" is invalid after an existing + declaration (does not redeclare the tag) as well as before: bug 107164. */ +/* { dg-do compile } */ +/* { dg-options "-std=c99 -pedantic-errors" } */ + +enum e1; /* { dg-error "ISO C forbids forward references to 'enum' types" } */ +enum e2 { E }; +enum e2; /* { dg-error "empty declaration of 'enum' type does not redeclare tag" } */ diff --git a/gcc/testsuite/gcc.dg/c99-tag-5.c b/gcc/testsuite/gcc.dg/c99-tag-5.c new file mode 100644 index 0000000..97fcc75 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-tag-5.c @@ -0,0 +1,8 @@ +/* Test for handling of tags. "enum foo;" is invalid after an existing + declaration (does not redeclare the tag) as well as before: bug 107164. */ +/* { dg-do compile } */ +/* { dg-options "-std=c99 -pedantic" } */ + +enum e1; /* { dg-warning "ISO C forbids forward references to 'enum' types" } */ +enum e2 { E }; +enum e2; /* { dg-warning "empty declaration of 'enum' type does not redeclare tag" } */ diff --git a/gcc/testsuite/gcc.dg/c99-tag-6.c b/gcc/testsuite/gcc.dg/c99-tag-6.c new file mode 100644 index 0000000..8307217 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-tag-6.c @@ -0,0 +1,9 @@ +/* Test for handling of tags. "enum foo;" is invalid after an existing + declaration (does not redeclare the tag) as well as before: bug 107164. + Test this is not diagnosed without -pedantic. */ +/* { dg-do compile } */ +/* { dg-options "-std=c99" } */ + +enum e1; +enum e2 { E }; +enum e2; diff --git a/gcc/testsuite/gcc.dg/ipa/ipcp-agg-11.c b/gcc/testsuite/gcc.dg/ipa/ipcp-agg-11.c index 3c496ee..48bf772 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipcp-agg-11.c +++ b/gcc/testsuite/gcc.dg/ipa/ipcp-agg-11.c @@ -73,5 +73,5 @@ entry () /* { dg-final { scan-ipa-dump "offset: 0, type: int, CONST: 101" "cp" } } */ /* { dg-final { scan-ipa-dump "offset: 32, type: int, PASS THROUGH: 0, op trunc_mod_expr 7" "cp" } } */ /* { dg-final { scan-ipa-dump "offset: 64, type: int, LOAD AGG: 1 \\\[offset: 0, by reference], op plus_expr 6" "cp" } } */ -/* { dg-final { scan-ipa-dump "Aggregate replacements: 0\\\[0]=1, 0\\\[32]=105, 0\\\[64]=-18" "cp" } } */ -/* { dg-final { scan-ipa-dump "Aggregate replacements: 0\\\[0]=101, 0\\\[32]=2, 0\\\[64]=9" "cp" } } */ +/* { dg-final { scan-ipa-dump "Aggregate replacements: 0\\\[0]=1\\(by_ref\\), 0\\\[4]=105\\(by_ref\\), 0\\\[8]=-18\\(by_ref\\)" "cp" } } */ +/* { dg-final { scan-ipa-dump "Aggregate replacements: 0\\\[0]=101, 0\\\[4]=2, 0\\\[8]=9" "cp" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipcp-agg-8.c b/gcc/testsuite/gcc.dg/ipa/ipcp-agg-8.c index 2d9c82f..8234702 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipcp-agg-8.c +++ b/gcc/testsuite/gcc.dg/ipa/ipcp-agg-8.c @@ -48,5 +48,5 @@ entry (int c) foo (4, i, &s); } } -/* { dg-final { scan-ipa-dump "Aggregate replacements: 1\\\[32]=64, 1\\\[64]=32" "cp" } } */ -/* { dg-final { scan-ipa-dump "Aggregate replacements: 1\\\[32]=0" "cp" } } */ +/* { dg-final { scan-ipa-dump "Aggregate replacements: 1\\\[4]=64\\(by_ref\\), 1\\\[8]=32\\(by_ref\\)" "cp" } } */ +/* { dg-final { scan-ipa-dump "Aggregate replacements: 1\\\[4]=0\\(by_ref\\)" "cp" } } */ diff --git a/gcc/testsuite/gcc.dg/pr106781.c b/gcc/testsuite/gcc.dg/pr106781.c new file mode 100644 index 0000000..339c28c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr106781.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wno-div-by-zero" } */ + +int n; + +__attribute__ ((noinline, returns_twice)) static int +bar (int) +{ + n /= 0; + + return n; +} + +int +foo (int x) +{ + return bar (x); +} diff --git a/gcc/testsuite/gcc.dg/pr107262.c b/gcc/testsuite/gcc.dg/pr107262.c new file mode 100644 index 0000000..2ced047 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr107262.c @@ -0,0 +1,13 @@ +/* PR middle-end/107262 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -ffast-math" } */ +/* { dg-add-options bfloat16 } */ +/* { dg-require-effective-target bfloat16_runtime } */ + +__bf16 +foo (__bf16 a) +{ + __bf16 b = 0; + b /= a; + return b; +} diff --git a/gcc/testsuite/gcc.dg/pr30260.c b/gcc/testsuite/gcc.dg/pr30260.c index e04a8be..3fac38e 100644 --- a/gcc/testsuite/gcc.dg/pr30260.c +++ b/gcc/testsuite/gcc.dg/pr30260.c @@ -1,6 +1,6 @@ /* PR 30260 */ /* { dg-do link } */ -/* { dg-options "-pedantic -O" } */ +/* { dg-options "-std=gnu11 -pedantic -O" } */ #include <limits.h> void link_error (void); @@ -30,5 +30,5 @@ int main(void) return 0; } -enum E1 { e10 = INT_MAX, e11 }; /* { dg-error "overflow in enumeration values" } */ -enum E2 { e20 = (unsigned) INT_MAX, e21 }; /* { dg-error "overflow in enumeration values" } */ +enum E1 { e10 = INT_MAX, e11 }; /* { dg-warning "ISO C restricts enumerator values to range of 'int' before C2X" } */ +enum E2 { e20 = (unsigned) INT_MAX, e21 }; /* { dg-warning "ISO C restricts enumerator values to range of 'int' before C2X" } */ diff --git a/gcc/testsuite/gcc.dg/torture/pr107301.c b/gcc/testsuite/gcc.dg/torture/pr107301.c new file mode 100644 index 0000000..5f0afcc --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr107301.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +__attribute__ ((pure, returns_twice)) int +foo (int x) +{ + int a; + + a = x ? 3 : 0; + x /= a; + a = foo (x); + if (x == a) + __builtin_unreachable (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr25183.c b/gcc/testsuite/gcc.dg/torture/pr25183.c index 0157b80..84b4c8f 100644 --- a/gcc/testsuite/gcc.dg/torture/pr25183.c +++ b/gcc/testsuite/gcc.dg/torture/pr25183.c @@ -3,10 +3,10 @@ enum err { err_IO = 0x8a450000, /* { dg-warning "int" } */ - err_NM, - err_EOF, - err_SE, - err_PT + err_NM, /* { dg-warning "int" } */ + err_EOF, /* { dg-warning "int" } */ + err_SE, /* { dg-warning "int" } */ + err_PT /* { dg-warning "int" } */ }; static enum err E_; int error() diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-19.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-19.c index 4d77138..6ca81cb 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-19.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-19.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O -fdump-tree-forwprop1" } */ +/* { dg-options "-O -fdump-tree-dse1" } */ typedef int vec __attribute__((vector_size (4 * sizeof (int)))); void f (vec *x1, vec *x2) @@ -11,4 +11,4 @@ void f (vec *x1, vec *x2) *x1 = z; } -/* { dg-final { scan-tree-dump-not "VEC_PERM_EXPR" "forwprop1" } } */ +/* { dg-final { scan-tree-dump-not "VEC_PERM_EXPR" "dse1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr107273-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr107273-1.c new file mode 100644 index 0000000..db2e2c0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr107273-1.c @@ -0,0 +1,31 @@ +/* { dg-do run } */ +/* { dg-options "-O3" } */ + +int printf(const char *, ...); +int a[1] = {1}; +short b, c = 5500; +int d; +long e; +char f = 1; +int main() { + while (1) { + long g = b < 1; + e = g; + break; + } + for (; f; f--) { + if (e) { + d = -(6L | -(c & 1000)); + } + char h = d; + if (b) + b = 0; + if (d < 200) + while (1) + printf("%d", a[c]); + short i = h * 210; + c = i; + } + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr107273-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr107273-2.c new file mode 100644 index 0000000..3374507 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr107273-2.c @@ -0,0 +1,27 @@ +/* { dg-do run } */ +/* { dg-options "-Os" } */ + +int a, d, f; +char b, g; +unsigned i; +int main() { + int c = 300, h = 40; + char e = 1; + for (; a < 1; a++) { + c = ~((i - ~c) | e); + L1: + e = f = c; + if (c) + if (c > -200) + e = g % (1 << h); + char k = 0; + L2:; + } + if (b) { + if (d) + goto L2; + if (!b) + goto L1; + } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr107293.c b/gcc/testsuite/gcc.dg/tree-ssa/pr107293.c new file mode 100644 index 0000000..724c31a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr107293.c @@ -0,0 +1,32 @@ +// { dg-do run } +// { dg-options "-w -Os" } + +short a; +int b[1]; + +int c(int p) { + return (p < 0) ? 0 : 10 + ((p / 100 - 16) / 4); +} + +void f(int n) { + while (1) { + int m = n; + while ((m ) ) + m /= 2; + break; + } +} + +void g() { + int h = a = 0; + for (; h + a <= 0; a++) { + if (b[c(a - 6)]) + break; + f(a); + } +} +int main() { + g(); + if (a != 1) + __builtin_abort (); +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3a.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3a.c new file mode 100644 index 0000000..5aadaa7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3a.c @@ -0,0 +1,19 @@ +// { dg-do compile } +// { dg-options "-O2 -fno-thread-jumps -fdisable-tree-fre1 -fdump-tree-evrp" } + +void link_error (); +void bar (); + +float +foo (float x) +{ + if (x != x) + { + // The true side of x != x implies NAN, so we should be able to + // fold this. + if (!__builtin_isnan (x)) + link_error (); + } +} + +// { dg-final { scan-tree-dump-not "link_error" "evrp" } } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4a.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4a.c new file mode 100644 index 0000000..7d3187b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4a.c @@ -0,0 +1,23 @@ +// { dg-do compile } +// { dg-options "-O2 -fno-thread-jumps -fdisable-tree-fre1 -fdump-tree-evrp" } + +void link_error (); +void bar (); + +float +foo (float x) +{ + if (x == x) + { + bar (); + } + else + { + // The false side of x == x implies NAN, so we should be able to + // fold this. + if (!__builtin_isnan (x)) + link_error (); + } +} + +// { dg-final { scan-tree-dump-not "link_error" "evrp" } } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-5a.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-5a.c new file mode 100644 index 0000000..0833230 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-5a.c @@ -0,0 +1,16 @@ +// { dg-do compile } +// { dg-options "-O2 -fno-thread-jumps -fdisable-tree-fre1 -fdump-tree-evrp" } + +void link_error (); + +float +foo (float x) +{ + if (__builtin_isnan (x)) + { + if (!__builtin_isnan (x)) + link_error (); + } +} + +// { dg-final { scan-tree-dump-not "link_error" "evrp" } } diff --git a/gcc/testsuite/gcc.dg/vect/pr107275.c b/gcc/testsuite/gcc.dg/vect/pr107275.c new file mode 100644 index 0000000..16327c4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr107275.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +struct st +{ + int a : 1; +}; + +void +foo (struct st *s, int n) +{ + for (int i = 0; i < n; ++i) + { + s[i].a = i; + __asm__ __volatile__ ("":::"memory"); + } +} diff --git a/gcc/testsuite/gcc.dg/vect/pr107302.c b/gcc/testsuite/gcc.dg/vect/pr107302.c new file mode 100644 index 0000000..293f7e4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr107302.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fno-tree-pre" } */ + +int a[2000]; +int s292_im1; + +void +s292() { + for (int i = 0; i < 2000; i++) { + a[i] = s292_im1; + s292_im1 = i; + } +} diff --git a/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s252.c b/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s252.c index f1302b6..83eaa7a 100644 --- a/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s252.c +++ b/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s252.c @@ -40,4 +40,4 @@ int main (int argc, char **argv) return 0; } -/* { dg-final { scan-tree-dump "vectorized 1 loops" "vect" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump "vectorized 1 loops" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s254.c b/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s254.c index bdc8a01..06e9b0a 100644 --- a/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s254.c +++ b/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s254.c @@ -39,4 +39,4 @@ int main (int argc, char **argv) return 0; } -/* { dg-final { scan-tree-dump "vectorized 1 loops" "vect" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump "vectorized 1 loops" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s291.c b/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s291.c index 0b474c2..91cdc12 100644 --- a/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s291.c +++ b/gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s291.c @@ -39,4 +39,4 @@ int main (int argc, char **argv) return 0; } -/* { dg-final { scan-tree-dump "vectorized 1 loops" "vect" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump "vectorized 1 loops" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-recurr-1.c b/gcc/testsuite/gcc.dg/vect/vect-recurr-1.c new file mode 100644 index 0000000..6eb59fd --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-recurr-1.c @@ -0,0 +1,38 @@ +/* { dg-do run } */ +/* { dg-require-effective-target vect_int } */ + +#include "tree-vect.h" + +void __attribute__((noipa)) +foo (int * __restrict__ a, int * __restrict__ b, int * __restrict__ c) +{ + int t = *c; + for (int i = 0; i < 64; ++i) + { + b[i] = a[i] - t; + t = a[i]; + } +} + +int a[64], b[64]; + +int +main () +{ + check_vect (); + for (int i = 0; i < 64; ++i) + { + a[i] = i; + __asm__ volatile ("" ::: "memory"); + } + int c = 7; + foo (a, b, &c); + for (int i = 1; i < 64; ++i) + if (b[i] != a[i] - a[i-1]) + abort (); + if (b[0] != -7) + abort (); + return 0; +} + +/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-recurr-2.c b/gcc/testsuite/gcc.dg/vect/vect-recurr-2.c new file mode 100644 index 0000000..97efaaa --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-recurr-2.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-require-effective-target vect_int } */ + +#include "tree-vect.h" + +void __attribute__((noipa)) +foo (int * __restrict__ a, short * __restrict__ b, int * __restrict__ c) +{ + int t = *c; + for (int i = 0; i < 64; ++i) + { + b[i] = a[i] - t; + t = a[i]; + } +} + +int a[64]; +short b[64]; + +int +main () +{ + check_vect (); + for (int i = 0; i < 64; ++i) + { + a[i] = i; + __asm__ volatile ("" ::: "memory"); + } + int c = 7; + foo (a, b, &c); + for (int i = 1; i < 64; ++i) + if (b[i] != a[i] - a[i-1]) + abort (); + if (b[0] != -7) + abort (); + return 0; +} + +/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-recurr-3.c b/gcc/testsuite/gcc.dg/vect/vect-recurr-3.c new file mode 100644 index 0000000..621a5d8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-recurr-3.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-require-effective-target vect_int } */ + +#include "tree-vect.h" + +void __attribute__((noipa)) +foo (int * __restrict__ a, signed char * __restrict__ b, int * __restrict__ c) +{ + int t = *c; + for (int i = 0; i < 64; ++i) + { + b[i] = a[i] - t; + t = a[i]; + } +} + +int a[64]; +signed char b[64]; + +int +main () +{ + check_vect (); + for (int i = 0; i < 64; ++i) + { + a[i] = i; + __asm__ volatile ("" ::: "memory"); + } + int c = 7; + foo (a, b, &c); + for (int i = 1; i < 64; ++i) + if (b[i] != a[i] - a[i-1]) + abort (); + if (b[0] != -7) + abort (); + return 0; +} + +/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-recurr-4.c b/gcc/testsuite/gcc.dg/vect/vect-recurr-4.c new file mode 100644 index 0000000..f6dbc49 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-recurr-4.c @@ -0,0 +1,42 @@ +/* { dg-do run } */ +/* { dg-require-effective-target vect_int } */ + +#include "tree-vect.h" + +void __attribute__((noipa)) +foo (int * __restrict__ a, int * __restrict__ b, int * __restrict__ c) +{ + int t1 = *c; + int t2 = *c; + for (int i = 0; i < 64; i+=2) + { + b[i] = a[i] - t1; + t1 = a[i]; + b[i+1] = a[i+1] - t2; + t2 = a[i+1]; + } +} + +int a[64], b[64]; + +int +main () +{ + check_vect (); + for (int i = 0; i < 64; ++i) + { + a[i] = i; + __asm__ volatile ("" ::: "memory"); + } + int c = 7; + foo (a, b, &c); + for (int i = 2; i < 64; i+=2) + if (b[i] != a[i] - a[i-2] + || b[i+1] != a[i+1] - a[i-1]) + abort (); + if (b[0] != -7 || b[1] != -6) + abort (); + return 0; +} + +/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-recurr-5.c b/gcc/testsuite/gcc.dg/vect/vect-recurr-5.c new file mode 100644 index 0000000..19c56df --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-recurr-5.c @@ -0,0 +1,43 @@ +/* { dg-do run } */ +/* { dg-require-effective-target vect_int } */ + +#include "tree-vect.h" + +void __attribute__((noipa)) +foo (int * __restrict__ a, short * __restrict__ b, int * __restrict__ c) +{ + int t1 = *c; + int t2 = *c; + for (int i = 0; i < 64; i+=2) + { + b[i] = a[i] - t1; + t1 = a[i]; + b[i+1] = a[i+1] - t2; + t2 = a[i+1]; + } +} + +int a[64]; +short b[64]; + +int +main () +{ + check_vect (); + for (int i = 0; i < 64; ++i) + { + a[i] = i; + __asm__ volatile ("" ::: "memory"); + } + int c = 7; + foo (a, b, &c); + for (int i = 2; i < 64; i+=2) + if (b[i] != a[i] - a[i-2] + || b[i+1] != a[i+1] - a[i-1]) + abort (); + if (b[0] != -7 || b[1] != -6) + abort (); + return 0; +} + +/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-recurr-6.c b/gcc/testsuite/gcc.dg/vect/vect-recurr-6.c new file mode 100644 index 0000000..e771268 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-recurr-6.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-require-effective-target vect_int } */ + +#include "tree-vect.h" + +void __attribute__((noipa)) +foo (int * __restrict__ a, int * __restrict__ b, int * __restrict__ c, int n) +{ + int t = *c; + for (int i = 0; i < n; ++i) + { + b[i] = a[i] - t; + t = a[i]; + } +} + +int a[64], b[64]; + +int +main () +{ + check_vect (); + for (int i = 0; i < 64; ++i) + { + a[i] = i; + __asm__ volatile ("" ::: "memory"); + } + int c = 7; + foo (a, b, &c, 63); + for (int i = 1; i < 63; ++i) + if (b[i] != a[i] - a[i-1]) + abort (); + if (b[0] != -7) + abort (); + return 0; +} + +/* ??? We miss epilogue handling for first order recurrences. */ +/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" { target vect_fully_masked } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr107271.c b/gcc/testsuite/gcc.target/i386/pr107271.c new file mode 100644 index 0000000..fe89c9a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr107271.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ + +typedef int __attribute__((__vector_size__ (16))) V; + +static inline __attribute__((__always_inline__)) V +bar (V v128u32_0) +{ + return __builtin_shuffle ((V){}, v128u32_0, v128u32_0); +} + +V +foo (void) +{ + return bar ((V){7, 4, 4}); +} diff --git a/gcc/testsuite/gcc.target/s390/pr106355-1.c b/gcc/testsuite/gcc.target/s390/pr106355-1.c new file mode 100644 index 0000000..1ec0f6b --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr106355-1.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-foptimize-sibling-calls" } */ +/* { dg-final { scan-assembler {brasl\t%r\d+,bar4} } } */ +/* { dg-final { scan-assembler {brasl\t%r\d+,bar8} } } */ + +/* Parameter E is passed in GPR 6 which is call-saved which prohibits + sibling call optimization. This must hold true also if the mode of the + parameter is BLKmode. */ + +/* 4 byte */ + +typedef struct +{ + char x; + char y[3]; +} t4; + +extern t4 e4; + +extern void bar4 (int a, int b, int c, int d, t4 e4); + +void foo4 (int a, int b, int c, int d) +{ + bar4 (a, b, c, d, e4); +} + +/* 8 byte */ + +typedef struct +{ + short x; + char y[6]; +} t8; + +extern t8 e8; + +extern void bar8 (int a, int b, int c, int d, t8 e8); + +void foo8 (int a, int b, int c, int d) +{ + bar8 (a, b, c, d, e8); +} diff --git a/gcc/testsuite/gcc.target/s390/pr106355-2.c b/gcc/testsuite/gcc.target/s390/pr106355-2.c new file mode 100644 index 0000000..ddbdba5 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr106355-2.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target { s390-*-* } } } */ +/* { dg-options "-foptimize-sibling-calls -mzarch" } */ +/* { dg-final { scan-assembler {brasl\t%r\d+,bar} } } */ + +/* This tests function s390_call_saved_register_used where + GET_CODE (parm_rtx) == PARALLEL holds. */ + +#include "pr106355.h" diff --git a/gcc/testsuite/gcc.target/s390/pr106355-3.c b/gcc/testsuite/gcc.target/s390/pr106355-3.c new file mode 100644 index 0000000..39daea4 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr106355-3.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target { s390-*-* } } } */ +/* { dg-options "-foptimize-sibling-calls -mesa" } */ +/* { dg-final { scan-assembler {brasl\t%r\d+,bar} } } */ + +/* This tests function s390_call_saved_register_used where + REG_P (parm_rtx) and nregs == 2 holds. */ + +#include "pr106355.h" diff --git a/gcc/testsuite/gcc.target/s390/pr106355.h b/gcc/testsuite/gcc.target/s390/pr106355.h new file mode 100644 index 0000000..362908e --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr106355.h @@ -0,0 +1,18 @@ +/* For the S/390 ABI parameter D is passed in GPR 5 and 6 and the latter is + call-saved which prohibits sibling call optimization. This must hold true + also if the mode of the parameter is BLKmode. */ + +typedef struct +{ + short x; + char y[6]; +} t; + +extern t d; + +extern void bar (int a, int b, int c, t d); + +void foo (int a, int b, int c) +{ + bar (a, b, c, d); +} diff --git a/gcc/testsuite/gfortran.dg/array_constructor_56.f90 b/gcc/testsuite/gfortran.dg/array_constructor_56.f90 new file mode 100644 index 0000000..4701fb3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/array_constructor_56.f90 @@ -0,0 +1,22 @@ +! { dg-do compile } +! +! Test the fix for the following: +! PR fortran/93483 +! PR fortran/107216 +! PR fortran/107219 +! +! Contributed by G.Steinmetz + +program p + real, parameter :: r0(*) = +[real :: +(1) ] + real, parameter :: r1(*) = +[real :: +[1] ] + real, parameter :: r2(*) = -[real :: [(1)]] + real, parameter :: r3(*) = +[real :: [-(1)]] + real, parameter :: r4(*) = -[real :: [[(1)]]] + real, parameter :: r5(*) = -[real :: -[1, 2]] + real, parameter :: r6(*) = +[real :: +[1, 2]] + real, parameter :: r7(*) = [real :: 1, 2] * [real :: 1, (2)] + real, parameter :: r8(*) = [real :: 1, (2)] * [real :: 1, 2] + real, parameter :: r9(*) = +[real :: 1, 2] * [real :: 1, (2)] + real, parameter :: rr(*) = -[real :: 1, (2)] * [real :: 1, 2] +end diff --git a/gcc/testsuite/gfortran.dg/array_constructor_57.f90 b/gcc/testsuite/gfortran.dg/array_constructor_57.f90 new file mode 100644 index 0000000..1298c09 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/array_constructor_57.f90 @@ -0,0 +1,30 @@ +! { dg-do run } +! PR fortran/93483 +! +! Verify that resolution (host associated parameter vs. contained function) works. +! +! Contributed by Mikael Morin + +module m + implicit none + integer, parameter :: a(*) = [ 7, 11 ] +contains + subroutine bug + real :: b(1), c(1) + b = [ real :: (a(1)) ] + c = [ real :: a(1) ] + print *, b, c + if (any (b /= [ 14. ])) stop 1 + if (any (c /= [ 14. ])) stop 2 + contains + function a(c) + integer :: a, c + a = c + 13 + end function a + end subroutine bug +end module m + +program p + use m + call bug +end program p diff --git a/gcc/testsuite/gfortran.dg/char4_decl-2.f90 b/gcc/testsuite/gfortran.dg/char4_decl-2.f90 new file mode 100644 index 0000000..d646161 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/char4_decl-2.f90 @@ -0,0 +1,63 @@ +! { dg-do run } +! { dg-additional-options "-fdump-tree-original" } + +! In this program shall be no kind=1, +! except for the 'argv' of the 'main' program. + +! PR fortran/107266 + +! { dg-final { scan-tree-dump-times "kind=1" 1 "original" } } +! { dg-final { scan-tree-dump-times "character\\(kind=1\\) \\* \\* argv\\)" 1 "original" } } + + +! { dg-final { scan-tree-dump-times "character\\(kind=4\\) f \\(character\\(kind=4\\) x\\)" 1 "original" } } + +character(kind=4) function f(x) bind(C) + character(kind=4), value :: x +end + +program testit + implicit none (type, external) + character (kind=4, len=:), allocatable :: aa + character (kind=4, len=:), pointer :: pp + + pp => NULL () + + call frobf (aa, pp) + if (.not. allocated (aa)) stop 101 + if (storage_size(aa) /= storage_size(4_'foo')) stop 1 + if (aa .ne. 4_'foo') stop 102 + if (.not. associated (pp)) stop 103 + if (storage_size(pp) /= storage_size(4_'bar')) stop 2 + if (pp .ne. 4_'bar') stop 104 + + pp => NULL () + + call frobc (aa, pp) + if (.not. allocated (aa)) stop 105 + if (storage_size(aa) /= storage_size(4_'frog')) stop 3 + if (aa .ne. 4_'frog') stop 106 + if (.not. associated (pp)) stop 107 + if (storage_size(pp) /= storage_size(4_'toad')) stop 4 + if (pp .ne. 4_'toad') stop 108 + + + contains + + subroutine frobf (a, p) Bind(C) + character (kind=4, len=:), allocatable :: a + character (kind=4, len=:), pointer :: p + allocate (character(kind=4, len=3) :: p) + a = 4_'foo' + p = 4_'bar' + end subroutine + + subroutine frobc (a, p) Bind(C) + character (kind=4, len=:), allocatable :: a + character (kind=4, len=:), pointer :: p + allocate (character(kind=4, len=4) :: p) + a = 4_'frog' + p = 4_'toad' + end subroutine + +end program diff --git a/gcc/testsuite/gfortran.dg/char4_decl.f90 b/gcc/testsuite/gfortran.dg/char4_decl.f90 new file mode 100644 index 0000000..bb6b6a8 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/char4_decl.f90 @@ -0,0 +1,56 @@ +! { dg-do run } +! { dg-additional-options "-fdump-tree-original" } + +! In this program shall be no kind=1, +! except for the 'argv' of the 'main' program. + +! Related PR fortran/107266 + +! { dg-final { scan-tree-dump-times "kind=1" 1 "original" } } +! { dg-final { scan-tree-dump-times "character\\(kind=1\\) \\* \\* argv\\)" 1 "original" } } + +program testit + implicit none (type, external) + character (kind=4, len=:), allocatable :: aa + character (kind=4, len=:), pointer :: pp + + pp => NULL () + + call frobf (aa, pp) + if (.not. allocated (aa)) stop 101 + if (storage_size(aa) /= storage_size(4_'foo')) stop 1 + if (aa .ne. 4_'foo') stop 102 + if (.not. associated (pp)) stop 103 + if (storage_size(pp) /= storage_size(4_'bar')) stop 2 + if (pp .ne. 4_'bar') stop 104 + + pp => NULL () + + call frobc (aa, pp) + if (.not. allocated (aa)) stop 105 + if (storage_size(aa) /= storage_size(4_'frog')) stop 3 + if (aa .ne. 4_'frog') stop 106 + if (.not. associated (pp)) stop 107 + if (storage_size(pp) /= storage_size(4_'toad')) stop 4 + if (pp .ne. 4_'toad') stop 108 + + + contains + + subroutine frobf (a, p) + character (kind=4, len=:), allocatable :: a + character (kind=4, len=:), pointer :: p + allocate (character(kind=4, len=3) :: p) + a = 4_'foo' + p = 4_'bar' + end subroutine + + subroutine frobc (a, p) + character (kind=4, len=:), allocatable :: a + character (kind=4, len=:), pointer :: p + allocate (character(kind=4, len=4) :: p) + a = 4_'frog' + p = 4_'toad' + end subroutine + +end program diff --git a/gcc/testsuite/gfortran.dg/pr104330.f90 b/gcc/testsuite/gfortran.dg/pr104330.f90 new file mode 100644 index 0000000..9ff48e2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr104330.f90 @@ -0,0 +1,20 @@ +! { dg-do compile } +! { dg-options "-fcoarray=lib" } +! +! PR fortran/104330 - ICE in gfc_simplify_image_index +! Contributed by G.Steinmetz + +program p + implicit none + type t + end type t + class(*), allocatable :: x[:] + class(t), allocatable :: y[:] + type(t), allocatable :: z[:] + allocate (real :: x[*]) + print *, image_index(x, [1]) + allocate (t :: y[*]) + print *, image_index(y, [1]) + allocate (t :: z[*]) + print *, image_index(z, [1]) +end diff --git a/gcc/testsuite/gfortran.dg/pr107272.f90 b/gcc/testsuite/gfortran.dg/pr107272.f90 new file mode 100644 index 0000000..4b5c6a0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr107272.f90 @@ -0,0 +1,21 @@ +! { dg-do compile } +! PR fortran/107272 - followup of PR/107217 for non-numeric types + +program p + print *, 2 <= [real :: (['1'])] ! { dg-error "Cannot convert" } + print *, 2 < [real :: (['1'])] ! { dg-error "Cannot convert" } + print *, 2 == [real :: (['1'])] ! { dg-error "Cannot convert" } + print *, 2 /= [real :: (['1'])] ! { dg-error "Cannot convert" } + print *, 2 >= [real :: (['1'])] ! { dg-error "Cannot convert" } + print *, 2 > [real :: (['1'])] ! { dg-error "Cannot convert" } + print *, [real :: (['1'])] >= 2 ! { dg-error "Cannot convert" } + print *, [real :: (['1'])] > 2 ! { dg-error "Cannot convert" } + print *, [real :: (['1'])] == 2 ! { dg-error "Cannot convert" } + print *, [real :: (['1'])] /= 2 ! { dg-error "Cannot convert" } + print *, [real :: (['1'])] <= 2 ! { dg-error "Cannot convert" } + print *, [real :: (['1'])] < 2 ! { dg-error "Cannot convert" } + print *, [logical :: (['1'])] .and. .true. ! { dg-error "Cannot convert" } + print *, [logical :: (['1'])] .or. .true. ! { dg-error "Cannot convert" } + print *, [logical :: (['1'])] .eqv. .true. ! { dg-error "Cannot convert" } + print *, [logical :: (['1'])] .neqv. .true. ! { dg-error "Cannot convert" } +end diff --git a/gcc/timevar.def b/gcc/timevar.def index eac4370..63d9b00 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -226,6 +226,7 @@ DEFTIMEVAR (TV_TREE_WIDEN_MUL , "gimple widening/fma detection") DEFTIMEVAR (TV_TRANS_MEM , "transactional memory") DEFTIMEVAR (TV_TREE_STRLEN , "tree strlen optimization") DEFTIMEVAR (TV_TREE_MODREF , "tree modref") +DEFTIMEVAR (TV_TREE_ASSUMPTIONS , "tree assumptions") DEFTIMEVAR (TV_CGRAPH_VERIFY , "callgraph verifier") DEFTIMEVAR (TV_DOM_FRONTIERS , "dominance frontiers") DEFTIMEVAR (TV_DOMINANCE , "dominance computation") diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index ae78187..9b2c0f6 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -5139,6 +5139,9 @@ verify_gimple_stmt (gimple *stmt) how to setup the parallel iteration. */ return false; + case GIMPLE_ASSUME: + return false; + case GIMPLE_DEBUG: return verify_gimple_debug (stmt); @@ -5252,6 +5255,10 @@ verify_gimple_in_seq_2 (gimple_seq stmts) as_a <gcatch *> (stmt))); break; + case GIMPLE_ASSUME: + err |= verify_gimple_in_seq_2 (gimple_assume_body (stmt)); + break; + case GIMPLE_TRANSACTION: err |= verify_gimple_transaction (as_a <gtransaction *> (stmt)); break; diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc index 01637c5..a83b013 100644 --- a/gcc/tree-if-conv.cc +++ b/gcc/tree-if-conv.cc @@ -1416,9 +1416,6 @@ if_convertible_loop_p_1 (class loop *loop, vec<data_reference_p> *refs) basic_block exit_bb = NULL; vec<basic_block> region; - if (find_data_references_in_loop (loop, refs) == chrec_dont_know) - return false; - calculate_dominance_info (CDI_DOMINATORS); for (i = 0; i < loop->num_nodes; i++) @@ -1541,12 +1538,11 @@ if_convertible_loop_p_1 (class loop *loop, vec<data_reference_p> *refs) - if its basic blocks and phi nodes are if convertible. */ static bool -if_convertible_loop_p (class loop *loop) +if_convertible_loop_p (class loop *loop, vec<data_reference_p> *refs) { edge e; edge_iterator ei; bool res = false; - vec<data_reference_p> refs; /* Handle only innermost loop. */ if (!loop || loop->inner) @@ -1578,15 +1574,7 @@ if_convertible_loop_p (class loop *loop) if (loop_exit_edge_p (loop, e)) return false; - refs.create (5); - res = if_convertible_loop_p_1 (loop, &refs); - - data_reference_p dr; - unsigned int i; - for (i = 0; refs.iterate (i, &dr); i++) - free (dr->aux); - - free_data_refs (refs); + res = if_convertible_loop_p_1 (loop, refs); delete innermost_DR_map; innermost_DR_map = NULL; @@ -3499,6 +3487,7 @@ tree_if_conversion (class loop *loop, vec<gimple *> *preds) auto_vec <gassign *, 4> writes_to_lower; bitmap exit_bbs; edge pe; + vec<data_reference_p> refs; again: rloop = NULL; @@ -3508,6 +3497,7 @@ tree_if_conversion (class loop *loop, vec<gimple *> *preds) need_to_predicate = false; need_to_rewrite_undefined = false; any_complicated_phi = false; + refs.create (5); /* Apply more aggressive if-conversion when loop or its outer loop were marked with simd pragma. When that's the case, we try to if-convert @@ -3537,11 +3527,14 @@ tree_if_conversion (class loop *loop, vec<gimple *> *preds) goto cleanup; } + if (find_data_references_in_loop (loop, &refs) == chrec_dont_know) + goto cleanup; + if (loop->num_nodes > 2) { need_to_ifcvt = true; - if (!if_convertible_loop_p (loop) || !dbg_cnt (if_conversion_tree)) + if (!if_convertible_loop_p (loop, &refs) || !dbg_cnt (if_conversion_tree)) goto cleanup; if ((need_to_predicate || any_complicated_phi) @@ -3658,6 +3651,13 @@ tree_if_conversion (class loop *loop, vec<gimple *> *preds) todo |= TODO_cleanup_cfg; cleanup: + data_reference_p dr; + unsigned int i; + for (i = 0; refs.iterate (i, &dr); i++) + free (dr->aux); + + refs.truncate (0); + if (ifc_bbs) { unsigned int i; diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc index 01d4700..8091ba8 100644 --- a/gcc/tree-inline.cc +++ b/gcc/tree-inline.cc @@ -1736,6 +1736,11 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) (as_a <gomp_critical *> (stmt))); break; + case GIMPLE_ASSUME: + s1 = remap_gimple_seq (gimple_assume_body (stmt), id); + copy = gimple_build_assume (gimple_assume_guard (stmt), s1); + break; + case GIMPLE_TRANSACTION: { gtransaction *old_trans_stmt = as_a <gtransaction *> (stmt); diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 4dfe05e..8480d41 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -227,6 +227,8 @@ protected: #define PROP_rtl_split_insns (1 << 17) /* RTL has insns split. */ #define PROP_loop_opts_done (1 << 18) /* SSA loop optimizations have completed. */ +#define PROP_assumptions_done (1 << 19) /* Assume function kept + around. */ #define PROP_gimple \ (PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh | PROP_gimple_lomp) @@ -301,7 +303,8 @@ protected: /* Rebuild the callgraph edges. */ #define TODO_rebuild_cgraph_edges (1 << 22) -/* Release function body and stop pass manager. */ +/* Release function body (unless assumption function) + and stop pass manager. */ #define TODO_discard_function (1 << 23) /* Internally used in execute_function_todo(). */ @@ -465,6 +468,7 @@ extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt); extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt); extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt); extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt); +extern gimple_opt_pass *make_pass_assumptions (gcc::context *ctxt); extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt); extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt); extern gimple_opt_pass *make_pass_reassoc (gcc::context *ctxt); diff --git a/gcc/tree-sra.cc b/gcc/tree-sra.cc index 1a3e12f..6cbeddf 100644 --- a/gcc/tree-sra.cc +++ b/gcc/tree-sra.cc @@ -260,6 +260,9 @@ struct access /* Should TREE_NO_WARNING of a replacement be set? */ unsigned grp_no_warning : 1; + + /* Result of propagation accross link from LHS to RHS. */ + unsigned grp_result_of_prop_from_lhs : 1; }; typedef struct access *access_p; @@ -2532,6 +2535,9 @@ analyze_access_subtree (struct access *root, struct access *parent, if (allow_replacements && expr_with_var_bounded_array_refs_p (root->expr)) allow_replacements = false; + if (!totally && root->grp_result_of_prop_from_lhs) + allow_replacements = false; + for (child = root->first_child; child; child = child->next_sibling) { hole |= covered_to < child->offset; @@ -2959,6 +2965,7 @@ propagate_subaccesses_from_lhs (struct access *lacc, struct access *racc) struct access *new_acc = create_artificial_child_access (racc, lchild, norm_offset, true, false); + new_acc->grp_result_of_prop_from_lhs = 1; propagate_subaccesses_from_lhs (lchild, new_acc); } else diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc index 85c0460..9778e77 100644 --- a/gcc/tree-ssa-ccp.cc +++ b/gcc/tree-ssa-ccp.cc @@ -4253,6 +4253,12 @@ pass_fold_builtins::execute (function *fun) } callee = gimple_call_fndecl (stmt); + if (!callee + && gimple_call_internal_p (stmt, IFN_ASSUME)) + { + gsi_remove (&i, true); + continue; + } if (!callee || !fndecl_built_in_p (callee, BUILT_IN_NORMAL)) { gsi_next (&i); diff --git a/gcc/tree-ssa-dom.cc b/gcc/tree-ssa-dom.cc index e6b8dac..c7f095d 100644 --- a/gcc/tree-ssa-dom.cc +++ b/gcc/tree-ssa-dom.cc @@ -1367,7 +1367,11 @@ dom_opt_dom_walker::set_global_ranges_from_unreachable_edges (basic_block bb) tree name; gori_compute &gori = m_ranger->gori (); FOR_EACH_GORI_EXPORT_NAME (gori, pred_e->src, name) - if (all_uses_feed_or_dominated_by_stmt (name, stmt)) + if (all_uses_feed_or_dominated_by_stmt (name, stmt) + // The condition must post-dominate the definition point. + && (SSA_NAME_IS_DEFAULT_DEF (name) + || (gimple_bb (SSA_NAME_DEF_STMT (name)) + == pred_e->src))) { Value_Range r (TREE_TYPE (name)); diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 98a943d..92790bd 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -529,6 +529,45 @@ vect_inner_phi_in_double_reduction_p (loop_vec_info loop_vinfo, gphi *phi) return false; } +/* Returns true if Phi is a first-order recurrence. A first-order + recurrence is a non-reduction recurrence relation in which the value of + the recurrence in the current loop iteration equals a value defined in + the previous iteration. */ + +static bool +vect_phi_first_order_recurrence_p (loop_vec_info loop_vinfo, class loop *loop, + gphi *phi) +{ + /* Ensure the loop latch definition is from within the loop. */ + edge latch = loop_latch_edge (loop); + tree ldef = PHI_ARG_DEF_FROM_EDGE (phi, latch); + if (TREE_CODE (ldef) != SSA_NAME + || SSA_NAME_IS_DEFAULT_DEF (ldef) + || !flow_bb_inside_loop_p (loop, gimple_bb (SSA_NAME_DEF_STMT (ldef)))) + return false; + + tree def = gimple_phi_result (phi); + + /* Ensure every use_stmt of the phi node is dominated by the latch + definition. */ + imm_use_iterator imm_iter; + use_operand_p use_p; + FOR_EACH_IMM_USE_FAST (use_p, imm_iter, def) + if (!is_gimple_debug (USE_STMT (use_p)) + && (SSA_NAME_DEF_STMT (ldef) == USE_STMT (use_p) + || !vect_stmt_dominates_stmt_p (SSA_NAME_DEF_STMT (ldef), + USE_STMT (use_p)))) + return false; + + /* First-order recurrence autovectorization needs shuffle vector. */ + tree scalar_type = TREE_TYPE (def); + tree vectype = get_vectype_for_scalar_type (loop_vinfo, scalar_type); + if (!vectype) + return false; + + return true; +} + /* Function vect_analyze_scalar_cycles_1. Examine the cross iteration def-use cycles of scalar variables @@ -666,6 +705,8 @@ vect_analyze_scalar_cycles_1 (loop_vec_info loop_vinfo, class loop *loop, } } } + else if (vect_phi_first_order_recurrence_p (loop_vinfo, loop, phi)) + STMT_VINFO_DEF_TYPE (stmt_vinfo) = vect_first_order_recurrence; else if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -1810,7 +1851,8 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) if ((STMT_VINFO_RELEVANT (stmt_info) == vect_used_in_scope || STMT_VINFO_LIVE_P (stmt_info)) - && STMT_VINFO_DEF_TYPE (stmt_info) != vect_induction_def) + && STMT_VINFO_DEF_TYPE (stmt_info) != vect_induction_def + && STMT_VINFO_DEF_TYPE (stmt_info) != vect_first_order_recurrence) /* A scalar-dependence cycle that we don't support. */ return opt_result::failure_at (phi, "not vectorized:" @@ -1831,6 +1873,11 @@ vect_analyze_loop_operations (loop_vec_info loop_vinfo) && ! PURE_SLP_STMT (stmt_info)) ok = vectorizable_reduction (loop_vinfo, stmt_info, NULL, NULL, &cost_vec); + else if ((STMT_VINFO_DEF_TYPE (stmt_info) + == vect_first_order_recurrence) + && ! PURE_SLP_STMT (stmt_info)) + ok = vectorizable_recurr (loop_vinfo, stmt_info, NULL, NULL, + &cost_vec); } /* SLP PHIs are tested by vect_slp_analyze_node_operations. */ @@ -8290,6 +8337,184 @@ vectorizable_phi (vec_info *, return true; } +/* Vectorizes first order recurrences. An overview of the transformation + is described below. Suppose we have the following loop. + + int t = 0; + for (int i = 0; i < n; ++i) + { + b[i] = a[i] - t; + t = a[i]; + } + + There is a first-order recurrence on 'a'. For this loop, the scalar IR + looks (simplified) like: + + scalar.preheader: + init = 0; + + scalar.body: + i = PHI <0(scalar.preheader), i+1(scalar.body)> + _2 = PHI <(init(scalar.preheader), <_1(scalar.body)> + _1 = a[i] + b[i] = _1 - _2 + if (i < n) goto scalar.body + + In this example, _2 is a recurrence because it's value depends on the + previous iteration. We vectorize this as (VF = 4) + + vector.preheader: + vect_init = vect_cst(..., ..., ..., 0) + + vector.body + i = PHI <0(vector.preheader), i+4(vector.body)> + vect_1 = PHI <vect_init(vector.preheader), v2(vector.body)> + vect_2 = a[i, i+1, i+2, i+3]; + vect_3 = vec_perm (vect_1, vect_2, { 3, 4, 5, 6 }) + b[i, i+1, i+2, i+3] = vect_2 - vect_3 + if (..) goto vector.body + + In this function, vectorizable_recurr, we code generate both the + vector PHI node and the permute since those together compute the + vectorized value of the scalar PHI. We do not yet have the + backedge value to fill in there nor into the vec_perm. Those + are filled in maybe_set_vectorized_backedge_value and + vect_schedule_scc. + + TODO: Since the scalar loop does not have a use of the recurrence + outside of the loop the natural way to implement peeling via + vectorizing the live value doesn't work. For now peeling of loops + with a recurrence is not implemented. For SLP the supported cases + are restricted to those requiring a single vector recurrence PHI. */ + +bool +vectorizable_recurr (loop_vec_info loop_vinfo, stmt_vec_info stmt_info, + gimple **vec_stmt, slp_tree slp_node, + stmt_vector_for_cost *cost_vec) +{ + if (!loop_vinfo || !is_a<gphi *> (stmt_info->stmt)) + return false; + + gphi *phi = as_a<gphi *> (stmt_info->stmt); + + /* So far we only support first-order recurrence auto-vectorization. */ + if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_first_order_recurrence) + return false; + + tree vectype = STMT_VINFO_VECTYPE (stmt_info); + unsigned ncopies; + if (slp_node) + ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); + else + ncopies = vect_get_num_copies (loop_vinfo, vectype); + poly_int64 nunits = TYPE_VECTOR_SUBPARTS (vectype); + unsigned dist = slp_node ? SLP_TREE_LANES (slp_node) : 1; + /* We need to be able to make progress with a single vector. */ + if (maybe_gt (dist * 2, nunits)) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "first order recurrence exceeds half of " + "a vector\n"); + return false; + } + + /* First-order recurrence autovectorization needs to handle permutation + with indices = [nunits-1, nunits, nunits+1, ...]. */ + vec_perm_builder sel (nunits, 1, 3); + for (int i = 0; i < 3; ++i) + sel.quick_push (nunits - dist + i); + vec_perm_indices indices (sel, 2, nunits); + + if (!vec_stmt) /* transformation not required. */ + { + if (!can_vec_perm_const_p (TYPE_MODE (vectype), TYPE_MODE (vectype), + indices)) + return false; + + if (slp_node) + { + /* We eventually need to set a vector type on invariant + arguments. */ + unsigned j; + slp_tree child; + FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (slp_node), j, child) + if (!vect_maybe_update_slp_op_vectype + (child, SLP_TREE_VECTYPE (slp_node))) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "incompatible vector types for " + "invariants\n"); + return false; + } + } + /* The recurrence costs the initialization vector and one permute + for each copy. */ + unsigned prologue_cost = record_stmt_cost (cost_vec, 1, scalar_to_vec, + stmt_info, 0, vect_prologue); + unsigned inside_cost = record_stmt_cost (cost_vec, ncopies, vector_stmt, + stmt_info, 0, vect_body); + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "vectorizable_recurr: inside_cost = %d, " + "prologue_cost = %d .\n", inside_cost, + prologue_cost); + + STMT_VINFO_TYPE (stmt_info) = recurr_info_type; + return true; + } + + edge pe = loop_preheader_edge (LOOP_VINFO_LOOP (loop_vinfo)); + basic_block bb = gimple_bb (phi); + tree preheader = PHI_ARG_DEF_FROM_EDGE (phi, pe); + tree vec_init = build_vector_from_val (vectype, preheader); + vec_init = vect_init_vector (loop_vinfo, stmt_info, vec_init, vectype, NULL); + + /* Create the vectorized first-order PHI node. */ + tree vec_dest = vect_get_new_vect_var (vectype, + vect_simple_var, "vec_recur_"); + gphi *new_phi = create_phi_node (vec_dest, bb); + add_phi_arg (new_phi, vec_init, pe, UNKNOWN_LOCATION); + + /* Insert shuffles the first-order recurrence autovectorization. + result = VEC_PERM <vec_recur, vect_1, index[nunits-1, nunits, ...]>. */ + tree perm = vect_gen_perm_mask_checked (vectype, indices); + + /* Insert the required permute after the latch definition. The + second and later operands are tentative and will be updated when we have + vectorized the latch definition. */ + edge le = loop_latch_edge (LOOP_VINFO_LOOP (loop_vinfo)); + gimple *latch_def = SSA_NAME_DEF_STMT (PHI_ARG_DEF_FROM_EDGE (phi, le)); + gimple_stmt_iterator gsi2; + if (is_a <gphi *> (latch_def)) + gsi2 = gsi_after_labels (gimple_bb (latch_def)); + else + { + gsi2 = gsi_for_stmt (latch_def); + gsi_next (&gsi2); + } + + for (unsigned i = 0; i < ncopies; ++i) + { + vec_dest = make_ssa_name (vectype); + gassign *vperm + = gimple_build_assign (vec_dest, VEC_PERM_EXPR, + i == 0 ? gimple_phi_result (new_phi) : NULL, + NULL, perm); + vect_finish_stmt_generation (loop_vinfo, stmt_info, vperm, &gsi2); + + if (slp_node) + SLP_TREE_VEC_STMTS (slp_node).quick_push (vperm); + else + STMT_VINFO_VEC_STMTS (stmt_info).safe_push (vperm); + } + + if (!slp_node) + *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0]; + return true; +} + /* Return true if VECTYPE represents a vector that requires lowering by the vector lowering pass. */ @@ -10242,27 +10467,53 @@ maybe_set_vectorized_backedge_value (loop_vec_info loop_vinfo, imm_use_iterator iter; use_operand_p use_p; FOR_EACH_IMM_USE_FAST (use_p, iter, def) - if (gphi *phi = dyn_cast <gphi *> (USE_STMT (use_p))) - if (gimple_bb (phi)->loop_father->header == gimple_bb (phi) - && (phi_info = loop_vinfo->lookup_stmt (phi)) - && STMT_VINFO_RELEVANT_P (phi_info) - && VECTORIZABLE_CYCLE_DEF (STMT_VINFO_DEF_TYPE (phi_info)) + { + gphi *phi = dyn_cast <gphi *> (USE_STMT (use_p)); + if (!phi) + continue; + if (!(gimple_bb (phi)->loop_father->header == gimple_bb (phi) + && (phi_info = loop_vinfo->lookup_stmt (phi)) + && STMT_VINFO_RELEVANT_P (phi_info))) + continue; + loop_p loop = gimple_bb (phi)->loop_father; + edge e = loop_latch_edge (loop); + if (PHI_ARG_DEF_FROM_EDGE (phi, e) != def) + continue; + + if (VECTORIZABLE_CYCLE_DEF (STMT_VINFO_DEF_TYPE (phi_info)) && STMT_VINFO_REDUC_TYPE (phi_info) != FOLD_LEFT_REDUCTION && STMT_VINFO_REDUC_TYPE (phi_info) != EXTRACT_LAST_REDUCTION) { - loop_p loop = gimple_bb (phi)->loop_father; - edge e = loop_latch_edge (loop); - if (PHI_ARG_DEF_FROM_EDGE (phi, e) == def) + vec<gimple *> &phi_defs = STMT_VINFO_VEC_STMTS (phi_info); + vec<gimple *> &latch_defs = STMT_VINFO_VEC_STMTS (def_stmt_info); + gcc_assert (phi_defs.length () == latch_defs.length ()); + for (unsigned i = 0; i < phi_defs.length (); ++i) + add_phi_arg (as_a <gphi *> (phi_defs[i]), + gimple_get_lhs (latch_defs[i]), e, + gimple_phi_arg_location (phi, e->dest_idx)); + } + else if (STMT_VINFO_DEF_TYPE (phi_info) == vect_first_order_recurrence) + { + /* For first order recurrences we have to update both uses of + the latch definition, the one in the PHI node and the one + in the generated VEC_PERM_EXPR. */ + vec<gimple *> &phi_defs = STMT_VINFO_VEC_STMTS (phi_info); + vec<gimple *> &latch_defs = STMT_VINFO_VEC_STMTS (def_stmt_info); + gcc_assert (phi_defs.length () == latch_defs.length ()); + tree phidef = gimple_assign_rhs1 (phi_defs[0]); + gphi *vphi = as_a <gphi *> (SSA_NAME_DEF_STMT (phidef)); + for (unsigned i = 0; i < phi_defs.length (); ++i) { - vec<gimple *> &phi_defs = STMT_VINFO_VEC_STMTS (phi_info); - vec<gimple *> &latch_defs = STMT_VINFO_VEC_STMTS (def_stmt_info); - gcc_assert (phi_defs.length () == latch_defs.length ()); - for (unsigned i = 0; i < phi_defs.length (); ++i) - add_phi_arg (as_a <gphi *> (phi_defs[i]), - gimple_get_lhs (latch_defs[i]), e, - gimple_phi_arg_location (phi, e->dest_idx)); + gassign *perm = as_a <gassign *> (phi_defs[i]); + if (i > 0) + gimple_assign_set_rhs1 (perm, gimple_get_lhs (latch_defs[i-1])); + gimple_assign_set_rhs2 (perm, gimple_get_lhs (latch_defs[i])); + update_stmt (perm); } + add_phi_arg (vphi, gimple_get_lhs (latch_defs.last ()), e, + gimple_phi_arg_location (phi, e->dest_idx)); } + } } /* Vectorize STMT_INFO if relevant, inserting any new instructions before GSI. @@ -10671,6 +10922,7 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) || STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def || STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def || STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle + || STMT_VINFO_DEF_TYPE (stmt_info) == vect_first_order_recurrence || STMT_VINFO_DEF_TYPE (stmt_info) == vect_internal_def) && ! PURE_SLP_STMT (stmt_info)) { @@ -10696,7 +10948,8 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) || STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def || STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def || STMT_VINFO_DEF_TYPE (stmt_info) == vect_nested_cycle - || STMT_VINFO_DEF_TYPE (stmt_info) == vect_internal_def) + || STMT_VINFO_DEF_TYPE (stmt_info) == vect_internal_def + || STMT_VINFO_DEF_TYPE (stmt_info) == vect_first_order_recurrence) && ! PURE_SLP_STMT (stmt_info)) maybe_set_vectorized_backedge_value (loop_vinfo, stmt_info); } diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc index af27fd5..e54414f 100644 --- a/gcc/tree-vect-slp.cc +++ b/gcc/tree-vect-slp.cc @@ -693,6 +693,7 @@ vect_get_and_check_slp_defs (vec_info *vinfo, unsigned char swap, case vect_reduction_def: case vect_induction_def: case vect_nested_cycle: + case vect_first_order_recurrence: break; default: @@ -1732,7 +1733,8 @@ vect_build_slp_tree_2 (vec_info *vinfo, slp_tree node, } else if (def_type == vect_reduction_def || def_type == vect_double_reduction_def - || def_type == vect_nested_cycle) + || def_type == vect_nested_cycle + || def_type == vect_first_order_recurrence) { /* Else def types have to match. */ stmt_vec_info other_info; @@ -1746,7 +1748,8 @@ vect_build_slp_tree_2 (vec_info *vinfo, slp_tree node, } class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); /* Reduction initial values are not explicitely represented. */ - if (!nested_in_vect_loop_p (loop, stmt_info)) + if (def_type != vect_first_order_recurrence + && !nested_in_vect_loop_p (loop, stmt_info)) skip_args[loop_preheader_edge (loop)->dest_idx] = true; /* Reduction chain backedge defs are filled manually. ??? Need a better way to identify a SLP reduction chain PHI. @@ -9210,11 +9213,34 @@ vect_schedule_scc (vec_info *vinfo, slp_tree node, slp_instance instance, child = SLP_TREE_CHILDREN (phi_node)[dest_idx]; if (!child || SLP_TREE_DEF_TYPE (child) != vect_internal_def) continue; + unsigned n = SLP_TREE_VEC_STMTS (phi_node).length (); /* Simply fill all args. */ - for (unsigned i = 0; i < SLP_TREE_VEC_STMTS (phi_node).length (); ++i) - add_phi_arg (as_a <gphi *> (SLP_TREE_VEC_STMTS (phi_node)[i]), - vect_get_slp_vect_def (child, i), - e, gimple_phi_arg_location (phi, dest_idx)); + if (STMT_VINFO_DEF_TYPE (SLP_TREE_REPRESENTATIVE (phi_node)) + != vect_first_order_recurrence) + for (unsigned i = 0; i < n; ++i) + add_phi_arg (as_a <gphi *> (SLP_TREE_VEC_STMTS (phi_node)[i]), + vect_get_slp_vect_def (child, i), + e, gimple_phi_arg_location (phi, dest_idx)); + else + { + /* Unless it is a first order recurrence which needs + args filled in for both the PHI node and the permutes. */ + gimple *perm = SLP_TREE_VEC_STMTS (phi_node)[0]; + gimple *rphi = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (perm)); + add_phi_arg (as_a <gphi *> (rphi), + vect_get_slp_vect_def (child, n - 1), + e, gimple_phi_arg_location (phi, dest_idx)); + for (unsigned i = 0; i < n; ++i) + { + gimple *perm = SLP_TREE_VEC_STMTS (phi_node)[i]; + if (i > 0) + gimple_assign_set_rhs1 (perm, + vect_get_slp_vect_def (child, i - 1)); + gimple_assign_set_rhs2 (perm, + vect_get_slp_vect_def (child, i)); + update_stmt (perm); + } + } } } } diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc index c8d1efc..4e0d75e 100644 --- a/gcc/tree-vect-stmts.cc +++ b/gcc/tree-vect-stmts.cc @@ -11176,6 +11176,7 @@ vect_analyze_stmt (vec_info *vinfo, break; case vect_induction_def: + case vect_first_order_recurrence: gcc_assert (!bb_vinfo); break; @@ -11234,7 +11235,9 @@ vect_analyze_stmt (vec_info *vinfo, || vectorizable_comparison (vinfo, stmt_info, NULL, NULL, node, cost_vec) || vectorizable_lc_phi (as_a <loop_vec_info> (vinfo), - stmt_info, NULL, node)); + stmt_info, NULL, node) + || vectorizable_recurr (as_a <loop_vec_info> (vinfo), + stmt_info, NULL, node, cost_vec)); else { if (bb_vinfo) @@ -11404,6 +11407,12 @@ vect_transform_stmt (vec_info *vinfo, gcc_assert (done); break; + case recurr_info_type: + done = vectorizable_recurr (as_a <loop_vec_info> (vinfo), + stmt_info, &vec_stmt, slp_node, NULL); + gcc_assert (done); + break; + case phi_info_type: done = vectorizable_phi (vinfo, stmt_info, &vec_stmt, slp_node, NULL); gcc_assert (done); @@ -11804,6 +11813,9 @@ vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt, case vect_nested_cycle: dump_printf (MSG_NOTE, "nested cycle\n"); break; + case vect_first_order_recurrence: + dump_printf (MSG_NOTE, "first order recurrence\n"); + break; case vect_unknown_def_type: dump_printf (MSG_NOTE, "unknown\n"); break; @@ -11852,7 +11864,8 @@ vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt, || *dt == vect_induction_def || *dt == vect_reduction_def || *dt == vect_double_reduction_def - || *dt == vect_nested_cycle) + || *dt == vect_nested_cycle + || *dt == vect_first_order_recurrence) { *vectype = STMT_VINFO_VECTYPE (def_stmt_info); gcc_assert (*vectype != NULL_TREE); diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 4870c75..016961d 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -65,6 +65,7 @@ enum vect_def_type { vect_reduction_def, vect_double_reduction_def, vect_nested_cycle, + vect_first_order_recurrence, vect_unknown_def_type }; @@ -1027,6 +1028,7 @@ enum stmt_vec_info_type { cycle_phi_info_type, lc_phi_info_type, phi_info_type, + recurr_info_type, loop_exit_ctrl_vec_info_type }; @@ -2331,6 +2333,8 @@ extern bool vectorizable_lc_phi (loop_vec_info, stmt_vec_info, gimple **, slp_tree); extern bool vectorizable_phi (vec_info *, stmt_vec_info, gimple **, slp_tree, stmt_vector_for_cost *); +extern bool vectorizable_recurr (loop_vec_info, stmt_vec_info, + gimple **, slp_tree, stmt_vector_for_cost *); extern bool vect_emulated_vector_p (tree); extern bool vect_can_vectorize_without_simd_p (tree_code); extern bool vect_can_vectorize_without_simd_p (code_helper); diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc index 93482e5..1adb15c 100644 --- a/gcc/tree-vrp.cc +++ b/gcc/tree-vrp.cc @@ -4441,6 +4441,35 @@ public: int my_pass; }; // class pass_vrp +const pass_data pass_data_assumptions = +{ + GIMPLE_PASS, /* type */ + "assumptions", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_TREE_ASSUMPTIONS, /* tv_id */ + PROP_ssa, /* properties_required */ + PROP_assumptions_done, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_end */ +}; + +class pass_assumptions : public gimple_opt_pass +{ +public: + pass_assumptions (gcc::context *ctxt) + : gimple_opt_pass (pass_data_assumptions, ctxt) + {} + + /* opt_pass methods: */ + bool gate (function *fun) final override { return fun->assume_function; } + unsigned int execute (function *) final override + { + return TODO_discard_function; + } + +}; // class pass_assumptions + } // anon namespace gimple_opt_pass * @@ -4454,3 +4483,9 @@ make_pass_early_vrp (gcc::context *ctxt) { return new pass_vrp (ctxt, pass_data_early_vrp); } + +gimple_opt_pass * +make_pass_assumptions (gcc::context *ctx) +{ + return new pass_assumptions (ctx); +} diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 4794d23..90d5e66 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -4022,10 +4022,13 @@ range_tests_floats () r0.intersect (r1); ASSERT_TRUE (r0.undefined_p ()); - // Make sure [-Inf, -Inf] doesn't get normalized. - r0 = frange_float ("-Inf", "-Inf"); - ASSERT_TRUE (real_isinf (&r0.lower_bound (), true)); - ASSERT_TRUE (real_isinf (&r0.upper_bound (), true)); + if (!flag_finite_math_only) + { + // Make sure [-Inf, -Inf] doesn't get normalized. + r0 = frange_float ("-Inf", "-Inf"); + ASSERT_TRUE (real_isinf (&r0.lower_bound (), true)); + ASSERT_TRUE (real_isinf (&r0.upper_bound (), true)); + } } void diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc index 50fc190..178a245 100644 --- a/gcc/value-relation.cc +++ b/gcc/value-relation.cc @@ -32,9 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "alloc-pool.h" #include "dominance.h" -#define VREL_LAST VREL_PE64 - -static const char *kind_string[VREL_LAST + 1] = +static const char *kind_string[VREL_LAST] = { "varying", "undefined", "<", "<=", ">", ">=", "==", "!=", "pe8", "pe16", "pe32", "pe64" }; @@ -47,7 +45,7 @@ print_relation (FILE *f, relation_kind rel) } // This table is used to negate the operands. op1 REL op2 -> !(op1 REL op2). -relation_kind rr_negate_table[VREL_LAST + 1] = { +relation_kind rr_negate_table[VREL_LAST] = { VREL_VARYING, VREL_UNDEFINED, VREL_GE, VREL_GT, VREL_LE, VREL_LT, VREL_NE, VREL_EQ }; @@ -60,7 +58,7 @@ relation_negate (relation_kind r) } // This table is used to swap the operands. op1 REL op2 -> op2 REL op1. -relation_kind rr_swap_table[VREL_LAST + 1] = { +relation_kind rr_swap_table[VREL_LAST] = { VREL_VARYING, VREL_UNDEFINED, VREL_GT, VREL_GE, VREL_LT, VREL_LE, VREL_EQ, VREL_NE }; @@ -74,7 +72,7 @@ relation_swap (relation_kind r) // This table is used to perform an intersection between 2 relations. -relation_kind rr_intersect_table[VREL_LAST + 1][VREL_LAST + 1] = { +relation_kind rr_intersect_table[VREL_LAST][VREL_LAST] = { // VREL_VARYING { VREL_VARYING, VREL_UNDEFINED, VREL_LT, VREL_LE, VREL_GT, VREL_GE, VREL_EQ, VREL_NE }, @@ -112,7 +110,7 @@ relation_intersect (relation_kind r1, relation_kind r2) // This table is used to perform a union between 2 relations. -relation_kind rr_union_table[VREL_LAST + 1][VREL_LAST + 1] = { +relation_kind rr_union_table[VREL_LAST][VREL_LAST] = { // VREL_VARYING { VREL_VARYING, VREL_VARYING, VREL_VARYING, VREL_VARYING, VREL_VARYING, VREL_VARYING, VREL_VARYING, VREL_VARYING }, @@ -150,7 +148,7 @@ relation_union (relation_kind r1, relation_kind r2) // This table is used to determine transitivity between 2 relations. // (A relation0 B) and (B relation1 C) implies (A result C) -relation_kind rr_transitive_table[VREL_LAST + 1][VREL_LAST + 1] = { +relation_kind rr_transitive_table[VREL_LAST][VREL_LAST] = { // VREL_VARYING { VREL_VARYING, VREL_VARYING, VREL_VARYING, VREL_VARYING, VREL_VARYING, VREL_VARYING, VREL_VARYING, VREL_VARYING }, @@ -187,7 +185,7 @@ relation_transitive (relation_kind r1, relation_kind r2) // This vector maps a relation to the equivalent tree code. -tree_code relation_to_code [VREL_LAST + 1] = { +tree_code relation_to_code [VREL_LAST] = { ERROR_MARK, ERROR_MARK, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EQ_EXPR, NE_EXPR }; @@ -226,7 +224,8 @@ relation_oracle::validate_relation (relation_kind rel, vrange &op1, vrange &op2) // If the relation cannot be folded for any reason, leave as is. Value_Range result (boolean_type_node); - if (!handler.fold_range (result, boolean_type_node, op1, op2, rel)) + if (!handler.fold_range (result, boolean_type_node, op1, op2, + relation_trio::op1_op2 (rel))) return rel; // The expression op1 REL op2 using REL should fold to [1,1]. @@ -381,7 +380,7 @@ equiv_oracle::add_partial_equiv (relation_kind r, tree op1, tree op2) EXECUTE_IF_SET_IN_BITMAP (pe1.members, 0, x, bi) { m_partial[x].ssa_base = op2; - m_partial[x].code = pe2.code; + m_partial[x].code = pe_min (m_partial[x].code, pe2.code); } bitmap_set_bit (pe1.members, v2); return; @@ -891,7 +890,7 @@ value_relation::dump (FILE *f) const { if (!name1 || !name2) { - fprintf (f, "uninitialized"); + fprintf (f, "no relation registered"); return; } fputc ('(', f); diff --git a/gcc/value-relation.h b/gcc/value-relation.h index a3bbe1e..027d741 100644 --- a/gcc/value-relation.h +++ b/gcc/value-relation.h @@ -35,20 +35,21 @@ along with GCC; see the file COPYING3. If not see // utilizes the relation information to enhance it's range calculations, this // is totally transparent to the client, and they are free to make queries. // -// -// relation_kind is a typedef of enum tree_code, but has restricted range -// and a couple of extra values. +// relation_kind is a new enum which represents the different relations, +// often with a direct mapping to treee codes. ie VREL_EQ is equivalent to +// EQ_EXPR. // // A query is made requesting the relation between SSA1 and SSA@ in a basic // block, or on an edge, the possible return values are: // -// EQ_EXPR, NE_EXPR, LT_EXPR, LE_EXPR, GT_EXPR, and GE_EXPR mean the same. +// VREL_EQ, VREL_NE, VREL_LT, VREL_LE, VREL_GT, and VREL_GE mean the same. // VREL_VARYING : No relation between the 2 names. // VREL_UNDEFINED : Impossible relation (ie, A < B && A > B) // -// The oracle maintains EQ_EXPR relations with equivalency sets, so if a -// relation comes back EQ_EXPR, it is also possible to query the set of -// equivlaencies. These are basically bitmaps over ssa_names. +// The oracle maintains VREL_EQ relations with equivalency sets, so if a +// relation comes back VREL_EQ, it is also possible to query the set of +// equivlaencies. These are basically bitmaps over ssa_names. An iterator is +// provided later for this activity. // // Relations are maintained via the dominace trees and are optimized assuming // they are registered in dominance order. When a new relation is added, it @@ -56,10 +57,8 @@ along with GCC; see the file COPYING3. If not see // and registered at the specified block. -// Rather than introduce a new enumerated type for relations, we can use the -// existing tree_codes for relations, plus add a couple of #defines for -// the other cases. These codes are arranged such that VREL_VARYING is the -// first code, and all the rest are contiguous. +// These codes are arranged such that VREL_VARYING is the first code, and all +// the rest are contiguous. typedef enum relation_kind_t { @@ -74,7 +73,8 @@ typedef enum relation_kind_t VREL_PE8, // 8 bit partial equivalency VREL_PE16, // 16 bit partial equivalency VREL_PE32, // 32 bit partial equivalency - VREL_PE64 // 64 bit partial equivalency + VREL_PE64, // 64 bit partial equivalency + VREL_LAST // terminate, not a real relation. } relation_kind; // General relation kind transformations. @@ -315,6 +315,101 @@ protected: ((equiv_name) = iter.get_name (&equiv_rel)); \ iter.next ()) +// ----------------------------------------------------------------------- + +// Range-ops deals with a LHS and 2 operands. A relation trio is a set of +// 3 potential relations packed into a single unsigned value. +// 1 - LHS relation OP1 +// 2 - LHS relation OP2 +// 3 - OP1 relation OP2 +// VREL_VARYING is a value of 0, and is the default for each position. +class relation_trio +{ +public: + relation_trio (); + relation_trio (relation_kind lhs_op1, relation_kind lhs_op2, + relation_kind op1_op2); + relation_kind lhs_op1 (); + relation_kind lhs_op2 (); + relation_kind op1_op2 (); + relation_trio swap_op1_op2 (); + + static relation_trio lhs_op1 (relation_kind k); + static relation_trio lhs_op2 (relation_kind k); + static relation_trio op1_op2 (relation_kind k); + +protected: + unsigned m_val; +}; + +// Default VREL_VARYING for all 3 relations. +#define TRIO_VARYING relation_trio () + +#define TRIO_SHIFT 4 +#define TRIO_MASK 0x000F + +// These 3 classes are shortcuts for when a caller has a single relation to +// pass as a trio, it can simply construct the appropriate one. The other +// unspecified realtions will be VREL_VARYING. + +inline relation_trio::relation_trio () +{ + STATIC_ASSERT (VREL_LAST <= (1 << TRIO_SHIFT)); + m_val = 0; +} + +inline relation_trio::relation_trio (relation_kind lhs_op1, + relation_kind lhs_op2, + relation_kind op1_op2) +{ + STATIC_ASSERT (VREL_LAST <= (1 << TRIO_SHIFT)); + unsigned i1 = (unsigned) lhs_op1; + unsigned i2 = ((unsigned) lhs_op2) << TRIO_SHIFT; + unsigned i3 = ((unsigned) op1_op2) << (TRIO_SHIFT * 2); + m_val = i1 | i2 | i3; +} + +inline relation_trio +relation_trio::lhs_op1 (relation_kind k) +{ + return relation_trio (k, VREL_VARYING, VREL_VARYING); +} +inline relation_trio +relation_trio::lhs_op2 (relation_kind k) +{ + return relation_trio (VREL_VARYING, k, VREL_VARYING); +} +inline relation_trio +relation_trio::op1_op2 (relation_kind k) +{ + return relation_trio (VREL_VARYING, VREL_VARYING, k); +} + +inline relation_kind +relation_trio::lhs_op1 () +{ + return (relation_kind) (m_val & TRIO_MASK); +} + +inline relation_kind +relation_trio::lhs_op2 () +{ + return (relation_kind) ((m_val >> TRIO_SHIFT) & TRIO_MASK); +} + +inline relation_kind +relation_trio::op1_op2 () +{ + return (relation_kind) ((m_val >> (TRIO_SHIFT * 2)) & TRIO_MASK); +} + +inline relation_trio +relation_trio::swap_op1_op2 () +{ + return relation_trio (lhs_op2 (), lhs_op1 (), relation_swap (op1_op2 ())); +} + +// ----------------------------------------------------------------------- // The value-relation class is used to encapsulate the represention of an // individual relation between 2 ssa-names, and to facilitate operating on @@ -349,6 +444,13 @@ value_relation::set_relation (relation_kind r, tree n1, tree n2) { gcc_checking_assert (TREE_CODE (n1) == SSA_NAME && TREE_CODE (n2) == SSA_NAME); + if (n1 == n2) + { + related = VREL_VARYING; + name1 = NULL_TREE; + name2 = NULL_TREE; + return; + } related = r; name1 = n1; name2 = n2; |