aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-10-19 15:25:12 +0200
committerMartin Liska <mliska@suse.cz>2022-10-19 15:25:12 +0200
commit4465e2a047c3b175bf6c4ca500547eb6b12df52f (patch)
tree3159c8256f9907538f186ce7c1087c83825b5519 /gcc
parent6c22519f33270a689fc8730ceff9212b376ed40d (diff)
parent09fed44cabd50f3d8e050f91cc2db02364ce9176 (diff)
downloadgcc-4465e2a047c3b175bf6c4ca500547eb6b12df52f.zip
gcc-4465e2a047c3b175bf6c4ca500547eb6b12df52f.tar.gz
gcc-4465e2a047c3b175bf6c4ca500547eb6b12df52f.tar.bz2
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog400
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/c-family/ChangeLog8
-rw-r--r--gcc/c-family/c-common.cc4
-rw-r--r--gcc/c/ChangeLog21
-rw-r--r--gcc/c/c-decl.cc151
-rw-r--r--gcc/cgraph.cc18
-rw-r--r--gcc/cgraphunit.cc14
-rw-r--r--gcc/common/config/h8300/h8300-common.cc2
-rw-r--r--gcc/config/gcn/gcn.cc14
-rw-r--r--gcc/config/h8300/combiner.md40
-rw-r--r--gcc/config/h8300/constraints.md8
-rw-r--r--gcc/config/h8300/extensions.md18
-rw-r--r--gcc/config/h8300/h8300-protos.h1
-rw-r--r--gcc/config/h8300/h8300.cc26
-rw-r--r--gcc/config/h8300/movepush.md70
-rw-r--r--gcc/config/i386/i386-builtin-types.def2
-rw-r--r--gcc/config/i386/i386-builtins.cc17
-rw-r--r--gcc/config/i386/i386-expand.cc17
-rw-r--r--gcc/config/riscv/riscv-vector-builtins.cc26
-rw-r--r--gcc/config/riscv/t-riscv2
-rw-r--r--gcc/config/s390/s390.cc47
-rw-r--r--gcc/config/s390/s390.md7
-rw-r--r--gcc/config/xtensa/constraints.md2
-rw-r--r--gcc/config/xtensa/predicates.md2
-rw-r--r--gcc/config/xtensa/xtensa-protos.h2
-rw-r--r--gcc/config/xtensa/xtensa.cc69
-rw-r--r--gcc/config/xtensa/xtensa.h8
-rw-r--r--gcc/config/xtensa/xtensa.md36
-rw-r--r--gcc/config/xtensa/xtensa.opt4
-rw-r--r--gcc/cp/ChangeLog23
-rw-r--r--gcc/cp/cp-gimplify.cc15
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/module.cc79
-rw-r--r--gcc/cp/parser.cc6
-rw-r--r--gcc/cp/pt.cc5
-rw-r--r--gcc/doc/extend.texi6
-rw-r--r--gcc/expr.cc11
-rw-r--r--gcc/fortran/ChangeLog48
-rw-r--r--gcc/fortran/arith.cc60
-rw-r--r--gcc/fortran/gfortran.h5
-rw-r--r--gcc/fortran/simplify.cc2
-rw-r--r--gcc/fortran/trans-decl.cc10
-rw-r--r--gcc/fortran/trans-expr.cc12
-rw-r--r--gcc/fortran/trans-types.cc2
-rw-r--r--gcc/function.h4
-rw-r--r--gcc/gimple-expr.cc2
-rw-r--r--gcc/gimple-low.cc395
-rw-r--r--gcc/gimple-pretty-print.cc29
-rw-r--r--gcc/gimple-range-fold.cc5
-rw-r--r--gcc/gimple-range-gori.cc43
-rw-r--r--gcc/gimple-range-op.cc40
-rw-r--r--gcc/gimple-range-op.h4
-rw-r--r--gcc/gimple-ssa-isolate-paths.cc6
-rw-r--r--gcc/gimple-walk.cc13
-rw-r--r--gcc/gimple.cc19
-rw-r--r--gcc/gimple.def5
-rw-r--r--gcc/gimple.h78
-rw-r--r--gcc/gimplify.cc28
-rw-r--r--gcc/gsstruct.def1
-rw-r--r--gcc/internal-fn.cc1
-rw-r--r--gcc/ipa-cp.cc1200
-rw-r--r--gcc/ipa-fnsummary.cc105
-rw-r--r--gcc/ipa-prop.cc370
-rw-r--r--gcc/ipa-prop.h261
-rw-r--r--gcc/lto-streamer-in.cc1
-rw-r--r--gcc/lto-streamer-out.cc1
-rw-r--r--gcc/match.pd10
-rw-r--r--gcc/omp-low.cc4
-rw-r--r--gcc/omp-oacc-kernels-decompose.cc1
-rw-r--r--gcc/passes.cc9
-rw-r--r--gcc/passes.def1
-rw-r--r--gcc/range-op-float.cc193
-rw-r--r--gcc/range-op.cc267
-rw-r--r--gcc/range-op.h29
-rw-r--r--gcc/testsuite/ChangeLog127
-rw-r--r--gcc/testsuite/c-c++-common/pointer-to-fn1.c1
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/pr106990.c29
-rw-r--r--gcc/testsuite/g++.dg/cpp23/attr-assume5.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp23/attr-assume6.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp23/attr-assume7.C56
-rw-r--r--gcc/testsuite/g++.dg/modules/cexpr-3_a.C14
-rw-r--r--gcc/testsuite/g++.dg/modules/cexpr-3_b.C7
-rw-r--r--gcc/testsuite/g++.dg/modules/pr105045_a.C7
-rw-r--r--gcc/testsuite/g++.dg/modules/pr105045_b.C6
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/pr105820.c26
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/pr107206.C27
-rw-r--r--gcc/testsuite/gcc.dg/c11-enum-1.c14
-rw-r--r--gcc/testsuite/gcc.dg/c11-enum-2.c14
-rw-r--r--gcc/testsuite/gcc.dg/c11-enum-3.c14
-rw-r--r--gcc/testsuite/gcc.dg/c2x-enum-1.c104
-rw-r--r--gcc/testsuite/gcc.dg/c2x-enum-2.c14
-rw-r--r--gcc/testsuite/gcc.dg/c2x-enum-3.c14
-rw-r--r--gcc/testsuite/gcc.dg/c2x-enum-4.c14
-rw-r--r--gcc/testsuite/gcc.dg/c2x-enum-5.c12
-rw-r--r--gcc/testsuite/gcc.dg/c99-tag-4.c8
-rw-r--r--gcc/testsuite/gcc.dg/c99-tag-5.c8
-rw-r--r--gcc/testsuite/gcc.dg/c99-tag-6.c9
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipcp-agg-11.c4
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipcp-agg-8.c4
-rw-r--r--gcc/testsuite/gcc.dg/pr106781.c18
-rw-r--r--gcc/testsuite/gcc.dg/pr107262.c13
-rw-r--r--gcc/testsuite/gcc.dg/pr30260.c6
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr107301.c15
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr25183.c8
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/forwprop-19.c4
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr107273-1.c31
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr107273-2.c27
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr107293.c32
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3a.c19
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4a.c23
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/vrp-float-5a.c16
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr107275.c15
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr107302.c13
-rw-r--r--gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s252.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s254.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/tsvc/vect-tsvc-s291.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-recurr-1.c38
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-recurr-2.c39
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-recurr-3.c39
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-recurr-4.c42
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-recurr-5.c43
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-recurr-6.c39
-rw-r--r--gcc/testsuite/gcc.target/i386/pr107271.c16
-rw-r--r--gcc/testsuite/gcc.target/s390/pr106355-1.c42
-rw-r--r--gcc/testsuite/gcc.target/s390/pr106355-2.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/pr106355-3.c8
-rw-r--r--gcc/testsuite/gcc.target/s390/pr106355.h18
-rw-r--r--gcc/testsuite/gfortran.dg/array_constructor_56.f9022
-rw-r--r--gcc/testsuite/gfortran.dg/array_constructor_57.f9030
-rw-r--r--gcc/testsuite/gfortran.dg/char4_decl-2.f9063
-rw-r--r--gcc/testsuite/gfortran.dg/char4_decl.f9056
-rw-r--r--gcc/testsuite/gfortran.dg/pr104330.f9020
-rw-r--r--gcc/testsuite/gfortran.dg/pr107272.f9021
-rw-r--r--gcc/timevar.def1
-rw-r--r--gcc/tree-cfg.cc7
-rw-r--r--gcc/tree-if-conv.cc30
-rw-r--r--gcc/tree-inline.cc5
-rw-r--r--gcc/tree-pass.h6
-rw-r--r--gcc/tree-sra.cc7
-rw-r--r--gcc/tree-ssa-ccp.cc6
-rw-r--r--gcc/tree-ssa-dom.cc6
-rw-r--r--gcc/tree-vect-loop.cc287
-rw-r--r--gcc/tree-vect-slp.cc38
-rw-r--r--gcc/tree-vect-stmts.cc17
-rw-r--r--gcc/tree-vectorizer.h4
-rw-r--r--gcc/tree-vrp.cc35
-rw-r--r--gcc/value-range.cc11
-rw-r--r--gcc/value-relation.cc23
-rw-r--r--gcc/value-relation.h126
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;