diff options
author | Martin Liska <mliska@suse.cz> | 2022-07-21 16:12:11 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-07-21 16:12:11 +0200 |
commit | bb743388df90352e5690848fc39bb9c10457b0e0 (patch) | |
tree | 0ce9895dcbfcdd3ca63f6970f67dddc10e3ae51a | |
parent | e9c8572e74d8de56551ed62f799df7742cd523e9 (diff) | |
parent | 24eae97625e9423e7344f6d7eb6bc2435a62fffd (diff) | |
download | gcc-bb743388df90352e5690848fc39bb9c10457b0e0.zip gcc-bb743388df90352e5690848fc39bb9c10457b0e0.tar.gz gcc-bb743388df90352e5690848fc39bb9c10457b0e0.tar.bz2 |
Merge branch 'master' into devel/sphinx
109 files changed, 4085 insertions, 468 deletions
@@ -23,7 +23,8 @@ autom4te.cache config.cache -config.h +# GCC does not support in-tree builds, do not conceal a stray config.h: +# config.h config.intl config.log config.status @@ -1,3 +1,7 @@ +2022-07-19 Alexander Monakov <amonakov@ispras.ru> + + * .gitignore: Do not ignore config.h. + 2022-07-15 Andrew Carlotti <andrew.carlotti@arm.com> * MAINTAINERS: Add myself to Write After Approval. diff --git a/MAINTAINERS b/MAINTAINERS index 7a7ad42..e2db0cf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -157,6 +157,7 @@ cygwin, mingw-w64 Jonathan Yong <10walls@gmail.com> C front end/ISO C99 Joseph Myers <joseph@codesourcery.com> Ada front end Arnaud Charlet <charlet@adacore.com> Ada front end Eric Botcazou <ebotcazou@libertysurf.fr> +Ada front end Marc Poulhiès <poulhies@adacore.com> Ada front end Pierre-Marie de Rodat <derodat@adacore.com> c++ Jason Merrill <jason@redhat.com> c++ Nathan Sidwell <nathan@acm.org> @@ -581,7 +582,6 @@ Nicolas Pitre <nico@cam.org> Michael Ploujnikov <michael.ploujnikov@oracle.com> Paul Pluzhnikov <ppluzhnikov@google.com> Antoniu Pop <antoniu.pop@gmail.com> -Marc Poulhiès <poulhies@adacore.com> Siddhesh Poyarekar <siddhesh@gotplt.org> Vidya Praveen <vidyapraveen@arm.com> Thomas Preud'homme <thomas.preudhomme@celest.fr> diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 43b70ba..9a8bfd0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,109 @@ +2022-07-20 Alexander Monakov <amonakov@ispras.ru> + + PR rtl-optimization/101347 + * builtins.cc (expand_builtin) [BUILT_IN_SETJMP_SETUP]: Move + population of nonlocal_goto_handler_labels from here ... + (expand_builtin) [BUILT_IN_SETJMP_RECEIVER]: ... to here. + * rtlanal.cc (remove_node_from_insn_list): Verify that a + duplicate is not present in the remainder of the list. + +2022-07-20 Alexander Monakov <amonakov@ispras.ru> + + * rtl.h (remove_node_from_expr_list): Remove declaration. + * rtlanal.cc (remove_node_from_expr_list): Remove (no uses). + +2022-07-20 Richard Biener <rguenther@suse.de> + + * tree-vect-data-refs.cc (bump_vector_ptr): Return an + invariant updated address when the input was invariant. + +2022-07-20 liuhongt <hongtao.liu@intel.com> + + * passes.def: (Split pass_cse_sincos to pass_expand_powcabs + and pass_cse_sincos, and move pass_cse_sincos after vectorizer). + * timevar.def (TV_TREE_POWCABS): New timevar. + * tree-pass.h (make_pass_expand_powcabs): Split from pass_cse_sincos. + * tree-ssa-math-opts.cc (gimple_expand_builtin_cabs): Ditto. + (class pass_expand_powcabs): Ditto. + (pass_expand_powcabs::execute): Ditto. + (make_pass_expand_powcabs): Ditto. + (pass_cse_sincos::execute): Remove pow/cabs expand part. + (make_pass_cse_sincos): Ditto. + +2022-07-20 Richard Biener <richard.guenther@gmail.com> + Hongtao Liu <hongtao.liu@intel.com> + + PR tree-optimization/106010 + * tree-complex.cc (init_dont_simulate_again): Lower complex + type move. + (expand_complex_move): Also expand COMPLEX_CST for rhs. + +2022-07-19 Andrew MacLeod <amacleod@redhat.com> + + * gimple-range-cache.cc (ranger_cache::range_from_dom): Check + for incoming ranges on join nodes and add to worklist. + +2022-07-19 Andrew MacLeod <amacleod@redhat.com> + + * gimple-range-cache.cc (ranger_cache::resolve_dom): New. + (ranger_cache::range_from_dom): Put all nodes to be calculated + in the worklist and resolve after the dom walk. + * gimple-range-cache.h (resolve_dom): New prototype. + +2022-07-19 Alexander Monakov <amonakov@ispras.ru> + + * tree-cfg.cc (gimple_verify_flow_info): Check placement of + returns_twice calls. + +2022-07-19 Alexander Monakov <amonakov@ispras.ru> + + * cfghooks.cc (duplicate_block): Expand comment. + * tree-cfg.cc (gimple_can_duplicate_bb_p): Reject blocks with + calls that may return twice. + +2022-07-19 Alexander Monakov <amonakov@ispras.ru> + + * tree-ssa-sink.cc (select_best_block): Punt if selected block + has incoming abnormal edges. + +2022-07-19 Martin Liska <mliska@suse.cz> + + * doc/extend.texi: Remove trailing :. + +2022-07-19 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org> + + * tree-ssa-forwprop.cc (simplify_permutation): Use lhs type + instead of TREE_TYPE (arg0) as result type in folding VEC_PERM_EXPR. + +2022-07-19 Richard Biener <rguenther@suse.de> + + PR middle-end/106331 + * builtins.cc (get_memory_rtx): Compute alignment from + the original address and set MEM_OFFSET to unknown when + we create a MEM_EXPR from the base object of the address. + +2022-07-19 Richard Biener <rguenther@suse.de> + + PR lto/106334 + * dwarf2out.cc (dwarf2out_register_external_die): Allow + map entry re-use during WPA. + +2022-07-19 Roger Sayle <roger@nextmovesoftware.com> + Richard Biener <rguenther@suse.de> + + PR c/106264 + * builtins.cc (fold_builtin_frexp): Call suppress_warning on + COMPOUND_EXPR to silence spurious warning if result isn't used. + (fold_builtin_modf): Likewise. + (do_mpfr_remquo): Likewise. + +2022-07-19 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/xtensa.cc (xtensa_rtx_costs): + Change the relative cost of '(set (reg) (const_int N))' where + N fits into signed 12-bit from 4 to 0 if optimizing for size. + And use the appropriate macro instead of the bare number 4. + 2022-07-18 Andrew MacLeod <amacleod@redhat.com> PR tree-optimization/106280 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index a394c7a..ace4919 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220719 +20220721 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 4f010eb..a94593e 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,40 @@ +2022-07-20 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/106373 + * sm-taint.cc (taint_state_machine::on_condition): Potentially + update the state of the RHS as well as the LHS. + +2022-07-20 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/106359 + * region.h (string_region::tracked_p): New. + * store.cc (binding_cluster::binding_cluster): Move here from + store.h. Add assertion that base_region is tracked_p. + * store.h (binding_cluster::binding_cluster): Move to store.cc. + +2022-07-19 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/106321 + * constraint-manager.h (bounded_ranges::get_count): New. + (bounded_ranges::get_range): New. + * engine.cc (impl_region_model_context::on_bounded_ranges): New. + * exploded-graph.h (impl_region_model_context::on_bounded_ranges): + New decl. + * region-model.cc (region_model::apply_constraints_for_gswitch): + Potentially call ctxt->on_bounded_ranges. + * region-model.h (region_model_context::on_bounded_ranges): New + vfunc. + (noop_region_model_context::on_bounded_ranges): New. + (region_model_context_decorator::on_bounded_ranges): New. + * sm-taint.cc: Include "analyzer/constraint-manager.h". + (taint_state_machine::on_bounded_ranges): New. + * sm.h (state_machine::on_bounded_ranges): New. + +2022-07-19 David Malcolm <dmalcolm@redhat.com> + + * engine.cc (exploded_graph::process_node): Show any description + of the out-edge when logging it for consideration. + 2022-07-15 David Malcolm <dmalcolm@redhat.com> PR analyzer/106284 diff --git a/gcc/analyzer/constraint-manager.h b/gcc/analyzer/constraint-manager.h index f67c764..1271f18 100644 --- a/gcc/analyzer/constraint-manager.h +++ b/gcc/analyzer/constraint-manager.h @@ -138,6 +138,9 @@ public: static int cmp (const bounded_ranges *a, const bounded_ranges *b); + unsigned get_count () const { return m_ranges.length (); } + const bounded_range &get_range (unsigned idx) const { return m_ranges[idx]; } + private: void canonicalize (); void validate () const; diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 9ffcc41..85b7c5e 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -916,6 +916,32 @@ impl_region_model_context::on_condition (const svalue *lhs, } } +/* Implementation of region_model_context::on_bounded_ranges vfunc. + Notify all state machines about the ranges, which could lead to + state transitions. */ + +void +impl_region_model_context::on_bounded_ranges (const svalue &sval, + const bounded_ranges &ranges) +{ + int sm_idx; + sm_state_map *smap; + FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap) + { + const state_machine &sm = m_ext_state.get_sm (sm_idx); + impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag, + m_old_state, m_new_state, + m_old_state->m_checker_states[sm_idx], + m_new_state->m_checker_states[sm_idx], + m_path_ctxt); + sm.on_bounded_ranges (&sm_ctxt, + (m_enode_for_diag + ? m_enode_for_diag->get_supernode () + : NULL), + m_stmt, sval, ranges); + } +} + /* Implementation of region_model_context::on_phi vfunc. Notify all state machines about the phi, which could lead to state transitions. */ @@ -3974,8 +4000,12 @@ exploded_graph::process_node (exploded_node *node) { found_a_superedge = true; if (logger) - logger->log ("considering SN: %i -> SN: %i", - succ->m_src->m_index, succ->m_dest->m_index); + { + label_text succ_desc (succ->get_description (false)); + logger->log ("considering SN: %i -> SN: %i (%s)", + succ->m_src->m_index, succ->m_dest->m_index, + succ_desc.get ()); + } program_point next_point = program_point::before_supernode (succ->m_dest, succ, diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h index 0613f55..f957568 100644 --- a/gcc/analyzer/exploded-graph.h +++ b/gcc/analyzer/exploded-graph.h @@ -65,6 +65,9 @@ class impl_region_model_context : public region_model_context enum tree_code op, const svalue *rhs) final override; + void on_bounded_ranges (const svalue &sval, + const bounded_ranges &ranges) final override; + void on_unknown_change (const svalue *sval, bool is_mutable) final override; void on_phi (const gphi *phi, tree rhs) final override; diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 8b7b4e1..5bb7112 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -4228,6 +4228,8 @@ region_model::apply_constraints_for_gswitch (const switch_cfg_superedge &edge, bool sat = m_constraints->add_bounded_ranges (index_sval, all_cases_ranges); if (!sat && out) *out = new rejected_ranges_constraint (*this, index, all_cases_ranges); + if (sat && ctxt && !all_cases_ranges->empty_p ()) + ctxt->on_bounded_ranges (*index_sval, *all_cases_ranges); return sat; } diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 6dda43f..42f8abe 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -931,6 +931,13 @@ class region_model_context enum tree_code op, const svalue *rhs) = 0; + /* Hook for clients to be notified when the condition that + SVAL is within RANGES is added to the region model. + Similar to on_condition, but for use when handling switch statements. + RANGES is non-empty. */ + virtual void on_bounded_ranges (const svalue &sval, + const bounded_ranges &ranges) = 0; + /* Hooks for clients to be notified when an unknown change happens to SVAL (in response to a call to an unknown function). */ virtual void on_unknown_change (const svalue *sval, bool is_mutable) = 0; @@ -991,6 +998,10 @@ public: const svalue *rhs ATTRIBUTE_UNUSED) override { } + void on_bounded_ranges (const svalue &, + const bounded_ranges &) override + { + } void on_unknown_change (const svalue *sval ATTRIBUTE_UNUSED, bool is_mutable ATTRIBUTE_UNUSED) override { @@ -1087,6 +1098,12 @@ class region_model_context_decorator : public region_model_context m_inner->on_condition (lhs, op, rhs); } + void on_bounded_ranges (const svalue &sval, + const bounded_ranges &ranges) override + { + m_inner->on_bounded_ranges (sval, ranges); + } + void on_unknown_change (const svalue *sval, bool is_mutable) override { m_inner->on_unknown_change (sval, is_mutable); diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc index a8d1ae9..b78bf4e 100644 --- a/gcc/analyzer/region.cc +++ b/gcc/analyzer/region.cc @@ -1152,6 +1152,11 @@ decl_region::get_svalue_for_initializer (region_model_manager *mgr) const if (binding->symbolic_p ()) return NULL; + /* If we don't care about tracking the content of this region, then + it's unused, and the value doesn't matter. */ + if (!tracked_p ()) + return NULL; + binding_cluster c (this); c.zero_fill_region (mgr->get_store_manager (), this); return mgr->get_or_create_compound_svalue (TREE_TYPE (m_decl), diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h index 60d8149..fd0d4a0 100644 --- a/gcc/analyzer/region.h +++ b/gcc/analyzer/region.h @@ -1151,6 +1151,10 @@ public: void dump_to_pp (pretty_printer *pp, bool simple) const final override; + /* We assume string literals are immutable, so we don't track them in + the store. */ + bool tracked_p () const final override { return false; } + tree get_string_cst () const { return m_string_cst; } private: diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc index 2de9284..51bfe06 100644 --- a/gcc/analyzer/sm-taint.cc +++ b/gcc/analyzer/sm-taint.cc @@ -51,6 +51,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/sm.h" #include "analyzer/program-state.h" #include "analyzer/pending-diagnostic.h" +#include "analyzer/constraint-manager.h" #if ENABLE_ANALYZER @@ -97,6 +98,11 @@ public: const svalue *lhs, enum tree_code op, const svalue *rhs) const final override; + void on_bounded_ranges (sm_context *sm_ctxt, + const supernode *node, + const gimple *stmt, + const svalue &sval, + const bounded_ranges &ranges) const final override; bool can_purge_p (state_t s) const final override; @@ -206,53 +212,96 @@ public: diagnostic_metadata m; /* CWE-129: "Improper Validation of Array Index". */ m.add_cwe (129); - switch (m_has_bounds) - { - default: - gcc_unreachable (); - case BOUNDS_NONE: - return warning_meta (rich_loc, m, get_controlling_option (), - "use of attacker-controlled value %qE" - " in array lookup without bounds checking", - m_arg); - break; - case BOUNDS_UPPER: - return warning_meta (rich_loc, m, get_controlling_option (), - "use of attacker-controlled value %qE" - " in array lookup without checking for negative", - m_arg); - break; - case BOUNDS_LOWER: - return warning_meta (rich_loc, m, get_controlling_option (), - "use of attacker-controlled value %qE" - " in array lookup without upper-bounds checking", - m_arg); - break; - } + if (m_arg) + switch (m_has_bounds) + { + default: + gcc_unreachable (); + case BOUNDS_NONE: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value %qE" + " in array lookup without bounds checking", + m_arg); + break; + case BOUNDS_UPPER: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value %qE" + " in array lookup without checking for negative", + m_arg); + break; + case BOUNDS_LOWER: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value %qE" + " in array lookup without upper-bounds checking", + m_arg); + break; + } + else + switch (m_has_bounds) + { + default: + gcc_unreachable (); + case BOUNDS_NONE: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value" + " in array lookup without bounds checking"); + break; + case BOUNDS_UPPER: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value" + " in array lookup without checking for" + " negative"); + break; + case BOUNDS_LOWER: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value" + " in array lookup without upper-bounds" + " checking"); + break; + } } label_text describe_final_event (const evdesc::final_event &ev) final override { - switch (m_has_bounds) - { - default: - gcc_unreachable (); - case BOUNDS_NONE: - return ev.formatted_print - ("use of attacker-controlled value %qE in array lookup" - " without bounds checking", - m_arg); - case BOUNDS_UPPER: - return ev.formatted_print - ("use of attacker-controlled value %qE" - " in array lookup without checking for negative", - m_arg); - case BOUNDS_LOWER: - return ev.formatted_print - ("use of attacker-controlled value %qE" - " in array lookup without upper-bounds checking", - m_arg); - } + if (m_arg) + switch (m_has_bounds) + { + default: + gcc_unreachable (); + case BOUNDS_NONE: + return ev.formatted_print + ("use of attacker-controlled value %qE in array lookup" + " without bounds checking", + m_arg); + case BOUNDS_UPPER: + return ev.formatted_print + ("use of attacker-controlled value %qE" + " in array lookup without checking for negative", + m_arg); + case BOUNDS_LOWER: + return ev.formatted_print + ("use of attacker-controlled value %qE" + " in array lookup without upper-bounds checking", + m_arg); + } + else + switch (m_has_bounds) + { + default: + gcc_unreachable (); + case BOUNDS_NONE: + return ev.formatted_print + ("use of attacker-controlled value in array lookup" + " without bounds checking"); + case BOUNDS_UPPER: + return ev.formatted_print + ("use of attacker-controlled value" + " in array lookup without checking for negative"); + case BOUNDS_LOWER: + return ev.formatted_print + ("use of attacker-controlled value" + " in array lookup without upper-bounds checking"); + } } }; @@ -388,50 +437,88 @@ public: { diagnostic_metadata m; m.add_cwe (129); - switch (m_has_bounds) - { - default: - gcc_unreachable (); - case BOUNDS_NONE: - return warning_meta (rich_loc, m, get_controlling_option (), - "use of attacker-controlled value %qE as size" - " without bounds checking", - m_arg); - break; - case BOUNDS_UPPER: - return warning_meta (rich_loc, m, get_controlling_option (), - "use of attacker-controlled value %qE as size" - " without lower-bounds checking", - m_arg); - break; - case BOUNDS_LOWER: - return warning_meta (rich_loc, m, get_controlling_option (), - "use of attacker-controlled value %qE as size" - " without upper-bounds checking", - m_arg); - break; - } + if (m_arg) + switch (m_has_bounds) + { + default: + gcc_unreachable (); + case BOUNDS_NONE: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value %qE as size" + " without bounds checking", + m_arg); + break; + case BOUNDS_UPPER: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value %qE as size" + " without lower-bounds checking", + m_arg); + break; + case BOUNDS_LOWER: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value %qE as size" + " without upper-bounds checking", + m_arg); + break; + } + else + switch (m_has_bounds) + { + default: + gcc_unreachable (); + case BOUNDS_NONE: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value as size" + " without bounds checking"); + break; + case BOUNDS_UPPER: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value as size" + " without lower-bounds checking"); + break; + case BOUNDS_LOWER: + return warning_meta (rich_loc, m, get_controlling_option (), + "use of attacker-controlled value as size" + " without upper-bounds checking"); + break; + } } label_text describe_final_event (const evdesc::final_event &ev) final override { - switch (m_has_bounds) - { - default: - gcc_unreachable (); - case BOUNDS_NONE: - return ev.formatted_print ("use of attacker-controlled value %qE" - " as size without bounds checking", - m_arg); - case BOUNDS_UPPER: - return ev.formatted_print ("use of attacker-controlled value %qE" - " as size without lower-bounds checking", - m_arg); - case BOUNDS_LOWER: - return ev.formatted_print ("use of attacker-controlled value %qE" - " as size without upper-bounds checking", - m_arg); - } + if (m_arg) + switch (m_has_bounds) + { + default: + gcc_unreachable (); + case BOUNDS_NONE: + return ev.formatted_print ("use of attacker-controlled value %qE" + " as size without bounds checking", + m_arg); + case BOUNDS_UPPER: + return ev.formatted_print ("use of attacker-controlled value %qE" + " as size without lower-bounds checking", + m_arg); + case BOUNDS_LOWER: + return ev.formatted_print ("use of attacker-controlled value %qE" + " as size without upper-bounds checking", + m_arg); + } + else + switch (m_has_bounds) + { + default: + gcc_unreachable (); + case BOUNDS_NONE: + return ev.formatted_print ("use of attacker-controlled value" + " as size without bounds checking"); + case BOUNDS_UPPER: + return ev.formatted_print ("use of attacker-controlled value" + " as size without lower-bounds checking"); + case BOUNDS_LOWER: + return ev.formatted_print ("use of attacker-controlled value" + " as size without upper-bounds checking"); + } } }; @@ -824,13 +911,11 @@ taint_state_machine::on_condition (sm_context *sm_ctxt, const gimple *stmt, const svalue *lhs, enum tree_code op, - const svalue *rhs ATTRIBUTE_UNUSED) const + const svalue *rhs) const { if (stmt == NULL) return; - // TODO: this doesn't use the RHS; should we make it symmetric? - // TODO switch (op) { @@ -839,10 +924,17 @@ taint_state_machine::on_condition (sm_context *sm_ctxt, case GE_EXPR: case GT_EXPR: { + /* (LHS >= RHS) or (LHS > RHS) + LHS gains a lower bound + RHS gains an upper bound. */ sm_ctxt->on_transition (node, stmt, lhs, m_tainted, m_has_lb); sm_ctxt->on_transition (node, stmt, lhs, m_has_ub, m_stop); + sm_ctxt->on_transition (node, stmt, rhs, m_tainted, + m_has_ub); + sm_ctxt->on_transition (node, stmt, rhs, m_has_lb, + m_stop); } break; case LE_EXPR: @@ -890,10 +982,17 @@ taint_state_machine::on_condition (sm_context *sm_ctxt, } } + /* (LHS <= RHS) or (LHS < RHS) + LHS gains an upper bound + RHS gains a lower bound. */ sm_ctxt->on_transition (node, stmt, lhs, m_tainted, m_has_ub); sm_ctxt->on_transition (node, stmt, lhs, m_has_lb, m_stop); + sm_ctxt->on_transition (node, stmt, rhs, m_tainted, + m_has_lb); + sm_ctxt->on_transition (node, stmt, rhs, m_has_ub, + m_stop); } break; default: @@ -901,6 +1000,58 @@ taint_state_machine::on_condition (sm_context *sm_ctxt, } } +/* Implementation of state_machine::on_bounded_ranges vfunc for + taint_state_machine, for handling switch statement cases. + Potentially transition state 'tainted' to 'has_ub' or 'has_lb', + and states 'has_ub' and 'has_lb' to 'stop'. */ + +void +taint_state_machine::on_bounded_ranges (sm_context *sm_ctxt, + const supernode *, + const gimple *stmt, + const svalue &sval, + const bounded_ranges &ranges) const +{ + gcc_assert (!ranges.empty_p ()); + gcc_assert (ranges.get_count () > 0); + + /* We have one or more ranges; this could be a "default:", or one or + more single or range cases. + + Look at the overall endpoints to see if the ranges impose any lower + bounds or upper bounds beyond those of the underlying numeric type. */ + + tree lowest_bound = ranges.get_range (0).m_lower; + tree highest_bound = ranges.get_range (ranges.get_count () - 1).m_upper; + gcc_assert (lowest_bound); + gcc_assert (highest_bound); + + bool ranges_have_lb + = (lowest_bound != TYPE_MIN_VALUE (TREE_TYPE (lowest_bound))); + bool ranges_have_ub + = (highest_bound != TYPE_MAX_VALUE (TREE_TYPE (highest_bound))); + + if (!ranges_have_lb && !ranges_have_ub) + return; + + /* We have new bounds from the ranges; combine them with any + existing bounds on SVAL. */ + state_t old_state = sm_ctxt->get_state (stmt, &sval); + if (old_state == m_tainted) + { + if (ranges_have_lb && ranges_have_ub) + sm_ctxt->set_next_state (stmt, &sval, m_stop); + else if (ranges_have_lb) + sm_ctxt->set_next_state (stmt, &sval, m_has_lb); + else if (ranges_have_ub) + sm_ctxt->set_next_state (stmt, &sval, m_has_ub); + } + else if (old_state == m_has_ub && ranges_have_lb) + sm_ctxt->set_next_state (stmt, &sval, m_stop); + else if (old_state == m_has_lb && ranges_have_ub) + sm_ctxt->set_next_state (stmt, &sval, m_stop); +} + bool taint_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const { diff --git a/gcc/analyzer/sm.h b/gcc/analyzer/sm.h index 353a6db..87ab11c 100644 --- a/gcc/analyzer/sm.h +++ b/gcc/analyzer/sm.h @@ -108,6 +108,15 @@ public: { } + virtual void + on_bounded_ranges (sm_context *sm_ctxt ATTRIBUTE_UNUSED, + const supernode *node ATTRIBUTE_UNUSED, + const gimple *stmt ATTRIBUTE_UNUSED, + const svalue &sval ATTRIBUTE_UNUSED, + const bounded_ranges &ranges ATTRIBUTE_UNUSED) const + { + } + /* Return true if it safe to discard the given state (to help when simplifying state objects). States that need leak detection should return false. */ diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index 06151d8..e3dabf3 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -1103,6 +1103,13 @@ binding_map::remove_overlapping_bindings (store_manager *mgr, /* class binding_cluster. */ +binding_cluster::binding_cluster (const region *base_region) +: m_base_region (base_region), m_map (), + m_escaped (false), m_touched (false) +{ + gcc_assert (base_region->tracked_p ()); +} + /* binding_cluster's copy ctor. */ binding_cluster::binding_cluster (const binding_cluster &other) diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h index 368b299..9b54c7b 100644 --- a/gcc/analyzer/store.h +++ b/gcc/analyzer/store.h @@ -544,9 +544,7 @@ public: typedef hash_map <const binding_key *, const svalue *> map_t; typedef map_t::iterator iterator_t; - binding_cluster (const region *base_region) - : m_base_region (base_region), m_map (), - m_escaped (false), m_touched (false) {} + binding_cluster (const region *base_region); binding_cluster (const binding_cluster &other); binding_cluster& operator=(const binding_cluster &other); diff --git a/gcc/builtins.cc b/gcc/builtins.cc index 0d13197..b08b436 100644 --- a/gcc/builtins.cc +++ b/gcc/builtins.cc @@ -7472,15 +7472,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, tree label = TREE_OPERAND (CALL_EXPR_ARG (exp, 1), 0); rtx_insn *label_r = label_rtx (label); - /* This is copied from the handling of non-local gotos. */ expand_builtin_setjmp_setup (buf_addr, label_r); - nonlocal_goto_handler_labels - = gen_rtx_INSN_LIST (VOIDmode, label_r, - nonlocal_goto_handler_labels); - /* ??? Do not let expand_label treat us as such since we would - not want to be both on the list of non-local labels and on - the list of forced labels. */ - FORCED_LABEL (label) = 0; return const0_rtx; } break; @@ -7493,6 +7485,13 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, rtx_insn *label_r = label_rtx (label); expand_builtin_setjmp_receiver (label_r); + nonlocal_goto_handler_labels + = gen_rtx_INSN_LIST (VOIDmode, label_r, + nonlocal_goto_handler_labels); + /* ??? Do not let expand_label treat us as such since we would + not want to be both on the list of non-local labels and on + the list of forced labels. */ + FORCED_LABEL (label) = 0; return const0_rtx; } break; diff --git a/gcc/cfghooks.cc b/gcc/cfghooks.cc index e435891..c6ac953 100644 --- a/gcc/cfghooks.cc +++ b/gcc/cfghooks.cc @@ -1086,9 +1086,16 @@ can_duplicate_block_p (const_basic_block bb) return cfg_hooks->can_duplicate_block_p (bb); } -/* Duplicates basic block BB and redirects edge E to it. Returns the - new basic block. The new basic block is placed after the basic block - AFTER. */ +/* Duplicate basic block BB, place it after AFTER (if non-null) and redirect + edge E to it (if non-null). Return the new basic block. + + If BB contains a returns_twice call, the caller is responsible for recreating + incoming abnormal edges corresponding to the "second return" for the copy. + gimple_can_duplicate_bb_p rejects such blocks, while RTL likes to live + dangerously. + + If BB has incoming abnormal edges for some other reason, their destinations + should be tied to label(s) of the original BB and not the copy. */ basic_block duplicate_block (basic_block bb, edge e, basic_block after, copy_bb_data *id) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ce6f8ea..2664940 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2022-07-19 Patrick Palka <ppalka@redhat.com> + + PR c++/94894 + PR c++/105766 + PR c++/106201 + * call.cc (enum conversion_kind): Add ck_deferred_bad enumerator. + (has_next): Return false for it. + (reference_binding): Return a ck_deferred_bad conversion instead + of an actual bad conversion when LOOKUP_SHORTCUT_BAD_CONVS is set. + Remove now obsolete early exit for the incomplete TO case. + (implicit_conversion_1): Don't mask out LOOKUP_SHORTCUT_BAD_CONVS. + (add_function_candidate): Set LOOKUP_SHORTCUT_BAD_CONVS iff + shortcut_bad_convs. + (missing_conversion_p): Also return true for a ck_deferred_bad + conversion. + * cp-tree.h (LOOKUP_SHORTCUT_BAD_CONVS): Define. + +2022-07-19 Jonathan Wakely <jwakely@redhat.com> + + * cp-objcp-common.cc (names_builtin_p): Return true for + RID_REF_CONSTRUCTS_FROM_TEMPORARY and + RID_REF_CONVERTS_FROM_TEMPORARY. + 2022-07-15 Marek Polacek <polacek@redhat.com> PR c++/104477 diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 191c68c..01a7be1 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -59,7 +59,13 @@ enum conversion_kind { ck_ambig, ck_list, ck_aggr, - ck_rvalue + ck_rvalue, + /* When LOOKUP_SHORTCUT_BAD_CONVS is set, we may return a conversion of + this kind whenever we know the true conversion is either bad or outright + invalid, but we don't want to attempt to compute the bad conversion (for + sake of avoiding unnecessary instantiation). bad_p should always be set + for these. */ + ck_deferred_bad, }; /* The rank of the conversion. Order of the enumerals matters; better @@ -775,7 +781,8 @@ has_next (conversion_kind code) return !(code == ck_identity || code == ck_ambig || code == ck_list - || code == ck_aggr); + || code == ck_aggr + || code == ck_deferred_bad); } static conversion * @@ -1912,18 +1919,38 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, difference in top-level cv-qualification is subsumed by the initialization itself and does not constitute a conversion. */ + bool maybe_valid_p = true; + /* [dcl.init.ref] Otherwise, the reference shall be an lvalue reference to a non-volatile const type, or the reference shall be an rvalue - reference. + reference. */ + if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto)) + maybe_valid_p = false; - We try below to treat this as a bad conversion to improve diagnostics, - but if TO is an incomplete class, we need to reject this conversion - now to avoid unnecessary instantiation. */ - if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto) - && !COMPLETE_TYPE_P (to)) - return NULL; + /* [dcl.init.ref] + + Otherwise, a temporary of type "cv1 T1" is created and + initialized from the initializer expression using the rules for a + non-reference copy initialization. If T1 is reference-related to + T2, cv1 must be the same cv-qualification as, or greater + cv-qualification than, cv2; otherwise, the program is ill-formed. */ + if (related_p && !at_least_as_qualified_p (to, from)) + maybe_valid_p = false; + + /* We try below to treat an invalid reference binding as a bad conversion + to improve diagnostics, but doing so may cause otherwise unnecessary + instantiations that can lead to a hard error. So during the first pass + of overload resolution wherein we shortcut bad conversions, instead just + produce a special conversion indicating a second pass is necessary if + there's no strictly viable candidate. */ + if (!maybe_valid_p && (flags & LOOKUP_SHORTCUT_BAD_CONVS)) + { + conv = alloc_conversion (ck_deferred_bad); + conv->bad_p = true; + return conv; + } /* We're generating a temporary now, but don't bind any more in the conversion (specifically, don't slice the temporary returned by a @@ -1967,7 +1994,9 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, sflags, complain); if (!new_second) return NULL; - return merge_conversion_sequences (t, new_second); + conv = merge_conversion_sequences (t, new_second); + gcc_assert (maybe_valid_p || conv->bad_p); + return conv; } } @@ -1976,24 +2005,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, creation of a temporary. */ conv->need_temporary_p = true; conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto); - - /* [dcl.init.ref] - - Otherwise, the reference shall be an lvalue reference to a - non-volatile const type, or the reference shall be an rvalue - reference. */ - if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto)) - conv->bad_p = true; - - /* [dcl.init.ref] - - Otherwise, a temporary of type "cv1 T1" is created and - initialized from the initializer expression using the rules for a - non-reference copy initialization. If T1 is reference-related to - T2, cv1 must be the same cv-qualification as, or greater - cv-qualification than, cv2; otherwise, the program is ill-formed. */ - if (related_p && !at_least_as_qualified_p (to, from)) - conv->bad_p = true; + conv->bad_p |= !maybe_valid_p; return conv; } @@ -2015,7 +2027,8 @@ implicit_conversion_1 (tree to, tree from, tree expr, bool c_cast_p, resolution, or after we've chosen one. */ flags &= (LOOKUP_ONLYCONVERTING|LOOKUP_NO_CONVERSION|LOOKUP_COPY_PARM |LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND|LOOKUP_PREFER_RVALUE - |LOOKUP_NO_NARROWING|LOOKUP_PROTECT|LOOKUP_NO_NON_INTEGRAL); + |LOOKUP_NO_NARROWING|LOOKUP_PROTECT|LOOKUP_NO_NON_INTEGRAL + |LOOKUP_SHORTCUT_BAD_CONVS); /* FIXME: actually we don't want warnings either, but we can't just have 'complain &= ~(tf_warning|tf_error)' because it would cause @@ -2433,6 +2446,11 @@ add_function_candidate (struct z_candidate **candidates, if (! viable) goto out; + if (shortcut_bad_convs) + flags |= LOOKUP_SHORTCUT_BAD_CONVS; + else + flags &= ~LOOKUP_SHORTCUT_BAD_CONVS; + /* Third, for F to be a viable function, there shall exist for each argument an implicit conversion sequence that converts that argument to the corresponding parameter of F. */ @@ -6038,14 +6056,24 @@ perfect_candidate_p (z_candidate *cand) return true; } -/* True iff one of CAND's argument conversions is NULL. */ +/* True iff one of CAND's argument conversions is missing. */ static bool missing_conversion_p (const z_candidate *cand) { for (unsigned i = 0; i < cand->num_convs; ++i) - if (!cand->convs[i]) - return true; + { + conversion *conv = cand->convs[i]; + if (!conv) + return true; + if (conv->kind == ck_deferred_bad) + { + /* We don't know whether this conversion is outright invalid or + just bad, so conservatively assume it's missing. */ + gcc_checking_assert (conv->bad_p); + return true; + } + } return false; } diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc index 0b70d55..4079a4b 100644 --- a/gcc/cp/cp-objcp-common.cc +++ b/gcc/cp/cp-objcp-common.cc @@ -461,6 +461,8 @@ names_builtin_p (const char *name) case RID_IS_ASSIGNABLE: case RID_IS_CONSTRUCTIBLE: case RID_UNDERLYING_TYPE: + case RID_REF_CONSTRUCTS_FROM_TEMPORARY: + case RID_REF_CONVERTS_FROM_TEMPORARY: return true; default: break; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index cf51c39..3278b41 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5877,6 +5877,11 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; #define LOOKUP_REVERSED (LOOKUP_REWRITTEN << 1) /* We're initializing an aggregate from a parenthesized list of values. */ #define LOOKUP_AGGREGATE_PAREN_INIT (LOOKUP_REVERSED << 1) +/* We're computing conversions as part of a first pass of overload resolution + wherein we don't try to distinguish an unviable candidate from a + non-strictly viable candidate and thus can avoid computing unnecessary + bad conversions. */ +#define LOOKUP_SHORTCUT_BAD_CONVS (LOOKUP_AGGREGATE_PAREN_INIT << 1) /* These flags are used by the conversion code. CONV_IMPLICIT : Perform implicit conversions (standard and user-defined). diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index cfe1e6d..1109cd2 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,18 @@ +2022-07-20 Harald Anlauf <anlauf@gmx.de> + + PR fortran/101330 + * openmp.cc (gfc_match_iterator): Remove left-over code from + development that could lead to a crash on invalid input. + +2022-07-19 Harald Anlauf <anlauf@gmx.de> + + PR fortran/103590 + * resolve.cc (find_array_spec): Change function result to bool to + enable error recovery. Generate error message for invalid array + reference of non-array entity instead of an internal error. + (gfc_resolve_ref): Use function result from find_array_spec for + error recovery. + 2022-07-15 Steve Kargl <kargl@gcc.gnu.org> PR fortran/104313 diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi index ceb5171..ce927ca 100644 --- a/gcc/fortran/intrinsic.texi +++ b/gcc/fortran/intrinsic.texi @@ -300,7 +300,7 @@ Some basic guidelines for editing this document: * @code{TRANSFER}: TRANSFER, Transfer bit patterns * @code{TRANSPOSE}: TRANSPOSE, Transpose an array of rank two * @code{TRIM}: TRIM, Remove trailing blank characters of a string -* @code{TTYNAM}: TTYNAM, Get the name of a terminal device. +* @code{TTYNAM}: TTYNAM, Get the name of a terminal device * @code{UBOUND}: UBOUND, Upper dimension bounds of an array * @code{UCOBOUND}: UCOBOUND, Upper codimension bounds of an array * @code{UMASK}: UMASK, Set the file creation mask @@ -8734,7 +8734,7 @@ END PROGRAM @node ISATTY -@section @code{ISATTY} --- Whether a unit is a terminal device. +@section @code{ISATTY} --- Whether a unit is a terminal device @fnindex ISATTY @cindex system, terminal @@ -14597,7 +14597,7 @@ END PROGRAM @node TTYNAM -@section @code{TTYNAM} --- Get the name of a terminal device. +@section @code{TTYNAM} --- Get the name of a terminal device @fnindex TTYNAM @cindex system, terminal diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc index bd4ff25..df9cdf4 100644 --- a/gcc/fortran/openmp.cc +++ b/gcc/fortran/openmp.cc @@ -1181,7 +1181,6 @@ gfc_match_iterator (gfc_namespace **ns, bool permit_var) } if (':' == gfc_peek_ascii_char ()) { - step = gfc_get_expr (); if (gfc_match (": %e ", &step) != MATCH_YES) { gfc_free_expr (begin); diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc index 2ebf076..ca11475 100644 --- a/gcc/fortran/resolve.cc +++ b/gcc/fortran/resolve.cc @@ -4976,7 +4976,7 @@ gfc_resolve_dim_arg (gfc_expr *dim) static void resolve_assoc_var (gfc_symbol* sym, bool resolve_target); -static void +static bool find_array_spec (gfc_expr *e) { gfc_array_spec *as; @@ -5004,7 +5004,11 @@ find_array_spec (gfc_expr *e) { case REF_ARRAY: if (as == NULL) - gfc_internal_error ("find_array_spec(): Missing spec"); + { + gfc_error ("Invalid array reference of a non-array entity at %L", + &ref->u.ar.where); + return false; + } ref->u.ar.as = as; as = NULL; @@ -5028,6 +5032,8 @@ find_array_spec (gfc_expr *e) if (as != NULL) gfc_internal_error ("find_array_spec(): unused as(2)"); + + return true; } @@ -5346,7 +5352,8 @@ gfc_resolve_ref (gfc_expr *expr) for (ref = expr->ref; ref; ref = ref->next) if (ref->type == REF_ARRAY && ref->u.ar.as == NULL) { - find_array_spec (expr); + if (!find_array_spec (expr)) + return false; break; } diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index da7b805..f3292fc 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -1312,6 +1312,38 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb) fprintf (dump_file, " Propagation update done.\n"); } +// Resolve the range of BB if the dominators range is R by calculating incoming +// edges to this block. All lead back to the dominator so should be cheap. +// The range for BB is set and returned in R. + +void +ranger_cache::resolve_dom (vrange &r, tree name, basic_block bb) +{ + basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (name)); + basic_block dom_bb = get_immediate_dominator (CDI_DOMINATORS, bb); + + // if it doesn't already have a value, store the incoming range. + if (!m_on_entry.bb_range_p (name, dom_bb) && def_bb != dom_bb) + { + // If the range can't be store, don't try to accumulate + // the range in PREV_BB due to excessive recalculations. + if (!m_on_entry.set_bb_range (name, dom_bb, r)) + return; + } + // With the dominator set, we should be able to cheaply query + // each incoming edge now and accumulate the results. + r.set_undefined (); + edge e; + edge_iterator ei; + Value_Range er (TREE_TYPE (name)); + FOR_EACH_EDGE (e, ei, bb->preds) + { + edge_range (er, e, name, RFD_READ_ONLY); + r.union_ (er); + } + // Set the cache in PREV_BB so it is not calculated again. + m_on_entry.set_bb_range (name, bb, r); +} // Get the range of NAME from dominators of BB and return it in R. Search the // dominator tree based on MODE. @@ -1341,7 +1373,7 @@ ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb, // Default value is global range. get_global_range (r, name); - // Search until a value is found, pushing outgoing edges encountered. + // Search until a value is found, pushing blocks which may need calculating. for (bb = get_immediate_dominator (CDI_DOMINATORS, start_bb); bb; prev_bb = bb, bb = get_immediate_dominator (CDI_DOMINATORS, bb)) @@ -1351,38 +1383,31 @@ ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb, // This block has an outgoing range. if (m_gori.has_edge_range_p (name, bb)) + m_workback.quick_push (prev_bb); + else { - // Only outgoing ranges to single_pred blocks are dominated by - // outgoing edge ranges, so those can be simply adjusted on the fly. - edge e = find_edge (bb, prev_bb); - if (e && single_pred_p (prev_bb)) - m_workback.quick_push (prev_bb); - else if (mode == RFD_FILL) + // Normally join blocks don't carry any new range information on + // incoming edges. If the first incoming edge to this block does + // generate a range, calculate the ranges if all incoming edges + // are also dominated by the dominator. (Avoids backedges which + // will break the rule of moving only upward in the domniator tree). + // If the first pred does not generate a range, then we will be + // using the dominator range anyway, so thats all the check needed. + if (EDGE_COUNT (prev_bb->preds) > 1 + && m_gori.has_edge_range_p (name, EDGE_PRED (prev_bb, 0)->src)) { - // Multiple incoming edges, so recursively satisfy this block - // if it doesn't already have a value, and store the range. - if (!m_on_entry.bb_range_p (name, bb) && def_bb != bb) - { - // If the dominator has not been set, look it up. - range_from_dom (r, name, bb, RFD_FILL); - // If the range can't be store, don't try to accumulate - // the range in PREV_BB due to excessive recalculations. - if (!m_on_entry.set_bb_range (name, bb, r)) - break; - } - // With the dominator set, we should be able to cheaply query - // each incoming edge now and accumulate the results. - r.set_undefined (); + edge e; edge_iterator ei; - Value_Range er (TREE_TYPE (name)); + bool all_dom = true; FOR_EACH_EDGE (e, ei, prev_bb->preds) - { - edge_range (er, e, name, RFD_READ_ONLY); - r.union_ (er); - } - // Set the cache in PREV_BB so it is not calculated again. - m_on_entry.set_bb_range (name, prev_bb, r); - break; + if (e->src != bb + && !dominated_by_p (CDI_DOMINATORS, e->src, bb)) + { + all_dom = false; + break; + } + if (all_dom) + m_workback.quick_push (prev_bb); } } @@ -1403,14 +1428,25 @@ ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb, fprintf (dump_file, " at function top\n"); } - // Now process any outgoing edges that we seen along the way. + // Now process any blocks wit incoming edges that nay have adjustemnts. while (m_workback.length () > start_limit) { int_range_max er; prev_bb = m_workback.pop (); + if (!single_pred_p (prev_bb)) + { + // Non single pred means we need to cache a vsalue in the dominator + // so we can cheaply calculate incoming edges to this block, and + // then store the resulting value. If processing mode is not + // RFD_FILL, then the cache cant be stored to, so don't try. + // Otherwise this becomes a quadratic timed calculation. + if (mode == RFD_FILL) + resolve_dom (r, name, prev_bb); + continue; + } + edge e = single_pred_edge (prev_bb); bb = e->src; - if (m_gori.outgoing_edge_range_p (er, e, name, *this)) { r.intersect (er); diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h index 0341192..45053b5 100644 --- a/gcc/gimple-range-cache.h +++ b/gcc/gimple-range-cache.h @@ -107,6 +107,7 @@ private: RFD_FILL // Scan DOM tree, updating important nodes. }; bool range_from_dom (vrange &r, tree name, basic_block bb, enum rfd_mode); + void resolve_dom (vrange &r, tree name, basic_block bb); void range_of_def (vrange &r, tree name, basic_block bb = NULL); void entry_range (vrange &r, tree expr, basic_block bb, enum rfd_mode); void exit_range (vrange &r, tree expr, basic_block bb, enum rfd_mode); diff --git a/gcc/match.pd b/gcc/match.pd index 8bbc0db..88a1a5a 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1938,6 +1938,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (tree_nop_conversion_p (type, TREE_TYPE (@0))) (bit_not (bit_xor (view_convert @0) @1)))) +/* ~(a ^ b) is a == b for truth valued a and b. */ +(simplify + (bit_not (bit_xor:s truth_valued_p@0 truth_valued_p@1)) + (if (!VECTOR_TYPE_P (type)) + (convert (eq @0 @1)))) + /* (x & ~m) | (y & m) -> ((x ^ y) & m) ^ x */ (simplify (bit_ior:c (bit_and:cs @0 (bit_not @2)) (bit_and:cs @1 @2)) diff --git a/gcc/passes.def b/gcc/passes.def index 375d3d6..6bb92ef 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -253,7 +253,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_ccp, true /* nonzero_p */); /* After CCP we rewrite no longer addressed locals into SSA form if possible. */ - NEXT_PASS (pass_cse_sincos); + NEXT_PASS (pass_expand_powcabs); NEXT_PASS (pass_optimize_bswap); NEXT_PASS (pass_laddress); NEXT_PASS (pass_lim); @@ -328,6 +328,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_simduid_cleanup); NEXT_PASS (pass_lower_vector_ssa); NEXT_PASS (pass_lower_switch); + NEXT_PASS (pass_cse_sincos); NEXT_PASS (pass_cse_reciprocals); NEXT_PASS (pass_reassoc, false /* early_p */); NEXT_PASS (pass_strength_reduction); @@ -3712,7 +3712,6 @@ extern unsigned hash_rtx_cb (const_rtx, machine_mode, int *, int *, extern rtx regno_use_in (unsigned int, rtx); extern int auto_inc_p (const_rtx); extern bool in_insn_list_p (const rtx_insn_list *, const rtx_insn *); -extern void remove_node_from_expr_list (const_rtx, rtx_expr_list **); extern void remove_node_from_insn_list (const rtx_insn *, rtx_insn_list **); extern int loc_mentioned_in_p (rtx *, const_rtx); extern rtx_insn *find_first_parameter_load (rtx_insn *, rtx_insn *); diff --git a/gcc/rtlanal.cc b/gcc/rtlanal.cc index d78cc60..56da743 100644 --- a/gcc/rtlanal.cc +++ b/gcc/rtlanal.cc @@ -2878,35 +2878,6 @@ in_insn_list_p (const rtx_insn_list *listp, const rtx_insn *node) return false; } -/* Search LISTP (an EXPR_LIST) for an entry whose first operand is NODE and - remove that entry from the list if it is found. - - A simple equality test is used to determine if NODE matches. */ - -void -remove_node_from_expr_list (const_rtx node, rtx_expr_list **listp) -{ - rtx_expr_list *temp = *listp; - rtx_expr_list *prev = NULL; - - while (temp) - { - if (node == temp->element ()) - { - /* Splice the node out of the list. */ - if (prev) - XEXP (prev, 1) = temp->next (); - else - *listp = temp->next (); - - return; - } - - prev = temp; - temp = temp->next (); - } -} - /* Search LISTP (an INSN_LIST) for an entry whose first operand is NODE and remove that entry from the list if it is found. @@ -2928,6 +2899,7 @@ remove_node_from_insn_list (const rtx_insn *node, rtx_insn_list **listp) else *listp = temp->next (); + gcc_checking_assert (!in_insn_list_p (temp->next (), node)); return; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 36913da..44d6ee2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,84 @@ +2022-07-20 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/106373 + * gcc.dg/analyzer/torture/taint-read-index-3.c: New test. + +2022-07-20 Harald Anlauf <anlauf@gmx.de> + + PR fortran/101330 + * gfortran.dg/gomp/affinity-clause-7.f90: New test. + +2022-07-20 liuhongt <hongtao.liu@intel.com> + + * gcc.dg/pow-sqrt-synth-1.c: Adjust testcase. + +2022-07-20 Richard Biener <richard.guenther@gmail.com> + Hongtao Liu <hongtao.liu@intel.com> + + * gcc.target/i386/pr106010-1a.c: New test. + * gcc.target/i386/pr106010-1b.c: New test. + * gcc.target/i386/pr106010-1c.c: New test. + * gcc.target/i386/pr106010-2a.c: New test. + * gcc.target/i386/pr106010-2b.c: New test. + * gcc.target/i386/pr106010-2c.c: New test. + * gcc.target/i386/pr106010-3a.c: New test. + * gcc.target/i386/pr106010-3b.c: New test. + * gcc.target/i386/pr106010-3c.c: New test. + * gcc.target/i386/pr106010-4a.c: New test. + * gcc.target/i386/pr106010-4b.c: New test. + * gcc.target/i386/pr106010-4c.c: New test. + * gcc.target/i386/pr106010-5a.c: New test. + * gcc.target/i386/pr106010-5b.c: New test. + * gcc.target/i386/pr106010-5c.c: New test. + * gcc.target/i386/pr106010-6a.c: New test. + * gcc.target/i386/pr106010-6b.c: New test. + * gcc.target/i386/pr106010-6c.c: New test. + * gcc.target/i386/pr106010-7a.c: New test. + * gcc.target/i386/pr106010-7b.c: New test. + * gcc.target/i386/pr106010-7c.c: New test. + * gcc.target/i386/pr106010-8a.c: New test. + * gcc.target/i386/pr106010-8b.c: New test. + * gcc.target/i386/pr106010-8c.c: New test. + * gcc.target/i386/pr106010-9a.c: New test. + * gcc.target/i386/pr106010-9b.c: New test. + * gcc.target/i386/pr106010-9c.c: New test. + * gcc.target/i386/pr106010-9d.c: New test. + +2022-07-19 Harald Anlauf <anlauf@gmx.de> + + PR fortran/103590 + * gfortran.dg/associate_54.f90: Adjust. + * gfortran.dg/associate_59.f90: New test. + +2022-07-19 Patrick Palka <ppalka@redhat.com> + + PR c++/94894 + PR c++/105766 + PR c++/106201 + * g++.dg/conversion/ref8.C: New test. + * g++.dg/conversion/ref9.C: New test. + +2022-07-19 Alexander Monakov <amonakov@ispras.ru> + + * gcc.dg/setjmp-7.c: New test. + +2022-07-19 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/106321 + * gcc.dg/analyzer/torture/taint-read-index-2.c: Add test coverage + for switch statements. + +2022-07-19 Richard Biener <rguenther@suse.de> + + PR middle-end/106331 + * gfortran.dg/pr106331.f90: New testcase. + +2022-07-19 Roger Sayle <roger@nextmovesoftware.com> + Richard Biener <rguenther@suse.de> + + PR c/106264 + * gcc.dg/pr106264.c: New test case. + 2022-07-18 Richard Biener <rguenther@suse.de> * gcc.dg/tree-ssa/ldist-24.c: XFAIL. diff --git a/gcc/testsuite/g++.dg/conversion/ref8.C b/gcc/testsuite/g++.dg/conversion/ref8.C new file mode 100644 index 0000000..0dd29f7 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/ref8.C @@ -0,0 +1,22 @@ +// PR c++/105766 +// { dg-do compile { target c++20 } } + +template<class T> +struct baz { + baz() = default; + baz(int) requires requires { T(0); }; +}; + +struct foo; + +struct bar { + bar() = default; + bar(foo&); + bar(int); +}; + +struct foo { + baz<bar> m_bars; +}; + +foo a; diff --git a/gcc/testsuite/g++.dg/conversion/ref9.C b/gcc/testsuite/g++.dg/conversion/ref9.C new file mode 100644 index 0000000..e6dfc03 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/ref9.C @@ -0,0 +1,21 @@ +// PR c++/106201 +// { dg-do compile { target c++11 } } + +struct A { + template<class T, class = decltype(f(*(T*)nullptr))> + A(const T&); +}; + +struct B { + template<class T> B(const T&); +}; + +void f(A&); +void f(B); + +struct C { }; + +int main() { + C c; + f(c); +} diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c b/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c index 6a4ebdb..b3dc177 100644 --- a/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c @@ -54,3 +54,88 @@ test_4 (unsigned uarg) { return called_by_test_4 (uarg); } + +int __attribute__((tainted_args)) +test_5 (int idx) +{ + switch (idx) + { + default: + return 0; + case 5 ... 20: + return arr[idx]; /* { dg-bogus "bounds checking" } */ + /* 20 is still an out-of-bounds error (off-by-one) + but we don't check for that, just that bounds have been imposed. */ + + /* Extra cases to avoid optimizing the switch away. */ + case 22: + return 22; + case 23: + return -17; + } +} + +int __attribute__((tainted_args)) +test_6 (int idx) +{ + switch (idx) + { + default: + return arr[idx]; /* { dg-warning "without bounds checking" } */ + + case 2: + return arr[idx]; /* { dg-bogus "bounds checking" } */ + + case 6 ... 19: + return arr[idx]; /* { dg-bogus "bounds checking" } */ + + case 22: + return 22; + case 23: + return -17; + } +} + +int __attribute__((tainted_args)) +test_7 (int idx) +{ + switch (idx) + { + default: + return arr[idx]; /* { dg-warning "without bounds checking" } */ + + case 2 ... 4: + case 7 ... 9: + return arr[idx]; /* { dg-bogus "bounds checking" } */ + + case 12 ... 19: + return arr[idx]; /* { dg-bogus "bounds checking" } */ + + case 22: + return 22; + case 23: + return -17; + } +} + +int __attribute__((tainted_args)) +test_8 (unsigned idx) +{ + switch (idx) + { + default: + return arr[idx]; /* { dg-warning "without upper-bounds checking" } */ + + case 2 ... 4: + case 7 ... 9: + return arr[idx]; /* { dg-bogus "bounds checking" } */ + + case 12 ... 19: + return arr[idx]; /* { dg-bogus "bounds checking" } */ + + case 22: + return 22; + case 23: + return -17; + } +} diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-3.c b/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-3.c new file mode 100644 index 0000000..8eb6061 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-3.c @@ -0,0 +1,52 @@ +// TODO: remove need for the taint option: +/* { dg-additional-options "-fanalyzer-checker=taint" } */ +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */ + +struct raw_ep { + /* ...snip... */ + int state; + /* ...snip... */ +}; + +struct raw_dev { + /* ...snip... */ + struct raw_ep eps[30]; + int eps_num; + /* ...snip... */ +}; + +int __attribute__((tainted_args)) +simplified_raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value) +{ + int ret = 0, i = value; + + if (i < 0 || i >= dev->eps_num) { + ret = -16; + goto out_unlock; + } + if (dev->eps[i].state == 0) { /* { dg-bogus "attacker-controlled" } */ + ret = -22; + goto out_unlock; + } + +out_unlock: + return ret; +} + +int __attribute__((tainted_args)) +test_2(struct raw_dev *dev, int i) +{ + int ret = 0; + + if (i < 0 || i >= dev->eps_num) { + ret = -16; + goto out_unlock; + } + if (dev->eps[i].state == 0) { /* { dg-bogus "attacker-controlled" } */ + ret = -22; + goto out_unlock; + } + +out_unlock: + return ret; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/untracked-2.c b/gcc/testsuite/gcc.dg/analyzer/untracked-2.c new file mode 100644 index 0000000..565a9cc --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/untracked-2.c @@ -0,0 +1,7 @@ +typedef unsigned char u8; +extern int foo(const u8 *key, unsigned int keylen); +int test (void) +{ + static const u8 default_salt[64]; + return foo(default_salt, 64); +} diff --git a/gcc/testsuite/gcc.dg/pow-sqrt-synth-1.c b/gcc/testsuite/gcc.dg/pow-sqrt-synth-1.c index 4a94325..484b29a 100644 --- a/gcc/testsuite/gcc.dg/pow-sqrt-synth-1.c +++ b/gcc/testsuite/gcc.dg/pow-sqrt-synth-1.c @@ -1,5 +1,5 @@ /* { dg-do compile { target sqrt_insn } } */ -/* { dg-options "-fdump-tree-sincos -Ofast --param max-pow-sqrt-depth=8" } */ +/* { dg-options "-fdump-tree-powcabs -Ofast --param max-pow-sqrt-depth=8" } */ /* { dg-additional-options "-mfloat-abi=softfp -mfpu=neon-vfpv4" { target arm*-*-* } } */ double @@ -34,4 +34,4 @@ vecfoo (double *a) a[i] = __builtin_pow (a[i], 1.25); } -/* { dg-final { scan-tree-dump-times "synthesizing" 7 "sincos" } } */ +/* { dg-final { scan-tree-dump-times "synthesizing" 7 "powcabs" } } */ diff --git a/gcc/testsuite/gcc.dg/pr106379-1.c b/gcc/testsuite/gcc.dg/pr106379-1.c new file mode 100644 index 0000000..7f2575e --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr106379-1.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-forwprop1" } */ + +_Bool foo (_Bool a, _Bool b) +{ + return !a == !b; +} + +/* { dg-final { scan-tree-dump "\[ab\]_\[0-9\]+\\(D\\) == \[ba\]_\[0-9\]+\\(D\\)" "forwprop1" } } */ diff --git a/gcc/testsuite/gcc.dg/setjmp-7.c b/gcc/testsuite/gcc.dg/setjmp-7.c new file mode 100644 index 0000000..44b5bcb --- /dev/null +++ b/gcc/testsuite/gcc.dg/setjmp-7.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-guess-branch-probability -w" } */ +/* { dg-require-effective-target indirect_jumps } */ + +struct __jmp_buf_tag { }; +typedef struct __jmp_buf_tag jmp_buf[1]; +struct globals { jmp_buf listingbuf; }; +extern struct globals *const ptr_to_globals; +void foo() +{ + if ( _setjmp ( ((*ptr_to_globals).listingbuf ))) + ; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-1a.c b/gcc/testsuite/gcc.target/i386/pr106010-1a.c new file mode 100644 index 0000000..b608f48 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-1a.c @@ -0,0 +1,58 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -fdump-tree-vect-details -mprefer-vector-width=256" } */ +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 6 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) double>} 2 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) float>} 2 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) long long int>} 2 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) int>} 2 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) short int>} 2 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(32\) char>} 2 "vect" } } */ + +#define N 10000 +void +__attribute__((noipa)) +foo_pd (_Complex double* a, _Complex double* b) +{ + for (int i = 0; i != N; i++) + a[i] = b[i]; +} + +void +__attribute__((noipa)) +foo_ps (_Complex float* a, _Complex float* b) +{ + for (int i = 0; i != N; i++) + a[i] = b[i]; +} + +void +__attribute__((noipa)) +foo_epi64 (_Complex long long* a, _Complex long long* b) +{ + for (int i = 0; i != N; i++) + a[i] = b[i]; +} + +void +__attribute__((noipa)) +foo_epi32 (_Complex int* a, _Complex int* b) +{ + for (int i = 0; i != N; i++) + a[i] = b[i]; +} + +void +__attribute__((noipa)) +foo_epi16 (_Complex short* a, _Complex short* b) +{ + for (int i = 0; i != N; i++) + a[i] = b[i]; +} + +void +__attribute__((noipa)) +foo_epi8 (_Complex char* a, _Complex char* b) +{ + for (int i = 0; i != N; i++) + a[i] = b[i]; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-1b.c b/gcc/testsuite/gcc.target/i386/pr106010-1b.c new file mode 100644 index 0000000..0f377c3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-1b.c @@ -0,0 +1,63 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256" } */ +/* { dg-require-effective-target avx } */ + +#include "avx-check.h" +#include <string.h> +#include "pr106010-1a.c" + +void +avx_test (void) +{ + _Complex double* pd_src = (_Complex double*) malloc (2 * N * sizeof (double)); + _Complex double* pd_dst = (_Complex double*) malloc (2 * N * sizeof (double)); + _Complex float* ps_src = (_Complex float*) malloc (2 * N * sizeof (float)); + _Complex float* ps_dst = (_Complex float*) malloc (2 * N * sizeof (float)); + _Complex long long* epi64_src = (_Complex long long*) malloc (2 * N * sizeof (long long)); + _Complex long long* epi64_dst = (_Complex long long*) malloc (2 * N * sizeof (long long)); + _Complex int* epi32_src = (_Complex int*) malloc (2 * N * sizeof (int)); + _Complex int* epi32_dst = (_Complex int*) malloc (2 * N * sizeof (int)); + _Complex short* epi16_src = (_Complex short*) malloc (2 * N * sizeof (short)); + _Complex short* epi16_dst = (_Complex short*) malloc (2 * N * sizeof (short)); + _Complex char* epi8_src = (_Complex char*) malloc (2 * N * sizeof (char)); + _Complex char* epi8_dst = (_Complex char*) malloc (2 * N * sizeof (char)); + char* p_init = (char*) malloc (2 * N * sizeof (double)); + + __builtin_memset (pd_dst, 0, 2 * N * sizeof (double)); + __builtin_memset (ps_dst, 0, 2 * N * sizeof (float)); + __builtin_memset (epi64_dst, 0, 2 * N * sizeof (long long)); + __builtin_memset (epi32_dst, 0, 2 * N * sizeof (int)); + __builtin_memset (epi16_dst, 0, 2 * N * sizeof (short)); + __builtin_memset (epi8_dst, 0, 2 * N * sizeof (char)); + + for (int i = 0; i != 2 * N * sizeof (double); i++) + p_init[i] = i; + + memcpy (pd_src, p_init, 2 * N * sizeof (double)); + memcpy (ps_src, p_init, 2 * N * sizeof (float)); + memcpy (epi64_src, p_init, 2 * N * sizeof (long long)); + memcpy (epi32_src, p_init, 2 * N * sizeof (int)); + memcpy (epi16_src, p_init, 2 * N * sizeof (short)); + memcpy (epi8_src, p_init, 2 * N * sizeof (char)); + + foo_pd (pd_dst, pd_src); + foo_ps (ps_dst, ps_src); + foo_epi64 (epi64_dst, epi64_src); + foo_epi32 (epi32_dst, epi32_src); + foo_epi16 (epi16_dst, epi16_src); + foo_epi8 (epi8_dst, epi8_src); + if (__builtin_memcmp (pd_dst, pd_src, N * 2 * sizeof (double)) != 0) + __builtin_abort (); + if (__builtin_memcmp (ps_dst, ps_src, N * 2 * sizeof (float)) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi64_dst, epi64_src, N * 2 * sizeof (long long)) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi32_dst, epi32_src, N * 2 * sizeof (int)) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi16_dst, epi16_src, N * 2 * sizeof (short)) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi8_dst, epi8_src, N * 2 * sizeof (char)) != 0) + __builtin_abort (); + + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-1c.c b/gcc/testsuite/gcc.target/i386/pr106010-1c.c new file mode 100644 index 0000000..f07e9fb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-1c.c @@ -0,0 +1,41 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256 -fdump-tree-vect-details" } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) _Float16>} 2 "vect" } } */ +/* { dg-require-effective-target avx512fp16 } */ + +#include <string.h> + +static void do_test (void); + +#define DO_TEST do_test +#define AVX512FP16 +#include "avx512-check.h" + +#define N 10000 + +void +__attribute__((noipa)) +foo_ph (_Complex _Float16* a, _Complex _Float16* b) +{ + for (int i = 0; i != N; i++) + a[i] = b[i]; +} + +static void +do_test (void) +{ + _Complex _Float16* ph_src = (_Complex _Float16*) malloc (2 * N * sizeof (_Float16)); + _Complex _Float16* ph_dst = (_Complex _Float16*) malloc (2 * N * sizeof (_Float16)); + char* p_init = (char*) malloc (2 * N * sizeof (_Float16)); + + __builtin_memset (ph_dst, 0, 2 * N * sizeof (_Float16)); + + for (int i = 0; i != 2 * N * sizeof (_Float16); i++) + p_init[i] = i; + + memcpy (ph_src, p_init, 2 * N * sizeof (_Float16)); + + foo_ph (ph_dst, ph_src); + if (__builtin_memcmp (ph_dst, ph_src, N * 2 * sizeof (_Float16)) != 0) + __builtin_abort (); +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-2a.c b/gcc/testsuite/gcc.target/i386/pr106010-2a.c new file mode 100644 index 0000000..d2e2f8d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-2a.c @@ -0,0 +1,82 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -fdump-tree-slp-details -mprefer-vector-width=256" } */ +/* { dg-final { scan-tree-dump-times "basic block part vectorized using (?:32|64) byte vectors" 6 "slp2" } }*/ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) double>} 2 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) float>} 2 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) long long int>} 2 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) int>} 2 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) short int>} 2 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(32\) char>} 2 "slp2" } } */ + +void +__attribute__((noipa)) +foo_pd (_Complex double* a, _Complex double* __restrict b) +{ + a[0] = b[0]; + a[1] = b[1]; +} + +void +__attribute__((noipa)) +foo_ps (_Complex float* a, _Complex float* __restrict b) +{ + a[0] = b[0]; + a[1] = b[1]; + a[2] = b[2]; + a[3] = b[3]; + +} + +void +__attribute__((noipa)) +foo_epi64 (_Complex long long* a, _Complex long long* __restrict b) +{ + a[0] = b[0]; + a[1] = b[1]; +} + +void +__attribute__((noipa)) +foo_epi32 (_Complex int* a, _Complex int* __restrict b) +{ + a[0] = b[0]; + a[1] = b[1]; + a[2] = b[2]; + a[3] = b[3]; +} + +void +__attribute__((noipa)) +foo_epi16 (_Complex short* a, _Complex short* __restrict b) +{ + a[0] = b[0]; + a[1] = b[1]; + a[2] = b[2]; + a[3] = b[3]; + a[4] = b[4]; + a[5] = b[5]; + a[6] = b[6]; + a[7] = b[7]; +} + +void +__attribute__((noipa)) +foo_epi8 (_Complex char* a, _Complex char* __restrict b) +{ + a[0] = b[0]; + a[1] = b[1]; + a[2] = b[2]; + a[3] = b[3]; + a[4] = b[4]; + a[5] = b[5]; + a[6] = b[6]; + a[7] = b[7]; + a[8] = b[8]; + a[9] = b[9]; + a[10] = b[10]; + a[11] = b[11]; + a[12] = b[12]; + a[13] = b[13]; + a[14] = b[14]; + a[15] = b[15]; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-2b.c b/gcc/testsuite/gcc.target/i386/pr106010-2b.c new file mode 100644 index 0000000..ac36075 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-2b.c @@ -0,0 +1,62 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256" } */ +/* { dg-require-effective-target avx } */ + +#include "avx-check.h" +#include <string.h> +#include "pr106010-2a.c" + +void +avx_test (void) +{ + _Complex double* pd_src = (_Complex double*) malloc (32); + _Complex double* pd_dst = (_Complex double*) malloc (32); + _Complex float* ps_src = (_Complex float*) malloc (32); + _Complex float* ps_dst = (_Complex float*) malloc (32); + _Complex long long* epi64_src = (_Complex long long*) malloc (32); + _Complex long long* epi64_dst = (_Complex long long*) malloc (32); + _Complex int* epi32_src = (_Complex int*) malloc (32); + _Complex int* epi32_dst = (_Complex int*) malloc (32); + _Complex short* epi16_src = (_Complex short*) malloc (32); + _Complex short* epi16_dst = (_Complex short*) malloc (32); + _Complex char* epi8_src = (_Complex char*) malloc (32); + _Complex char* epi8_dst = (_Complex char*) malloc (32); + char* p = (char* ) malloc (32); + + __builtin_memset (pd_dst, 0, 32); + __builtin_memset (ps_dst, 0, 32); + __builtin_memset (epi64_dst, 0, 32); + __builtin_memset (epi32_dst, 0, 32); + __builtin_memset (epi16_dst, 0, 32); + __builtin_memset (epi8_dst, 0, 32); + + for (int i = 0; i != 32; i++) + p[i] = i; + __builtin_memcpy (pd_src, p, 32); + __builtin_memcpy (ps_src, p, 32); + __builtin_memcpy (epi64_src, p, 32); + __builtin_memcpy (epi32_src, p, 32); + __builtin_memcpy (epi16_src, p, 32); + __builtin_memcpy (epi8_src, p, 32); + + foo_pd (pd_dst, pd_src); + foo_ps (ps_dst, ps_src); + foo_epi64 (epi64_dst, epi64_src); + foo_epi32 (epi32_dst, epi32_src); + foo_epi16 (epi16_dst, epi16_src); + foo_epi8 (epi8_dst, epi8_src); + if (__builtin_memcmp (pd_dst, pd_src, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (ps_dst, ps_src, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi64_dst, epi64_src, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi32_dst, epi32_src, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi16_dst, epi16_src, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi16_dst, epi16_src, 32) != 0) + __builtin_abort (); + + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-2c.c b/gcc/testsuite/gcc.target/i386/pr106010-2c.c new file mode 100644 index 0000000..a002f20 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-2c.c @@ -0,0 +1,47 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256 -fdump-tree-slp-details" } */ +/* { dg-require-effective-target avx512fp16 } */ + +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) _Float16>} 2 "slp2" } } */ +/* { dg-final { scan-tree-dump-times "basic block part vectorized using (?:32|64) byte vectors" 1 "slp2" } }*/ + +#include <string.h> + +static void do_test (void); +#define DO_TEST do_test +#define AVX512FP16 +#include "avx512-check.h" + +void +__attribute__((noipa)) +foo_ph (_Complex _Float16* a, _Complex _Float16* __restrict b) +{ + a[0] = b[0]; + a[1] = b[1]; + a[2] = b[2]; + a[3] = b[3]; + a[4] = b[4]; + a[5] = b[5]; + a[6] = b[6]; + a[7] = b[7]; +} + +void +do_test (void) +{ + _Complex _Float16* ph_src = (_Complex _Float16*) malloc (32); + _Complex _Float16* ph_dst = (_Complex _Float16*) malloc (32); + char* p = (char* ) malloc (32); + + __builtin_memset (ph_dst, 0, 32); + + for (int i = 0; i != 32; i++) + p[i] = i; + __builtin_memcpy (ph_src, p, 32); + + foo_ph (ph_dst, ph_src); + if (__builtin_memcmp (ph_dst, ph_src, 32) != 0) + __builtin_abort (); + + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-3a.c b/gcc/testsuite/gcc.target/i386/pr106010-3a.c new file mode 100644 index 0000000..c1b64b5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-3a.c @@ -0,0 +1,80 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx2 -ftree-vectorize -fvect-cost-model=unlimited -fdump-tree-slp-details" } */ +/* { dg-final { scan-tree-dump-times "basic block part vectorized using (?:32|64) byte vectors" 6 "slp2" } }*/ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*VEC_PERM_EXPR.*\{ 2, 3, 0, 1 \}} 2 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*VEC_PERM_EXPR.*\{ 6, 7, 4, 5, 2, 3, 0, 1 \}} 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*VEC_PERM_EXPR.*\{ 2, 3, 0, 1, 6, 7, 4, 5 \}} 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*VEC_PERM_EXPR.*\{ 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1 \}} 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*VEC_PERM_EXPR.*\{ 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1, 30, 31, 28, 29, 26, 27, 24, 25, 22, 23, 20, 21, 18, 19, 16, 17 \}} 1 "slp2" } } */ + +void +__attribute__((noipa)) +foo_pd (_Complex double* a, _Complex double* __restrict b) +{ + a[0] = b[1]; + a[1] = b[0]; +} + +void +__attribute__((noipa)) +foo_ps (_Complex float* a, _Complex float* __restrict b) +{ + a[0] = b[1]; + a[1] = b[0]; + a[2] = b[3]; + a[3] = b[2]; +} + +void +__attribute__((noipa)) +foo_epi64 (_Complex long long* a, _Complex long long* __restrict b) +{ + a[0] = b[1]; + a[1] = b[0]; +} + +void +__attribute__((noipa)) +foo_epi32 (_Complex int* a, _Complex int* __restrict b) +{ + a[0] = b[3]; + a[1] = b[2]; + a[2] = b[1]; + a[3] = b[0]; +} + +void +__attribute__((noipa)) +foo_epi16 (_Complex short* a, _Complex short* __restrict b) +{ + a[0] = b[7]; + a[1] = b[6]; + a[2] = b[5]; + a[3] = b[4]; + a[4] = b[3]; + a[5] = b[2]; + a[6] = b[1]; + a[7] = b[0]; +} + +void +__attribute__((noipa)) +foo_epi8 (_Complex char* a, _Complex char* __restrict b) +{ + a[0] = b[7]; + a[1] = b[6]; + a[2] = b[5]; + a[3] = b[4]; + a[4] = b[3]; + a[5] = b[2]; + a[6] = b[1]; + a[7] = b[0]; + a[8] = b[15]; + a[9] = b[14]; + a[10] = b[13]; + a[11] = b[12]; + a[12] = b[11]; + a[13] = b[10]; + a[14] = b[9]; + a[15] = b[8]; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-3b.c b/gcc/testsuite/gcc.target/i386/pr106010-3b.c new file mode 100644 index 0000000..e4fa3f3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-3b.c @@ -0,0 +1,126 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx2 -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256" } */ +/* { dg-require-effective-target avx2 } */ + +#include "avx2-check.h" +#include <string.h> +#include "pr106010-3a.c" + +void +avx2_test (void) +{ + _Complex double* pd_src = (_Complex double*) malloc (32); + _Complex double* pd_dst = (_Complex double*) malloc (32); + _Complex double* pd_exp = (_Complex double*) malloc (32); + _Complex float* ps_src = (_Complex float*) malloc (32); + _Complex float* ps_dst = (_Complex float*) malloc (32); + _Complex float* ps_exp = (_Complex float*) malloc (32); + _Complex long long* epi64_src = (_Complex long long*) malloc (32); + _Complex long long* epi64_dst = (_Complex long long*) malloc (32); + _Complex long long* epi64_exp = (_Complex long long*) malloc (32); + _Complex int* epi32_src = (_Complex int*) malloc (32); + _Complex int* epi32_dst = (_Complex int*) malloc (32); + _Complex int* epi32_exp = (_Complex int*) malloc (32); + _Complex short* epi16_src = (_Complex short*) malloc (32); + _Complex short* epi16_dst = (_Complex short*) malloc (32); + _Complex short* epi16_exp = (_Complex short*) malloc (32); + _Complex char* epi8_src = (_Complex char*) malloc (32); + _Complex char* epi8_dst = (_Complex char*) malloc (32); + _Complex char* epi8_exp = (_Complex char*) malloc (32); + char* p = (char* ) malloc (32); + char* q = (char* ) malloc (32); + + __builtin_memset (pd_dst, 0, 32); + __builtin_memset (ps_dst, 0, 32); + __builtin_memset (epi64_dst, 0, 32); + __builtin_memset (epi32_dst, 0, 32); + __builtin_memset (epi16_dst, 0, 32); + __builtin_memset (epi8_dst, 0, 32); + + for (int i = 0; i != 32; i++) + p[i] = i; + __builtin_memcpy (pd_src, p, 32); + __builtin_memcpy (ps_src, p, 32); + __builtin_memcpy (epi64_src, p, 32); + __builtin_memcpy (epi32_src, p, 32); + __builtin_memcpy (epi16_src, p, 32); + __builtin_memcpy (epi8_src, p, 32); + + for (int i = 0; i != 16; i++) + { + p[i] = i + 16; + p[i + 16] = i; + } + __builtin_memcpy (pd_exp, p, 32); + __builtin_memcpy (epi64_exp, p, 32); + + for (int i = 0; i != 8; i++) + { + p[i] = i + 8; + p[i + 8] = i; + p[i + 16] = i + 24; + p[i + 24] = i + 16; + q[i] = i + 24; + q[i + 8] = i + 16; + q[i + 16] = i + 8; + q[i + 24] = i; + } + __builtin_memcpy (ps_exp, p, 32); + __builtin_memcpy (epi32_exp, q, 32); + + + for (int i = 0; i != 4; i++) + { + q[i] = i + 28; + q[i + 4] = i + 24; + q[i + 8] = i + 20; + q[i + 12] = i + 16; + q[i + 16] = i + 12; + q[i + 20] = i + 8; + q[i + 24] = i + 4; + q[i + 28] = i; + } + __builtin_memcpy (epi16_exp, q, 32); + + for (int i = 0; i != 2; i++) + { + q[i] = i + 14; + q[i + 2] = i + 12; + q[i + 4] = i + 10; + q[i + 6] = i + 8; + q[i + 8] = i + 6; + q[i + 10] = i + 4; + q[i + 12] = i + 2; + q[i + 14] = i; + q[i + 16] = i + 30; + q[i + 18] = i + 28; + q[i + 20] = i + 26; + q[i + 22] = i + 24; + q[i + 24] = i + 22; + q[i + 26] = i + 20; + q[i + 28] = i + 18; + q[i + 30] = i + 16; + } + __builtin_memcpy (epi8_exp, q, 32); + + foo_pd (pd_dst, pd_src); + foo_ps (ps_dst, ps_src); + foo_epi64 (epi64_dst, epi64_src); + foo_epi32 (epi32_dst, epi32_src); + foo_epi16 (epi16_dst, epi16_src); + foo_epi8 (epi8_dst, epi8_src); + if (__builtin_memcmp (pd_dst, pd_exp, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (ps_dst, ps_exp, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi64_dst, epi64_exp, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi32_dst, epi32_exp, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi16_dst, epi16_exp, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi8_dst, epi8_exp, 32) != 0) + __builtin_abort (); + + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-3c.c b/gcc/testsuite/gcc.target/i386/pr106010-3c.c new file mode 100644 index 0000000..5a5a3d4 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-3c.c @@ -0,0 +1,69 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256 -fdump-tree-slp-details" } */ +/* { dg-require-effective-target avx512fp16 } */ +/* { dg-final { scan-tree-dump-times "basic block part vectorized using (?:32|64) byte vectors" 1 "slp2" } }*/ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*VEC_PERM_EXPR.*\{ 2, 3, 0, 1, 8, 9, 6, 7, 14, 15, 12, 13, 4, 5, 10, 11 \}} 1 "slp2" } } */ + +#include <string.h> + +static void do_test (void); +#define DO_TEST do_test +#define AVX512FP16 +#include "avx512-check.h" + +void +__attribute__((noipa)) +foo_ph (_Complex _Float16* a, _Complex _Float16* __restrict b) +{ + a[0] = b[1]; + a[1] = b[0]; + a[2] = b[4]; + a[3] = b[3]; + a[4] = b[7]; + a[5] = b[6]; + a[6] = b[2]; + a[7] = b[5]; +} + +void +do_test (void) +{ + _Complex _Float16* ph_src = (_Complex _Float16*) malloc (32); + _Complex _Float16* ph_dst = (_Complex _Float16*) malloc (32); + _Complex _Float16* ph_exp = (_Complex _Float16*) malloc (32); + char* p = (char* ) malloc (32); + char* q = (char* ) malloc (32); + + __builtin_memset (ph_dst, 0, 32); + + for (int i = 0; i != 32; i++) + p[i] = i; + __builtin_memcpy (ph_src, p, 32); + + for (int i = 0; i != 4; i++) + { + p[i] = i + 4; + p[i + 4] = i; + p[i + 8] = i + 16; + p[i + 12] = i + 12; + p[i + 16] = i + 28; + p[i + 20] = i + 24; + p[i + 24] = i + 8; + p[i + 28] = i + 20; + q[i] = i + 28; + q[i + 4] = i + 24; + q[i + 8] = i + 20; + q[i + 12] = i + 16; + q[i + 16] = i + 12; + q[i + 20] = i + 8; + q[i + 24] = i + 4; + q[i + 28] = i; + } + __builtin_memcpy (ph_exp, p, 32); + + foo_ph (ph_dst, ph_src); + if (__builtin_memcmp (ph_dst, ph_exp, 32) != 0) + __builtin_abort (); + + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-4a.c b/gcc/testsuite/gcc.target/i386/pr106010-4a.c new file mode 100644 index 0000000..b7b0b53 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-4a.c @@ -0,0 +1,101 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -fdump-tree-slp-details" } */ +/* { dg-final { scan-tree-dump-times "basic block part vectorized using (?:32|64) byte vectors" 6 "slp2" } }*/ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) double>} 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) float>} 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) long long int>} 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) int>} 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) short int>} 1 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(32\) char>} 1 "slp2" } } */ + +void +__attribute__((noipa)) +foo_pd (_Complex double* a, + _Complex double b1, + _Complex double b2) +{ + a[0] = b1; + a[1] = b2; +} + +void +__attribute__((noipa)) +foo_ps (_Complex float* a, + _Complex float b1, _Complex float b2, + _Complex float b3, _Complex float b4) +{ + a[0] = b1; + a[1] = b2; + a[2] = b3; + a[3] = b4; +} + +void +__attribute__((noipa)) +foo_epi64 (_Complex long long* a, + _Complex long long b1, + _Complex long long b2) +{ + a[0] = b1; + a[1] = b2; +} + +void +__attribute__((noipa)) +foo_epi32 (_Complex int* a, + _Complex int b1, _Complex int b2, + _Complex int b3, _Complex int b4) +{ + a[0] = b1; + a[1] = b2; + a[2] = b3; + a[3] = b4; +} + +void +__attribute__((noipa)) +foo_epi16 (_Complex short* a, + _Complex short b1, _Complex short b2, + _Complex short b3, _Complex short b4, + _Complex short b5, _Complex short b6, + _Complex short b7,_Complex short b8) +{ + a[0] = b1; + a[1] = b2; + a[2] = b3; + a[3] = b4; + a[4] = b5; + a[5] = b6; + a[6] = b7; + a[7] = b8; +} + +void +__attribute__((noipa)) +foo_epi8 (_Complex char* a, + _Complex char b1, _Complex char b2, + _Complex char b3, _Complex char b4, + _Complex char b5, _Complex char b6, + _Complex char b7,_Complex char b8, + _Complex char b9, _Complex char b10, + _Complex char b11, _Complex char b12, + _Complex char b13, _Complex char b14, + _Complex char b15,_Complex char b16) +{ + a[0] = b1; + a[1] = b2; + a[2] = b3; + a[3] = b4; + a[4] = b5; + a[5] = b6; + a[6] = b7; + a[7] = b8; + a[8] = b9; + a[9] = b10; + a[10] = b11; + a[11] = b12; + a[12] = b13; + a[13] = b14; + a[14] = b15; + a[15] = b16; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-4b.c b/gcc/testsuite/gcc.target/i386/pr106010-4b.c new file mode 100644 index 0000000..e2e7950 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-4b.c @@ -0,0 +1,67 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256" } */ +/* { dg-require-effective-target avx } */ + +#include "avx-check.h" +#include <string.h> +#include "pr106010-4a.c" + +void +avx_test (void) +{ + _Complex double* pd_src = (_Complex double*) malloc (32); + _Complex double* pd_dst = (_Complex double*) malloc (32); + _Complex float* ps_src = (_Complex float*) malloc (32); + _Complex float* ps_dst = (_Complex float*) malloc (32); + _Complex long long* epi64_src = (_Complex long long*) malloc (32); + _Complex long long* epi64_dst = (_Complex long long*) malloc (32); + _Complex int* epi32_src = (_Complex int*) malloc (32); + _Complex int* epi32_dst = (_Complex int*) malloc (32); + _Complex short* epi16_src = (_Complex short*) malloc (32); + _Complex short* epi16_dst = (_Complex short*) malloc (32); + _Complex char* epi8_src = (_Complex char*) malloc (32); + _Complex char* epi8_dst = (_Complex char*) malloc (32); + char* p = (char* ) malloc (32); + + __builtin_memset (pd_dst, 0, 32); + __builtin_memset (ps_dst, 0, 32); + __builtin_memset (epi64_dst, 0, 32); + __builtin_memset (epi32_dst, 0, 32); + __builtin_memset (epi16_dst, 0, 32); + __builtin_memset (epi8_dst, 0, 32); + + for (int i = 0; i != 32; i++) + p[i] = i; + __builtin_memcpy (pd_src, p, 32); + __builtin_memcpy (ps_src, p, 32); + __builtin_memcpy (epi64_src, p, 32); + __builtin_memcpy (epi32_src, p, 32); + __builtin_memcpy (epi16_src, p, 32); + __builtin_memcpy (epi8_src, p, 32); + + foo_pd (pd_dst, pd_src[0], pd_src[1]); + foo_ps (ps_dst, ps_src[0], ps_src[1], ps_src[2], ps_src[3]); + foo_epi64 (epi64_dst, epi64_src[0], epi64_src[1]); + foo_epi32 (epi32_dst, epi32_src[0], epi32_src[1], epi32_src[2], epi32_src[3]); + foo_epi16 (epi16_dst, epi16_src[0], epi16_src[1], epi16_src[2], epi16_src[3], + epi16_src[4], epi16_src[5], epi16_src[6], epi16_src[7]); + foo_epi8 (epi8_dst, epi8_src[0], epi8_src[1], epi8_src[2], epi8_src[3], + epi8_src[4], epi8_src[5], epi8_src[6], epi8_src[7], + epi8_src[8], epi8_src[9], epi8_src[10], epi8_src[11], + epi8_src[12], epi8_src[13], epi8_src[14], epi8_src[15]); + + if (__builtin_memcmp (pd_dst, pd_src, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (ps_dst, ps_src, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi64_dst, epi64_src, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi32_dst, epi32_src, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi16_dst, epi16_src, 32) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi8_dst, epi8_src, 32) != 0) + __builtin_abort (); + + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-4c.c b/gcc/testsuite/gcc.target/i386/pr106010-4c.c new file mode 100644 index 0000000..8e02aef --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-4c.c @@ -0,0 +1,54 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -fdump-tree-slp-details -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256" } */ +/* { dg-require-effective-target avx512fp16 } */ +/* { dg-final { scan-tree-dump-times "basic block part vectorized using (?:32|64) byte vectors" 1 "slp2" } }*/ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) _Float16>} 1 "slp2" } } */ + +#include <string.h> + +static void do_test (void); +#define DO_TEST do_test +#define AVX512FP16 +#include "avx512-check.h" + +void +__attribute__((noipa)) +foo_ph (_Complex _Float16* a, + _Complex _Float16 b1, _Complex _Float16 b2, + _Complex _Float16 b3, _Complex _Float16 b4, + _Complex _Float16 b5, _Complex _Float16 b6, + _Complex _Float16 b7,_Complex _Float16 b8) +{ + a[0] = b1; + a[1] = b2; + a[2] = b3; + a[3] = b4; + a[4] = b5; + a[5] = b6; + a[6] = b7; + a[7] = b8; +} + +void +do_test (void) +{ + + _Complex _Float16* ph_src = (_Complex _Float16*) malloc (32); + _Complex _Float16* ph_dst = (_Complex _Float16*) malloc (32); + + char* p = (char* ) malloc (32); + + __builtin_memset (ph_dst, 0, 32); + + for (int i = 0; i != 32; i++) + p[i] = i; + + __builtin_memcpy (ph_src, p, 32); + + foo_ph (ph_dst, ph_src[0], ph_src[1], ph_src[2], ph_src[3], + ph_src[4], ph_src[5], ph_src[6], ph_src[7]); + + if (__builtin_memcmp (ph_dst, ph_src, 32) != 0) + __builtin_abort (); + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-5a.c b/gcc/testsuite/gcc.target/i386/pr106010-5a.c new file mode 100644 index 0000000..9d4a6f9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-5a.c @@ -0,0 +1,117 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -fdump-tree-slp-details -mprefer-vector-width=256" } */ +/* { dg-final { scan-tree-dump-times "basic block part vectorized using (?:32|64) byte vectors" 6 "slp2" } }*/ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) double>} 4 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) float>} 4 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) long long int>} 4 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) int>} 4 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) short int>} 4 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(32\) char>} 4 "slp2" } } */ + +void +__attribute__((noipa)) +foo_pd (_Complex double* a, _Complex double* __restrict b) +{ + a[0] = b[2]; + a[1] = b[3]; + a[2] = b[0]; + a[3] = b[1]; +} + +void +__attribute__((noipa)) +foo_ps (_Complex float* a, _Complex float* __restrict b) +{ + a[0] = b[4]; + a[1] = b[5]; + a[2] = b[6]; + a[3] = b[7]; + a[4] = b[0]; + a[5] = b[1]; + a[6] = b[2]; + a[7] = b[3]; +} + +void +__attribute__((noipa)) +foo_epi64 (_Complex long long* a, _Complex long long* __restrict b) +{ + a[0] = b[2]; + a[1] = b[3]; + a[2] = b[0]; + a[3] = b[1]; +} + +void +__attribute__((noipa)) +foo_epi32 (_Complex int* a, _Complex int* __restrict b) +{ + a[0] = b[4]; + a[1] = b[5]; + a[2] = b[6]; + a[3] = b[7]; + a[4] = b[0]; + a[5] = b[1]; + a[6] = b[2]; + a[7] = b[3]; +} + +void +__attribute__((noipa)) +foo_epi16 (_Complex short* a, _Complex short* __restrict b) +{ + a[0] = b[8]; + a[1] = b[9]; + a[2] = b[10]; + a[3] = b[11]; + a[4] = b[12]; + a[5] = b[13]; + a[6] = b[14]; + a[7] = b[15]; + a[8] = b[0]; + a[9] = b[1]; + a[10] = b[2]; + a[11] = b[3]; + a[12] = b[4]; + a[13] = b[5]; + a[14] = b[6]; + a[15] = b[7]; +} + +void +__attribute__((noipa)) +foo_epi8 (_Complex char* a, _Complex char* __restrict b) +{ + a[0] = b[16]; + a[1] = b[17]; + a[2] = b[18]; + a[3] = b[19]; + a[4] = b[20]; + a[5] = b[21]; + a[6] = b[22]; + a[7] = b[23]; + a[8] = b[24]; + a[9] = b[25]; + a[10] = b[26]; + a[11] = b[27]; + a[12] = b[28]; + a[13] = b[29]; + a[14] = b[30]; + a[15] = b[31]; + a[16] = b[0]; + a[17] = b[1]; + a[18] = b[2]; + a[19] = b[3]; + a[20] = b[4]; + a[21] = b[5]; + a[22] = b[6]; + a[23] = b[7]; + a[24] = b[8]; + a[25] = b[9]; + a[26] = b[10]; + a[27] = b[11]; + a[28] = b[12]; + a[29] = b[13]; + a[30] = b[14]; + a[31] = b[15]; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-5b.c b/gcc/testsuite/gcc.target/i386/pr106010-5b.c new file mode 100644 index 0000000..d5c6ebe --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-5b.c @@ -0,0 +1,80 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256" } */ +/* { dg-require-effective-target avx } */ + +#include "avx-check.h" +#include <string.h> +#include "pr106010-5a.c" + +void +avx_test (void) +{ + _Complex double* pd_src = (_Complex double*) malloc (64); + _Complex double* pd_dst = (_Complex double*) malloc (64); + _Complex double* pd_exp = (_Complex double*) malloc (64); + _Complex float* ps_src = (_Complex float*) malloc (64); + _Complex float* ps_dst = (_Complex float*) malloc (64); + _Complex float* ps_exp = (_Complex float*) malloc (64); + _Complex long long* epi64_src = (_Complex long long*) malloc (64); + _Complex long long* epi64_dst = (_Complex long long*) malloc (64); + _Complex long long* epi64_exp = (_Complex long long*) malloc (64); + _Complex int* epi32_src = (_Complex int*) malloc (64); + _Complex int* epi32_dst = (_Complex int*) malloc (64); + _Complex int* epi32_exp = (_Complex int*) malloc (64); + _Complex short* epi16_src = (_Complex short*) malloc (64); + _Complex short* epi16_dst = (_Complex short*) malloc (64); + _Complex short* epi16_exp = (_Complex short*) malloc (64); + _Complex char* epi8_src = (_Complex char*) malloc (64); + _Complex char* epi8_dst = (_Complex char*) malloc (64); + _Complex char* epi8_exp = (_Complex char*) malloc (64); + char* p = (char* ) malloc (64); + char* q = (char* ) malloc (64); + + __builtin_memset (pd_dst, 0, 64); + __builtin_memset (ps_dst, 0, 64); + __builtin_memset (epi64_dst, 0, 64); + __builtin_memset (epi32_dst, 0, 64); + __builtin_memset (epi16_dst, 0, 64); + __builtin_memset (epi8_dst, 0, 64); + + for (int i = 0; i != 64; i++) + { + p[i] = i; + q[i] = (i + 32) % 64; + } + __builtin_memcpy (pd_src, p, 64); + __builtin_memcpy (ps_src, p, 64); + __builtin_memcpy (epi64_src, p, 64); + __builtin_memcpy (epi32_src, p, 64); + __builtin_memcpy (epi16_src, p, 64); + __builtin_memcpy (epi8_src, p, 64); + + __builtin_memcpy (pd_exp, q, 64); + __builtin_memcpy (ps_exp, q, 64); + __builtin_memcpy (epi64_exp, q, 64); + __builtin_memcpy (epi32_exp, q, 64); + __builtin_memcpy (epi16_exp, q, 64); + __builtin_memcpy (epi8_exp, q, 64); + + foo_pd (pd_dst, pd_src); + foo_ps (ps_dst, ps_src); + foo_epi64 (epi64_dst, epi64_src); + foo_epi32 (epi32_dst, epi32_src); + foo_epi16 (epi16_dst, epi16_src); + foo_epi8 (epi8_dst, epi8_src); + + if (__builtin_memcmp (pd_dst, pd_exp, 64) != 0) + __builtin_abort (); + if (__builtin_memcmp (ps_dst, ps_exp, 64) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi64_dst, epi64_exp, 64) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi32_dst, epi32_exp, 64) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi16_dst, epi16_exp, 64) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi8_dst, epi8_exp, 64) != 0) + __builtin_abort (); + + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-5c.c b/gcc/testsuite/gcc.target/i386/pr106010-5c.c new file mode 100644 index 0000000..9ce4e6d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-5c.c @@ -0,0 +1,62 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -ftree-vectorize -fvect-cost-model=unlimited -fdump-tree-slp-details -mprefer-vector-width=256" } */ +/* { dg-require-effective-target avx512fp16 } */ +/* { dg-final { scan-tree-dump-times "basic block part vectorized using (?:32|64) byte vectors" 1 "slp2" } }*/ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) _Float16>} 4 "slp2" } } */ + +#include <string.h> + +static void do_test (void); +#define DO_TEST do_test +#define AVX512FP16 +#include "avx512-check.h" + +void +__attribute__((noipa)) +foo_ph (_Complex _Float16* a, _Complex _Float16* __restrict b) +{ + a[0] = b[8]; + a[1] = b[9]; + a[2] = b[10]; + a[3] = b[11]; + a[4] = b[12]; + a[5] = b[13]; + a[6] = b[14]; + a[7] = b[15]; + a[8] = b[0]; + a[9] = b[1]; + a[10] = b[2]; + a[11] = b[3]; + a[12] = b[4]; + a[13] = b[5]; + a[14] = b[6]; + a[15] = b[7]; +} + +void +do_test (void) +{ + _Complex _Float16* ph_src = (_Complex _Float16*) malloc (64); + _Complex _Float16* ph_dst = (_Complex _Float16*) malloc (64); + _Complex _Float16* ph_exp = (_Complex _Float16*) malloc (64); + char* p = (char* ) malloc (64); + char* q = (char* ) malloc (64); + + __builtin_memset (ph_dst, 0, 64); + + for (int i = 0; i != 64; i++) + { + p[i] = i; + q[i] = (i + 32) % 64; + } + __builtin_memcpy (ph_src, p, 64); + + __builtin_memcpy (ph_exp, q, 64); + + foo_ph (ph_dst, ph_src); + + if (__builtin_memcmp (ph_dst, ph_exp, 64) != 0) + __builtin_abort (); + + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-6a.c b/gcc/testsuite/gcc.target/i386/pr106010-6a.c new file mode 100644 index 0000000..65a90d0 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-6a.c @@ -0,0 +1,115 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx2 -ftree-vectorize -fvect-cost-model=unlimited -fdump-tree-slp-details -mprefer-vector-width=256" } */ +/* { dg-final { scan-tree-dump-times "basic block part vectorized using (?:32|64) byte vectors" 6 "slp2" } }*/ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*VEC_PERM_EXPR.*\{ 2, 3, 0, 1 \}} 4 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*VEC_PERM_EXPR.*\{ 6, 7, 4, 5, 2, 3, 0, 1 \}} 4 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*VEC_PERM_EXPR.*\{ 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1 \}} 2 "slp2" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*VEC_PERM_EXPR.*\{ 30, 31, 28, 29, 26, 27, 24, 25, 22, 23, 20, 21, 18, 19, 16, 17, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1 \}} 2 "slp2" } } */ + +void +__attribute__((noipa)) +foo_pd (_Complex double* a, _Complex double* __restrict b) +{ + a[0] = b[3]; + a[1] = b[2]; + a[2] = b[1]; + a[3] = b[0]; +} + +void +__attribute__((noipa)) +foo_ps (_Complex float* a, _Complex float* __restrict b) +{ + a[0] = b[7]; + a[1] = b[6]; + a[2] = b[5]; + a[3] = b[4]; + a[4] = b[3]; + a[5] = b[2]; + a[6] = b[1]; + a[7] = b[0]; +} + +void +__attribute__((noipa)) +foo_epi64 (_Complex long long* a, _Complex long long* __restrict b) +{ + a[0] = b[3]; + a[1] = b[2]; + a[2] = b[1]; + a[3] = b[0]; +} + +void +__attribute__((noipa)) +foo_epi32 (_Complex int* a, _Complex int* __restrict b) +{ + a[0] = b[7]; + a[1] = b[6]; + a[2] = b[5]; + a[3] = b[4]; + a[4] = b[3]; + a[5] = b[2]; + a[6] = b[1]; + a[7] = b[0]; +} + +void +__attribute__((noipa)) +foo_epi16 (_Complex short* a, _Complex short* __restrict b) +{ + a[0] = b[15]; + a[1] = b[14]; + a[2] = b[13]; + a[3] = b[12]; + a[4] = b[11]; + a[5] = b[10]; + a[6] = b[9]; + a[7] = b[8]; + a[8] = b[7]; + a[9] = b[6]; + a[10] = b[5]; + a[11] = b[4]; + a[12] = b[3]; + a[13] = b[2]; + a[14] = b[1]; + a[15] = b[0]; +} + +void +__attribute__((noipa)) +foo_epi8 (_Complex char* a, _Complex char* __restrict b) +{ + a[0] = b[31]; + a[1] = b[30]; + a[2] = b[29]; + a[3] = b[28]; + a[4] = b[27]; + a[5] = b[26]; + a[6] = b[25]; + a[7] = b[24]; + a[8] = b[23]; + a[9] = b[22]; + a[10] = b[21]; + a[11] = b[20]; + a[12] = b[19]; + a[13] = b[18]; + a[14] = b[17]; + a[15] = b[16]; + a[16] = b[15]; + a[17] = b[14]; + a[18] = b[13]; + a[19] = b[12]; + a[20] = b[11]; + a[21] = b[10]; + a[22] = b[9]; + a[23] = b[8]; + a[24] = b[7]; + a[25] = b[6]; + a[26] = b[5]; + a[27] = b[4]; + a[28] = b[3]; + a[29] = b[2]; + a[30] = b[1]; + a[31] = b[0]; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-6b.c b/gcc/testsuite/gcc.target/i386/pr106010-6b.c new file mode 100644 index 0000000..1c5bb02 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-6b.c @@ -0,0 +1,157 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx2 -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256" } */ +/* { dg-require-effective-target avx2 } */ + +#include "avx2-check.h" +#include <string.h> +#include "pr106010-6a.c" + +void +avx2_test (void) +{ + _Complex double* pd_src = (_Complex double*) malloc (64); + _Complex double* pd_dst = (_Complex double*) malloc (64); + _Complex double* pd_exp = (_Complex double*) malloc (64); + _Complex float* ps_src = (_Complex float*) malloc (64); + _Complex float* ps_dst = (_Complex float*) malloc (64); + _Complex float* ps_exp = (_Complex float*) malloc (64); + _Complex long long* epi64_src = (_Complex long long*) malloc (64); + _Complex long long* epi64_dst = (_Complex long long*) malloc (64); + _Complex long long* epi64_exp = (_Complex long long*) malloc (64); + _Complex int* epi32_src = (_Complex int*) malloc (64); + _Complex int* epi32_dst = (_Complex int*) malloc (64); + _Complex int* epi32_exp = (_Complex int*) malloc (64); + _Complex short* epi16_src = (_Complex short*) malloc (64); + _Complex short* epi16_dst = (_Complex short*) malloc (64); + _Complex short* epi16_exp = (_Complex short*) malloc (64); + _Complex char* epi8_src = (_Complex char*) malloc (64); + _Complex char* epi8_dst = (_Complex char*) malloc (64); + _Complex char* epi8_exp = (_Complex char*) malloc (64); + char* p = (char* ) malloc (64); + char* q = (char* ) malloc (64); + + __builtin_memset (pd_dst, 0, 64); + __builtin_memset (ps_dst, 0, 64); + __builtin_memset (epi64_dst, 0, 64); + __builtin_memset (epi32_dst, 0, 64); + __builtin_memset (epi16_dst, 0, 64); + __builtin_memset (epi8_dst, 0, 64); + + for (int i = 0; i != 64; i++) + p[i] = i; + + __builtin_memcpy (pd_src, p, 64); + __builtin_memcpy (ps_src, p, 64); + __builtin_memcpy (epi64_src, p, 64); + __builtin_memcpy (epi32_src, p, 64); + __builtin_memcpy (epi16_src, p, 64); + __builtin_memcpy (epi8_src, p, 64); + + + for (int i = 0; i != 16; i++) + { + q[i] = i + 48; + q[i + 16] = i + 32; + q[i + 32] = i + 16; + q[i + 48] = i; + } + + __builtin_memcpy (pd_exp, q, 64); + __builtin_memcpy (epi64_exp, q, 64); + + for (int i = 0; i != 8; i++) + { + q[i] = i + 56; + q[i + 8] = i + 48; + q[i + 16] = i + 40; + q[i + 24] = i + 32; + q[i + 32] = i + 24; + q[i + 40] = i + 16; + q[i + 48] = i + 8; + q[i + 56] = i; + } + + __builtin_memcpy (ps_exp, q, 64); + __builtin_memcpy (epi32_exp, q, 64); + + for (int i = 0; i != 4; i++) + { + q[i] = i + 60; + q[i + 4] = i + 56; + q[i + 8] = i + 52; + q[i + 12] = i + 48; + q[i + 16] = i + 44; + q[i + 20] = i + 40; + q[i + 24] = i + 36; + q[i + 28] = i + 32; + q[i + 32] = i + 28; + q[i + 36] = i + 24; + q[i + 40] = i + 20; + q[i + 44] = i + 16; + q[i + 48] = i + 12; + q[i + 52] = i + 8; + q[i + 56] = i + 4; + q[i + 60] = i; + } + + __builtin_memcpy (epi16_exp, q, 64); + + for (int i = 0; i != 2; i++) + { + q[i] = i + 62; + q[i + 2] = i + 60; + q[i + 4] = i + 58; + q[i + 6] = i + 56; + q[i + 8] = i + 54; + q[i + 10] = i + 52; + q[i + 12] = i + 50; + q[i + 14] = i + 48; + q[i + 16] = i + 46; + q[i + 18] = i + 44; + q[i + 20] = i + 42; + q[i + 22] = i + 40; + q[i + 24] = i + 38; + q[i + 26] = i + 36; + q[i + 28] = i + 34; + q[i + 30] = i + 32; + q[i + 32] = i + 30; + q[i + 34] = i + 28; + q[i + 36] = i + 26; + q[i + 38] = i + 24; + q[i + 40] = i + 22; + q[i + 42] = i + 20; + q[i + 44] = i + 18; + q[i + 46] = i + 16; + q[i + 48] = i + 14; + q[i + 50] = i + 12; + q[i + 52] = i + 10; + q[i + 54] = i + 8; + q[i + 56] = i + 6; + q[i + 58] = i + 4; + q[i + 60] = i + 2; + q[i + 62] = i; + } + __builtin_memcpy (epi8_exp, q, 64); + + foo_pd (pd_dst, pd_src); + foo_ps (ps_dst, ps_src); + foo_epi64 (epi64_dst, epi64_src); + foo_epi32 (epi32_dst, epi32_src); + foo_epi16 (epi16_dst, epi16_src); + foo_epi8 (epi8_dst, epi8_src); + + if (__builtin_memcmp (pd_dst, pd_exp, 64) != 0) + __builtin_abort (); + if (__builtin_memcmp (ps_dst, ps_exp, 64) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi64_dst, epi64_exp, 64) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi32_dst, epi32_exp, 64) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi16_dst, epi16_exp, 64) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi8_dst, epi8_exp, 64) != 0) + __builtin_abort (); + + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-6c.c b/gcc/testsuite/gcc.target/i386/pr106010-6c.c new file mode 100644 index 0000000..b859d88 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-6c.c @@ -0,0 +1,80 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256 -fdump-tree-slp-details" } */ +/* { dg-require-effective-target avx512fp16 } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*VEC_PERM_EXPR.*\{ 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1 \}} 2 "slp2" } } */ +/* { dg-final { scan-tree-dump-times "basic block part vectorized using (?:32|64) byte vectors" 1 "slp2" } } */ + +#include <string.h> + +static void do_test (void); +#define DO_TEST do_test +#define AVX512FP16 +#include "avx512-check.h" + +void +__attribute__((noipa)) +foo_ph (_Complex _Float16* a, _Complex _Float16* __restrict b) +{ + a[0] = b[15]; + a[1] = b[14]; + a[2] = b[13]; + a[3] = b[12]; + a[4] = b[11]; + a[5] = b[10]; + a[6] = b[9]; + a[7] = b[8]; + a[8] = b[7]; + a[9] = b[6]; + a[10] = b[5]; + a[11] = b[4]; + a[12] = b[3]; + a[13] = b[2]; + a[14] = b[1]; + a[15] = b[0]; +} + +void +do_test (void) +{ + _Complex _Float16* ph_src = (_Complex _Float16*) malloc (64); + _Complex _Float16* ph_dst = (_Complex _Float16*) malloc (64); + _Complex _Float16* ph_exp = (_Complex _Float16*) malloc (64); + char* p = (char* ) malloc (64); + char* q = (char* ) malloc (64); + + __builtin_memset (ph_dst, 0, 64); + + for (int i = 0; i != 64; i++) + p[i] = i; + + __builtin_memcpy (ph_src, p, 64); + + for (int i = 0; i != 4; i++) + { + q[i] = i + 60; + q[i + 4] = i + 56; + q[i + 8] = i + 52; + q[i + 12] = i + 48; + q[i + 16] = i + 44; + q[i + 20] = i + 40; + q[i + 24] = i + 36; + q[i + 28] = i + 32; + q[i + 32] = i + 28; + q[i + 36] = i + 24; + q[i + 40] = i + 20; + q[i + 44] = i + 16; + q[i + 48] = i + 12; + q[i + 52] = i + 8; + q[i + 56] = i + 4; + q[i + 60] = i; + } + + __builtin_memcpy (ph_exp, q, 64); + + foo_ph (ph_dst, ph_src); + + if (__builtin_memcmp (ph_dst, ph_exp, 64) != 0) + __builtin_abort (); + + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-7a.c b/gcc/testsuite/gcc.target/i386/pr106010-7a.c new file mode 100644 index 0000000..2ea01fa --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-7a.c @@ -0,0 +1,58 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -fdump-tree-vect-details -mprefer-vector-width=256" } */ +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 6 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) double>} 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) float>} 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) long long int>} 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) int>} 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) short int>} 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(32\) char>} 1 "vect" } } */ + +#define N 10000 +void +__attribute__((noipa)) +foo_pd (_Complex double* a, _Complex double b) +{ + for (int i = 0; i != N; i++) + a[i] = b; +} + +void +__attribute__((noipa)) +foo_ps (_Complex float* a, _Complex float b) +{ + for (int i = 0; i != N; i++) + a[i] = b; +} + +void +__attribute__((noipa)) +foo_epi64 (_Complex long long* a, _Complex long long b) +{ + for (int i = 0; i != N; i++) + a[i] = b; +} + +void +__attribute__((noipa)) +foo_epi32 (_Complex int* a, _Complex int b) +{ + for (int i = 0; i != N; i++) + a[i] = b; +} + +void +__attribute__((noipa)) +foo_epi16 (_Complex short* a, _Complex short b) +{ + for (int i = 0; i != N; i++) + a[i] = b; +} + +void +__attribute__((noipa)) +foo_epi8 (_Complex char* a, _Complex char b) +{ + for (int i = 0; i != N; i++) + a[i] = b; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-7b.c b/gcc/testsuite/gcc.target/i386/pr106010-7b.c new file mode 100644 index 0000000..26482cc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-7b.c @@ -0,0 +1,63 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256" } */ +/* { dg-require-effective-target avx } */ + +#include "avx-check.h" +#include <string.h> +#include "pr106010-7a.c" + +void +avx_test (void) +{ + _Complex double* pd_src = (_Complex double*) malloc (2 * N * sizeof (double)); + _Complex double* pd_dst = (_Complex double*) malloc (2 * N * sizeof (double)); + _Complex float* ps_src = (_Complex float*) malloc (2 * N * sizeof (float)); + _Complex float* ps_dst = (_Complex float*) malloc (2 * N * sizeof (float)); + _Complex long long* epi64_src = (_Complex long long*) malloc (2 * N * sizeof (long long)); + _Complex long long* epi64_dst = (_Complex long long*) malloc (2 * N * sizeof (long long)); + _Complex int* epi32_src = (_Complex int*) malloc (2 * N * sizeof (int)); + _Complex int* epi32_dst = (_Complex int*) malloc (2 * N * sizeof (int)); + _Complex short* epi16_src = (_Complex short*) malloc (2 * N * sizeof (short)); + _Complex short* epi16_dst = (_Complex short*) malloc (2 * N * sizeof (short)); + _Complex char* epi8_src = (_Complex char*) malloc (2 * N * sizeof (char)); + _Complex char* epi8_dst = (_Complex char*) malloc (2 * N * sizeof (char)); + char* p_init = (char*) malloc (2 * N * sizeof (double)); + + __builtin_memset (pd_dst, 0, 2 * N * sizeof (double)); + __builtin_memset (ps_dst, 0, 2 * N * sizeof (float)); + __builtin_memset (epi64_dst, 0, 2 * N * sizeof (long long)); + __builtin_memset (epi32_dst, 0, 2 * N * sizeof (int)); + __builtin_memset (epi16_dst, 0, 2 * N * sizeof (short)); + __builtin_memset (epi8_dst, 0, 2 * N * sizeof (char)); + + for (int i = 0; i != 2 * N * sizeof (double); i++) + p_init[i] = i % 2 + 3; + + memcpy (pd_src, p_init, 2 * N * sizeof (double)); + memcpy (ps_dst, p_init, 2 * N * sizeof (float)); + memcpy (epi64_dst, p_init, 2 * N * sizeof (long long)); + memcpy (epi32_dst, p_init, 2 * N * sizeof (int)); + memcpy (epi16_dst, p_init, 2 * N * sizeof (short)); + memcpy (epi8_dst, p_init, 2 * N * sizeof (char)); + + foo_pd (pd_dst, pd_src[0]); + foo_ps (ps_dst, ps_src[0]); + foo_epi64 (epi64_dst, epi64_src[0]); + foo_epi32 (epi32_dst, epi32_src[0]); + foo_epi16 (epi16_dst, epi16_src[0]); + foo_epi8 (epi8_dst, epi8_src[0]); + if (__builtin_memcmp (pd_dst, pd_src, N * 2 * sizeof (double)) != 0) + __builtin_abort (); + if (__builtin_memcmp (ps_dst, ps_src, N * 2 * sizeof (float)) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi64_dst, epi64_src, N * 2 * sizeof (long long)) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi32_dst, epi32_src, N * 2 * sizeof (int)) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi16_dst, epi16_src, N * 2 * sizeof (short)) != 0) + __builtin_abort (); + if (__builtin_memcmp (epi8_dst, epi8_src, N * 2 * sizeof (char)) != 0) + __builtin_abort (); + + return; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-7c.c b/gcc/testsuite/gcc.target/i386/pr106010-7c.c new file mode 100644 index 0000000..7f4056a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-7c.c @@ -0,0 +1,41 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256 -fdump-tree-vect-details" } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) _Float16>} 1 "vect" } } */ +/* { dg-require-effective-target avx512fp16 } */ + +#include <string.h> + +static void do_test (void); + +#define DO_TEST do_test +#define AVX512FP16 +#include "avx512-check.h" + +#define N 10000 + +void +__attribute__((noipa)) +foo_ph (_Complex _Float16* a, _Complex _Float16 b) +{ + for (int i = 0; i != N; i++) + a[i] = b; +} + +static void +do_test (void) +{ + _Complex _Float16* ph_src = (_Complex _Float16*) malloc (2 * N * sizeof (_Float16)); + _Complex _Float16* ph_dst = (_Complex _Float16*) malloc (2 * N * sizeof (_Float16)); + char* p_init = (char*) malloc (2 * N * sizeof (_Float16)); + + __builtin_memset (ph_dst, 0, 2 * N * sizeof (_Float16)); + + for (int i = 0; i != 2 * N * sizeof (_Float16); i++) + p_init[i] = i % 2 + 3; + + memcpy (ph_src, p_init, 2 * N * sizeof (_Float16)); + + foo_ph (ph_dst, ph_src[0]); + if (__builtin_memcmp (ph_dst, ph_src, N * 2 * sizeof (_Float16)) != 0) + __builtin_abort (); +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-8a.c b/gcc/testsuite/gcc.target/i386/pr106010-8a.c new file mode 100644 index 0000000..11054b6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-8a.c @@ -0,0 +1,58 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -fdump-tree-vect-details -mprefer-vector-width=256" } */ +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 6 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) double>} 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) float>} 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(4\) long long int>} 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(8\) int>} 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) short int>} 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(32\) char>} 1 "vect" } } */ + +#define N 10000 +void +__attribute__((noipa)) +foo_pd (_Complex double* a) +{ + for (int i = 0; i != N; i++) + a[i] = 1.0 + 2.0i; +} + +void +__attribute__((noipa)) +foo_ps (_Complex float* a) +{ + for (int i = 0; i != N; i++) + a[i] = 1.0f + 2.0fi; +} + +void +__attribute__((noipa)) +foo_epi64 (_Complex long long* a) +{ + for (int i = 0; i != N; i++) + a[i] = 1 + 2i; +} + +void +__attribute__((noipa)) +foo_epi32 (_Complex int* a) +{ + for (int i = 0; i != N; i++) + a[i] = 1 + 2i; +} + +void +__attribute__((noipa)) +foo_epi16 (_Complex short* a) +{ + for (int i = 0; i != N; i++) + a[i] = 1 + 2i; +} + +void +__attribute__((noipa)) +foo_epi8 (_Complex char* a) +{ + for (int i = 0; i != N; i++) + a[i] = 1 + 2i; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-8b.c b/gcc/testsuite/gcc.target/i386/pr106010-8b.c new file mode 100644 index 0000000..6bb0073 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-8b.c @@ -0,0 +1,53 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256" } */ +/* { dg-require-effective-target avx } */ + +#include "avx-check.h" +#include <string.h> +#include "pr106010-8a.c" + +void +avx_test (void) +{ + _Complex double pd_src = 1.0 + 2.0i; + _Complex double* pd_dst = (_Complex double*) malloc (2 * N * sizeof (double)); + _Complex float ps_src = 1.0 + 2.0i; + _Complex float* ps_dst = (_Complex float*) malloc (2 * N * sizeof (float)); + _Complex long long epi64_src = 1 + 2i;; + _Complex long long* epi64_dst = (_Complex long long*) malloc (2 * N * sizeof (long long)); + _Complex int epi32_src = 1 + 2i; + _Complex int* epi32_dst = (_Complex int*) malloc (2 * N * sizeof (int)); + _Complex short epi16_src = 1 + 2i; + _Complex short* epi16_dst = (_Complex short*) malloc (2 * N * sizeof (short)); + _Complex char epi8_src = 1 + 2i; + _Complex char* epi8_dst = (_Complex char*) malloc (2 * N * sizeof (char)); + + __builtin_memset (pd_dst, 0, 2 * N * sizeof (double)); + __builtin_memset (ps_dst, 0, 2 * N * sizeof (float)); + __builtin_memset (epi64_dst, 0, 2 * N * sizeof (long long)); + __builtin_memset (epi32_dst, 0, 2 * N * sizeof (int)); + __builtin_memset (epi16_dst, 0, 2 * N * sizeof (short)); + __builtin_memset (epi8_dst, 0, 2 * N * sizeof (char)); + + foo_pd (pd_dst); + foo_ps (ps_dst); + foo_epi64 (epi64_dst); + foo_epi32 (epi32_dst); + foo_epi16 (epi16_dst); + foo_epi8 (epi8_dst); + for (int i = 0 ; i != N; i++) + { + if (pd_dst[i] != pd_src) + __builtin_abort (); + if (ps_dst[i] != ps_src) + __builtin_abort (); + if (epi64_dst[i] != epi64_src) + __builtin_abort (); + if (epi32_dst[i] != epi32_src) + __builtin_abort (); + if (epi16_dst[i] != epi16_src) + __builtin_abort (); + if (epi8_dst[i] != epi8_src) + __builtin_abort (); + } +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-8c.c b/gcc/testsuite/gcc.target/i386/pr106010-8c.c new file mode 100644 index 0000000..61ae131 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-8c.c @@ -0,0 +1,38 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -ftree-vectorize -fvect-cost-model=unlimited -mprefer-vector-width=256 -fdump-tree-vect-details" } */ +/* { dg-final { scan-tree-dump-times {(?n)add new stmt:.*MEM <vector\(16\) _Float16>} 1 "vect" } } */ +/* { dg-require-effective-target avx512fp16 } */ + +#include <string.h> + +static void do_test (void); + +#define DO_TEST do_test +#define AVX512FP16 +#include "avx512-check.h" + +#define N 10000 + +void +__attribute__((noipa)) +foo_ph (_Complex _Float16* a) +{ + for (int i = 0; i != N; i++) + a[i] = 1.0f16 + 2.0f16i; +} + +static void +do_test (void) +{ + _Complex _Float16 ph_src = 1.0f16 + 2.0f16i; + _Complex _Float16* ph_dst = (_Complex _Float16*) malloc (2 * N * sizeof (_Float16)); + + __builtin_memset (ph_dst, 0, 2 * N * sizeof (_Float16)); + + foo_ph (ph_dst); + for (int i = 0; i != N; i++) + { + if (ph_dst[i] != ph_src) + __builtin_abort (); + } +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-9a.c b/gcc/testsuite/gcc.target/i386/pr106010-9a.c new file mode 100644 index 0000000..e922f7b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-9a.c @@ -0,0 +1,89 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -mavx2 -fvect-cost-model=unlimited -fdump-tree-vect-details" } */ +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 6 "vect" } } */ + +typedef struct { _Complex double c; double a1; double a2;} + cdf; +typedef struct { _Complex double c; double a1; double a2; double a3; double a4;} + cdf2; +typedef struct { _Complex double c1; _Complex double c2; double a1; double a2; double a3; double a4;} + cdf3; +typedef struct { _Complex double c1; _Complex double c2; double a1; double a2;} + cdf4; + +#define N 100 +/* VMAT_ELEMENTWISE. */ +void +__attribute__((noipa)) +foo (cdf* a, cdf* __restrict b) +{ + for (int i = 0; i < N; ++i) + { + a[i].c = b[i].c; + a[i].a1 = b[i].a1; + a[i].a2 = b[i].a2; + } +} + +/* VMAT_CONTIGUOUS_PERMUTE. */ +void +__attribute__((noipa)) +foo1 (cdf2* a, cdf2* __restrict b) +{ + for (int i = 0; i < N; ++i) + { + a[i].c = b[i].c; + a[i].a1 = b[i].a1; + a[i].a2 = b[i].a2; + a[i].a3 = b[i].a3; + a[i].a4 = b[i].a4; + } +} + +/* VMAT_CONTIGUOUS. */ +void +__attribute__((noipa)) +foo2 (cdf3* a, cdf3* __restrict b) +{ + for (int i = 0; i < N; ++i) + { + a[i].c1 = b[i].c1; + a[i].c2 = b[i].c2; + a[i].a1 = b[i].a1; + a[i].a2 = b[i].a2; + a[i].a3 = b[i].a3; + a[i].a4 = b[i].a4; + } +} + +/* VMAT_STRIDED_SLP. */ +void +__attribute__((noipa)) +foo3 (cdf4* a, cdf4* __restrict b) +{ + for (int i = 0; i < N; ++i) + { + a[i].c1 = b[i].c1; + a[i].c2 = b[i].c2; + a[i].a1 = b[i].a1; + a[i].a2 = b[i].a2; + } +} + +/* VMAT_CONTIGUOUS_REVERSE. */ +void +__attribute__((noipa)) +foo4 (_Complex double* a, _Complex double* __restrict b) +{ + for (int i = 0; i != N; i++) + a[i] = b[N-i-1]; +} + +/* VMAT_CONTIGUOUS_DOWN. */ +void +__attribute__((noipa)) +foo5 (_Complex double* a, _Complex double* __restrict b) +{ + for (int i = 0; i != N; i++) + a[N-i-1] = b[0]; +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-9b.c b/gcc/testsuite/gcc.target/i386/pr106010-9b.c new file mode 100644 index 0000000..e220445 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-9b.c @@ -0,0 +1,90 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -msse2 -fvect-cost-model=unlimited" } */ +/* { dg-require-effective-target sse2 } */ + +#include <string.h> +#include "sse2-check.h" +#include "pr106010-9a.c" + +static void +sse2_test (void) +{ + _Complex double* pd_src = (_Complex double*) malloc (N * sizeof (_Complex double)); + _Complex double* pd_dst = (_Complex double*) malloc (N * sizeof (_Complex double)); + _Complex double* pd_src2 = (_Complex double*) malloc (N * sizeof (_Complex double)); + _Complex double* pd_dst2 = (_Complex double*) malloc (N * sizeof (_Complex double)); + cdf* cdf_src = (cdf*) malloc (N * sizeof (cdf)); + cdf* cdf_dst = (cdf*) malloc (N * sizeof (cdf)); + cdf2* cdf2_src = (cdf2*) malloc (N * sizeof (cdf2)); + cdf2* cdf2_dst = (cdf2*) malloc (N * sizeof (cdf2)); + cdf3* cdf3_src = (cdf3*) malloc (N * sizeof (cdf3)); + cdf3* cdf3_dst = (cdf3*) malloc (N * sizeof (cdf3)); + cdf4* cdf4_src = (cdf4*) malloc (N * sizeof (cdf4)); + cdf4* cdf4_dst = (cdf4*) malloc (N * sizeof (cdf4)); + + char* p_init = (char*) malloc (N * sizeof (cdf3)); + + __builtin_memset (cdf_dst, 0, N * sizeof (cdf)); + __builtin_memset (cdf2_dst, 0, N * sizeof (cdf2)); + __builtin_memset (cdf3_dst, 0, N * sizeof (cdf3)); + __builtin_memset (cdf4_dst, 0, N * sizeof (cdf4)); + __builtin_memset (pd_dst, 0, N * sizeof (_Complex double)); + __builtin_memset (pd_dst2, 0, N * sizeof (_Complex double)); + + for (int i = 0; i != N * sizeof (cdf3); i++) + p_init[i] = i; + + memcpy (cdf_src, p_init, N * sizeof (cdf)); + memcpy (cdf2_src, p_init, N * sizeof (cdf2)); + memcpy (cdf3_src, p_init, N * sizeof (cdf3)); + memcpy (cdf4_src, p_init, N * sizeof (cdf4)); + memcpy (pd_src, p_init, N * sizeof (_Complex double)); + for (int i = 0; i != 2 * N * sizeof (double); i++) + p_init[i] = i % 16; + memcpy (pd_src2, p_init, N * sizeof (_Complex double)); + + foo (cdf_dst, cdf_src); + foo1 (cdf2_dst, cdf2_src); + foo2 (cdf3_dst, cdf3_src); + foo3 (cdf4_dst, cdf4_src); + foo4 (pd_dst, pd_src); + foo5 (pd_dst2, pd_src2); + for (int i = 0; i != N; i++) + { + p_init[(N - i - 1) * 16] = i * 16; + p_init[(N - i - 1) * 16 + 1] = i * 16 + 1; + p_init[(N - i - 1) * 16 + 2] = i * 16 + 2; + p_init[(N - i - 1) * 16 + 3] = i * 16 + 3; + p_init[(N - i - 1) * 16 + 4] = i * 16 + 4; + p_init[(N - i - 1) * 16 + 5] = i * 16 + 5; + p_init[(N - i - 1) * 16 + 6] = i * 16 + 6; + p_init[(N - i - 1) * 16 + 7] = i * 16 + 7; + p_init[(N - i - 1) * 16 + 8] = i * 16 + 8; + p_init[(N - i - 1) * 16 + 9] = i * 16 + 9; + p_init[(N - i - 1) * 16 + 10] = i * 16 + 10; + p_init[(N - i - 1) * 16 + 11] = i * 16 + 11; + p_init[(N - i - 1) * 16 + 12] = i * 16 + 12; + p_init[(N - i - 1) * 16 + 13] = i * 16 + 13; + p_init[(N - i - 1) * 16 + 14] = i * 16 + 14; + p_init[(N - i - 1) * 16 + 15] = i * 16 + 15; + } + memcpy (pd_src, p_init, N * 16); + + if (__builtin_memcmp (pd_dst, pd_src, N * 2 * sizeof (double)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (pd_dst2, pd_src2, N * 2 * sizeof (double)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf_dst, cdf_src, N * sizeof (cdf)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf2_dst, cdf2_src, N * sizeof (cdf2)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf3_dst, cdf3_src, N * sizeof (cdf3)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf4_dst, cdf4_src, N * sizeof (cdf4)) != 0) + __builtin_abort (); +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-9c.c b/gcc/testsuite/gcc.target/i386/pr106010-9c.c new file mode 100644 index 0000000..ff51f61 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-9c.c @@ -0,0 +1,90 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -mavx2 -fvect-cost-model=unlimited" } */ +/* { dg-require-effective-target avx2 } */ + +#include <string.h> +#include "avx2-check.h" +#include "pr106010-9a.c" + +static void +avx2_test (void) +{ + _Complex double* pd_src = (_Complex double*) malloc (N * sizeof (_Complex double)); + _Complex double* pd_dst = (_Complex double*) malloc (N * sizeof (_Complex double)); + _Complex double* pd_src2 = (_Complex double*) malloc (N * sizeof (_Complex double)); + _Complex double* pd_dst2 = (_Complex double*) malloc (N * sizeof (_Complex double)); + cdf* cdf_src = (cdf*) malloc (N * sizeof (cdf)); + cdf* cdf_dst = (cdf*) malloc (N * sizeof (cdf)); + cdf2* cdf2_src = (cdf2*) malloc (N * sizeof (cdf2)); + cdf2* cdf2_dst = (cdf2*) malloc (N * sizeof (cdf2)); + cdf3* cdf3_src = (cdf3*) malloc (N * sizeof (cdf3)); + cdf3* cdf3_dst = (cdf3*) malloc (N * sizeof (cdf3)); + cdf4* cdf4_src = (cdf4*) malloc (N * sizeof (cdf4)); + cdf4* cdf4_dst = (cdf4*) malloc (N * sizeof (cdf4)); + + char* p_init = (char*) malloc (N * sizeof (cdf3)); + + __builtin_memset (cdf_dst, 0, N * sizeof (cdf)); + __builtin_memset (cdf2_dst, 0, N * sizeof (cdf2)); + __builtin_memset (cdf3_dst, 0, N * sizeof (cdf3)); + __builtin_memset (cdf4_dst, 0, N * sizeof (cdf4)); + __builtin_memset (pd_dst, 0, N * sizeof (_Complex double)); + __builtin_memset (pd_dst2, 0, N * sizeof (_Complex double)); + + for (int i = 0; i != N * sizeof (cdf3); i++) + p_init[i] = i; + + memcpy (cdf_src, p_init, N * sizeof (cdf)); + memcpy (cdf2_src, p_init, N * sizeof (cdf2)); + memcpy (cdf3_src, p_init, N * sizeof (cdf3)); + memcpy (cdf4_src, p_init, N * sizeof (cdf4)); + memcpy (pd_src, p_init, N * sizeof (_Complex double)); + for (int i = 0; i != 2 * N * sizeof (double); i++) + p_init[i] = i % 16; + memcpy (pd_src2, p_init, N * sizeof (_Complex double)); + + foo (cdf_dst, cdf_src); + foo1 (cdf2_dst, cdf2_src); + foo2 (cdf3_dst, cdf3_src); + foo3 (cdf4_dst, cdf4_src); + foo4 (pd_dst, pd_src); + foo5 (pd_dst2, pd_src2); + for (int i = 0; i != N; i++) + { + p_init[(N - i - 1) * 16] = i * 16; + p_init[(N - i - 1) * 16 + 1] = i * 16 + 1; + p_init[(N - i - 1) * 16 + 2] = i * 16 + 2; + p_init[(N - i - 1) * 16 + 3] = i * 16 + 3; + p_init[(N - i - 1) * 16 + 4] = i * 16 + 4; + p_init[(N - i - 1) * 16 + 5] = i * 16 + 5; + p_init[(N - i - 1) * 16 + 6] = i * 16 + 6; + p_init[(N - i - 1) * 16 + 7] = i * 16 + 7; + p_init[(N - i - 1) * 16 + 8] = i * 16 + 8; + p_init[(N - i - 1) * 16 + 9] = i * 16 + 9; + p_init[(N - i - 1) * 16 + 10] = i * 16 + 10; + p_init[(N - i - 1) * 16 + 11] = i * 16 + 11; + p_init[(N - i - 1) * 16 + 12] = i * 16 + 12; + p_init[(N - i - 1) * 16 + 13] = i * 16 + 13; + p_init[(N - i - 1) * 16 + 14] = i * 16 + 14; + p_init[(N - i - 1) * 16 + 15] = i * 16 + 15; + } + memcpy (pd_src, p_init, N * 16); + + if (__builtin_memcmp (pd_dst, pd_src, N * 2 * sizeof (double)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (pd_dst2, pd_src2, N * 2 * sizeof (double)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf_dst, cdf_src, N * sizeof (cdf)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf2_dst, cdf2_src, N * sizeof (cdf2)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf3_dst, cdf3_src, N * sizeof (cdf3)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf4_dst, cdf4_src, N * sizeof (cdf4)) != 0) + __builtin_abort (); +} diff --git a/gcc/testsuite/gcc.target/i386/pr106010-9d.c b/gcc/testsuite/gcc.target/i386/pr106010-9d.c new file mode 100644 index 0000000..d4d8f1d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106010-9d.c @@ -0,0 +1,92 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -mavx512f -mavx512vl -fvect-cost-model=unlimited -mprefer-vector-width=512" } */ +/* { dg-require-effective-target avx512f } */ + +#include <string.h> +#include <stdlib.h> +#define AVX512F +#include "avx512-check.h" +#include "pr106010-9a.c" + +static void +test_512 (void) +{ + _Complex double* pd_src = (_Complex double*) malloc (N * sizeof (_Complex double)); + _Complex double* pd_dst = (_Complex double*) malloc (N * sizeof (_Complex double)); + _Complex double* pd_src2 = (_Complex double*) malloc (N * sizeof (_Complex double)); + _Complex double* pd_dst2 = (_Complex double*) malloc (N * sizeof (_Complex double)); + cdf* cdf_src = (cdf*) malloc (N * sizeof (cdf)); + cdf* cdf_dst = (cdf*) malloc (N * sizeof (cdf)); + cdf2* cdf2_src = (cdf2*) malloc (N * sizeof (cdf2)); + cdf2* cdf2_dst = (cdf2*) malloc (N * sizeof (cdf2)); + cdf3* cdf3_src = (cdf3*) malloc (N * sizeof (cdf3)); + cdf3* cdf3_dst = (cdf3*) malloc (N * sizeof (cdf3)); + cdf4* cdf4_src = (cdf4*) malloc (N * sizeof (cdf4)); + cdf4* cdf4_dst = (cdf4*) malloc (N * sizeof (cdf4)); + + char* p_init = (char*) malloc (N * sizeof (cdf3)); + + __builtin_memset (cdf_dst, 0, N * sizeof (cdf)); + __builtin_memset (cdf2_dst, 0, N * sizeof (cdf2)); + __builtin_memset (cdf3_dst, 0, N * sizeof (cdf3)); + __builtin_memset (cdf4_dst, 0, N * sizeof (cdf4)); + __builtin_memset (pd_dst, 0, N * sizeof (_Complex double)); + __builtin_memset (pd_dst2, 0, N * sizeof (_Complex double)); + + for (int i = 0; i != N * sizeof (cdf3); i++) + p_init[i] = i; + + memcpy (cdf_src, p_init, N * sizeof (cdf)); + memcpy (cdf2_src, p_init, N * sizeof (cdf2)); + memcpy (cdf3_src, p_init, N * sizeof (cdf3)); + memcpy (cdf4_src, p_init, N * sizeof (cdf4)); + memcpy (pd_src, p_init, N * sizeof (_Complex double)); + for (int i = 0; i != 2 * N * sizeof (double); i++) + p_init[i] = i % 16; + memcpy (pd_src2, p_init, N * sizeof (_Complex double)); + + foo (cdf_dst, cdf_src); + foo1 (cdf2_dst, cdf2_src); + foo2 (cdf3_dst, cdf3_src); + foo3 (cdf4_dst, cdf4_src); + foo4 (pd_dst, pd_src); + foo5 (pd_dst2, pd_src2); + for (int i = 0; i != N; i++) + { + p_init[(N - i - 1) * 16] = i * 16; + p_init[(N - i - 1) * 16 + 1] = i * 16 + 1; + p_init[(N - i - 1) * 16 + 2] = i * 16 + 2; + p_init[(N - i - 1) * 16 + 3] = i * 16 + 3; + p_init[(N - i - 1) * 16 + 4] = i * 16 + 4; + p_init[(N - i - 1) * 16 + 5] = i * 16 + 5; + p_init[(N - i - 1) * 16 + 6] = i * 16 + 6; + p_init[(N - i - 1) * 16 + 7] = i * 16 + 7; + p_init[(N - i - 1) * 16 + 8] = i * 16 + 8; + p_init[(N - i - 1) * 16 + 9] = i * 16 + 9; + p_init[(N - i - 1) * 16 + 10] = i * 16 + 10; + p_init[(N - i - 1) * 16 + 11] = i * 16 + 11; + p_init[(N - i - 1) * 16 + 12] = i * 16 + 12; + p_init[(N - i - 1) * 16 + 13] = i * 16 + 13; + p_init[(N - i - 1) * 16 + 14] = i * 16 + 14; + p_init[(N - i - 1) * 16 + 15] = i * 16 + 15; + } + memcpy (pd_src, p_init, N * 16); + + if (__builtin_memcmp (pd_dst, pd_src, N * 2 * sizeof (double)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (pd_dst2, pd_src2, N * 2 * sizeof (double)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf_dst, cdf_src, N * sizeof (cdf)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf2_dst, cdf2_src, N * sizeof (cdf2)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf3_dst, cdf3_src, N * sizeof (cdf3)) != 0) + __builtin_abort (); + + if (__builtin_memcmp (cdf4_dst, cdf4_src, N * sizeof (cdf4)) != 0) + __builtin_abort (); +} diff --git a/gcc/testsuite/gcc.target/i386/vec-maskstore-vn.c b/gcc/testsuite/gcc.target/i386/vec-maskstore-vn.c new file mode 100644 index 0000000..9821390 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/vec-maskstore-vn.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -mavx2 -fdump-tree-fre5" } */ + +void __attribute__((noinline,noclone)) +foo (int *out, int *res) +{ + int mask[] = { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }; + int i; + for (i = 0; i < 16; ++i) + { + if (mask[i]) + out[i] = i; + } + int o0 = out[0]; + int o7 = out[7]; + int o14 = out[14]; + int o15 = out[15]; + res[0] = o0; + res[2] = o7; + res[4] = o14; + res[6] = o15; +} + +/* Vectorization produces .MASK_STORE, unrolling will unroll the two + vector iterations. FRE5 after that should be able to CSE + out[7] and out[15], but leave out[0] and out[14] alone. */ +/* { dg-final { scan-tree-dump " = o0_\[0-9\]+;" "fre5" } } */ +/* { dg-final { scan-tree-dump " = 7;" "fre5" } } */ +/* { dg-final { scan-tree-dump " = o14_\[0-9\]+;" "fre5" } } */ +/* { dg-final { scan-tree-dump " = 15;" "fre5" } } */ diff --git a/gcc/testsuite/gfortran.dg/associate_54.f90 b/gcc/testsuite/gfortran.dg/associate_54.f90 index 003175a..680ad5d 100644 --- a/gcc/testsuite/gfortran.dg/associate_54.f90 +++ b/gcc/testsuite/gfortran.dg/associate_54.f90 @@ -26,9 +26,8 @@ contains integer, intent(in) :: a associate (state => obj%state(TEST_STATES)) ! { dg-error "is used as array" } ! state = a - state(TEST_STATE) = a + state(TEST_STATE) = a ! { dg-error "array reference of a non-array" } end associate end subroutine test_alter_state1 end module test - diff --git a/gcc/testsuite/gfortran.dg/associate_59.f90 b/gcc/testsuite/gfortran.dg/associate_59.f90 new file mode 100644 index 0000000..2da9773 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/associate_59.f90 @@ -0,0 +1,9 @@ +! { dg-do compile } +! PR fortran/103590 - ICE: find_array_spec(): Missing spec +! Contributed by G.Steinmetz + +program p + associate (a => 1) + print *, [character(a(1)) :: '1'] ! { dg-error "Scalar INTEGER expression" } + end associate +end diff --git a/gcc/testsuite/gfortran.dg/gomp/affinity-clause-7.f90 b/gcc/testsuite/gfortran.dg/gomp/affinity-clause-7.f90 new file mode 100644 index 0000000..5b1ca85 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/affinity-clause-7.f90 @@ -0,0 +1,19 @@ +! { dg-do compile } +! PR fortran/101330 - ICE in free_expr0(): Bad expr type +! Contributed by G.Steinmetz + + implicit none + integer :: j, b(10) +!$omp task affinity (iterator(j=1:2:1) : b(j)) +!$omp end task +!$omp task affinity (iterator(j=1:2:) : b(j)) ! { dg-error "Invalid character" } +!!$omp end task +!$omp task affinity (iterator(j=1:2: ! { dg-error "Invalid character" } +!!$omp end task +!$omp task affinity (iterator(j=1:2:) ! { dg-error "Invalid character" } +!!$omp end task +!$omp task affinity (iterator(j=1:2::) ! { dg-error "Invalid character" } +!!$omp end task +!$omp task affinity (iterator(j=1:2:)) ! { dg-error "Invalid character" } +!!$omp end task +end diff --git a/gcc/timevar.def b/gcc/timevar.def index 2dae5e1..651af19 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -220,6 +220,7 @@ DEFTIMEVAR (TV_TREE_SWITCH_CONVERSION, "tree switch conversion") DEFTIMEVAR (TV_TREE_SWITCH_LOWERING, "tree switch lowering") DEFTIMEVAR (TV_TREE_RECIP , "gimple CSE reciprocals") DEFTIMEVAR (TV_TREE_SINCOS , "gimple CSE sin/cos") +DEFTIMEVAR (TV_TREE_POWCABS , "gimple expand pow/cabs") DEFTIMEVAR (TV_TREE_WIDEN_MUL , "gimple widening/fma detection") DEFTIMEVAR (TV_TRANS_MEM , "transactional memory") DEFTIMEVAR (TV_TREE_STRLEN , "tree strlen optimization") diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index bfcb142..5bcf781 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -5653,6 +5653,7 @@ gimple_verify_flow_info (void) } /* Verify that body of basic block BB is free of control flow. */ + bool seen_nondebug_stmt = false; for (; !gsi_end_p (gsi); gsi_next (&gsi)) { gimple *stmt = gsi_stmt (gsi); @@ -5673,6 +5674,38 @@ gimple_verify_flow_info (void) gimple_label_label (label_stmt), bb->index); err = 1; } + + /* Check that no statements appear between a returns_twice call + and its associated abnormal edge. */ + if (gimple_code (stmt) == GIMPLE_CALL + && gimple_call_flags (stmt) & ECF_RETURNS_TWICE) + { + const char *misplaced = NULL; + /* TM is an exception: it points abnormal edges just after the + call that starts a transaction, i.e. it must end the BB. */ + if (gimple_call_builtin_p (stmt, BUILT_IN_TM_START)) + { + if (single_succ_p (bb) + && bb_has_abnormal_pred (single_succ (bb)) + && !gsi_one_nondebug_before_end_p (gsi)) + misplaced = "not last"; + } + else + { + if (seen_nondebug_stmt + && bb_has_abnormal_pred (bb)) + misplaced = "not first"; + } + if (misplaced) + { + error ("returns_twice call is %s in basic block %d", + misplaced, bb->index); + print_gimple_stmt (stderr, stmt, 0, TDF_SLIM); + err = 1; + } + } + if (!is_gimple_debug (stmt)) + seen_nondebug_stmt = true; } gsi = gsi_last_nondebug_bb (bb); @@ -6313,12 +6346,15 @@ gimple_can_duplicate_bb_p (const_basic_block bb) { gimple *g = gsi_stmt (gsi); - /* An IFN_GOMP_SIMT_ENTER_ALLOC/IFN_GOMP_SIMT_EXIT call must be + /* Prohibit duplication of returns_twice calls, otherwise associated + abnormal edges also need to be duplicated properly. + An IFN_GOMP_SIMT_ENTER_ALLOC/IFN_GOMP_SIMT_EXIT call must be duplicated as part of its group, or not at all. The IFN_GOMP_SIMT_VOTE_ANY and IFN_GOMP_SIMT_XCHG_* are part of such a group, so the same holds there. */ if (is_gimple_call (g) - && (gimple_call_internal_p (g, IFN_GOMP_SIMT_ENTER_ALLOC) + && (gimple_call_flags (g) & ECF_RETURNS_TWICE + || gimple_call_internal_p (g, IFN_GOMP_SIMT_ENTER_ALLOC) || gimple_call_internal_p (g, IFN_GOMP_SIMT_EXIT) || gimple_call_internal_p (g, IFN_GOMP_SIMT_VOTE_ANY) || gimple_call_internal_p (g, IFN_GOMP_SIMT_XCHG_BFLY) diff --git a/gcc/tree-complex.cc b/gcc/tree-complex.cc index 61950a0..ea9df61 100644 --- a/gcc/tree-complex.cc +++ b/gcc/tree-complex.cc @@ -297,6 +297,11 @@ init_dont_simulate_again (void) break; default: + /* When expand_complex_move would trigger make sure we + perform lowering even when there is no actual complex + operation. This helps consistency and vectorization. */ + if (TREE_CODE (TREE_TYPE (gimple_op (stmt, 0))) == COMPLEX_TYPE) + saw_a_complex_op = true; break; } @@ -869,7 +874,9 @@ expand_complex_move (gimple_stmt_iterator *gsi, tree type) update_complex_assignment (gsi, r, i); } } - else if (rhs && TREE_CODE (rhs) == SSA_NAME && !TREE_SIDE_EFFECTS (lhs)) + else if (rhs + && (TREE_CODE (rhs) == SSA_NAME || TREE_CODE (rhs) == COMPLEX_CST) + && !TREE_SIDE_EFFECTS (lhs)) { tree x; gimple *t; diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 606d1d6..4dfe05e 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -444,6 +444,7 @@ extern gimple_opt_pass *make_pass_early_warn_uninitialized (gcc::context *ctxt); extern gimple_opt_pass *make_pass_late_warn_uninitialized (gcc::context *ctxt); extern gimple_opt_pass *make_pass_cse_reciprocals (gcc::context *ctxt); extern gimple_opt_pass *make_pass_cse_sincos (gcc::context *ctxt); +extern gimple_opt_pass *make_pass_expand_powcabs (gcc::context *ctxt); extern gimple_opt_pass *make_pass_optimize_bswap (gcc::context *ctxt); extern gimple_opt_pass *make_pass_store_merging (gcc::context *ctxt); extern gimple_opt_pass *make_pass_optimize_widening_mul (gcc::context *ctxt); diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc index 782266b..390cd87 100644 --- a/gcc/tree-ssa-alias.cc +++ b/gcc/tree-ssa-alias.cc @@ -47,6 +47,7 @@ along with GCC; see the file COPYING3. If not see #include "print-tree.h" #include "tree-ssa-alias-compare.h" #include "builtins.h" +#include "internal-fn.h" /* Broad overview of how alias analysis on gimple works: @@ -2793,8 +2794,38 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p) if (ref->volatile_p) return true; - callee = gimple_call_fndecl (call); + if (gimple_call_internal_p (call)) + switch (gimple_call_internal_fn (call)) + { + case IFN_MASK_STORE: + case IFN_SCATTER_STORE: + case IFN_MASK_SCATTER_STORE: + case IFN_LEN_STORE: + return false; + case IFN_MASK_STORE_LANES: + goto process_args; + case IFN_MASK_LOAD: + case IFN_LEN_LOAD: + case IFN_MASK_LOAD_LANES: + { + ao_ref rhs_ref; + tree lhs = gimple_call_lhs (call); + if (lhs) + { + ao_ref_init_from_ptr_and_size (&rhs_ref, + gimple_call_arg (call, 0), + TYPE_SIZE_UNIT (TREE_TYPE (lhs))); + rhs_ref.ref_alias_set = rhs_ref.base_alias_set + = tbaa_p ? get_deref_alias_set (TREE_TYPE + (gimple_call_arg (call, 1))) : 0; + return refs_may_alias_p_1 (ref, &rhs_ref, tbaa_p); + } + break; + } + default:; + } + callee = gimple_call_fndecl (call); if (callee != NULL_TREE) { struct cgraph_node *node = cgraph_node::get (callee); @@ -3005,7 +3036,7 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p) & (ECF_PURE|ECF_CONST|ECF_LOOPING_CONST_OR_PURE|ECF_NOVOPS)) return false; if (gimple_call_internal_p (call)) - switch (gimple_call_internal_fn (call)) + switch (auto fn = gimple_call_internal_fn (call)) { /* Treat these internal calls like ECF_PURE for aliasing, they don't write to any memory the program should care about. @@ -3018,6 +3049,20 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref, bool tbaa_p) case IFN_UBSAN_PTR: case IFN_ASAN_CHECK: return false; + case IFN_MASK_STORE: + case IFN_LEN_STORE: + case IFN_MASK_STORE_LANES: + { + tree rhs = gimple_call_arg (call, + internal_fn_stored_value_index (fn)); + ao_ref lhs_ref; + ao_ref_init_from_ptr_and_size (&lhs_ref, gimple_call_arg (call, 0), + TYPE_SIZE_UNIT (TREE_TYPE (rhs))); + lhs_ref.ref_alias_set = lhs_ref.base_alias_set + = tbaa_p ? get_deref_alias_set + (TREE_TYPE (gimple_call_arg (call, 1))) : 0; + return refs_may_alias_p_1 (ref, &lhs_ref, tbaa_p); + } default: break; } diff --git a/gcc/tree-ssa-dse.cc b/gcc/tree-ssa-dse.cc index 8d1739a..34cfd1a 100644 --- a/gcc/tree-ssa-dse.cc +++ b/gcc/tree-ssa-dse.cc @@ -93,7 +93,9 @@ static bitmap need_eh_cleanup; static bitmap need_ab_cleanup; /* STMT is a statement that may write into memory. Analyze it and - initialize WRITE to describe how STMT affects memory. + initialize WRITE to describe how STMT affects memory. When + MAY_DEF_OK is true then the function initializes WRITE to what + the stmt may define. Return TRUE if the statement was analyzed, FALSE otherwise. @@ -101,7 +103,7 @@ static bitmap need_ab_cleanup; can be achieved by analyzing more statements. */ static bool -initialize_ao_ref_for_dse (gimple *stmt, ao_ref *write) +initialize_ao_ref_for_dse (gimple *stmt, ao_ref *write, bool may_def_ok = false) { /* It's advantageous to handle certain mem* functions. */ if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) @@ -146,6 +148,32 @@ initialize_ao_ref_for_dse (gimple *stmt, ao_ref *write) break; } } + else if (is_gimple_call (stmt) + && gimple_call_internal_p (stmt)) + { + switch (gimple_call_internal_fn (stmt)) + { + case IFN_LEN_STORE: + ao_ref_init_from_ptr_and_size + (write, gimple_call_arg (stmt, 0), + int_const_binop (MINUS_EXPR, + gimple_call_arg (stmt, 2), + gimple_call_arg (stmt, 4))); + return true; + case IFN_MASK_STORE: + /* We cannot initialize a must-def ao_ref (in all cases) but we + can provide a may-def variant. */ + if (may_def_ok) + { + ao_ref_init_from_ptr_and_size + (write, gimple_call_arg (stmt, 0), + TYPE_SIZE_UNIT (TREE_TYPE (gimple_call_arg (stmt, 2)))); + return true; + } + break; + default:; + } + } else if (tree lhs = gimple_get_lhs (stmt)) { if (TREE_CODE (lhs) != SSA_NAME) @@ -1328,8 +1356,10 @@ dse_optimize_stmt (function *fun, gimple_stmt_iterator *gsi, sbitmap live_bytes) ao_ref ref; /* If this is not a store we can still remove dead call using - modref summary. */ - if (!initialize_ao_ref_for_dse (stmt, &ref)) + modref summary. Note we specifically allow ref to be initialized + to a conservative may-def since we are looking for followup stores + to kill all of it. */ + if (!initialize_ao_ref_for_dse (stmt, &ref, true)) { dse_optimize_call (gsi, live_bytes); return; @@ -1398,6 +1428,23 @@ dse_optimize_stmt (function *fun, gimple_stmt_iterator *gsi, sbitmap live_bytes) return; } } + else if (is_gimple_call (stmt) + && gimple_call_internal_p (stmt)) + { + switch (gimple_call_internal_fn (stmt)) + { + case IFN_LEN_STORE: + case IFN_MASK_STORE: + { + enum dse_store_status store_status; + store_status = dse_classify_store (&ref, stmt, false, live_bytes); + if (store_status == DSE_STORE_DEAD) + delete_dead_or_redundant_call (gsi, "dead"); + return; + } + default:; + } + } bool by_clobber_p = false; diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc index d04cf4b..fdc4bc8 100644 --- a/gcc/tree-ssa-forwprop.cc +++ b/gcc/tree-ssa-forwprop.cc @@ -2661,7 +2661,7 @@ simplify_permutation (gimple_stmt_iterator *gsi) /* Shuffle of a constructor. */ bool ret = false; - tree res_type = TREE_TYPE (gimple_assign_lhs (stmt)); + tree res_type = TREE_TYPE (arg0); tree opt = fold_ternary (VEC_PERM_EXPR, res_type, arg0, arg1, op2); if (!opt || (TREE_CODE (opt) != CONSTRUCTOR && TREE_CODE (opt) != VECTOR_CST)) diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc index a4492c9..58152b5 100644 --- a/gcc/tree-ssa-math-opts.cc +++ b/gcc/tree-ssa-math-opts.cc @@ -2226,8 +2226,7 @@ gimple_expand_builtin_cabs (gimple_stmt_iterator *gsi, location_t loc, tree arg) } /* Go through all calls to sin, cos and cexpi and call execute_cse_sincos_1 - on the SSA_NAME argument of each of them. Also expand powi(x,n) into - an optimal number of multiplies, when n is a constant. */ + on the SSA_NAME argument of each of them. */ namespace { @@ -2254,8 +2253,6 @@ public: /* opt_pass methods: */ bool gate (function *) final override { - /* We no longer require either sincos or cexp, since powi expansion - piggybacks on this pass. */ return optimize; } @@ -2275,24 +2272,15 @@ pass_cse_sincos::execute (function *fun) FOR_EACH_BB_FN (bb, fun) { gimple_stmt_iterator gsi; - bool cleanup_eh = false; for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple *stmt = gsi_stmt (gsi); - /* Only the last stmt in a bb could throw, no need to call - gimple_purge_dead_eh_edges if we change something in the middle - of a basic block. */ - cleanup_eh = false; - if (is_gimple_call (stmt) && gimple_call_lhs (stmt)) { - tree arg, arg0, arg1, result; - HOST_WIDE_INT n; - location_t loc; - + tree arg; switch (gimple_call_combined_fn (stmt)) { CASE_CFN_COS: @@ -2309,7 +2297,94 @@ pass_cse_sincos::execute (function *fun) if (TREE_CODE (arg) == SSA_NAME) cfg_changed |= execute_cse_sincos_1 (arg); break; + default: + break; + } + } + } + } + + statistics_counter_event (fun, "sincos statements inserted", + sincos_stats.inserted); + statistics_counter_event (fun, "conv statements removed", + sincos_stats.conv_removed); + + return cfg_changed ? TODO_cleanup_cfg : 0; +} + +} // anon namespace + +gimple_opt_pass * +make_pass_cse_sincos (gcc::context *ctxt) +{ + return new pass_cse_sincos (ctxt); +} + +/* Expand powi(x,n) into an optimal number of multiplies, when n is a constant. + Also expand CABS. */ +namespace { + +const pass_data pass_data_expand_powcabs = +{ + GIMPLE_PASS, /* type */ + "powcabs", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_TREE_POWCABS, /* tv_id */ + PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_update_ssa, /* todo_flags_finish */ +}; + +class pass_expand_powcabs : public gimple_opt_pass +{ +public: + pass_expand_powcabs (gcc::context *ctxt) + : gimple_opt_pass (pass_data_expand_powcabs, ctxt) + {} + /* opt_pass methods: */ + bool gate (function *) final override + { + return optimize; + } + + unsigned int execute (function *) final override; + +}; // class pass_expand_powcabs + +unsigned int +pass_expand_powcabs::execute (function *fun) +{ + basic_block bb; + bool cfg_changed = false; + + calculate_dominance_info (CDI_DOMINATORS); + + FOR_EACH_BB_FN (bb, fun) + { + gimple_stmt_iterator gsi; + bool cleanup_eh = false; + + for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + + /* Only the last stmt in a bb could throw, no need to call + gimple_purge_dead_eh_edges if we change something in the middle + of a basic block. */ + cleanup_eh = false; + + if (is_gimple_call (stmt) + && gimple_call_lhs (stmt)) + { + tree arg0, arg1, result; + HOST_WIDE_INT n; + location_t loc; + + switch (gimple_call_combined_fn (stmt)) + { CASE_CFN_POW: arg0 = gimple_call_arg (stmt, 0); arg1 = gimple_call_arg (stmt, 1); @@ -2405,20 +2480,15 @@ pass_cse_sincos::execute (function *fun) cfg_changed |= gimple_purge_dead_eh_edges (bb); } - statistics_counter_event (fun, "sincos statements inserted", - sincos_stats.inserted); - statistics_counter_event (fun, "conv statements removed", - sincos_stats.conv_removed); - return cfg_changed ? TODO_cleanup_cfg : 0; } } // anon namespace gimple_opt_pass * -make_pass_cse_sincos (gcc::context *ctxt) +make_pass_expand_powcabs (gcc::context *ctxt) { - return new pass_cse_sincos (ctxt); + return new pass_expand_powcabs (ctxt); } /* Return true if stmt is a type conversion operation that can be stripped diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index f41d503..7d947b5 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -1790,6 +1790,7 @@ struct pd_range struct pd_data { tree rhs; + HOST_WIDE_INT rhs_off; HOST_WIDE_INT offset; HOST_WIDE_INT size; }; @@ -1816,6 +1817,7 @@ struct vn_walk_cb_data unsigned int pos = 0, prec = w.get_precision (); pd_data pd; pd.rhs = build_constructor (NULL_TREE, NULL); + pd.rhs_off = 0; /* When bitwise and with a constant is done on a memory load, we don't really need all the bits to be defined or defined to constants, we don't really care what is in the position @@ -1976,6 +1978,7 @@ vn_walk_cb_data::push_partial_def (pd_data pd, bool pd_constant_p = (TREE_CODE (pd.rhs) == CONSTRUCTOR || CONSTANT_CLASS_P (pd.rhs)); + pd_range *r; if (partial_defs.is_empty ()) { /* If we get a clobber upfront, fail. */ @@ -1989,65 +1992,70 @@ vn_walk_cb_data::push_partial_def (pd_data pd, first_set = set; first_base_set = base_set; last_vuse_ptr = NULL; - /* Continue looking for partial defs. */ - return NULL; - } - - if (!known_ranges) - { - /* ??? Optimize the case where the 2nd partial def completes things. */ - gcc_obstack_init (&ranges_obstack); - known_ranges = splay_tree_new_with_allocator (pd_range_compare, 0, 0, - pd_tree_alloc, - pd_tree_dealloc, this); - splay_tree_insert (known_ranges, - (splay_tree_key)&first_range.offset, - (splay_tree_value)&first_range); - } - - pd_range newr = { pd.offset, pd.size }; - splay_tree_node n; - pd_range *r; - /* Lookup the predecessor of offset + 1 and see if we need to merge. */ - HOST_WIDE_INT loffset = newr.offset + 1; - if ((n = splay_tree_predecessor (known_ranges, (splay_tree_key)&loffset)) - && ((r = (pd_range *)n->value), true) - && ranges_known_overlap_p (r->offset, r->size + 1, - newr.offset, newr.size)) - { - /* Ignore partial defs already covered. Here we also drop shadowed - clobbers arriving here at the floor. */ - if (known_subrange_p (newr.offset, newr.size, r->offset, r->size)) - return NULL; - r->size = MAX (r->offset + r->size, newr.offset + newr.size) - r->offset; + r = &first_range; + /* Go check if the first partial definition was a full one in case + the caller didn't optimize for this. */ } else { - /* newr.offset wasn't covered yet, insert the range. */ - r = XOBNEW (&ranges_obstack, pd_range); - *r = newr; - splay_tree_insert (known_ranges, (splay_tree_key)&r->offset, - (splay_tree_value)r); - } - /* Merge r which now contains newr and is a member of the splay tree with - adjacent overlapping ranges. */ - pd_range *rafter; - while ((n = splay_tree_successor (known_ranges, (splay_tree_key)&r->offset)) - && ((rafter = (pd_range *)n->value), true) - && ranges_known_overlap_p (r->offset, r->size + 1, - rafter->offset, rafter->size)) - { - r->size = MAX (r->offset + r->size, - rafter->offset + rafter->size) - r->offset; - splay_tree_remove (known_ranges, (splay_tree_key)&rafter->offset); - } - /* If we get a clobber, fail. */ - if (TREE_CLOBBER_P (pd.rhs)) - return (void *)-1; - /* Non-constants are OK as long as they are shadowed by a constant. */ - if (!pd_constant_p) - return (void *)-1; - partial_defs.safe_push (pd); + if (!known_ranges) + { + /* ??? Optimize the case where the 2nd partial def completes + things. */ + gcc_obstack_init (&ranges_obstack); + known_ranges = splay_tree_new_with_allocator (pd_range_compare, 0, 0, + pd_tree_alloc, + pd_tree_dealloc, this); + splay_tree_insert (known_ranges, + (splay_tree_key)&first_range.offset, + (splay_tree_value)&first_range); + } + + pd_range newr = { pd.offset, pd.size }; + splay_tree_node n; + /* Lookup the predecessor of offset + 1 and see if we need to merge. */ + HOST_WIDE_INT loffset = newr.offset + 1; + if ((n = splay_tree_predecessor (known_ranges, (splay_tree_key)&loffset)) + && ((r = (pd_range *)n->value), true) + && ranges_known_overlap_p (r->offset, r->size + 1, + newr.offset, newr.size)) + { + /* Ignore partial defs already covered. Here we also drop shadowed + clobbers arriving here at the floor. */ + if (known_subrange_p (newr.offset, newr.size, r->offset, r->size)) + return NULL; + r->size + = MAX (r->offset + r->size, newr.offset + newr.size) - r->offset; + } + else + { + /* newr.offset wasn't covered yet, insert the range. */ + r = XOBNEW (&ranges_obstack, pd_range); + *r = newr; + splay_tree_insert (known_ranges, (splay_tree_key)&r->offset, + (splay_tree_value)r); + } + /* Merge r which now contains newr and is a member of the splay tree with + adjacent overlapping ranges. */ + pd_range *rafter; + while ((n = splay_tree_successor (known_ranges, + (splay_tree_key)&r->offset)) + && ((rafter = (pd_range *)n->value), true) + && ranges_known_overlap_p (r->offset, r->size + 1, + rafter->offset, rafter->size)) + { + r->size = MAX (r->offset + r->size, + rafter->offset + rafter->size) - r->offset; + splay_tree_remove (known_ranges, (splay_tree_key)&rafter->offset); + } + /* If we get a clobber, fail. */ + if (TREE_CLOBBER_P (pd.rhs)) + return (void *)-1; + /* Non-constants are OK as long as they are shadowed by a constant. */ + if (!pd_constant_p) + return (void *)-1; + partial_defs.safe_push (pd); + } /* Now we have merged newr into the range tree. When we have covered [offseti, sizei] then the tree will contain exactly one node which has @@ -2081,7 +2089,8 @@ vn_walk_cb_data::push_partial_def (pd_data pd, else { len = native_encode_expr (pd.rhs, this_buffer, bufsize, - MAX (0, -pd.offset) / BITS_PER_UNIT); + (MAX (0, -pd.offset) + + pd.rhs_off) / BITS_PER_UNIT); if (len <= 0 || len < (ROUND_UP (pd.size, BITS_PER_UNIT) / BITS_PER_UNIT - MAX (0, -pd.offset) / BITS_PER_UNIT)) @@ -2906,6 +2915,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, { pd_data pd; pd.rhs = build_constructor (NULL_TREE, NULL); + pd.rhs_off = 0; pd.offset = offset2i; pd.size = leni << LOG2_BITS_PER_UNIT; return data->push_partial_def (pd, 0, 0, offseti, maxsizei); @@ -2955,6 +2965,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, by a later def. */ pd_data pd; pd.rhs = gimple_assign_rhs1 (def_stmt); + pd.rhs_off = 0; pd.offset = offset2i; pd.size = size2i; return data->push_partial_def (pd, ao_ref_alias_set (&lhs_ref), @@ -3107,6 +3118,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, if (TREE_CODE (rhs) == SSA_NAME) rhs = SSA_VAL (rhs); pd.rhs = rhs; + pd.rhs_off = 0; pd.offset = offset2i; pd.size = size2i; return data->push_partial_def (pd, ao_ref_alias_set (&lhs_ref), @@ -3186,6 +3198,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, { pd_data pd; pd.rhs = SSA_VAL (def_rhs); + pd.rhs_off = 0; pd.offset = offset2i; pd.size = size2i; return data->push_partial_def (pd, ao_ref_alias_set (&lhs_ref), @@ -3195,6 +3208,133 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, } } + /* 4b) Assignment done via one of the vectorizer internal store + functions where we may be able to access pieces from or we can + combine to a larger entity. */ + else if (known_eq (ref->size, maxsize) + && is_gimple_reg_type (vr->type) + && !reverse_storage_order_for_component_p (vr->operands) + && !contains_storage_order_barrier_p (vr->operands) + && is_gimple_call (def_stmt) + && gimple_call_internal_p (def_stmt) + && internal_store_fn_p (gimple_call_internal_fn (def_stmt))) + { + gcall *call = as_a <gcall *> (def_stmt); + internal_fn fn = gimple_call_internal_fn (call); + tree def_rhs = gimple_call_arg (call, + internal_fn_stored_value_index (fn)); + def_rhs = vn_valueize (def_rhs); + if (TREE_CODE (def_rhs) != VECTOR_CST) + return (void *)-1; + + tree mask = NULL_TREE, len = NULL_TREE, bias = NULL_TREE; + switch (fn) + { + case IFN_MASK_STORE: + mask = gimple_call_arg (call, internal_fn_mask_index (fn)); + mask = vn_valueize (mask); + if (TREE_CODE (mask) != VECTOR_CST) + return (void *)-1; + break; + case IFN_LEN_STORE: + len = gimple_call_arg (call, 2); + bias = gimple_call_arg (call, 4); + if (!tree_fits_uhwi_p (len) || !tree_fits_shwi_p (bias)) + return (void *)-1; + break; + default: + return (void *)-1; + } + ao_ref_init_from_ptr_and_size (&lhs_ref, + vn_valueize (gimple_call_arg (call, 0)), + TYPE_SIZE_UNIT (TREE_TYPE (def_rhs))); + tree base2; + poly_int64 offset2, size2, maxsize2; + HOST_WIDE_INT offset2i, size2i, offseti; + base2 = ao_ref_base (&lhs_ref); + offset2 = lhs_ref.offset; + size2 = lhs_ref.size; + maxsize2 = lhs_ref.max_size; + if (known_size_p (maxsize2) + && known_eq (maxsize2, size2) + && adjust_offsets_for_equal_base_address (base, &offset, + base2, &offset2) + && maxsize.is_constant (&maxsizei) + && offset.is_constant (&offseti) + && offset2.is_constant (&offset2i) + && size2.is_constant (&size2i)) + { + if (!ranges_maybe_overlap_p (offset, maxsize, offset2, size2)) + /* Poor-mans disambiguation. */ + return NULL; + else if (ranges_known_overlap_p (offset, maxsize, offset2, size2)) + { + pd_data pd; + pd.rhs = def_rhs; + tree aa = gimple_call_arg (call, 1); + alias_set_type set = get_deref_alias_set (TREE_TYPE (aa)); + tree vectype = TREE_TYPE (def_rhs); + unsigned HOST_WIDE_INT elsz + = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (vectype))); + if (mask) + { + HOST_WIDE_INT start = 0, len = 0; + unsigned mask_idx = 0; + do + { + if (integer_zerop (VECTOR_CST_ELT (mask, mask_idx))) + { + if (len != 0) + { + pd.rhs_off = start; + pd.offset = offset2i + start; + pd.size = len; + if (ranges_known_overlap_p + (offset, maxsize, pd.offset, pd.size)) + { + void *res = data->push_partial_def + (pd, set, set, offseti, maxsizei); + if (res != NULL) + return res; + } + } + start = (mask_idx + 1) * elsz; + len = 0; + } + else + len += elsz; + mask_idx++; + } + while (known_lt (mask_idx, TYPE_VECTOR_SUBPARTS (vectype))); + if (len != 0) + { + pd.rhs_off = start; + pd.offset = offset2i + start; + pd.size = len; + if (ranges_known_overlap_p (offset, maxsize, + pd.offset, pd.size)) + return data->push_partial_def (pd, set, set, + offseti, maxsizei); + } + } + else if (fn == IFN_LEN_STORE) + { + pd.rhs_off = 0; + pd.offset = offset2i; + pd.size = (tree_to_uhwi (len) + + -tree_to_shwi (bias)) * BITS_PER_UNIT; + if (ranges_known_overlap_p (offset, maxsize, + pd.offset, pd.size)) + return data->push_partial_def (pd, set, set, + offseti, maxsizei); + } + else + gcc_unreachable (); + return NULL; + } + } + } + /* 5) For aggregate copies translate the reference through them if the copy kills ref. */ else if (data->vn_walk_kind == VN_WALKREWRITE @@ -3327,6 +3467,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, { pd_data pd; pd.rhs = val; + pd.rhs_off = 0; pd.offset = 0; pd.size = maxsizei; return data->push_partial_def (pd, ao_ref_alias_set (&lhs_ref), diff --git a/gcc/tree-ssa-sink.cc b/gcc/tree-ssa-sink.cc index 2e744d6..9213052 100644 --- a/gcc/tree-ssa-sink.cc +++ b/gcc/tree-ssa-sink.cc @@ -208,6 +208,12 @@ select_best_block (basic_block early_bb, temp_bb = get_immediate_dominator (CDI_DOMINATORS, temp_bb); } + /* Placing a statement before a setjmp-like function would be invalid + (it cannot be reevaluated when execution follows an abnormal edge). + If we selected a block with abnormal predecessors, just punt. */ + if (bb_has_abnormal_pred (best_bb)) + return early_bb; + /* If we found a shallower loop nest, then we always consider that a win. This will always give us the most control dependent block within that loop nest. */ diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index 609cacc..b279a82 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -5195,6 +5195,14 @@ bump_vector_ptr (vec_info *vinfo, if (TREE_CODE (dataref_ptr) == SSA_NAME) new_dataref_ptr = copy_ssa_name (dataref_ptr); + else if (is_gimple_min_invariant (dataref_ptr)) + /* When possible avoid emitting a separate increment stmt that will + force the addressed object addressable. */ + return build1 (ADDR_EXPR, TREE_TYPE (dataref_ptr), + fold_build2 (MEM_REF, + TREE_TYPE (TREE_TYPE (dataref_ptr)), + dataref_ptr, + fold_convert (ptr_type_node, update))); else new_dataref_ptr = make_ssa_name (TREE_TYPE (dataref_ptr)); incr_stmt = gimple_build_assign (new_dataref_ptr, POINTER_PLUS_EXPR, diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index eb1486f..8186d99 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,80 @@ +2022-07-20 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/100823 + * include/bits/stl_iterator.h (common_iterator): Define + destructor, copy constructor and move constructor as trivial + when the underlying types allow. + * testsuite/24_iterators/common_iterator/100823.cc: Check + triviality of special members. + +2022-07-20 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/100823 + * include/bits/stl_iterator.h (common_iterator): Define move + constructor and move assignment operator. + (common_iterator::_M_assign): New function implementing + assignment. + (common_iterator::operator=): Use _M_assign. + (common_iterator::_S_valueless): New constant. + * testsuite/24_iterators/common_iterator/100823.cc: New test. + +2022-07-20 Jonathan Wakely <jwakely@redhat.com> + + * include/bits/stl_iterator.h (common_iterator): Fix incorrect + uses of is_nothrow_assignable_v. Fix inconsistent constraints on + friend declaration. Do not move argument in copy constructor. + * testsuite/24_iterators/common_iterator/1.cc: Check for + noexcept constructibnle/assignable. + +2022-07-19 François Dumont <fdumont@gcc.gnu.org> + + * include/debug/debug.h [_GLIBCXX_DEBUG](__glibcxx_requires_string): Define + using _GLIBCXX_DEBUG_PEDASSERT. + [_GLIBCXX_DEBUG](__glibcxx_requires_string_len): Likewise. + * include/debug/macros.h + (__glibcxx_check_string, __glibcxx_check_string_len): Move... + * include/debug/string + (__glibcxx_check_string, __glibcxx_check_string_len): ...here. And define depending + on _GLIBCXX_DEBUG_PEDANTIC no matter if _GLIBCXX_DEBUG is defined. + Add using of std::string find, rfind, find_first_of, find_last_of, find_first_not_of + and find_last_not_of. Remove debug implementations having no debug assertion. + * testsuite/util/testsuite_string.h: New file. Provides __gnu_test::string and + __gnu_test::wtring which definition depends on _GLIBCXX_DEBUG. + * testsuite/21_strings/basic_string/debug/find1_neg.cc: New test case. + * testsuite/21_strings/basic_string/debug/find2_neg.cc: New test case. + * testsuite/21_strings/basic_string/operations/find/char/1.cc: + Include <testsuite_string.h> and use __gnu_test::string. + * testsuite/21_strings/basic_string/operations/find/char/2.cc: Likewise. + * testsuite/21_strings/basic_string/operations/find/char/3.cc: Likewise. + * testsuite/21_strings/basic_string/operations/find/char/4.cc: Likewise. + * testsuite/21_strings/basic_string/operations/find/char/5.cc: Likewise. + * testsuite/21_strings/basic_string/operations/find/char/6.cc: Likewise. + * testsuite/21_strings/basic_string/operations/find/wchar_t/1.cc: + Include <testsuite_string.h> and use __gnu_test::wstring. + * testsuite/21_strings/basic_string/operations/find/wchar_t/2.cc: Likewise. + * testsuite/21_strings/basic_string/operations/find/wchar_t/3.cc: Likewise. + * testsuite/21_strings/basic_string/operations/find/wchar_t/4.cc: Likewise. + * testsuite/21_strings/basic_string/operations/find/wchar_t/5.cc: Likewise. + * testsuite/21_strings/basic_string/operations/find/wchar_t/6.cc: Likewise. + +2022-07-19 Jonathan Wakely <jwakely@redhat.com> + + * include/std/type_traits (__cpp_lib_reference_from_temporary) + (reference_constructs_from_temporary) + (reference_converts_from_temporary): Only define when the + built-ins are available. + +2022-07-19 Marco Falke <falke.marco@gmail.com> + + * include/std/charconv (__from_chars_alnum_to_val): Replace + implicit conversion from int to unsigned char with explicit + cast. + +2022-07-19 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * configure: Regnerate. + * configure.ac (newlib, *-rtems*): Remove HAVE_POLL. + 2022-07-18 François Dumont <fdumont@gcc.gnu.org> * include/bits/stl_algo.h diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 049cb02..9cd262c 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -1838,7 +1838,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _S_noexcept1() { if constexpr (is_trivially_default_constructible_v<_Tp>) - return is_nothrow_assignable_v<_Tp, _Up>; + return is_nothrow_assignable_v<_Tp&, _Up>; else return is_nothrow_constructible_v<_Tp, _Up>; } @@ -1908,6 +1908,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(_S_noexcept<const _It2&, const _Sent2&>()) : _M_valueless(), _M_index(__x._M_index) { + __glibcxx_assert(__x._M_has_value()); if (_M_index == 0) { if constexpr (is_trivially_default_constructible_v<_It>) @@ -1924,35 +1925,85 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } + common_iterator(const common_iterator&) = default; + constexpr common_iterator(const common_iterator& __x) noexcept(_S_noexcept<const _It&, const _Sent&>()) + requires (!is_trivially_copyable_v<_It> || !is_trivially_copyable_v<_Sent>) : _M_valueless(), _M_index(__x._M_index) { if (_M_index == 0) { if constexpr (is_trivially_default_constructible_v<_It>) - _M_it = std::move(__x._M_it); + _M_it = __x._M_it; else std::construct_at(std::__addressof(_M_it), __x._M_it); } else if (_M_index == 1) { if constexpr (is_trivially_default_constructible_v<_Sent>) - _M_sent = std::move(__x._M_sent); + _M_sent = __x._M_sent; else std::construct_at(std::__addressof(_M_sent), __x._M_sent); } } + common_iterator(common_iterator&&) = default; + + constexpr + common_iterator(common_iterator&& __x) + noexcept(_S_noexcept<_It, _Sent>()) + requires (!is_trivially_copyable_v<_It> || !is_trivially_copyable_v<_Sent>) + : _M_valueless(), _M_index(__x._M_index) + { + if (_M_index == 0) + { + if constexpr (is_trivially_default_constructible_v<_It>) + _M_it = std::move(__x._M_it); + else + std::construct_at(std::__addressof(_M_it), std::move(__x._M_it)); + } + else if (_M_index == 1) + { + if constexpr (is_trivially_default_constructible_v<_Sent>) + _M_sent = std::move(__x._M_sent); + else + std::construct_at(std::__addressof(_M_sent), + std::move(__x._M_sent)); + } + } + + constexpr common_iterator& + operator=(const common_iterator&) = default; + constexpr common_iterator& operator=(const common_iterator& __x) noexcept(is_nothrow_copy_assignable_v<_It> && is_nothrow_copy_assignable_v<_Sent> && is_nothrow_copy_constructible_v<_It> && is_nothrow_copy_constructible_v<_Sent>) + requires (!is_trivially_copy_assignable_v<_It> + || !is_trivially_copy_assignable_v<_Sent>) + { + _M_assign(__x); + return *this; + } + + constexpr common_iterator& + operator=(common_iterator&&) = default; + + constexpr common_iterator& + operator=(common_iterator&& __x) + noexcept(is_nothrow_move_assignable_v<_It> + && is_nothrow_move_assignable_v<_Sent> + && is_nothrow_move_constructible_v<_It> + && is_nothrow_move_constructible_v<_Sent>) + requires (!is_trivially_move_assignable_v<_It> + || !is_trivially_move_assignable_v<_Sent>) { - return this->operator=<_It, _Sent>(__x); + _M_assign(std::move(__x)); + return *this; } template<typename _It2, typename _Sent2> @@ -1964,52 +2015,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator=(const common_iterator<_It2, _Sent2>& __x) noexcept(is_nothrow_constructible_v<_It, const _It2&> && is_nothrow_constructible_v<_Sent, const _Sent2&> - && is_nothrow_assignable_v<_It, const _It2&> - && is_nothrow_assignable_v<_Sent, const _Sent2&>) + && is_nothrow_assignable_v<_It&, const _It2&> + && is_nothrow_assignable_v<_Sent&, const _Sent2&>) { - switch(_M_index << 2 | __x._M_index) - { - case 0b0000: - _M_it = __x._M_it; - break; - case 0b0101: - _M_sent = __x._M_sent; - break; - case 0b0001: - _M_it.~_It(); - _M_index = -1; - [[fallthrough]]; - case 0b1001: - std::construct_at(std::__addressof(_M_sent), _Sent(__x._M_sent)); - _M_index = 1; - break; - case 0b0100: - _M_sent.~_Sent(); - _M_index = -1; - [[fallthrough]]; - case 0b1000: - std::construct_at(std::__addressof(_M_it), _It(__x._M_it)); - _M_index = 0; - break; - default: - __glibcxx_assert(__x._M_has_value()); - __builtin_unreachable(); - } + __glibcxx_assert(__x._M_has_value()); + _M_assign(__x); return *this; } +#if __cpp_concepts >= 202002L // Constrained special member functions + ~common_iterator() = default; + + constexpr + ~common_iterator() + requires (!is_trivially_destructible_v<_It> + || !is_trivially_destructible_v<_Sent>) +#else constexpr ~common_iterator() +#endif { - switch (_M_index) - { - case 0: - _M_it.~_It(); - break; - case 1: - _M_sent.~_Sent(); - break; - } + if (_M_index == 0) + _M_it.~_It(); + else if (_M_index == 1) + _M_sent.~_Sent(); } [[nodiscard]] @@ -2164,9 +2193,40 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: template<input_or_output_iterator _It2, sentinel_for<_It2> _Sent2> + requires (!same_as<_It2, _Sent2>) && copyable<_It2> friend class common_iterator; - constexpr bool _M_has_value() const noexcept { return _M_index < 2; } + constexpr bool + _M_has_value() const noexcept { return _M_index != _S_valueless; } + + template<typename _CIt> + constexpr void + _M_assign(_CIt&& __x) + { + if (_M_index == __x._M_index) + { + if (_M_index == 0) + _M_it = std::forward<_CIt>(__x)._M_it; + else if (_M_index == 1) + _M_sent = std::forward<_CIt>(__x)._M_sent; + } + else + { + if (_M_index == 0) + _M_it.~_It(); + else if (_M_index == 1) + _M_sent.~_Sent(); + _M_index = _S_valueless; + + if (__x._M_index == 0) + std::construct_at(std::__addressof(_M_it), + std::forward<_CIt>(__x)._M_it); + else if (__x._M_index == 1) + std::construct_at(std::__addressof(_M_sent), + std::forward<_CIt>(__x)._M_sent); + _M_index = __x._M_index; + } + } union { @@ -2174,7 +2234,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Sent _M_sent; unsigned char _M_valueless; }; - unsigned char _M_index; // 0==_M_it, 1==_M_sent, 2==valueless + unsigned char _M_index; // 0 == _M_it, 1 == _M_sent, 2 == valueless + + static constexpr unsigned char _S_valueless{2}; }; template<typename _It, typename _Sent> diff --git a/libstdc++-v3/include/debug/debug.h b/libstdc++-v3/include/debug/debug.h index d3cdfbc..28e250f 100644 --- a/libstdc++-v3/include/debug/debug.h +++ b/libstdc++-v3/include/debug/debug.h @@ -118,9 +118,10 @@ namespace __gnu_debug __glibcxx_check_heap(_First,_Last) # define __glibcxx_requires_heap_pred(_First,_Last,_Pred) \ __glibcxx_check_heap_pred(_First,_Last,_Pred) -# define __glibcxx_requires_string(_String) __glibcxx_check_string(_String) +# define __glibcxx_requires_string(_String) \ + _GLIBCXX_DEBUG_PEDASSERT(_String != 0) # define __glibcxx_requires_string_len(_String,_Len) \ - __glibcxx_check_string_len(_String,_Len) + _GLIBCXX_DEBUG_PEDASSERT(_String != 0 || _Len == 0) # define __glibcxx_requires_irreflexive(_First,_Last) \ __glibcxx_check_irreflexive(_First,_Last) # define __glibcxx_requires_irreflexive2(_First,_Last) \ diff --git a/libstdc++-v3/include/debug/macros.h b/libstdc++-v3/include/debug/macros.h index 7b86292..5fb6832 100644 --- a/libstdc++-v3/include/debug/macros.h +++ b/libstdc++-v3/include/debug/macros.h @@ -467,8 +467,4 @@ _GLIBCXX_DEBUG_VERIFY(_This.get_allocator() == _Other.get_allocator(), \ _M_message(__gnu_debug::__msg_equal_allocs) \ ._M_sequence(_This, "this")) -#define __glibcxx_check_string(_String) _GLIBCXX_DEBUG_PEDASSERT(_String != 0) -#define __glibcxx_check_string_len(_String,_Len) \ - _GLIBCXX_DEBUG_PEDASSERT(_String != 0 || _Len == 0) - #endif diff --git a/libstdc++-v3/include/debug/string b/libstdc++-v3/include/debug/string index 3ec55d4..a4482db 100644 --- a/libstdc++-v3/include/debug/string +++ b/libstdc++-v3/include/debug/string @@ -49,6 +49,20 @@ # define _GLIBCXX_INSERT_RETURNS_ITERATOR_ONLY(expr) #endif +#ifdef _GLIBCXX_DEBUG_PEDANTIC +# define __glibcxx_check_string(_String) \ + _GLIBCXX_DEBUG_VERIFY_STR_COND_AT(_String != 0, \ + __FILE__, __LINE__, \ + __PRETTY_FUNCTION__); +# define __glibcxx_check_string_len(_String,_Len) \ + _GLIBCXX_DEBUG_VERIFY_STR_COND_AT(_String != 0 || _Len == 0, \ + __FILE__, __LINE__, \ + __PRETTY_FUNCTION__); +#else +# define __glibcxx_check_string(_String) +# define __glibcxx_check_string_len(_String,_Len) +#endif + namespace __gnu_debug { /** Checks that __s is non-NULL or __n == 0, and then returns __s. */ @@ -868,34 +882,28 @@ namespace __gnu_debug using _Base::get_allocator; - size_type - find(const basic_string& __str, size_type __pos = 0) const - _GLIBCXX_NOEXCEPT - { return _Base::find(__str, __pos); } + using _Base::find; + _GLIBCXX20_CONSTEXPR size_type find(const _CharT* __s, size_type __pos, size_type __n) const + _GLIBCXX_NOEXCEPT { __glibcxx_check_string(__s); return _Base::find(__s, __pos, __n); } + _GLIBCXX20_CONSTEXPR size_type - find(const _CharT* __s, size_type __pos = 0) const + find(const _CharT* __s, size_type __pos = 0) const _GLIBCXX_NOEXCEPT { __glibcxx_check_string(__s); return _Base::find(__s, __pos); } - size_type - find(_CharT __c, size_type __pos = 0) const _GLIBCXX_NOEXCEPT - { return _Base::find(__c, __pos); } - - size_type - rfind(const basic_string& __str, size_type __pos = _Base::npos) const - _GLIBCXX_NOEXCEPT - { return _Base::rfind(__str, __pos); } + using _Base::rfind; + _GLIBCXX20_CONSTEXPR size_type rfind(const _CharT* __s, size_type __pos, size_type __n) const { @@ -903,6 +911,7 @@ namespace __gnu_debug return _Base::rfind(__s, __pos, __n); } + _GLIBCXX20_CONSTEXPR size_type rfind(const _CharT* __s, size_type __pos = _Base::npos) const { @@ -910,105 +919,85 @@ namespace __gnu_debug return _Base::rfind(__s, __pos); } - size_type - rfind(_CharT __c, size_type __pos = _Base::npos) const _GLIBCXX_NOEXCEPT - { return _Base::rfind(__c, __pos); } - - size_type - find_first_of(const basic_string& __str, size_type __pos = 0) const - _GLIBCXX_NOEXCEPT - { return _Base::find_first_of(__str, __pos); } + using _Base::find_first_of; + _GLIBCXX20_CONSTEXPR size_type find_first_of(const _CharT* __s, size_type __pos, size_type __n) const + _GLIBCXX_NOEXCEPT { __glibcxx_check_string(__s); return _Base::find_first_of(__s, __pos, __n); } + _GLIBCXX20_CONSTEXPR size_type - find_first_of(const _CharT* __s, size_type __pos = 0) const + find_first_of(const _CharT* __s, size_type __pos = 0) const _GLIBCXX_NOEXCEPT { __glibcxx_check_string(__s); return _Base::find_first_of(__s, __pos); } - size_type - find_first_of(_CharT __c, size_type __pos = 0) const _GLIBCXX_NOEXCEPT - { return _Base::find_first_of(__c, __pos); } - - size_type - find_last_of(const basic_string& __str, - size_type __pos = _Base::npos) const _GLIBCXX_NOEXCEPT - { return _Base::find_last_of(__str, __pos); } + using _Base::find_last_of; + _GLIBCXX20_CONSTEXPR size_type find_last_of(const _CharT* __s, size_type __pos, size_type __n) const + _GLIBCXX_NOEXCEPT { __glibcxx_check_string(__s); return _Base::find_last_of(__s, __pos, __n); } + _GLIBCXX20_CONSTEXPR size_type find_last_of(const _CharT* __s, size_type __pos = _Base::npos) const + _GLIBCXX_NOEXCEPT { __glibcxx_check_string(__s); return _Base::find_last_of(__s, __pos); } - size_type - find_last_of(_CharT __c, size_type __pos = _Base::npos) const - _GLIBCXX_NOEXCEPT - { return _Base::find_last_of(__c, __pos); } - - size_type - find_first_not_of(const basic_string& __str, size_type __pos = 0) const - _GLIBCXX_NOEXCEPT - { return _Base::find_first_not_of(__str, __pos); } + using _Base::find_first_not_of; + _GLIBCXX20_CONSTEXPR size_type find_first_not_of(const _CharT* __s, size_type __pos, size_type __n) const + _GLIBCXX_NOEXCEPT { __glibcxx_check_string_len(__s, __n); return _Base::find_first_not_of(__s, __pos, __n); } + _GLIBCXX20_CONSTEXPR size_type find_first_not_of(const _CharT* __s, size_type __pos = 0) const + _GLIBCXX_NOEXCEPT { __glibcxx_check_string(__s); return _Base::find_first_not_of(__s, __pos); } - size_type - find_first_not_of(_CharT __c, size_type __pos = 0) const _GLIBCXX_NOEXCEPT - { return _Base::find_first_not_of(__c, __pos); } - - size_type - find_last_not_of(const basic_string& __str, - size_type __pos = _Base::npos) const - _GLIBCXX_NOEXCEPT - { return _Base::find_last_not_of(__str, __pos); } + using _Base::find_last_not_of; + _GLIBCXX20_CONSTEXPR size_type find_last_not_of(const _CharT* __s, size_type __pos, size_type __n) const + _GLIBCXX_NOEXCEPT { __glibcxx_check_string(__s); return _Base::find_last_not_of(__s, __pos, __n); } + _GLIBCXX20_CONSTEXPR size_type find_last_not_of(const _CharT* __s, size_type __pos = _Base::npos) const + _GLIBCXX_NOEXCEPT { __glibcxx_check_string(__s); return _Base::find_last_not_of(__s, __pos); } - size_type - find_last_not_of(_CharT __c, size_type __pos = _Base::npos) const - _GLIBCXX_NOEXCEPT - { return _Base::find_last_not_of(__c, __pos); } - basic_string substr(size_type __pos = 0, size_type __n = _Base::npos) const { return basic_string(_Base::substr(__pos, __n)); } diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv index 218813e..533320e 100644 --- a/libstdc++-v3/include/std/charconv +++ b/libstdc++-v3/include/std/charconv @@ -436,7 +436,7 @@ namespace __detail __from_chars_alnum_to_val(unsigned char __c) { if _GLIBCXX17_CONSTEXPR (_DecOnly) - return __c - '0'; + return static_cast<unsigned char>(__c - '0'); else { // This initializer is deliberately made dependent in order to work diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index b1a1dee..14b029c 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -3505,6 +3505,9 @@ template<typename _Ret, typename _Fn, typename... _Args> template<typename _Tp> inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value; +#if __has_builtin(__reference_constructs_from_temporary) \ + && __has_builtin(__reference_converts_from_temporary) + #define __cpp_lib_reference_from_temporary 202202L /// True if _Tp is a reference type, a _Up value can be bound to _Tp in @@ -3544,6 +3547,7 @@ template<typename _Ret, typename _Fn, typename... _Args> template<typename _Tp, typename _Up> inline constexpr bool reference_converts_from_temporary_v = reference_converts_from_temporary<_Tp, _Up>::value; +#endif // __has_builtin for reference_from_temporary #endif // C++23 #if _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/debug/find1_neg.cc b/libstdc++-v3/testsuite/21_strings/basic_string/debug/find1_neg.cc new file mode 100644 index 0000000..02babbc --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/debug/find1_neg.cc @@ -0,0 +1,35 @@ +// Copyright (C) 2022 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. +// +// { dg-do run { xfail *-*-* } } + +#define _GLIBCXX_DEBUG_PEDANTIC + +#include <debug/string> + +void test01() +{ + const char* __null_str = 0; + __gnu_debug::string str; + str.find(__null_str); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/debug/find2_neg.cc b/libstdc++-v3/testsuite/21_strings/basic_string/debug/find2_neg.cc new file mode 100644 index 0000000..89250e2 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/debug/find2_neg.cc @@ -0,0 +1,35 @@ +// Copyright (C) 2022 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. +// +// { dg-do run { xfail *-*-* } } + +#define _GLIBCXX_DEBUG_PEDANTIC + +#include <debug/string> + +void test01() +{ + const char* __null_str = 0; + __gnu_debug::string str; + str.find(__null_str, 0, 0); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/1.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/1.cc index e76473d..862cfef 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/1.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/1.cc @@ -19,22 +19,22 @@ // 21.3.6.1 basic_string find -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> void test01(void) { - typedef std::string::size_type csize_type; - typedef std::string::const_reference cref; - typedef std::string::reference ref; - csize_type npos = std::string::npos; + typedef __gnu_test::string::size_type csize_type; + typedef __gnu_test::string::const_reference cref; + typedef __gnu_test::string::reference ref; + csize_type npos = __gnu_test::string::npos; csize_type csz01, csz02; const char str_lit01[] = "mave"; - const std::string str01("mavericks, santa cruz"); - std::string str02(str_lit01); - std::string str03("s, s"); - std::string str04; + const __gnu_test::string str01("mavericks, santa cruz"); + __gnu_test::string str02(str_lit01); + __gnu_test::string str03("s, s"); + __gnu_test::string str04; // size_type find(const string&, size_type pos = 0) const; csz01 = str01.find(str01); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/2.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/2.cc index baeab8b..756ad85 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/2.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/2.cc @@ -19,23 +19,23 @@ // 21.3.6.3 basic_string find_first_of -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> void test02(void) { - typedef std::string::size_type csize_type; - csize_type npos = std::string::npos; + typedef __gnu_test::string::size_type csize_type; + csize_type npos = __gnu_test::string::npos; csize_type csz01, csz02; const char str_lit01[] = "mave"; - const std::string str01("mavericks, santa cruz"); - std::string str02(str_lit01); - std::string str03("s, s"); - std::string str04; + const __gnu_test::string str01("mavericks, santa cruz"); + __gnu_test::string str02(str_lit01); + __gnu_test::string str03("s, s"); + __gnu_test::string str04; // size_type find_first_of(const string&, size_type pos = 0) const; - std::string str05("xena rulez"); + __gnu_test::string str05("xena rulez"); csz01 = str01.find_first_of(str01); VERIFY( csz01 == 0 ); csz01 = str01.find_first_of(str01, 4); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/3.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/3.cc index 7c21080..8386ae8 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/3.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/3.cc @@ -19,20 +19,20 @@ // 21.3.6.5 basic_string find_first_not_of -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> void test03(void) { - typedef std::string::size_type csize_type; - csize_type npos = std::string::npos; + typedef __gnu_test::string::size_type csize_type; + csize_type npos = __gnu_test::string::npos; csize_type csz01; - const std::string str01("Bob Rock, per me"); + const __gnu_test::string str01("Bob Rock, per me"); const char str_lit01[] = "Bob Rock"; - std::string str02("ovvero Trivi"); - std::string str03(str_lit01); - std::string str04; + __gnu_test::string str02("ovvero Trivi"); + __gnu_test::string str03(str_lit01); + __gnu_test::string str04; // size_type find_first_not_of(const string&, size_type pos = 0) const; csz01 = str01.find_first_not_of(str01); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/4.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/4.cc index cf8c0c9..72965d0 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/4.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/4.cc @@ -19,16 +19,16 @@ // 21.3.6.1 basic_string find -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> // libstdc++/31401 void test01() { - typedef std::string::size_type csize_type; - csize_type npos = std::string::npos; + typedef __gnu_test::string::size_type csize_type; + csize_type npos = __gnu_test::string::npos; - std::string use = "anu"; + __gnu_test::string use = "anu"; csize_type pos1 = use.find("a", npos); VERIFY( pos1 == npos ); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/5.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/5.cc index 7464a3c..a366975 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/5.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/5.cc @@ -24,14 +24,14 @@ // [string::find.first.not.of] // [string::find.last.not.of] -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> void test03() { std::string_view str1("bar"); - std::string str2("foobar"); + __gnu_test::string str2("foobar"); auto x = str2.find(str1); VERIFY (x == 3); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/6.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/6.cc index b901e7d..51d7b25 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/6.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/6.cc @@ -19,13 +19,13 @@ // C++11 21.4.7.2 [string::find] basic_string find -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> // https://gcc.gnu.org/ml/libstdc++/2017-01/msg00021.html void test01() { - typedef std::string string_type; + typedef __gnu_test::string string_type; string_type::size_type npos = string_type::npos; string_type use = "aaa"; diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/1.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/1.cc index f1f5548..bb65c0c 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/1.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/1.cc @@ -19,22 +19,22 @@ // 21.3.6.1 basic_string find -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> void test01(void) { - typedef std::wstring::size_type csize_type; - typedef std::wstring::const_reference cref; - typedef std::wstring::reference ref; - csize_type npos = std::wstring::npos; + typedef __gnu_test::wstring::size_type csize_type; + typedef __gnu_test::wstring::const_reference cref; + typedef __gnu_test::wstring::reference ref; + csize_type npos = __gnu_test::wstring::npos; csize_type csz01, csz02; const wchar_t str_lit01[] = L"mave"; - const std::wstring str01(L"mavericks, santa cruz"); - std::wstring str02(str_lit01); - std::wstring str03(L"s, s"); - std::wstring str04; + const __gnu_test::wstring str01(L"mavericks, santa cruz"); + __gnu_test::wstring str02(str_lit01); + __gnu_test::wstring str03(L"s, s"); + __gnu_test::wstring str04; // size_type find(const wstring&, size_type pos = 0) const; csz01 = str01.find(str01); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/2.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/2.cc index e7ab9e8..0bd1533 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/2.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/2.cc @@ -19,23 +19,23 @@ // 21.3.6.3 basic_string find_first_of -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> void test02(void) { - typedef std::wstring::size_type csize_type; - csize_type npos = std::wstring::npos; + typedef __gnu_test::wstring::size_type csize_type; + csize_type npos = __gnu_test::wstring::npos; csize_type csz01, csz02; const wchar_t str_lit01[] = L"mave"; - const std::wstring str01(L"mavericks, santa cruz"); - std::wstring str02(str_lit01); - std::wstring str03(L"s, s"); - std::wstring str04; + const __gnu_test::wstring str01(L"mavericks, santa cruz"); + __gnu_test::wstring str02(str_lit01); + __gnu_test::wstring str03(L"s, s"); + __gnu_test::wstring str04; // size_type find_first_of(const wstring&, size_type pos = 0) const; - std::wstring str05(L"xena rulez"); + __gnu_test::wstring str05(L"xena rulez"); csz01 = str01.find_first_of(str01); VERIFY( csz01 == 0 ); csz01 = str01.find_first_of(str01, 4); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/3.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/3.cc index 9daf26b..8c595fd 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/3.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/3.cc @@ -19,20 +19,20 @@ // 21.3.6.5 basic_string find_first_not_of -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> void test03(void) { - typedef std::wstring::size_type csize_type; - csize_type npos = std::wstring::npos; + typedef __gnu_test::wstring::size_type csize_type; + csize_type npos = __gnu_test::wstring::npos; csize_type csz01; - const std::wstring str01(L"Bob Rock, per me"); + const __gnu_test::wstring str01(L"Bob Rock, per me"); const wchar_t str_lit01[] = L"Bob Rock"; - std::wstring str02(L"ovvero Trivi"); - std::wstring str03(str_lit01); - std::wstring str04; + __gnu_test::wstring str02(L"ovvero Trivi"); + __gnu_test::wstring str03(str_lit01); + __gnu_test::wstring str04; // size_type find_first_not_of(const string&, size_type pos = 0) const; csz01 = str01.find_first_not_of(str01); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/4.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/4.cc index f9b9605..98c3a18 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/4.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/4.cc @@ -19,16 +19,16 @@ // 21.3.6.1 basic_string find -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> // libstdc++/31401 void test01() { - typedef std::wstring::size_type csize_type; - csize_type npos = std::wstring::npos; + typedef __gnu_test::wstring::size_type csize_type; + csize_type npos = __gnu_test::wstring::npos; - std::wstring use = L"anu"; + __gnu_test::wstring use = L"anu"; csize_type pos1 = use.find(L"a", npos); VERIFY( pos1 == npos ); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/5.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/5.cc index d04e613..76126a7 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/5.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/5.cc @@ -24,14 +24,14 @@ // [string::find.first.not.of] // [string::find.last.not.of] -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> void test03() { std::wstring_view str1(L"bar"); - std::wstring str2(L"foobar"); + __gnu_test::wstring str2(L"foobar"); auto x = str2.find(str1); VERIFY (x == 3); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/6.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/6.cc index 24a8c81..58c4db0 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/6.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/6.cc @@ -19,13 +19,13 @@ // C++11 21.4.7.2 [string::find] basic_string find -#include <string> +#include <testsuite_string.h> #include <testsuite_hooks.h> // https://gcc.gnu.org/ml/libstdc++/2017-01/msg00021.html void test01() { - typedef std::wstring string_type; + typedef __gnu_test::wstring string_type; string_type::size_type npos = string_type::npos; string_type use = L"aaa"; diff --git a/libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc b/libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc index 365ee89..ec4a86c 100644 --- a/libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc +++ b/libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc @@ -27,15 +27,30 @@ test01() using I = std::common_iterator<int*, const int*>; static_assert( std::is_default_constructible_v<I> ); static_assert( std::is_copy_constructible_v<I> ); + static_assert( std::is_move_constructible_v<I> ); static_assert( std::is_copy_assignable_v<I> ); + static_assert( std::is_move_assignable_v<I> ); static_assert( std::is_constructible_v<I, int*> ); static_assert( std::is_constructible_v<I, const int*> ); - struct sentinel { operator int*() const { return nullptr; } }; + static_assert( std::is_nothrow_copy_constructible_v<I> ); // GCC extension + static_assert( std::is_nothrow_move_constructible_v<I> ); // GCC extension + static_assert( std::is_nothrow_copy_assignable_v<I> ); // GCC extension + static_assert( std::is_nothrow_move_assignable_v<I> ); // GCC extension + + struct sentinel { operator int*() const noexcept { return nullptr; } }; using K = std::common_iterator<int*, sentinel>; static_assert( std::is_constructible_v<I, const K&> ); static_assert( std::is_assignable_v<I, const K&> ); + static_assert( std::is_nothrow_assignable_v<I&, const K&> ); // GCC extension + + struct sentinel_throwing { operator int*() const { return nullptr; } }; + using K_throwing = std::common_iterator<int*, sentinel_throwing>; + // Conversion is noexcept(false) + static_assert( ! std::is_nothrow_assignable_v<I&, const K_throwing&> ); + + struct sentinel2 { const int* p; @@ -46,6 +61,12 @@ test01() using J = std::common_iterator<const int*, sentinel2>; static_assert( std::is_constructible_v<J, const I&> ); static_assert( std::is_convertible_v<const I&, J> ); + + static_assert( std::is_constructible_v<J, I> ); + static_assert( std::is_convertible_v<I, J> ); + + // Constructor is noexcept(false) + static_assert( ! std::is_nothrow_constructible_v<J, I> ); } void diff --git a/libstdc++-v3/testsuite/24_iterators/common_iterator/100823.cc b/libstdc++-v3/testsuite/24_iterators/common_iterator/100823.cc new file mode 100644 index 0000000..b42dd08 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/common_iterator/100823.cc @@ -0,0 +1,58 @@ +// { dg-options "-std=gnu++20 -D_GLIBCXX_ASSERTIONS" } +// { dg-do run { target c++20 } } +#include <iterator> +#include <testsuite_iterators.h> +#include <testsuite_hooks.h> + +void +test_triviality() +{ + using I = std::common_iterator<int*, const int*>; + + // Cannot be trivial, because it has to initialize members. + static_assert( ! std::is_trivially_default_constructible_v<I> ); + + static_assert( std::is_trivially_destructible_v<I> ); + static_assert( std::is_trivially_copy_constructible_v<I> ); + static_assert( std::is_trivially_copy_assignable_v<I> ); + static_assert( std::is_trivially_move_constructible_v<I> ); + static_assert( std::is_trivially_move_assignable_v<I> ); +} + +void +test_valueless_assignment() +{ + int x[1] { }; + __gnu_test::test_forward_range<int> r(x); + using Iter = decltype(r.begin()); + using Sent = decltype(r.end()); + + std::common_iterator<Iter, Sent> i; + const std::common_iterator<Iter, Sent> j(r.begin()); + try + { + struct Bomb + { + bool operator==(Iter) const { return true; } + operator Sent() const { throw 1; } + }; + std::common_iterator<Iter, Bomb> b{Bomb{}}; + i = b; // Throws, leaving i valueless-by-exception. + VERIFY(false); + } + catch (int) + { + std::common_iterator<Iter, Sent> k(i); + + // PR libstdc++/100823 + k = i; // Valid even though both operands are valueless. + + i = j; // No longer valueless. + } + VERIFY( i == j ); +} + +int main() +{ + test_valueless_assignment(); +} diff --git a/libstdc++-v3/testsuite/util/testsuite_string.h b/libstdc++-v3/testsuite/util/testsuite_string.h new file mode 100644 index 0000000..7121ff8 --- /dev/null +++ b/libstdc++-v3/testsuite/util/testsuite_string.h @@ -0,0 +1,20 @@ +#ifndef _GLIBCXX_TESTSUITE_STRING_H +#define _GLIBCXX_TESTSUITE_STRING_H + +#ifdef _GLIBCXX_DEBUG +# include <debug/string> +namespace __gnu_test +{ + using __gnu_debug::string; + using __gnu_debug::wstring; +} +#else +# include <string> +namespace __gnu_test +{ + using std::string; + using std::wstring; +} +#endif + +#endif |