aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-07-21 16:12:11 +0200
committerMartin Liska <mliska@suse.cz>2022-07-21 16:12:11 +0200
commitbb743388df90352e5690848fc39bb9c10457b0e0 (patch)
tree0ce9895dcbfcdd3ca63f6970f67dddc10e3ae51a
parente9c8572e74d8de56551ed62f799df7742cd523e9 (diff)
parent24eae97625e9423e7344f6d7eb6bc2435a62fffd (diff)
downloadgcc-bb743388df90352e5690848fc39bb9c10457b0e0.zip
gcc-bb743388df90352e5690848fc39bb9c10457b0e0.tar.gz
gcc-bb743388df90352e5690848fc39bb9c10457b0e0.tar.bz2
Merge branch 'master' into devel/sphinx
-rw-r--r--.gitignore3
-rw-r--r--ChangeLog4
-rw-r--r--MAINTAINERS2
-rw-r--r--gcc/ChangeLog106
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/analyzer/ChangeLog37
-rw-r--r--gcc/analyzer/constraint-manager.h3
-rw-r--r--gcc/analyzer/engine.cc34
-rw-r--r--gcc/analyzer/exploded-graph.h3
-rw-r--r--gcc/analyzer/region-model.cc2
-rw-r--r--gcc/analyzer/region-model.h17
-rw-r--r--gcc/analyzer/region.cc5
-rw-r--r--gcc/analyzer/region.h4
-rw-r--r--gcc/analyzer/sm-taint.cc323
-rw-r--r--gcc/analyzer/sm.h9
-rw-r--r--gcc/analyzer/store.cc7
-rw-r--r--gcc/analyzer/store.h4
-rw-r--r--gcc/builtins.cc15
-rw-r--r--gcc/cfghooks.cc13
-rw-r--r--gcc/cp/ChangeLog23
-rw-r--r--gcc/cp/call.cc92
-rw-r--r--gcc/cp/cp-objcp-common.cc2
-rw-r--r--gcc/cp/cp-tree.h5
-rw-r--r--gcc/fortran/ChangeLog15
-rw-r--r--gcc/fortran/intrinsic.texi6
-rw-r--r--gcc/fortran/openmp.cc1
-rw-r--r--gcc/fortran/resolve.cc13
-rw-r--r--gcc/gimple-range-cache.cc98
-rw-r--r--gcc/gimple-range-cache.h1
-rw-r--r--gcc/match.pd6
-rw-r--r--gcc/passes.def3
-rw-r--r--gcc/rtl.h1
-rw-r--r--gcc/rtlanal.cc30
-rw-r--r--gcc/testsuite/ChangeLog81
-rw-r--r--gcc/testsuite/g++.dg/conversion/ref8.C22
-rw-r--r--gcc/testsuite/g++.dg/conversion/ref9.C21
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c85
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-3.c52
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/untracked-2.c7
-rw-r--r--gcc/testsuite/gcc.dg/pow-sqrt-synth-1.c4
-rw-r--r--gcc/testsuite/gcc.dg/pr106379-1.c9
-rw-r--r--gcc/testsuite/gcc.dg/setjmp-7.c13
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-1a.c58
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-1b.c63
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-1c.c41
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-2a.c82
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-2b.c62
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-2c.c47
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-3a.c80
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-3b.c126
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-3c.c69
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-4a.c101
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-4b.c67
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-4c.c54
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-5a.c117
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-5b.c80
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-5c.c62
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-6a.c115
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-6b.c157
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-6c.c80
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-7a.c58
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-7b.c63
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-7c.c41
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-8a.c58
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-8b.c53
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-8c.c38
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-9a.c89
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-9b.c90
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-9c.c90
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106010-9d.c92
-rw-r--r--gcc/testsuite/gcc.target/i386/vec-maskstore-vn.c30
-rw-r--r--gcc/testsuite/gfortran.dg/associate_54.f903
-rw-r--r--gcc/testsuite/gfortran.dg/associate_59.f909
-rw-r--r--gcc/testsuite/gfortran.dg/gomp/affinity-clause-7.f9019
-rw-r--r--gcc/timevar.def1
-rw-r--r--gcc/tree-cfg.cc40
-rw-r--r--gcc/tree-complex.cc9
-rw-r--r--gcc/tree-pass.h1
-rw-r--r--gcc/tree-ssa-alias.cc49
-rw-r--r--gcc/tree-ssa-dse.cc55
-rw-r--r--gcc/tree-ssa-forwprop.cc2
-rw-r--r--gcc/tree-ssa-math-opts.cc112
-rw-r--r--gcc/tree-ssa-sccvn.cc255
-rw-r--r--gcc/tree-ssa-sink.cc6
-rw-r--r--gcc/tree-vect-data-refs.cc8
-rw-r--r--libstdc++-v3/ChangeLog77
-rw-r--r--libstdc++-v3/include/bits/stl_iterator.h152
-rw-r--r--libstdc++-v3/include/debug/debug.h5
-rw-r--r--libstdc++-v3/include/debug/macros.h4
-rw-r--r--libstdc++-v3/include/debug/string95
-rw-r--r--libstdc++-v3/include/std/charconv2
-rw-r--r--libstdc++-v3/include/std/type_traits4
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/debug/find1_neg.cc35
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/debug/find2_neg.cc35
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/1.cc18
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/2.cc16
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/3.cc14
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/4.cc8
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/5.cc4
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/char/6.cc4
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/1.cc18
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/2.cc16
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/3.cc14
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/4.cc8
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/5.cc4
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/operations/find/wchar_t/6.cc4
-rw-r--r--libstdc++-v3/testsuite/24_iterators/common_iterator/1.cc23
-rw-r--r--libstdc++-v3/testsuite/24_iterators/common_iterator/100823.cc58
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_string.h20
109 files changed, 4085 insertions, 468 deletions
diff --git a/.gitignore b/.gitignore
index 021a8c7..5cc4a0f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/ChangeLog b/ChangeLog
index 171f490..4842de2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 488016b..645c009 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -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