From 11c4a06a6c1a9db0bfdb3ee8509392dd7163709c Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Sat, 13 Nov 2021 04:16:55 +0000 Subject: tree-optimization: [PR103218] Fold ((type)(a<0)) << SIGNBITOFA into ((type)a) & signbit This folds Fold ((type)(a<0)) << SIGNBITOFA into ((type)a) & signbit inside match.pd. This was already handled in fold-cost by: /* A < 0 ? : 0 is simply (A & ). */ I have not removed as we only simplify "a ? POW2 : 0" at the gimple level to "a << CST1" and fold actually does the reverse of folding "(a<0)<> C) into -(x > 0) where C = precision(type) - 1. */ (for cst (INTEGER_CST VECTOR_CST) (simplify diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr103218-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr103218-1.c new file mode 100644 index 0000000..f086f07 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr103218-1.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* PR tree-optimization/103218 */ + +/* These first two are removed during forwprop1 */ +signed char f(signed char a) +{ + signed char t = a < 0; + int tt = (unsigned char)(t << 7); + return tt; +} +signed char f0(signed char a) +{ + unsigned char t = a < 0; + int tt = (unsigned char)(t << 7); + return tt; +} + +/* This one is removed during phiopt. */ +signed char f1(signed char a) +{ + if (a < 0) + return 1u<<7; + return 0; +} + +/* These three examples should remove "a < 0" by optimized. */ +/* { dg-final { scan-tree-dump-times "< 0" 0 "optimized"} } */ -- cgit v1.1 From 132f1c27770fa6dafdf14591878d301aedd5ae16 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 29 Oct 2021 16:39:01 -0400 Subject: c++: improve print_node of PTRMEM_CST It's been inconvenient that pretty-printing of PTRMEM_CST didn't display what member the constant refers to. Adding that is complicated by the absence of a langhook for CONSTANT_CLASS_P nodes; the simplest fix for that is to use the tcc_exceptional hook for tcc_constant as well. gcc/cp/ChangeLog: * ptree.c (cxx_print_xnode): Handle PTRMEM_CST. gcc/ChangeLog: * langhooks.h (struct lang_hooks): Adjust comment. * print-tree.c (print_node): Also call print_xnode hook for tcc_constant class. --- gcc/cp/ptree.c | 3 +++ gcc/langhooks.h | 2 +- gcc/print-tree.c | 3 +-- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c index ca7884d..d514aa2 100644 --- a/gcc/cp/ptree.c +++ b/gcc/cp/ptree.c @@ -379,6 +379,9 @@ cxx_print_xnode (FILE *file, tree node, int indent) if (tree message = STATIC_ASSERT_MESSAGE (node)) print_node (file, "message", message, indent+4); break; + case PTRMEM_CST: + print_node (file, "member", PTRMEM_CST_MEMBER (node), indent+4); + break; default: break; } diff --git a/gcc/langhooks.h b/gcc/langhooks.h index 3e89134..3db8f2a 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -477,7 +477,7 @@ struct lang_hooks void (*print_statistics) (void); /* Called by print_tree when there is a tree of class tcc_exceptional - that it doesn't know how to display. */ + or tcc_constant that it doesn't know how to display. */ lang_print_tree_hook print_xnode; /* Called to print language-dependent parts of tcc_decl, tcc_type, diff --git a/gcc/print-tree.c b/gcc/print-tree.c index d1fbd04..b5dc523 100644 --- a/gcc/print-tree.c +++ b/gcc/print-tree.c @@ -1004,8 +1004,7 @@ print_node (FILE *file, const char *prefix, tree node, int indent, break; default: - if (EXCEPTIONAL_CLASS_P (node)) - lang_hooks.print_xnode (file, node, indent); + lang_hooks.print_xnode (file, node, indent); break; } -- cgit v1.1 From e1c0c908f85816240b685a5be4f0e5a0e6634979 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Mon, 15 Nov 2021 16:12:37 -0500 Subject: analyzer: fix overeager sharing of bounded_range instances [PR102662] This was leading to an assertion failure ICE on a switch stmt when using -fstrict-enums, due to erroneously reusing a range involving one enum with a range involving a different enum. gcc/analyzer/ChangeLog: PR analyzer/102662 * constraint-manager.cc (bounded_range::operator==): Require the types to be the same for equality. gcc/testsuite/ChangeLog: PR analyzer/102662 * g++.dg/analyzer/pr102662.C: New test. Signed-off-by: David Malcolm --- gcc/analyzer/constraint-manager.cc | 4 +++- gcc/testsuite/g++.dg/analyzer/pr102662.C | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/analyzer/pr102662.C (limited to 'gcc') diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc index 6df23fb..ea6b5dc 100644 --- a/gcc/analyzer/constraint-manager.cc +++ b/gcc/analyzer/constraint-manager.cc @@ -432,7 +432,9 @@ bounded_range::intersects_p (const bounded_range &other, bool bounded_range::operator== (const bounded_range &other) const { - return (tree_int_cst_equal (m_lower, other.m_lower) + return (TREE_TYPE (m_lower) == TREE_TYPE (other.m_lower) + && TREE_TYPE (m_upper) == TREE_TYPE (other.m_upper) + && tree_int_cst_equal (m_lower, other.m_lower) && tree_int_cst_equal (m_upper, other.m_upper)); } diff --git a/gcc/testsuite/g++.dg/analyzer/pr102662.C b/gcc/testsuite/g++.dg/analyzer/pr102662.C new file mode 100644 index 0000000..99252c7 --- /dev/null +++ b/gcc/testsuite/g++.dg/analyzer/pr102662.C @@ -0,0 +1,39 @@ +/* { dg-additional-options "-fstrict-enums" } */ + +enum OpCode { + OP_MOVE, + OP_LOADK, + OP_LOADBOOL, + OP_LOADNIL, + OP_GETUPVAL, + OP_SETUPVAL +}; + +enum OpArg { + OpArgN, + OpArgU, + OpArgR, + OpArgK +}; + +void +symbexec_lastpc (enum OpCode symbexec_lastpc_op, enum OpArg luaP_opmodes) +{ + switch (luaP_opmodes) + { + case OpArgN: + case OpArgK: + { + switch (symbexec_lastpc_op) + { + case OP_LOADNIL: + case OP_SETUPVAL: + break; + default: + break; + } + } + default: + break; + } +} -- cgit v1.1 From 9836e907c4f20ab7638a5125e63634afafc772e7 Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Tue, 16 Nov 2021 15:38:28 +0000 Subject: signbit-2: make test check for scalar or vector versions This updates the signbit-2 test to check for the scalar optimization if the target does not support vectorization. gcc/testsuite/ChangeLog: * gcc.dg/signbit-2.c: CHeck vect or scalar. --- gcc/testsuite/gcc.dg/signbit-2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/signbit-2.c b/gcc/testsuite/gcc.dg/signbit-2.c index d8501e9..b609f67 100644 --- a/gcc/testsuite/gcc.dg/signbit-2.c +++ b/gcc/testsuite/gcc.dg/signbit-2.c @@ -19,5 +19,6 @@ void fun2(int32_t *x, int n) x[i] = (-x[i]) >> 30; } -/* { dg-final { scan-tree-dump {\s+>\s+\{ 0, 0, 0(, 0)+ \}} optimized } } */ +/* { dg-final { scan-tree-dump {\s+>\s+\{ 0(, 0)+ \}} optimized { target vect_int } } } */ +/* { dg-final { scan-tree-dump {\s+>\s+0} optimized { target { ! vect_int } } } } */ /* { dg-final { scan-tree-dump-not {\s+>>\s+31} optimized } } */ -- cgit v1.1 From 0002a8a1997c7beb3c4facc17ed0d1294e3dce14 Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Tue, 16 Nov 2021 15:39:28 +0000 Subject: shrn-combine-10: update test to current codegen. When the rshrn commit was reverted I missed this testcase. This now updates it. gcc/testsuite/ChangeLog: * gcc.target/aarch64/shrn-combine-10.c: Use shrn. --- gcc/testsuite/gcc.target/aarch64/shrn-combine-10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/aarch64/shrn-combine-10.c b/gcc/testsuite/gcc.target/aarch64/shrn-combine-10.c index 3a1cfce..dc9e9be 100644 --- a/gcc/testsuite/gcc.target/aarch64/shrn-combine-10.c +++ b/gcc/testsuite/gcc.target/aarch64/shrn-combine-10.c @@ -6,7 +6,7 @@ uint32x4_t foo (uint64x2_t a, uint64x2_t b) { - return vrshrn_high_n_u64 (vrshrn_n_u64 (a, 32), b, 32); + return vshrn_high_n_u64 (vshrn_n_u64 (a, 32), b, 32); } /* { dg-final { scan-assembler-times {\tuzp2\t} 1 } } */ -- cgit v1.1 From ba6e17e78db543b336c196b55fa6430e513f1941 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Tue, 16 Nov 2021 09:18:25 -0700 Subject: Avoid assuming maximum string length is constant [PR102960]. Resolves: PR tree-optimization/102960 - ICE: in sign_mask, at wide-int.h:855 in GCC 10.3.0 gcc/ChangeLog: PR tree-optimization/102960 * gimple-fold.c (get_range_strlen): Take bitmap as an argument rather than a pointer to it. (get_range_strlen_tree): Same. Remove bitmap allocation. Use an auto_bitmap. (get_maxval_strlen): Use an auto_bitmap. * tree-ssa-strlen.c (get_range_strlen_dynamic): Factor out PHI handling... (get_range_strlen_phi): ...into this function. Avoid assuming maximum string length is constant (printf_strlen_execute): Dump pointer query cache contents when details are requisted. gcc/testsuite/ChangeLog: PR tree-optimization/102960 * gcc.dg/Wstringop-overflow-84.c: New test. --- gcc/gimple-fold.c | 24 ++--- gcc/testsuite/gcc.dg/Wstringop-overflow-84.c | 15 +++ gcc/tree-ssa-strlen.c | 152 ++++++++++++++------------- 3 files changed, 102 insertions(+), 89 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Wstringop-overflow-84.c (limited to 'gcc') diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 765726c..ad9703e 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -86,7 +86,7 @@ enum strlen_range_kind { }; static bool -get_range_strlen (tree, bitmap *, strlen_range_kind, c_strlen_data *, unsigned); +get_range_strlen (tree, bitmap, strlen_range_kind, c_strlen_data *, unsigned); /* Return true when DECL can be referenced from current unit. FROM_DECL (if non-null) specify constructor of variable DECL was taken from. @@ -1525,7 +1525,7 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len) /* Helper of get_range_strlen for ARG that is not an SSA_NAME. */ static bool -get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind, +get_range_strlen_tree (tree arg, bitmap visited, strlen_range_kind rkind, c_strlen_data *pdata, unsigned eltsize) { gcc_assert (TREE_CODE (arg) != SSA_NAME); @@ -1849,7 +1849,7 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind, Return true if *PDATA was successfully populated and false otherwise. */ static bool -get_range_strlen (tree arg, bitmap *visited, +get_range_strlen (tree arg, bitmap visited, strlen_range_kind rkind, c_strlen_data *pdata, unsigned eltsize) { @@ -1863,9 +1863,7 @@ get_range_strlen (tree arg, bitmap *visited, return false; /* If we were already here, break the infinite cycle. */ - if (!*visited) - *visited = BITMAP_ALLOC (NULL); - if (!bitmap_set_bit (*visited, SSA_NAME_VERSION (arg))) + if (!bitmap_set_bit (visited, SSA_NAME_VERSION (arg))) return true; tree var = arg; @@ -1962,10 +1960,10 @@ get_range_strlen (tree arg, bitmap *visited, bool get_range_strlen (tree arg, c_strlen_data *pdata, unsigned eltsize) { - bitmap visited = NULL; + auto_bitmap visited; tree maxbound = pdata->maxbound; - if (!get_range_strlen (arg, &visited, SRK_LENRANGE, pdata, eltsize)) + if (!get_range_strlen (arg, visited, SRK_LENRANGE, pdata, eltsize)) { /* On failure extend the length range to an impossible maximum (a valid MAXLEN must be less than PTRDIFF_MAX - 1). Other @@ -1981,9 +1979,6 @@ get_range_strlen (tree arg, c_strlen_data *pdata, unsigned eltsize) if (maxbound && pdata->maxbound == maxbound) pdata->maxbound = build_all_ones_cst (size_type_node); - if (visited) - BITMAP_FREE (visited); - return !integer_all_onesp (pdata->maxlen); } @@ -2005,19 +2000,16 @@ get_maxval_strlen (tree arg, strlen_range_kind rkind, tree *nonstr = NULL) /* ARG must have an integral type when RKIND says so. */ gcc_assert (rkind != SRK_INT_VALUE || INTEGRAL_TYPE_P (TREE_TYPE (arg))); - bitmap visited = NULL; + auto_bitmap visited; /* Reset DATA.MAXLEN if the call fails or when DATA.MAXLEN is unbounded. */ c_strlen_data lendata = { }; - if (!get_range_strlen (arg, &visited, rkind, &lendata, /* eltsize = */1)) + if (!get_range_strlen (arg, visited, rkind, &lendata, /* eltsize = */1)) lendata.maxlen = NULL_TREE; else if (lendata.maxlen && integer_all_onesp (lendata.maxlen)) lendata.maxlen = NULL_TREE; - if (visited) - BITMAP_FREE (visited); - if (nonstr) { /* For callers prepared to handle unterminated arrays set diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-84.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-84.c new file mode 100644 index 0000000..2c0f507 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-84.c @@ -0,0 +1,15 @@ +/* PR middle-end/102960 - ICE: in sign_mask, at wide-int.h:855 in GCC 10.3.0 + { dg-do compile } + { dg-options "-Og -Wall" } */ + +void f (int i) +{ + const char *s; + if (i) + s = &"abcd"[i]; + + __builtin_printf ("%s", s); +} + +/* The use of s in the call to sprintf should result in: + { dg-prune-output "-Wmaybe-uninitialized" } */ diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index c0ec7d2..536f796 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -193,6 +193,8 @@ struct laststmt_struct } laststmt; static int get_stridx_plus_constant (strinfo *, unsigned HOST_WIDE_INT, tree); +static bool get_range_strlen_dynamic (tree, gimple *s, c_strlen_data *, + bitmap, range_query *, unsigned *); /* Sets MINMAX to either the constant value or the range VAL is in and returns either the constant value or VAL on success or null @@ -1087,6 +1089,76 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals) } } +/* Helper of get_range_strlen_dynamic(). See below. */ + +static bool +get_range_strlen_phi (tree src, gphi *phi, + c_strlen_data *pdata, bitmap visited, + range_query *rvals, unsigned *pssa_def_max) +{ + if (!bitmap_set_bit (visited, SSA_NAME_VERSION (src))) + return true; + + if (*pssa_def_max == 0) + return false; + + --*pssa_def_max; + + /* Iterate over the PHI arguments and determine the minimum and maximum + length/size of each and incorporate them into the overall result. */ + for (unsigned i = 0; i != gimple_phi_num_args (phi); ++i) + { + tree arg = gimple_phi_arg_def (phi, i); + if (arg == gimple_phi_result (phi)) + continue; + + c_strlen_data argdata = { }; + if (!get_range_strlen_dynamic (arg, phi, &argdata, visited, rvals, + pssa_def_max)) + { + pdata->maxlen = build_all_ones_cst (size_type_node); + continue; + } + + /* Set the DECL of an unterminated array this argument refers to + if one hasn't been found yet. */ + if (!pdata->decl && argdata.decl) + pdata->decl = argdata.decl; + + if (!argdata.minlen + || (integer_zerop (argdata.minlen) + && (!argdata.maxbound + || integer_all_onesp (argdata.maxbound)) + && integer_all_onesp (argdata.maxlen))) + { + /* Set the upper bound of the length to unbounded. */ + pdata->maxlen = build_all_ones_cst (size_type_node); + continue; + } + + /* Adjust the minimum and maximum length determined so far and + the upper bound on the array size. */ + if (!pdata->minlen + || tree_int_cst_lt (argdata.minlen, pdata->minlen)) + pdata->minlen = argdata.minlen; + + if (!pdata->maxlen + || (argdata.maxlen + && TREE_CODE (argdata.maxlen) == INTEGER_CST + && tree_int_cst_lt (pdata->maxlen, argdata.maxlen))) + pdata->maxlen = argdata.maxlen; + + if (!pdata->maxbound + || TREE_CODE (pdata->maxbound) != INTEGER_CST + || (argdata.maxbound + && tree_int_cst_lt (pdata->maxbound, argdata.maxbound) + && !integer_all_onesp (argdata.maxbound))) + pdata->maxbound = argdata.maxbound; + } + + return true; +} + /* Attempt to determine the length of the string SRC. On success, store the length in *PDATA and return true. Otherwise, return false. VISITED is a bitmap of visited PHI nodes. RVALS points to the valuation @@ -1095,7 +1167,7 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals) static bool get_range_strlen_dynamic (tree src, gimple *stmt, - c_strlen_data *pdata, bitmap *visited, + c_strlen_data *pdata, bitmap visited, range_query *rvals, unsigned *pssa_def_max) { int idx = get_stridx (src, stmt); @@ -1104,72 +1176,9 @@ get_range_strlen_dynamic (tree src, gimple *stmt, if (TREE_CODE (src) == SSA_NAME) { gimple *def_stmt = SSA_NAME_DEF_STMT (src); - if (gimple_code (def_stmt) == GIMPLE_PHI) - { - if (!*visited) - *visited = BITMAP_ALLOC (NULL); - - if (!bitmap_set_bit (*visited, SSA_NAME_VERSION (src))) - return true; - - if (*pssa_def_max == 0) - return false; - - --*pssa_def_max; - - /* Iterate over the PHI arguments and determine the minimum - and maximum length/size of each and incorporate them into - the overall result. */ - gphi *phi = as_a (def_stmt); - for (unsigned i = 0; i != gimple_phi_num_args (phi); ++i) - { - tree arg = gimple_phi_arg_def (phi, i); - if (arg == gimple_phi_result (def_stmt)) - continue; - - c_strlen_data argdata = { }; - if (get_range_strlen_dynamic (arg, phi, &argdata, visited, - rvals, pssa_def_max)) - { - /* Set the DECL of an unterminated array this argument - refers to if one hasn't been found yet. */ - if (!pdata->decl && argdata.decl) - pdata->decl = argdata.decl; - - if (!argdata.minlen - || (integer_zerop (argdata.minlen) - && (!argdata.maxbound - || integer_all_onesp (argdata.maxbound)) - && integer_all_onesp (argdata.maxlen))) - { - /* Set the upper bound of the length to unbounded. */ - pdata->maxlen = build_all_ones_cst (size_type_node); - continue; - } - - /* Adjust the minimum and maximum length determined - so far and the upper bound on the array size. */ - if (!pdata->minlen - || tree_int_cst_lt (argdata.minlen, pdata->minlen)) - pdata->minlen = argdata.minlen; - if (!pdata->maxlen - || (argdata.maxlen - && tree_int_cst_lt (pdata->maxlen, argdata.maxlen))) - pdata->maxlen = argdata.maxlen; - if (!pdata->maxbound - || TREE_CODE (pdata->maxbound) != INTEGER_CST - || (argdata.maxbound - && tree_int_cst_lt (pdata->maxbound, - argdata.maxbound) - && !integer_all_onesp (argdata.maxbound))) - pdata->maxbound = argdata.maxbound; - } - else - pdata->maxlen = build_all_ones_cst (size_type_node); - } - - return true; - } + if (gphi *phi = dyn_cast(def_stmt)) + return get_range_strlen_phi (src, phi, pdata, visited, rvals, + pssa_def_max); } /* Return success regardless of the result and handle *PDATA @@ -1286,11 +1295,11 @@ void get_range_strlen_dynamic (tree src, gimple *stmt, c_strlen_data *pdata, range_query *rvals) { - bitmap visited = NULL; + auto_bitmap visited; tree maxbound = pdata->maxbound; unsigned limit = param_ssa_name_def_chain_limit; - if (!get_range_strlen_dynamic (src, stmt, pdata, &visited, rvals, &limit)) + if (!get_range_strlen_dynamic (src, stmt, pdata, visited, rvals, &limit)) { /* On failure extend the length range to an impossible maximum (a valid MAXLEN must be less than PTRDIFF_MAX - 1). Other @@ -1305,9 +1314,6 @@ get_range_strlen_dynamic (tree src, gimple *stmt, c_strlen_data *pdata, MAXBOUND to SIZE_MAX. Otherwise leave it null (if it is null). */ if (maxbound && pdata->maxbound == maxbound) pdata->maxbound = build_all_ones_cst (size_type_node); - - if (visited) - BITMAP_FREE (visited); } /* Invalidate string length information for strings whose length might @@ -5831,7 +5837,7 @@ printf_strlen_execute (function *fun, bool warn_only) walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun)); if (dump_file && (dump_flags & TDF_DETAILS)) - walker.ptr_qry.dump (dump_file); + walker.ptr_qry.dump (dump_file, true); ssa_ver_to_stridx.release (); strinfo_pool.release (); -- cgit v1.1 From c31733c3bf57d4cfc31e8d7a95b0ba2cd41e6ea3 Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Sun, 7 Nov 2021 14:39:47 +0100 Subject: fortran: Tiny sort_actual internal refactoring Preliminary refactoring to make further changes more obvious. No functional change. gcc/fortran/ChangeLog: * intrinsic.c (sort_actual): initialise variable and use it earlier. --- gcc/fortran/intrinsic.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index 2d7d246..33b8276 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -4379,19 +4379,18 @@ do_sort: for (f = formal; f; f = f->next) { - if (f->actual && f->actual->label != NULL && f->ts.type) + a = f->actual; + if (a && a->label != NULL && f->ts.type) { gfc_error ("ALTERNATE RETURN not permitted at %L", where); return false; } - if (f->actual == NULL) + if (a == NULL) { a = gfc_get_actual_arglist (); a->missing_arg_type = f->ts.type; } - else - a = f->actual; if (actual == NULL) *ap = a; -- cgit v1.1 From 5888512f24121032a438e3aaf10dc93550dc2819 Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Sun, 7 Nov 2021 14:39:59 +0100 Subject: fortran: Reverse actual vs dummy argument mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was originally no way from an actual argument to get to the corresponding dummy argument, even if the job of sorting and matching actual with dummy arguments was done. The closest was a field named actual in gfc_intrinsic_arg that was used as scratch data when sorting arguments of one specific call. However that value was overwritten later on as arguments of another call to the same procedure were sorted and matched. This change removes that field from gfc_intrinsic_arg and adds instead a new field associated_dummy in gfc_actual_arglist. The new field has as type a new wrapper struct gfc_dummy_arg that provides a common interface to both dummy arguments of user-defined procedures (which have type gfc_formal_arglist) and dummy arguments of intrinsic procedures (which have type gfc_intrinsic_arg). As the removed field was used in the code sorting and matching arguments, that code has to be updated. Two local vectors with matching indices are introduced for respectively dummy and actual arguments, and the loops are modified to use indices and update those argument vectors. gcc/fortran/ChangeLog: * gfortran.h (gfc_dummy_arg_kind, gfc_dummy_arg): New. (gfc_actual_arglist): New field associated_dummy. (gfc_intrinsic_arg): Remove field actual. * interface.c (get_nonintrinsic_dummy_arg): New. (gfc_compare_actual): Initialize associated_dummy. * intrinsic.c (get_intrinsic_dummy_arg): New. (sort_actual):  Add argument vectors. Use loops with indices on argument vectors. Initialize associated_dummy. --- gcc/fortran/gfortran.h | 31 +++++++++++++++++++++++++++++-- gcc/fortran/interface.c | 21 +++++++++++++++++++-- gcc/fortran/intrinsic.c | 43 ++++++++++++++++++++++++++++++++----------- 3 files changed, 80 insertions(+), 15 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 1ad2f0d..86c096a 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1199,6 +1199,9 @@ gfc_formal_arglist; #define gfc_get_formal_arglist() XCNEW (gfc_formal_arglist) +struct gfc_dummy_arg; + + /* The gfc_actual_arglist structure is for actual arguments and for type parameter specification lists. */ typedef struct gfc_actual_arglist @@ -1215,6 +1218,11 @@ typedef struct gfc_actual_arglist gfc_param_spec_type spec_type; struct gfc_expr *expr; + + /* The dummy arg this actual arg is associated with, if the interface + is explicit. NULL otherwise. */ + gfc_dummy_arg *associated_dummy; + struct gfc_actual_arglist *next; } gfc_actual_arglist; @@ -2299,14 +2307,33 @@ typedef struct gfc_intrinsic_arg gfc_typespec ts; unsigned optional:1, value:1; ENUM_BITFIELD (sym_intent) intent:2; - gfc_actual_arglist *actual; struct gfc_intrinsic_arg *next; - } gfc_intrinsic_arg; +typedef enum { + GFC_UNDEFINED_DUMMY_ARG = 0, + GFC_INTRINSIC_DUMMY_ARG, + GFC_NON_INTRINSIC_DUMMY_ARG +} +gfc_dummy_arg_intrinsicness; + +/* dummy arg of either an intrinsic or a user-defined procedure. */ +struct gfc_dummy_arg +{ + gfc_dummy_arg_intrinsicness intrinsicness; + + union { + gfc_intrinsic_arg *intrinsic; + gfc_formal_arglist *non_intrinsic; + } u; +}; + +#define gfc_get_dummy_arg() XCNEW (gfc_dummy_arg) + + /* Specifies the various kinds of check functions used to verify the argument lists of intrinsic functions. fX with X an integer refer to check functions of intrinsics with X arguments. f1m is used for diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index 30c99ef..2c9d371 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -3043,6 +3043,18 @@ lookup_arg_fuzzy (const char *arg, gfc_formal_arglist *arguments) } +static gfc_dummy_arg * +get_nonintrinsic_dummy_arg (gfc_formal_arglist *formal) +{ + gfc_dummy_arg * const dummy_arg = gfc_get_dummy_arg (); + + dummy_arg->intrinsicness = GFC_NON_INTRINSIC_DUMMY_ARG; + dummy_arg->u.non_intrinsic = formal; + + return dummy_arg; +} + + /* Given formal and actual argument lists, see if they are compatible. If they are compatible, the actual argument list is sorted to correspond with the formal list, and elements for missing optional @@ -3151,6 +3163,8 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, "call at %L", where); return false; } + else + a->associated_dummy = get_nonintrinsic_dummy_arg (f); if (a->expr == NULL) { @@ -3680,9 +3694,12 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, /* The argument lists are compatible. We now relink a new actual argument list with null arguments in the right places. The head of the list remains the head. */ - for (i = 0; i < n; i++) + for (f = formal, i = 0; f; f = f->next, i++) if (new_arg[i] == NULL) - new_arg[i] = gfc_get_actual_arglist (); + { + new_arg[i] = gfc_get_actual_arglist (); + new_arg[i]->associated_dummy = get_nonintrinsic_dummy_arg (f); + } if (na != 0) { diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index 33b8276..cb07326 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -4237,6 +4237,18 @@ remove_nullargs (gfc_actual_arglist **ap) } +static gfc_dummy_arg * +get_intrinsic_dummy_arg (gfc_intrinsic_arg *intrinsic) +{ + gfc_dummy_arg * const dummy_arg = gfc_get_dummy_arg (); + + dummy_arg->intrinsicness = GFC_INTRINSIC_DUMMY_ARG; + dummy_arg->u.intrinsic = intrinsic; + + return dummy_arg; +} + + /* Given an actual arglist and a formal arglist, sort the actual arglist so that its arguments are in a one-to-one correspondence with the format arglist. Arguments that are not present are given @@ -4254,8 +4266,14 @@ sort_actual (const char *name, gfc_actual_arglist **ap, remove_nullargs (ap); actual = *ap; + auto_vec dummy_args; + auto_vec ordered_actual_args; + for (f = formal; f; f = f->next) - f->actual = NULL; + dummy_args.safe_push (f); + + ordered_actual_args.safe_grow_cleared (dummy_args.length (), + /* exact = */true); f = formal; a = actual; @@ -4307,7 +4325,7 @@ sort_actual (const char *name, gfc_actual_arglist **ap, } } - for (;;) + for (int i = 0;; i++) { /* Put the nonkeyword arguments in a 1:1 correspondence */ if (f == NULL) break; @@ -4317,7 +4335,7 @@ sort_actual (const char *name, gfc_actual_arglist **ap, if (a->name != NULL) goto keywords; - f->actual = a; + ordered_actual_args[i] = a; f = f->next; a = a->next; @@ -4335,7 +4353,8 @@ keywords: to be keyword arguments. */ for (; a; a = a->next) { - for (f = formal; f; f = f->next) + int idx; + FOR_EACH_VEC_ELT (dummy_args, idx, f) if (strcmp (a->name, f->name) == 0) break; @@ -4350,21 +4369,21 @@ keywords: return false; } - if (f->actual != NULL) + if (ordered_actual_args[idx] != NULL) { gfc_error ("Argument %qs appears twice in call to %qs at %L", f->name, name, where); return false; } - - f->actual = a; + ordered_actual_args[idx] = a; } optional: /* At this point, all unmatched formal args must be optional. */ - for (f = formal; f; f = f->next) + int idx; + FOR_EACH_VEC_ELT (dummy_args, idx, f) { - if (f->actual == NULL && f->optional == 0) + if (ordered_actual_args[idx] == NULL && f->optional == 0) { gfc_error ("Missing actual argument %qs in call to %qs at %L", f->name, name, where); @@ -4377,9 +4396,9 @@ do_sort: together in a way that corresponds with the formal list. */ actual = NULL; - for (f = formal; f; f = f->next) + FOR_EACH_VEC_ELT (dummy_args, idx, f) { - a = f->actual; + a = ordered_actual_args[idx]; if (a && a->label != NULL && f->ts.type) { gfc_error ("ALTERNATE RETURN not permitted at %L", where); @@ -4392,6 +4411,8 @@ do_sort: a->missing_arg_type = f->ts.type; } + a->associated_dummy = get_intrinsic_dummy_arg (f); + if (actual == NULL) *ap = a; else -- cgit v1.1 From 5d9d16db96f2fcb47a00a7ce7e2d0e51400b47ab Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Sun, 7 Nov 2021 14:40:11 +0100 Subject: fortran: simplify elemental arguments walking This adds two functions working with the wrapper struct gfc_dummy_arg and makes usage of them to simplify a bit the walking of elemental procedure arguments for scalarization. As information about dummy arguments can be obtained from the actual argument through the just-introduced associated_dummy field, there is no need to carry around the procedure interface and walk dummy arguments manually together with actual arguments. gcc/fortran/ChangeLog: * interface.c (gfc_dummy_arg_get_typespec, gfc_dummy_arg_is_optional): New functions. * gfortran.h (gfc_dummy_arg_get_typespec, gfc_dummy_arg_is_optional): Declare them. * trans.h (gfc_ss_info::dummy_arg): Use the wrapper type as declaration type. * trans-array.c (gfc_scalar_elemental_arg_saved_as_reference): use gfc_dummy_arg_get_typespec function to get the type. (gfc_walk_elemental_function_args): Remove proc_ifc argument. Get info about the dummy arg using the associated_dummy field. * trans-array.h (gfc_walk_elemental_function_args): Update declaration. * trans-intrinsic.c (gfc_walk_intrinsic_function): Update call to gfc_walk_elemental_function_args. * trans-stmt.c (gfc_trans_call): Ditto. (get_proc_ifc_for_call): Remove. --- gcc/fortran/gfortran.h | 4 ++++ gcc/fortran/interface.c | 34 ++++++++++++++++++++++++++++++++++ gcc/fortran/trans-array.c | 19 ++++++------------- gcc/fortran/trans-array.h | 2 +- gcc/fortran/trans-intrinsic.c | 2 +- gcc/fortran/trans-stmt.c | 22 ---------------------- gcc/fortran/trans.h | 4 ++-- 7 files changed, 48 insertions(+), 39 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 86c096a..4230b5a 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -2334,6 +2334,10 @@ struct gfc_dummy_arg #define gfc_get_dummy_arg() XCNEW (gfc_dummy_arg) +const gfc_typespec & gfc_dummy_arg_get_typespec (gfc_dummy_arg &); +bool gfc_dummy_arg_is_optional (gfc_dummy_arg &); + + /* Specifies the various kinds of check functions used to verify the argument lists of intrinsic functions. fX with X an integer refer to check functions of intrinsics with X arguments. f1m is used for diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index 2c9d371..9194fe7 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -5537,3 +5537,37 @@ gfc_get_formal_from_actual_arglist (gfc_symbol *sym, f = &((*f)->next); } } + + +const gfc_typespec & +gfc_dummy_arg_get_typespec (gfc_dummy_arg & dummy_arg) +{ + switch (dummy_arg.intrinsicness) + { + case GFC_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.intrinsic->ts; + + case GFC_NON_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.non_intrinsic->sym->ts; + + default: + gcc_unreachable (); + } +} + + +bool +gfc_dummy_arg_is_optional (gfc_dummy_arg & dummy_arg) +{ + switch (dummy_arg.intrinsicness) + { + case GFC_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.intrinsic->optional; + + case GFC_NON_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.non_intrinsic->sym->attr.optional; + + default: + gcc_unreachable (); + } +} diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 7932185..d37c1e7 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -3010,7 +3010,8 @@ gfc_scalar_elemental_arg_saved_as_reference (gfc_ss_info * ss_info) /* If the expression is of polymorphic type, it's actual size is not known, so we avoid copying it anywhere. */ if (ss_info->data.scalar.dummy_arg - && ss_info->data.scalar.dummy_arg->ts.type == BT_CLASS + && gfc_dummy_arg_get_typespec (*ss_info->data.scalar.dummy_arg).type + == BT_CLASS && ss_info->expr->ts.type == BT_CLASS) return true; @@ -11521,9 +11522,8 @@ arg_evaluated_for_scalarization (gfc_intrinsic_sym *function, gfc_ss * gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, gfc_intrinsic_sym *intrinsic_sym, - gfc_symbol *proc_ifc, gfc_ss_type type) + gfc_ss_type type) { - gfc_formal_arglist *dummy_arg; int scalar; gfc_ss *head; gfc_ss *tail; @@ -11532,15 +11532,11 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, head = gfc_ss_terminator; tail = NULL; - if (proc_ifc) - dummy_arg = gfc_sym_get_dummy_args (proc_ifc); - else - dummy_arg = NULL; - int arg_num = 0; scalar = 1; for (; arg; arg = arg->next) { + gfc_dummy_arg * const dummy_arg = arg->associated_dummy; if (!arg->expr || arg->expr->expr_type == EXPR_NULL || !arg_evaluated_for_scalarization (intrinsic_sym, *arg, arg_num)) @@ -11554,13 +11550,13 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, newss = gfc_get_scalar_ss (head, arg->expr); newss->info->type = type; if (dummy_arg) - newss->info->data.scalar.dummy_arg = dummy_arg->sym; + newss->info->data.scalar.dummy_arg = dummy_arg; } else scalar = 0; if (dummy_arg != NULL - && dummy_arg->sym->attr.optional + && gfc_dummy_arg_is_optional (*dummy_arg) && arg->expr->expr_type == EXPR_VARIABLE && (gfc_expr_attr (arg->expr).optional || gfc_expr_attr (arg->expr).allocatable @@ -11577,8 +11573,6 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, loop_continue: arg_num++; - if (dummy_arg != NULL) - dummy_arg = dummy_arg->next; } if (scalar) @@ -11638,7 +11632,6 @@ gfc_walk_function_expr (gfc_ss * ss, gfc_expr * expr) ss = gfc_walk_elemental_function_args (old_ss, expr->value.function.actual, gfc_get_intrinsic_for_expr (expr), - gfc_get_proc_ifc_for_expr (expr), GFC_SS_REFERENCE); if (ss != old_ss && (comp diff --git a/gcc/fortran/trans-array.h b/gcc/fortran/trans-array.h index 8f806c3..9c4bd06 100644 --- a/gcc/fortran/trans-array.h +++ b/gcc/fortran/trans-array.h @@ -87,7 +87,7 @@ gfc_ss *gfc_walk_array_ref (gfc_ss *, gfc_expr *, gfc_ref * ref); /* Walk the arguments of an elemental function. */ gfc_ss *gfc_walk_elemental_function_args (gfc_ss *, gfc_actual_arglist *, gfc_intrinsic_sym *, - gfc_symbol *, gfc_ss_type); + gfc_ss_type); /* Walk an intrinsic function. */ gfc_ss *gfc_walk_intrinsic_function (gfc_ss *, gfc_expr *, gfc_intrinsic_sym *); diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index 3f86791..c1b51f4 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -11085,7 +11085,7 @@ gfc_walk_intrinsic_function (gfc_ss * ss, gfc_expr * expr, if (isym->elemental) return gfc_walk_elemental_function_args (ss, expr->value.function.actual, expr->value.function.isym, - NULL, GFC_SS_SCALAR); + GFC_SS_SCALAR); if (expr->rank == 0) return ss; diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index bdf7957..1fc6d3a 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -375,27 +375,6 @@ get_intrinsic_for_code (gfc_code *code) } -/* Get the interface symbol for the procedure corresponding to the given call. - We can't get the procedure symbol directly as we have to handle the case - of (deferred) type-bound procedures. */ - -static gfc_symbol * -get_proc_ifc_for_call (gfc_code *c) -{ - gfc_symbol *sym; - - gcc_assert (c->op == EXEC_ASSIGN_CALL || c->op == EXEC_CALL); - - sym = gfc_get_proc_ifc_for_expr (c->expr1); - - /* Fall back/last resort try. */ - if (sym == NULL) - sym = c->resolved_sym; - - return sym; -} - - /* Translate the CALL statement. Builds a call to an F95 subroutine. */ tree @@ -422,7 +401,6 @@ gfc_trans_call (gfc_code * code, bool dependency_check, if (code->resolved_sym->attr.elemental) ss = gfc_walk_elemental_function_args (ss, code->ext.actual, get_intrinsic_for_code (code), - get_proc_ifc_for_call (code), GFC_SS_REFERENCE); /* MVBITS is inlined but needs the dependency checking found here. */ diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index 0d4eed2..15012a3 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -266,8 +266,8 @@ typedef struct gfc_ss_info struct { /* If the scalar is passed as actual argument to an (elemental) procedure, - this is the symbol of the corresponding dummy argument. */ - gfc_symbol *dummy_arg; + this is the corresponding dummy argument. */ + gfc_dummy_arg *dummy_arg; tree value; /* Tells that the scalar is a reference to a variable that might be present on the lhs, so that we should evaluate the value -- cgit v1.1 From e94e2cf9f9b31167cfaa6e33f731c3735515662d Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Sun, 7 Nov 2021 14:40:24 +0100 Subject: fortran: Delete redundant missing_arg_type field Now that we can get information about an actual arg's associated dummy using the associated_dummy attribute, the field missing_arg_type contains redundant information. This removes it. gcc/fortran/ChangeLog: * gfortran.h (gfc_actual_arglist::missing_arg_type): Remove. * interface.c (gfc_compare_actual_formal): Remove missing_arg_type initialization. * intrinsic.c (sort_actual): Ditto. * trans-expr.c (gfc_conv_procedure_call): Use associated_dummy and gfc_dummy_arg_get_typespec to get the dummy argument type. --- gcc/fortran/gfortran.h | 5 ----- gcc/fortran/interface.c | 5 ----- gcc/fortran/intrinsic.c | 5 +---- gcc/fortran/trans-expr.c | 9 +++++++-- 4 files changed, 8 insertions(+), 16 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 4230b5a..bf61770 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1210,11 +1210,6 @@ typedef struct gfc_actual_arglist /* Alternate return label when the expr member is null. */ struct gfc_st_label *label; - /* This is set to the type of an eventual omitted optional - argument. This is used to determine if a hidden string length - argument has to be added to a function call. */ - bt missing_arg_type; - gfc_param_spec_type spec_type; struct gfc_expr *expr; diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index 9194fe7..12574f8 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -3715,11 +3715,6 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, if (*ap == NULL && n > 0) *ap = new_arg[0]; - /* Note the types of omitted optional arguments. */ - for (a = *ap, f = formal; a; a = a->next, f = f->next) - if (a->expr == NULL && a->label == NULL) - a->missing_arg_type = f->sym->ts.type; - return true; } diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index cb07326..3682f9a 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -4406,10 +4406,7 @@ do_sort: } if (a == NULL) - { - a = gfc_get_actual_arglist (); - a->missing_arg_type = f->ts.type; - } + a = gfc_get_actual_arglist (); a->associated_dummy = get_intrinsic_dummy_arg (f); diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index e7aec38..bc502c0 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -6157,7 +6157,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, { /* Pass a NULL pointer for an absent arg. */ parmse.expr = null_pointer_node; - if (arg->missing_arg_type == BT_CHARACTER) + gfc_dummy_arg * const dummy_arg = arg->associated_dummy; + if (dummy_arg + && gfc_dummy_arg_get_typespec (*dummy_arg).type + == BT_CHARACTER) parmse.string_length = build_int_cst (gfc_charlen_type_node, 0); } @@ -6174,7 +6177,9 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, || !CLASS_DATA (fsym)->attr.allocatable)); gfc_init_se (&parmse, NULL); parmse.expr = null_pointer_node; - if (arg->missing_arg_type == BT_CHARACTER) + if (arg->associated_dummy + && gfc_dummy_arg_get_typespec (*arg->associated_dummy).type + == BT_CHARACTER) parmse.string_length = build_int_cst (gfc_charlen_type_node, 0); } else if (fsym && fsym->ts.type == BT_CLASS -- cgit v1.1 From 48a8c5be5b98240d664672a2b7b7d26f3c36cf84 Mon Sep 17 00:00:00 2001 From: Mikael Morin Date: Sun, 7 Nov 2021 14:40:36 +0100 Subject: fortran: Identify arguments by their names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This provides a new function to get the name of a dummy argument, so that identifying an argument can be made using just its name instead of a mix of name matching (for keyword actual arguments) and argument counting (for other actual arguments). gcc/fortran/ChangeLog: * interface.c (gfc_dummy_arg_get_name): New function. * gfortran.h (gfc_dummy_arg_get_name): Declare it. * trans-array.c (arg_evaluated_for_scalarization): Pass a dummy argument wrapper as argument instead of an actual argument and an index number. Check it’s non-NULL. Use its name to identify it. (gfc_walk_elemental_function_args): Update call to arg_evaluated for scalarization. Remove argument counting. --- gcc/fortran/gfortran.h | 1 + gcc/fortran/interface.c | 17 +++++++++++++++++ gcc/fortran/trans-array.c | 16 +++++----------- 3 files changed, 23 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index bf61770..1846ee4 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -2329,6 +2329,7 @@ struct gfc_dummy_arg #define gfc_get_dummy_arg() XCNEW (gfc_dummy_arg) +const char * gfc_dummy_arg_get_name (gfc_dummy_arg &); const gfc_typespec & gfc_dummy_arg_get_typespec (gfc_dummy_arg &); bool gfc_dummy_arg_is_optional (gfc_dummy_arg &); diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index 12574f8..8571709 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -5534,6 +5534,23 @@ gfc_get_formal_from_actual_arglist (gfc_symbol *sym, } +const char * +gfc_dummy_arg_get_name (gfc_dummy_arg & dummy_arg) +{ + switch (dummy_arg.intrinsicness) + { + case GFC_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.intrinsic->name; + + case GFC_NON_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.non_intrinsic->sym->name; + + default: + gcc_unreachable (); + } +} + + const gfc_typespec & gfc_dummy_arg_get_typespec (gfc_dummy_arg & dummy_arg) { diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index d37c1e7..2090adf 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -11492,16 +11492,14 @@ gfc_get_intrinsic_for_expr (gfc_expr *call) static bool arg_evaluated_for_scalarization (gfc_intrinsic_sym *function, - gfc_actual_arglist &actual_arg, int arg_num) + gfc_dummy_arg *dummy_arg) { - if (function != NULL) + if (function != NULL && dummy_arg != NULL) { switch (function->id) { case GFC_ISYM_INDEX: - if ((actual_arg.name == NULL && arg_num == 3) - || (actual_arg.name != NULL - && strcmp ("kind", actual_arg.name) == 0)) + if (strcmp ("kind", gfc_dummy_arg_get_name (*dummy_arg)) == 0) return false; /* Fallthrough. */ @@ -11532,15 +11530,14 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, head = gfc_ss_terminator; tail = NULL; - int arg_num = 0; scalar = 1; for (; arg; arg = arg->next) { gfc_dummy_arg * const dummy_arg = arg->associated_dummy; if (!arg->expr || arg->expr->expr_type == EXPR_NULL - || !arg_evaluated_for_scalarization (intrinsic_sym, *arg, arg_num)) - goto loop_continue; + || !arg_evaluated_for_scalarization (intrinsic_sym, dummy_arg)) + continue; newss = gfc_walk_subexpr (head, arg->expr); if (newss == head) @@ -11570,9 +11567,6 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, while (tail->next != gfc_ss_terminator) tail = tail->next; } - -loop_continue: - arg_num++; } if (scalar) -- cgit v1.1 From 4cdf7db9a39d18bd536d816a5751d4d3cf23808b Mon Sep 17 00:00:00 2001 From: Peter Bergner Date: Tue, 16 Nov 2021 12:14:22 -0600 Subject: rs6000: MMA test case emits wrong code when building a vector pair [PR102976] PR102976 shows a test case where we generate wrong code when building a vector pair from 2 vector registers. The bug here is that with unlucky register assignments, we can clobber one of the input operands before we write both registers of the output operand. The solution is to use early-clobbers in the assemble pair and accumulator patterns. 2021-11-16 Peter Bergner gcc/ PR target/102976 * config/rs6000/mma.md (*vsx_assemble_pair): Add early-clobber for output operand. (*mma_assemble_acc): Likewise. gcc/testsuite/ PR target/102976 * gcc.target/powerpc/pr102976.c: New test. --- gcc/config/rs6000/mma.md | 10 ++++++++-- gcc/testsuite/gcc.target/powerpc/pr102976.c | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/pr102976.c (limited to 'gcc') diff --git a/gcc/config/rs6000/mma.md b/gcc/config/rs6000/mma.md index 1990a21..fa08160 100644 --- a/gcc/config/rs6000/mma.md +++ b/gcc/config/rs6000/mma.md @@ -338,8 +338,11 @@ DONE; }) +;; We cannot update the two output registers atomically, so mark the output +;; as an early clobber so we don't accidentally clobber the input operands. */ + (define_insn_and_split "*vsx_assemble_pair" - [(set (match_operand:OO 0 "vsx_register_operand" "=wa") + [(set (match_operand:OO 0 "vsx_register_operand" "=&wa") (unspec:OO [(match_operand:V16QI 1 "mma_assemble_input_operand" "mwa") (match_operand:V16QI 2 "mma_assemble_input_operand" "mwa")] UNSPEC_MMA_ASSEMBLE))] @@ -404,8 +407,11 @@ DONE; }) +;; We cannot update the four output registers atomically, so mark the output +;; as an early clobber so we don't accidentally clobber the input operands. */ + (define_insn_and_split "*mma_assemble_acc" - [(set (match_operand:XO 0 "fpr_reg_operand" "=d") + [(set (match_operand:XO 0 "fpr_reg_operand" "=&d") (unspec:XO [(match_operand:V16QI 1 "mma_assemble_input_operand" "mwa") (match_operand:V16QI 2 "mma_assemble_input_operand" "mwa") (match_operand:V16QI 3 "mma_assemble_input_operand" "mwa") diff --git a/gcc/testsuite/gcc.target/powerpc/pr102976.c b/gcc/testsuite/gcc.target/powerpc/pr102976.c new file mode 100644 index 0000000..5a4320f --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr102976.c @@ -0,0 +1,14 @@ +/* { dg-require-effective-target power10_ok } */ +/* { dg-options "-O2 -mdejagnu-cpu=power10" } */ + +#include +void +bug (__vector_pair *dst) +{ + register vector unsigned char vec0 asm ("vs44"); + register vector unsigned char vec1 asm ("vs32"); + __builtin_vsx_build_pair (dst, vec0, vec1); +} + +/* { dg-final { scan-assembler-times {(?p)\mxxlor \d+,44,44\M} 1 } } */ +/* { dg-final { scan-assembler-times {(?p)\mxxlor \d+,32,32\M} 1 } } */ -- cgit v1.1 From e4641191287ca613529d78a906afe4f029c1c3cd Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sat, 13 Nov 2021 12:26:16 +0000 Subject: PCH: Make the save and restore diagnostics more robust. When saving, if we cannot obtain a suitable memory segment there is no point in continuing, so exit with an error. When reading in the PCH, we have a situation that the read-in data will replace the line tables used by the diagnostics output. However, the state of the read-oin line tables is indeterminate at some points where diagnostics might be needed. To make this more robust, we save the existing line tables at the start and, once we have read in the pointer to the new one, put that to one side and restore the original table. This avoids compiler hangs if the read or memory acquisition code issues an assert, fatal_error, segv etc. Once the read is complete, we swap in the new line table that came from the PCH. If the read-in PCH is corrupted then we still have a broken compilation w.r.t any future diagnostics - but there is little that can be done about that without more careful validation of the file. Signed-off-by: Iain Sandoe gcc/ChangeLog: * ggc-common.c (gt_pch_save): If we cannot find a suitable memory segment for save, then error-out, do not try to continue. (gt_pch_restore): Save the existing line table, and when the replacement is being read, use that when constructing diagnostics. --- gcc/ggc-common.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c index 32ba5be..b6abed1 100644 --- a/gcc/ggc-common.c +++ b/gcc/ggc-common.c @@ -440,6 +440,10 @@ gt_pch_save (FILE *f) (The extra work goes in HOST_HOOKS_GT_PCH_GET_ADDRESS and HOST_HOOKS_GT_PCH_USE_ADDRESS.) */ mmi.preferred_base = host_hooks.gt_pch_get_address (mmi.size, fileno (f)); + /* If the host cannot supply any suitable address for this, we are stuck. */ + if (mmi.preferred_base == NULL) + fatal_error (input_location, + "cannot write PCH file: required memory segment unavailable"); ggc_pch_this_base (state.d, mmi.preferred_base); @@ -589,6 +593,13 @@ gt_pch_restore (FILE *f) struct mmap_info mmi; int result; + /* We are about to reload the line maps along with the rest of the PCH + data, which means that the (loaded) ones cannot be guaranteed to be + in any valid state for reporting diagnostics that happen during the + load. Save the current table (and use it during the loading process + below). */ + class line_maps *save_line_table = line_table; + /* Delete any deletable objects. This makes ggc_pch_read much faster, as it can be sure that no GCable objects remain other than the ones just read in. */ @@ -603,20 +614,40 @@ gt_pch_restore (FILE *f) fatal_error (input_location, "cannot read PCH file: %m"); /* Read in all the global pointers, in 6 easy loops. */ + bool error_reading_pointers = false; for (rt = gt_ggc_rtab; *rt; rt++) for (rti = *rt; rti->base != NULL; rti++) for (i = 0; i < rti->nelt; i++) if (fread ((char *)rti->base + rti->stride * i, sizeof (void *), 1, f) != 1) - fatal_error (input_location, "cannot read PCH file: %m"); + error_reading_pointers = true; + + /* Stash the newly read-in line table pointer - it does not point to + anything meaningful yet, so swap the old one back in. */ + class line_maps *new_line_table = line_table; + line_table = save_line_table; + if (error_reading_pointers) + fatal_error (input_location, "cannot read PCH file: %m"); if (fread (&mmi, sizeof (mmi), 1, f) != 1) fatal_error (input_location, "cannot read PCH file: %m"); result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size, fileno (f), mmi.offset); + + /* We could not mmap or otherwise allocate the required memory at the + address needed. */ if (result < 0) - fatal_error (input_location, "had to relocate PCH"); + { + sorry_at (input_location, "PCH relocation is not yet supported"); + /* There is no point in continuing from here, we will only end up + with a crashed (most likely hanging) compiler. */ + exit (-1); + } + + /* (0) We allocated memory, but did not mmap the file, so we need to read + the data in manually. (>0) Otherwise the mmap succeed for the address + we wanted. */ if (result == 0) { if (fseek (f, mmi.offset, SEEK_SET) != 0 @@ -629,6 +660,10 @@ gt_pch_restore (FILE *f) ggc_pch_read (f, mmi.preferred_base); gt_pch_restore_stringpool (); + + /* Barring corruption of the PCH file, the restored line table should be + complete and usable. */ + line_table = new_line_table; } /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present. -- cgit v1.1 From 3b3c9932338650c9a402cf1bfbdf7dfc03e185e7 Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Tue, 16 Nov 2021 21:06:06 +0100 Subject: Fortran: avoid NULL pointer dereference on invalid range in logical SELECT CASE gcc/fortran/ChangeLog: PR fortran/103286 * resolve.c (resolve_select): Choose appropriate range limit to avoid NULL pointer dereference when generating error message. gcc/testsuite/ChangeLog: PR fortran/103286 * gfortran.dg/pr103286.f90: New test. --- gcc/fortran/resolve.c | 3 ++- gcc/testsuite/gfortran.dg/pr103286.f90 | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gfortran.dg/pr103286.f90 (limited to 'gcc') diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 705d232..f074a0a 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -8846,7 +8846,8 @@ resolve_select (gfc_code *code, bool select_type) || cp->low != cp->high)) { gfc_error ("Logical range in CASE statement at %L is not " - "allowed", &cp->low->where); + "allowed", + cp->low ? &cp->low->where : &cp->high->where); t = false; break; } diff --git a/gcc/testsuite/gfortran.dg/pr103286.f90 b/gcc/testsuite/gfortran.dg/pr103286.f90 new file mode 100644 index 0000000..1c18b71 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr103286.f90 @@ -0,0 +1,11 @@ +! { dg-do compile } +! { dg-options "std=gnu" } +! PR fortran/103286 - ICE in resolve_select + +program p + select case (.true.) ! { dg-warning "Extension: Conversion" } + case (1_8) + case (:0) ! { dg-error "Logical range in CASE statement" } + case (2:) ! { dg-error "Logical range in CASE statement" } + end select +end -- cgit v1.1 From 6dc90c4dbb6f9589dea9c670c3468496bb207de5 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 16 Nov 2021 23:01:28 +0100 Subject: Use modref summaries for byte-wise dead store elimination. gcc/ChangeLog: * ipa-modref.c (get_modref_function_summary): Declare. * ipa-modref.h (get_modref_function_summary): New function. * tree-ssa-dse.c (clear_live_bytes_for_ref): Break out from ... (clear_bytes_written_by): ... here; also clear memory killed by calls. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/modref-dse-4.c: New test. --- gcc/ipa-modref.c | 22 ++++++++++++++ gcc/ipa-modref.h | 1 + gcc/testsuite/gcc.dg/tree-ssa/modref-dse-4.c | 26 +++++++++++++++++ gcc/tree-ssa-dse.c | 43 +++++++++++++++++++++------- 4 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/modref-dse-4.c (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 5783430..a70575bc 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -740,6 +740,28 @@ get_modref_function_summary (cgraph_node *func) return r; } +/* Get function summary for CALL if it exists, return NULL otherwise. + If non-null set interposed to indicate whether function may not + bind to current def. In this case sometimes loads from function + needs to be ignored. */ + +modref_summary * +get_modref_function_summary (gcall *call, bool *interposed) +{ + tree callee = gimple_call_fndecl (call); + if (!callee) + return NULL; + struct cgraph_node *node = cgraph_node::get (callee); + if (!node) + return NULL; + modref_summary *r = get_modref_function_summary (node); + if (interposed && r) + *interposed = r->calls_interposable + || !node->binds_to_current_def_p (); + return r; +} + + namespace { /* Construct modref_access_node from REF. */ diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h index 4eb696d..f868eb6 100644 --- a/gcc/ipa-modref.h +++ b/gcc/ipa-modref.h @@ -70,6 +70,7 @@ struct GTY(()) modref_summary }; modref_summary *get_modref_function_summary (cgraph_node *func); +modref_summary *get_modref_function_summary (gcall *call, bool *interposed); void ipa_modref_c_finalize (); void ipa_merge_modref_summary_after_inlining (cgraph_edge *e); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-dse-4.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-dse-4.c new file mode 100644 index 0000000..81aa7dc --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-dse-4.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dse2-details" } */ +struct a {int a,b,c;}; +__attribute__ ((noinline)) +void +kill_me (struct a *a) +{ + a->a=0; + a->b=0; + a->c=0; +} +__attribute__ ((noinline)) +void +my_pleasure (struct a *a) +{ + a->a=1; + a->c=2; +} +void +set (struct a *a) +{ + kill_me (a); + my_pleasure (a); + a->b=1; +} +/* { dg-final { scan-tree-dump "Deleted dead store: kill_me" "dse2" } } */ diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c index ce0083a..231e827 100644 --- a/gcc/tree-ssa-dse.c +++ b/gcc/tree-ssa-dse.c @@ -209,6 +209,26 @@ normalize_ref (ao_ref *copy, ao_ref *ref) return true; } +/* Update LIVE_BYTES tracking REF for write to WRITE: + Verify we have the same base memory address, the write + has a known size and overlaps with REF. */ +static void +clear_live_bytes_for_ref (sbitmap live_bytes, ao_ref *ref, ao_ref write) +{ + HOST_WIDE_INT start, size; + + if (valid_ao_ref_for_dse (&write) + && operand_equal_p (write.base, ref->base, OEP_ADDRESS_OF) + && known_eq (write.size, write.max_size) + /* normalize_ref modifies write and for that reason write is not + passed by reference. */ + && normalize_ref (&write, ref) + && (write.offset - ref->offset).is_constant (&start) + && write.size.is_constant (&size)) + bitmap_clear_range (live_bytes, start / BITS_PER_UNIT, + size / BITS_PER_UNIT); +} + /* Clear any bytes written by STMT from the bitmap LIVE_BYTES. The base address written by STMT must match the one found in REF, which must have its base address previously initialized. @@ -220,20 +240,21 @@ static void clear_bytes_written_by (sbitmap live_bytes, gimple *stmt, ao_ref *ref) { ao_ref write; + + if (gcall *call = dyn_cast (stmt)) + { + bool interposed; + modref_summary *summary = get_modref_function_summary (call, &interposed); + + if (summary && !interposed) + for (auto kill : summary->kills) + if (kill.get_ao_ref (as_a (stmt), &write)) + clear_live_bytes_for_ref (live_bytes, ref, write); + } if (!initialize_ao_ref_for_dse (stmt, &write)) return; - /* Verify we have the same base memory address, the write - has a known size and overlaps with REF. */ - HOST_WIDE_INT start, size; - if (valid_ao_ref_for_dse (&write) - && operand_equal_p (write.base, ref->base, OEP_ADDRESS_OF) - && known_eq (write.size, write.max_size) - && normalize_ref (&write, ref) - && (write.offset - ref->offset).is_constant (&start) - && write.size.is_constant (&size)) - bitmap_clear_range (live_bytes, start / BITS_PER_UNIT, - size / BITS_PER_UNIT); + clear_live_bytes_for_ref (live_bytes, ref, write); } /* REF is a memory write. Extract relevant information from it and -- cgit v1.1 From 395848255cfa88f6f0f33a9b14c79e584a05d6fc Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 10 Nov 2021 16:23:12 -0500 Subject: c-family: don't cache large vecs Patrick observed recently that an element of the vector cache could be arbitrarily large. Let's only cache relatively small vecs. gcc/c-family/ChangeLog: * c-common.c (release_tree_vector): Only cache vecs smaller than 16 elements. --- gcc/c-family/c-common.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 436df45..90e8ec8 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -8213,8 +8213,16 @@ release_tree_vector (vec *vec) { if (vec != NULL) { - vec->truncate (0); - vec_safe_push (tree_vector_cache, vec); + if (vec->allocated () >= 16) + /* Don't cache vecs that have expanded more than once. On a p64 + target, vecs double in alloc size with each power of 2 elements, e.g + at 16 elements the alloc increases from 128 to 256 bytes. */ + vec_free (vec); + else + { + vec->truncate (0); + vec_safe_push (tree_vector_cache, vec); + } } } -- cgit v1.1 From 6b1695f4a094f99575c9d067da6277bb4302fb89 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 17 Nov 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/ChangeLog | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 6 +++ gcc/c-family/ChangeLog | 5 ++ gcc/cp/ChangeLog | 4 ++ gcc/fortran/ChangeLog | 60 ++++++++++++++++++++++ gcc/testsuite/ChangeLog | 94 ++++++++++++++++++++++++++++++++++ 7 files changed, 301 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 52de288..0fb2567 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,134 @@ +2021-11-16 Jan Hubicka + + * ipa-modref.c (get_modref_function_summary): Declare. + * ipa-modref.h (get_modref_function_summary): New function. + * tree-ssa-dse.c (clear_live_bytes_for_ref): Break out from ... + (clear_bytes_written_by): ... here; also clear memory killed by + calls. + +2021-11-16 Iain Sandoe + + * ggc-common.c (gt_pch_save): If we cannot find a suitable + memory segment for save, then error-out, do not try to + continue. + (gt_pch_restore): Save the existing line table, and when + the replacement is being read, use that when constructing + diagnostics. + +2021-11-16 Peter Bergner + + PR target/102976 + * config/rs6000/mma.md (*vsx_assemble_pair): Add early-clobber for + output operand. + (*mma_assemble_acc): Likewise. + +2021-11-16 Martin Sebor + + PR tree-optimization/102960 + * gimple-fold.c (get_range_strlen): Take bitmap as an argument rather + than a pointer to it. + (get_range_strlen_tree): Same. Remove bitmap allocation. Use + an auto_bitmap. + (get_maxval_strlen): Use an auto_bitmap. + * tree-ssa-strlen.c (get_range_strlen_dynamic): Factor out PHI + handling... + (get_range_strlen_phi): ...into this function. + Avoid assuming maximum string length is constant + (printf_strlen_execute): Dump pointer query cache contents when + details are requisted. + +2021-11-16 Jason Merrill + + * langhooks.h (struct lang_hooks): Adjust comment. + * print-tree.c (print_node): Also call print_xnode hook for + tcc_constant class. + +2021-11-16 Andrew Pinski + + PR tree-optimization/103218 + * match.pd: New pattern for "((type)(a<0)) << SIGNBITOFA". + +2021-11-16 Claudiu Zissulescu + + * config/arc/arc.md (maddhisi4): Use a single move to accumulator. + (umaddhisi4): Likewise. + (machi): Update pattern. + (umachi): Likewise. + +2021-11-16 Richard Biener + + PR tree-optimization/102880 + * tree-ssa-dce.c (sort_phi_args): New function. + (make_forwarders_with_degenerate_phis): Likewise. + (perform_tree_ssa_dce): Call + make_forwarders_with_degenerate_phis. + +2021-11-16 Richard Biener + + PR tree-optimization/102880 + * tree-ssa-phiopt.c (tree_ssa_phiopt_worker): Push + single_pred (bb1) condition to places that really need it. + (match_simplify_replacement): Likewise. + (value_replacement): Likewise. + (replace_phi_edge_with_variable): Deal with extra edges + into the middle BB. + +2021-11-16 Martin Jambor + + * cfgexpand.c (expand_gimple_basic_block): Use build_debug_expr_decl, + add a fixme note about the mode assignment perhaps being unnecessary. + * ipa-param-manipulation.c (ipa_param_adjustments::modify_call): + Likewise. + (ipa_param_body_adjustments::mark_dead_statements): Likewise. + (ipa_param_body_adjustments::reset_debug_stmts): Likewise. + * tree-inline.c (remap_ssa_name): Likewise. + (tree_function_versioning): Likewise. + * tree-into-ssa.c (rewrite_debug_stmt_uses): Likewise. + * tree-ssa-loop-ivopts.c (remove_unused_ivs): Likewise. + * tree-ssa.c (insert_debug_temp_for_var_def): Likewise. + +2021-11-16 Jakub Jelinek + + PR tree-optimization/103208 + * omp-expand.c (expand_omp_build_cond): New function. + (expand_omp_for_init_counts, expand_omp_for_init_vars, + expand_omp_for_static_nochunk, expand_omp_for_static_chunk): Use it. + +2021-11-16 Jakub Jelinek + + PR tree-optimization/102009 + * gimple-ssa-warn-access.cc (pass_waccess::check_alloc_size_call): + Punt if any of alloc_size arguments is out of bounds vs. number of + call arguments. + +2021-11-16 Roger Sayle + + * config/i386/i386.md (*bmi2_rorx_1): Make conditional + on !optimize_function_for_size_p. + (*3_1): Add preferred_for_size attribute. + (define_splits): Conditionalize on !optimize_function_for_size_p. + (*bmi2_rorxsi3_1_zext): Likewise. + (*si2_1_zext): Add preferred_for_size attribute. + (define_splits): Conditionalize on !optimize_function_for_size_p. + +2021-11-16 Jan Hubicka + + PR ipa/103262 + * ipa-modref.c (merge_call_side_effects): Fix uninitialized + access. + +2021-11-16 Andrew Pinski + + PR tree-optimization/103245 + * match.pd: Combine the abs pattern matching using multiplication. + Adding optional nop_convert too. + +2021-11-16 H.J. Lu + + PR middle-end/103268 + * tree-ssa-ccp.c (optimize_atomic_bit_test_and): Add a missing + return. + 2021-11-15 Siddhesh Poyarekar * gimple-fold.c (gimple_fold_builtin_strncat): Use ranges to diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 7090fb4..530e4a5 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20211116 +20211117 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 40678a1..be7b286 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,9 @@ +2021-11-16 David Malcolm + + PR analyzer/102662 + * constraint-manager.cc (bounded_range::operator==): Require the + types to be the same for equality. + 2021-11-13 David Malcolm * analyzer.opt (Wanalyzer-tainted-allocation-size): New. diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 7ed0102..c5ae8c1 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2021-11-16 Jason Merrill + + * c-common.c (release_tree_vector): Only cache vecs smaller than + 16 elements. + 2021-11-15 Jason Merrill * c.opt: Add -fimplicit-constexpr. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 61ce629..ac52e3b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,7 @@ +2021-11-16 Jason Merrill + + * ptree.c (cxx_print_xnode): Handle PTRMEM_CST. + 2021-11-15 Jason Merrill * cp-tree.h (struct lang_decl_fn): Add implicit_constexpr. diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 10dfca4..f5abad9 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,63 @@ +2021-11-16 Harald Anlauf + + PR fortran/103286 + * resolve.c (resolve_select): Choose appropriate range limit to + avoid NULL pointer dereference when generating error message. + +2021-11-16 Mikael Morin + + * interface.c (gfc_dummy_arg_get_name): New function. + * gfortran.h (gfc_dummy_arg_get_name): Declare it. + * trans-array.c (arg_evaluated_for_scalarization): Pass a dummy + argument wrapper as argument instead of an actual argument + and an index number. Check it’s non-NULL. Use its name + to identify it. + (gfc_walk_elemental_function_args): Update call to + arg_evaluated for scalarization. Remove argument counting. + +2021-11-16 Mikael Morin + + * gfortran.h (gfc_actual_arglist::missing_arg_type): Remove. + * interface.c (gfc_compare_actual_formal): Remove + missing_arg_type initialization. + * intrinsic.c (sort_actual): Ditto. + * trans-expr.c (gfc_conv_procedure_call): Use associated_dummy + and gfc_dummy_arg_get_typespec to get the dummy argument type. + +2021-11-16 Mikael Morin + + * interface.c (gfc_dummy_arg_get_typespec, + gfc_dummy_arg_is_optional): New functions. + * gfortran.h (gfc_dummy_arg_get_typespec, + gfc_dummy_arg_is_optional): Declare them. + * trans.h (gfc_ss_info::dummy_arg): Use the wrapper type + as declaration type. + * trans-array.c (gfc_scalar_elemental_arg_saved_as_reference): + use gfc_dummy_arg_get_typespec function to get the type. + (gfc_walk_elemental_function_args): Remove proc_ifc argument. + Get info about the dummy arg using the associated_dummy field. + * trans-array.h (gfc_walk_elemental_function_args): Update declaration. + * trans-intrinsic.c (gfc_walk_intrinsic_function): + Update call to gfc_walk_elemental_function_args. + * trans-stmt.c (gfc_trans_call): Ditto. + (get_proc_ifc_for_call): Remove. + +2021-11-16 Mikael Morin + + * gfortran.h (gfc_dummy_arg_kind, gfc_dummy_arg): New. + (gfc_actual_arglist): New field associated_dummy. + (gfc_intrinsic_arg): Remove field actual. + * interface.c (get_nonintrinsic_dummy_arg): New. + (gfc_compare_actual): Initialize associated_dummy. + * intrinsic.c (get_intrinsic_dummy_arg): New. + (sort_actual):  Add argument vectors. + Use loops with indices on argument vectors. + Initialize associated_dummy. + +2021-11-16 Mikael Morin + + * intrinsic.c (sort_actual): initialise variable and use it earlier. + 2021-11-15 Tobias Burnus * openmp.c (OMP_TARGET_CLAUSES): Add thread_limit. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b221cba..566c571 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,97 @@ +2021-11-16 Jan Hubicka + + * gcc.dg/tree-ssa/modref-dse-4.c: New test. + +2021-11-16 Harald Anlauf + + PR fortran/103286 + * gfortran.dg/pr103286.f90: New test. + +2021-11-16 Peter Bergner + + PR target/102976 + * gcc.target/powerpc/pr102976.c: New test. + +2021-11-16 Martin Sebor + + PR tree-optimization/102960 + * gcc.dg/Wstringop-overflow-84.c: New test. + +2021-11-16 Tamar Christina + + * gcc.target/aarch64/shrn-combine-10.c: Use shrn. + +2021-11-16 Tamar Christina + + * gcc.dg/signbit-2.c: CHeck vect or scalar. + +2021-11-16 David Malcolm + + PR analyzer/102662 + * g++.dg/analyzer/pr102662.C: New test. + +2021-11-16 Andrew Pinski + + PR tree-optimization/103218 + * gcc.dg/tree-ssa/pr103218-1.c: New test. + +2021-11-16 Claudiu Zissulescu + + * gcc.target/arc/tmac-4.c: New test. + +2021-11-16 Richard Biener + + PR tree-optimization/102880 + * gcc.dg/tree-ssa/pr102880.c: New testcase. + * gcc.dg/tree-ssa/pr69270-3.c: Robustify. + * gcc.dg/tree-ssa/ssa-dom-thread-7.c: Change the number of + expected threadings. + +2021-11-16 Richard Biener + + PR tree-optimization/102880 + * gcc.dg/tree-ssa/phi-opt-26.c: New testcase. + +2021-11-16 Claudiu Zissulescu + + * gcc.target/arc/add_n-combine.c: Update test patterns. + * gcc.target/arc/builtin_eh.c: Update test for linux platforms. + * gcc.target/arc/mul64-1.c: Disable this test while running on + linux. + * gcc.target/arc/tls-gd.c: Update matching patterns. + * gcc.target/arc/tls-ie.c: Likewise. + * gcc.target/arc/tls-ld.c: Likewise. + * gcc.target/arc/uncached-8.c: Likewise. + +2021-11-16 Martin Jambor + + * gcc.dg/ipa/ipa-sra-ret-nonull.c: New test. + +2021-11-16 Jakub Jelinek + + PR tree-optimization/103208 + * c-c++-common/gomp/loop-11.c: New test. + +2021-11-16 Jakub Jelinek + + PR tree-optimization/102009 + * gcc.dg/pr102009.c: New test. + +2021-11-16 Jan Hubicka + + * gcc.dg/tree-ssa/modref-dse-5.c: New test. + +2021-11-16 Andrew Pinski + + PR tree-optimization/103245 + * gcc.dg/tree-ssa/pr103245-1.c: New test. + +2021-11-16 H.J. Lu + + PR middle-end/103268 + * gcc.dg/pr103268-1.c: New test. + * gcc.dg/pr103268-2.c: Likewise. + 2021-11-15 Jason Merrill * lib/g++-dg.exp: Handle "impcx". -- cgit v1.1 From 8c693978dd64b16637577ebf50c760053d7d2165 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 17 Nov 2021 01:43:57 +0100 Subject: Fix clearing of to_info_lto in ipa_merge_modref_summary_after_inlining This patch fixes bug that caused some optimizations to be dropped with -fdump-ipa-inline. gcc/ChangeLog: 2021-11-17 Jan Hubicka PR ipa/103246 * ipa-modref.c (ipa_merge_modref_summary_after_inlining): Fix clearing of to_info_lto --- gcc/ipa-modref.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index a70575bc..90cd1be 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -5123,6 +5123,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) fprintf (dump_file, "Removed mod-ref summary for %s\n", to->dump_name ()); summaries_lto->remove (to); + to_info_lto = NULL; } else if (to_info_lto && dump_file) { @@ -5130,7 +5131,6 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) fprintf (dump_file, "Updated mod-ref summary for %s\n", to->dump_name ()); to_info_lto->dump (dump_file); - to_info_lto = NULL; } if (callee_info_lto) summaries_lto->remove (edge->callee); -- cgit v1.1 From a80d4e098b10d5cd161f55e4fce64a6be9683ed3 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Mon, 15 Nov 2021 18:23:08 -0500 Subject: analyzer: don't assume target has alloca [PR102779] gcc/testsuite/ChangeLog: PR analyzer/102779 * gcc.dg/analyzer/capacity-1.c: Add dg-require-effective-target alloca. Use __builtin_alloca rather than alloca. * gcc.dg/analyzer/capacity-3.c: Likewise. Signed-off-by: David Malcolm --- gcc/testsuite/gcc.dg/analyzer/capacity-1.c | 4 +++- gcc/testsuite/gcc.dg/analyzer/capacity-3.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/analyzer/capacity-1.c b/gcc/testsuite/gcc.dg/analyzer/capacity-1.c index 9ea41f7..2d12483 100644 --- a/gcc/testsuite/gcc.dg/analyzer/capacity-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/capacity-1.c @@ -1,3 +1,5 @@ +/* { dg-require-effective-target alloca } */ + #include #include "analyzer-decls.h" @@ -53,7 +55,7 @@ test_malloc (void) void test_alloca (size_t sz) { - void *p = alloca (sz); + void *p = __builtin_alloca (sz); __analyzer_dump_capacity (p); /* { dg-warning "capacity: 'INIT_VAL\\(sz_\[^\n\r\]*\\)'" } */ } diff --git a/gcc/testsuite/gcc.dg/analyzer/capacity-3.c b/gcc/testsuite/gcc.dg/analyzer/capacity-3.c index 41e282c..c099ff5 100644 --- a/gcc/testsuite/gcc.dg/analyzer/capacity-3.c +++ b/gcc/testsuite/gcc.dg/analyzer/capacity-3.c @@ -1,10 +1,12 @@ +/* { dg-require-effective-target alloca } */ + #include #include "analyzer-decls.h" static void __attribute__((noinline)) __analyzer_callee_1 (size_t inner_sz) { - void *p = alloca (inner_sz); + void *p = __builtin_alloca (inner_sz); __analyzer_dump_capacity (p); /* { dg-warning "capacity: 'INIT_VAL\\(outer_sz_\[^\n\r\]*\\)'" } */ } -- cgit v1.1 From 111fd515f2894d7cddf62f80c69765c43ae18577 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 16 Nov 2021 10:36:49 -0500 Subject: analyzer: fix missing -Wanalyzer-write-to-const [PR102695] This patch fixes -Wanalyzer-write-to-const so that it will complain about attempts to write to functions, to labels. It also "teaches" the analyzer about strchr, in that strchr can either return a pointer into the input area (and thus -Wanalyzer-write-to-const can now complain about writes into a string literal seen this way), or return NULL (and thus the analyzer can complain about NULL dereferences if the result is used without a check). gcc/analyzer/ChangeLog: PR analyzer/102695 * region-model-impl-calls.cc (region_model::impl_call_strchr): New. * region-model-manager.cc (region_model_manager::maybe_fold_unaryop): Simplify cast to pointer type of an existing pointer to a region. * region-model.cc (region_model::on_call_pre): Handle BUILT_IN_STRCHR and "strchr". (write_to_const_diagnostic::emit): Add auto_diagnostic_group. Add alternate wordings for functions and labels. (write_to_const_diagnostic::describe_final_event): Add alternate wordings for functions and labels. (region_model::check_for_writable_region): Handle RK_FUNCTION and RK_LABEL. * region-model.h (region_model::impl_call_strchr): New decl. gcc/testsuite/ChangeLog: PR analyzer/102695 * gcc.dg/analyzer/pr102695.c: New test. * gcc.dg/analyzer/strchr-1.c: New test. Signed-off-by: David Malcolm --- gcc/analyzer/region-model-impl-calls.cc | 69 ++++++++++++++++++++++++++++++++ gcc/analyzer/region-model-manager.cc | 7 ++++ gcc/analyzer/region-model.cc | 52 ++++++++++++++++++++++-- gcc/analyzer/region-model.h | 1 + gcc/testsuite/gcc.dg/analyzer/pr102695.c | 44 ++++++++++++++++++++ gcc/testsuite/gcc.dg/analyzer/strchr-1.c | 26 ++++++++++++ 6 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr102695.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/strchr-1.c (limited to 'gcc') diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc index 90d4cf9..ae50e69 100644 --- a/gcc/analyzer/region-model-impl-calls.cc +++ b/gcc/analyzer/region-model-impl-calls.cc @@ -678,6 +678,75 @@ region_model::impl_call_realloc (const call_details &cd) } } +/* Handle the on_call_pre part of "strchr" and "__builtin_strchr". */ + +void +region_model::impl_call_strchr (const call_details &cd) +{ + class strchr_call_info : public call_info + { + public: + strchr_call_info (const call_details &cd, bool found) + : call_info (cd), m_found (found) + { + } + + label_text get_desc (bool can_colorize) const FINAL OVERRIDE + { + if (m_found) + return make_label_text (can_colorize, + "when %qE returns non-NULL", + get_fndecl ()); + else + return make_label_text (can_colorize, + "when %qE returns NULL", + get_fndecl ()); + } + + bool update_model (region_model *model, + const exploded_edge *, + region_model_context *ctxt) const FINAL OVERRIDE + { + const call_details cd (get_call_details (model, ctxt)); + if (tree lhs_type = cd.get_lhs_type ()) + { + region_model_manager *mgr = model->get_manager (); + const svalue *result; + if (m_found) + { + const svalue *str_sval = cd.get_arg_svalue (0); + const region *str_reg + = model->deref_rvalue (str_sval, cd.get_arg_tree (0), + cd.get_ctxt ()); + /* We want str_sval + OFFSET for some unknown OFFSET. + Use a conjured_svalue to represent the offset, + using the str_reg as the id of the conjured_svalue. */ + const svalue *offset + = mgr->get_or_create_conjured_svalue (size_type_node, + cd.get_call_stmt (), + str_reg); + result = mgr->get_or_create_binop (lhs_type, POINTER_PLUS_EXPR, + str_sval, offset); + } + else + result = mgr->get_or_create_int_cst (lhs_type, 0); + cd.maybe_set_lhs (result); + } + return true; + } + private: + bool m_found; + }; + + /* Bifurcate state, creating a "not found" out-edge. */ + if (cd.get_ctxt ()) + cd.get_ctxt ()->bifurcate (new strchr_call_info (cd, false)); + + /* The "unbifurcated" state is the "found" case. */ + strchr_call_info found (cd, true); + found.update_model (this, NULL, cd.get_ctxt ()); +} + /* Handle the on_call_pre part of "strcpy" and "__builtin_strcpy_chk". */ void diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc index 1cdec1b..fdf3212 100644 --- a/gcc/analyzer/region-model-manager.cc +++ b/gcc/analyzer/region-model-manager.cc @@ -380,6 +380,13 @@ region_model_manager::maybe_fold_unaryop (tree type, enum tree_code op, == boolean_true_node)) return maybe_fold_unaryop (type, op, innermost_arg); } + /* Avoid creating symbolic regions for pointer casts by + simplifying (T*)(®ION) to ((T*)®ION). */ + if (const region_svalue *region_sval = arg->dyn_cast_region_svalue ()) + if (POINTER_TYPE_P (type) + && region_sval->get_type () + && POINTER_TYPE_P (region_sval->get_type ())) + return get_ptr_svalue (type, region_sval->get_pointee ()); } break; case TRUTH_NOT_EXPR: diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 416a5ac..bbb15ab 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -1133,6 +1133,9 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt, break; case BUILT_IN_REALLOC: return false; + case BUILT_IN_STRCHR: + impl_call_strchr (cd); + return false; case BUILT_IN_STRCPY: case BUILT_IN_STRCPY_CHK: impl_call_strcpy (cd); @@ -1225,6 +1228,12 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt, impl_call_memset (cd); return false; } + else if (is_named_call_p (callee_fndecl, "strchr", call, 2) + && POINTER_TYPE_P (cd.get_arg_type (0))) + { + impl_call_strchr (cd); + return false; + } else if (is_named_call_p (callee_fndecl, "strlen", call, 1) && POINTER_TYPE_P (cd.get_arg_type (0))) { @@ -2161,8 +2170,23 @@ public: bool emit (rich_location *rich_loc) FINAL OVERRIDE { - bool warned = warning_at (rich_loc, OPT_Wanalyzer_write_to_const, - "write to % object %qE", m_decl); + auto_diagnostic_group d; + bool warned; + switch (m_reg->get_kind ()) + { + default: + warned = warning_at (rich_loc, OPT_Wanalyzer_write_to_const, + "write to % object %qE", m_decl); + break; + case RK_FUNCTION: + warned = warning_at (rich_loc, OPT_Wanalyzer_write_to_const, + "write to function %qE", m_decl); + break; + case RK_LABEL: + warned = warning_at (rich_loc, OPT_Wanalyzer_write_to_const, + "write to label %qE", m_decl); + break; + } if (warned) inform (DECL_SOURCE_LOCATION (m_decl), "declared here"); return warned; @@ -2170,7 +2194,15 @@ public: label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE { - return ev.formatted_print ("write to % object %qE here", m_decl); + switch (m_reg->get_kind ()) + { + default: + return ev.formatted_print ("write to % object %qE here", m_decl); + case RK_FUNCTION: + return ev.formatted_print ("write to function %qE here", m_decl); + case RK_LABEL: + return ev.formatted_print ("write to label %qE here", m_decl); + } } private: @@ -2231,6 +2263,20 @@ region_model::check_for_writable_region (const region* dest_reg, { default: break; + case RK_FUNCTION: + { + const function_region *func_reg = as_a (base_reg); + tree fndecl = func_reg->get_fndecl (); + ctxt->warn (new write_to_const_diagnostic (func_reg, fndecl)); + } + break; + case RK_LABEL: + { + const label_region *label_reg = as_a (base_reg); + tree label = label_reg->get_label (); + ctxt->warn (new write_to_const_diagnostic (label_reg, label)); + } + break; case RK_DECL: { const decl_region *decl_reg = as_a (base_reg); diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 13e8109..5434011 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -586,6 +586,7 @@ class region_model void impl_call_memcpy (const call_details &cd); void impl_call_memset (const call_details &cd); void impl_call_realloc (const call_details &cd); + void impl_call_strchr (const call_details &cd); void impl_call_strcpy (const call_details &cd); void impl_call_strlen (const call_details &cd); void impl_call_operator_new (const call_details &cd); diff --git a/gcc/testsuite/gcc.dg/analyzer/pr102695.c b/gcc/testsuite/gcc.dg/analyzer/pr102695.c new file mode 100644 index 0000000..2ca9882 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/pr102695.c @@ -0,0 +1,44 @@ +extern void* malloc (__SIZE_TYPE__); + +const char* write_strchr_literal (int x) +{ + char *p = __builtin_strchr ("123", x); + *p = 0; /* { dg-warning "dereference of NULL 'p'" "null deref" } */ + /* { dg-warning "write to string literal" "string literal" { target *-*-* } .-1 } */ + return p; +} + +const char* write_strchr_const_array (int x) +{ + static const char a[] = "123"; + char *p = __builtin_strchr (a, x); + *p = 0; /* { dg-warning "dereference of NULL 'p'" "null deref" } */ + /* { dg-warning "write to 'const' object 'a'" "write to const" { target *-*-* } .-1 } */ + return a; +} + +char* write_function (void) +{ + char *p = (char*)malloc /* forgot arguments */; + p[1] = 'a'; /* { dg-warning "write to function 'malloc'" } */ + __builtin_strcpy (p, "123"); /* { dg-warning "write to function 'malloc'" } */ + return p; +} + +char* write_label (void) +{ + char *p = (char*)&&L; + *p = 0; /* { dg-warning "write to label 'L'" } */ +L: + return p; +} + +struct A { const int i; }; + +extern /* not const */ struct A a; + +void write_const_member (void) +{ + char *p = (char*)&a.i; + *p = 0; // missing warning +} diff --git a/gcc/testsuite/gcc.dg/analyzer/strchr-1.c b/gcc/testsuite/gcc.dg/analyzer/strchr-1.c new file mode 100644 index 0000000..dfe1bc9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/strchr-1.c @@ -0,0 +1,26 @@ +#include +#include "analyzer-decls.h" + +const char* test_literal (int x) +{ + char *p = __builtin_strchr ("123", x); + if (p) + { + __analyzer_eval (*p == x); /* { dg-message "UNKNOWN" } */ + /* TODO: this ought to be TRUE, but it's unclear that it's + worth stashing this constraint. */ + } + return p; +} + +void test_2 (const char *s, int c) +{ + char *p = __builtin_strchr (s, c); /* { dg-message "when '__builtin_strchr' returns NULL"} */ + *p = 'A'; /* { dg-warning "dereference of NULL 'p'" "null deref" } */ +} + +void test_3 (const char *s, int c) +{ + char *p = strchr (s, c); /* { dg-message "when 'strchr' returns NULL"} */ + *p = 'A'; /* { dg-warning "dereference of NULL 'p'" "null deref" } */ +} -- cgit v1.1 From 51c500269bf53749b107807d84271385fad35628 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 6 Oct 2021 14:33:59 -0400 Subject: libcpp: Implement -Wbidi-chars for CVE-2021-42574 [PR103026] From a link below: "An issue was discovered in the Bidirectional Algorithm in the Unicode Specification through 14.0. It permits the visual reordering of characters via control sequences, which can be used to craft source code that renders different logic than the logical ordering of tokens ingested by compilers and interpreters. Adversaries can leverage this to encode source code for compilers accepting Unicode such that targeted vulnerabilities are introduced invisibly to human reviewers." More info: https://nvd.nist.gov/vuln/detail/CVE-2021-42574 https://trojansource.codes/ This is not a compiler bug. However, to mitigate the problem, this patch implements -Wbidi-chars=[none|unpaired|any] to warn about possibly misleading Unicode bidirectional control characters the preprocessor may encounter. The default is =unpaired, which warns about improperly terminated bidirectional control characters; e.g. a LRE without its corresponding PDF. The level =any warns about any use of bidirectional control characters. This patch handles both UCNs and UTF-8 characters. UCNs designating bidi characters in identifiers are accepted since r204886. Then r217144 enabled -fextended-identifiers by default. Extended characters in C/C++ identifiers have been accepted since r275979. However, this patch still warns about mixing UTF-8 and UCN bidi characters; there seems to be no good reason to allow mixing them. We warn in different contexts: comments (both C and C++-style), string literals, character constants, and identifiers. Expectedly, UCNs are ignored in comments and raw string literals. The bidirectional control characters can nest so this patch handles that as well. I have not included nor tested this at all with Fortran (which also has string literals and line comments). Dave M. posted patches improving diagnostic involving Unicode characters. This patch does not make use of this new infrastructure yet. PR preprocessor/103026 gcc/c-family/ChangeLog: * c.opt (Wbidi-chars, Wbidi-chars=): New option. gcc/ChangeLog: * doc/invoke.texi: Document -Wbidi-chars. libcpp/ChangeLog: * include/cpplib.h (enum cpp_bidirectional_level): New. (struct cpp_options): Add cpp_warn_bidirectional. (enum cpp_warning_reason): Add CPP_W_BIDIRECTIONAL. * internal.h (struct cpp_reader): Add warn_bidi_p member function. * init.c (cpp_create_reader): Set cpp_warn_bidirectional. * lex.c (bidi): New namespace. (get_bidi_utf8): New function. (get_bidi_ucn): Likewise. (maybe_warn_bidi_on_close): Likewise. (maybe_warn_bidi_on_char): Likewise. (_cpp_skip_block_comment): Implement warning about bidirectional control characters. (skip_line_comment): Likewise. (forms_identifier_p): Likewise. (lex_identifier): Likewise. (lex_string): Likewise. (lex_raw_string): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/Wbidi-chars-1.c: New test. * c-c++-common/Wbidi-chars-2.c: New test. * c-c++-common/Wbidi-chars-3.c: New test. * c-c++-common/Wbidi-chars-4.c: New test. * c-c++-common/Wbidi-chars-5.c: New test. * c-c++-common/Wbidi-chars-6.c: New test. * c-c++-common/Wbidi-chars-7.c: New test. * c-c++-common/Wbidi-chars-8.c: New test. * c-c++-common/Wbidi-chars-9.c: New test. * c-c++-common/Wbidi-chars-10.c: New test. * c-c++-common/Wbidi-chars-11.c: New test. * c-c++-common/Wbidi-chars-12.c: New test. * c-c++-common/Wbidi-chars-13.c: New test. * c-c++-common/Wbidi-chars-14.c: New test. * c-c++-common/Wbidi-chars-15.c: New test. * c-c++-common/Wbidi-chars-16.c: New test. * c-c++-common/Wbidi-chars-17.c: New test. --- gcc/c-family/c.opt | 24 ++++ gcc/doc/invoke.texi | 21 +++- gcc/testsuite/c-c++-common/Wbidi-chars-1.c | 12 ++ gcc/testsuite/c-c++-common/Wbidi-chars-10.c | 27 ++++ gcc/testsuite/c-c++-common/Wbidi-chars-11.c | 13 ++ gcc/testsuite/c-c++-common/Wbidi-chars-12.c | 19 +++ gcc/testsuite/c-c++-common/Wbidi-chars-13.c | 17 +++ gcc/testsuite/c-c++-common/Wbidi-chars-14.c | 38 ++++++ gcc/testsuite/c-c++-common/Wbidi-chars-15.c | 59 +++++++++ gcc/testsuite/c-c++-common/Wbidi-chars-16.c | 26 ++++ gcc/testsuite/c-c++-common/Wbidi-chars-17.c | 30 +++++ gcc/testsuite/c-c++-common/Wbidi-chars-2.c | 9 ++ gcc/testsuite/c-c++-common/Wbidi-chars-3.c | 11 ++ gcc/testsuite/c-c++-common/Wbidi-chars-4.c | 188 ++++++++++++++++++++++++++++ gcc/testsuite/c-c++-common/Wbidi-chars-5.c | 188 ++++++++++++++++++++++++++++ gcc/testsuite/c-c++-common/Wbidi-chars-6.c | 155 +++++++++++++++++++++++ gcc/testsuite/c-c++-common/Wbidi-chars-7.c | 9 ++ gcc/testsuite/c-c++-common/Wbidi-chars-8.c | 13 ++ gcc/testsuite/c-c++-common/Wbidi-chars-9.c | 29 +++++ 19 files changed, 887 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-1.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-10.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-11.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-12.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-13.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-14.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-15.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-16.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-17.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-2.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-3.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-4.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-5.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-6.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-7.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-8.c create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-9.c (limited to 'gcc') diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 8a4cd63..3976fc3 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -374,6 +374,30 @@ Wbad-function-cast C ObjC Var(warn_bad_function_cast) Warning Warn about casting functions to incompatible types. +Wbidi-chars +C ObjC C++ ObjC++ Warning Alias(Wbidi-chars=,any,none) +; + +Wbidi-chars= +C ObjC C++ ObjC++ RejectNegative Joined Warning CPP(cpp_warn_bidirectional) CppReason(CPP_W_BIDIRECTIONAL) Var(warn_bidirectional) Init(bidirectional_unpaired) Enum(cpp_bidirectional_level) +-Wbidi-chars=[none|unpaired|any] Warn about UTF-8 bidirectional control characters. + +; Required for these enum values. +SourceInclude +cpplib.h + +Enum +Name(cpp_bidirectional_level) Type(int) UnknownError(argument %qs to %<-Wbidi-chars%> not recognized) + +EnumValue +Enum(cpp_bidirectional_level) String(none) Value(bidirectional_none) + +EnumValue +Enum(cpp_bidirectional_level) String(unpaired) Value(bidirectional_unpaired) + +EnumValue +Enum(cpp_bidirectional_level) String(any) Value(bidirectional_any) + Wbool-compare C ObjC C++ ObjC++ Var(warn_bool_compare) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) Warn about boolean expression compared with an integer value different from true/false. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 6070288..a22758d 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -327,7 +327,9 @@ Objective-C and Objective-C++ Dialects}. -Warith-conversion @gol -Warray-bounds -Warray-bounds=@var{n} -Warray-compare @gol -Wno-attributes -Wattribute-alias=@var{n} -Wno-attribute-alias @gol --Wno-attribute-warning -Wbool-compare -Wbool-operation @gol +-Wno-attribute-warning @gol +-Wbidi-chars=@r{[}none@r{|}unpaired@r{|}any@r{]} @gol +-Wbool-compare -Wbool-operation @gol -Wno-builtin-declaration-mismatch @gol -Wno-builtin-macro-redefined -Wc90-c99-compat -Wc99-c11-compat @gol -Wc11-c2x-compat @gol @@ -7678,6 +7680,23 @@ Attributes considered include @code{alloc_align}, @code{alloc_size}, This is the default. You can disable these warnings with either @option{-Wno-attribute-alias} or @option{-Wattribute-alias=0}. +@item -Wbidi-chars=@r{[}none@r{|}unpaired@r{|}any@r{]} +@opindex Wbidi-chars= +@opindex Wbidi-chars +@opindex Wno-bidi-chars +Warn about possibly misleading UTF-8 bidirectional control characters in +comments, string literals, character constants, and identifiers. Such +characters can change left-to-right writing direction into right-to-left +(and vice versa), which can cause confusion between the logical order and +visual order. This may be dangerous; for instance, it may seem that a piece +of code is not commented out, whereas it in fact is. + +There are three levels of warning supported by GCC@. The default is +@option{-Wbidi-chars=unpaired}, which warns about improperly terminated +bidi contexts. @option{-Wbidi-chars=none} turns the warning off. +@option{-Wbidi-chars=any} warns about any use of bidirectional control +characters. + @item -Wbool-compare @opindex Wno-bool-compare @opindex Wbool-compare diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-1.c b/gcc/testsuite/c-c++-common/Wbidi-chars-1.c new file mode 100644 index 0000000..34f5ac1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-1.c @@ -0,0 +1,12 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ + +int main() { + int isAdmin = 0; + /*‮ } ⁦if (isAdmin)⁩ ⁦ begin admins only */ +/* { dg-warning "bidirectional" "" { target *-*-* } .-1 } */ + __builtin_printf("You are an admin.\n"); + /* end admins only ‮ { ⁦*/ +/* { dg-warning "bidirectional" "" { target *-*-* } .-1 } */ + return 0; +} diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-10.c b/gcc/testsuite/c-c++-common/Wbidi-chars-10.c new file mode 100644 index 0000000..3f851b6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-10.c @@ -0,0 +1,27 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=unpaired" } */ +/* More nesting testing. */ + +/* RLE‫ LRI⁦ PDF‬ PDI⁩*/ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int LRE_\u202a_PDF_\u202c; +int LRE_\u202a_PDF_\u202c_LRE_\u202a_PDF_\u202c; +int LRE_\u202a_LRI_\u2066_PDF_\u202c_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int RLE_\u202b_RLI_\u2067_PDF_\u202c_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int RLE_\u202b_RLI_\u2067_PDI_\u2069_PDF_\u202c; +int FSI_\u2068_LRO_\u202d_PDI_\u2069_PDF_\u202c; +int FSI_\u2068; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int FSI_\u2068_PDI_\u2069; +int FSI_\u2068_FSI_\u2068_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDI_\u2069; +int RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDF_\u202c; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int RLI_\u2067_RLI_\u2067_RLI_\u2067_RLI_\u2067_FSI_\u2068_PDI_\u2069_PDI_\u2069_PDI_\u2069_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-11.c b/gcc/testsuite/c-c++-common/Wbidi-chars-11.c new file mode 100644 index 0000000..270ce23 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-11.c @@ -0,0 +1,13 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=unpaired" } */ +/* Test that we warn when mixing UCN and UTF-8. */ + +int LRE_‪_PDF_\u202c; +/* { dg-warning "mismatch" "" { target *-*-* } .-1 } */ +int LRE_\u202a_PDF_‬_; +/* { dg-warning "mismatch" "" { target *-*-* } .-1 } */ +const char *s1 = "LRE_‪_PDF_\u202c"; +/* { dg-warning "mismatch" "" { target *-*-* } .-1 } */ +const char *s2 = "LRE_\u202a_PDF_‬"; +/* { dg-warning "mismatch" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-12.c b/gcc/testsuite/c-c++-common/Wbidi-chars-12.c new file mode 100644 index 0000000..b07eec1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-12.c @@ -0,0 +1,19 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile { target { c || c++11 } } } */ +/* { dg-options "-Wbidi-chars=any" } */ +/* Test raw strings. */ + +const char *s1 = R"(a b c LRE‪ 1 2 3 PDF‬ x y z)"; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ +const char *s2 = R"(a b c RLE‫ 1 2 3 PDF‬ x y z)"; +/* { dg-warning "U\\+202B" "" { target *-*-* } .-1 } */ +const char *s3 = R"(a b c LRO‭ 1 2 3 PDF‬ x y z)"; +/* { dg-warning "U\\+202D" "" { target *-*-* } .-1 } */ +const char *s4 = R"(a b c RLO‮ 1 2 3 PDF‬ x y z)"; +/* { dg-warning "U\\+202E" "" { target *-*-* } .-1 } */ +const char *s7 = R"(a b c FSI⁨ 1 2 3 PDI⁩ x y) z"; +/* { dg-warning "U\\+2068" "" { target *-*-* } .-1 } */ +const char *s8 = R"(a b c PDI⁩ x y )z"; +/* { dg-warning "U\\+2069" "" { target *-*-* } .-1 } */ +const char *s9 = R"(a b c PDF‬ x y z)"; +/* { dg-warning "U\\+202C" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-13.c b/gcc/testsuite/c-c++-common/Wbidi-chars-13.c new file mode 100644 index 0000000..b2dd9fd --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-13.c @@ -0,0 +1,17 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile { target { c || c++11 } } } */ +/* { dg-options "-Wbidi-chars=unpaired" } */ +/* Test raw strings. */ + +const char *s1 = R"(a b c LRE‪ 1 2 3)"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +const char *s2 = R"(a b c RLE‫ 1 2 3)"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +const char *s3 = R"(a b c LRO‭ 1 2 3)"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +const char *s4 = R"(a b c FSI⁨ 1 2 3)"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +const char *s5 = R"(a b c LRI⁦ 1 2 3)"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +const char *s6 = R"(a b c RLI⁧ 1 2 3)"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-14.c b/gcc/testsuite/c-c++-common/Wbidi-chars-14.c new file mode 100644 index 0000000..ba5f75d --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-14.c @@ -0,0 +1,38 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=unpaired" } */ +/* Test PDI handling, which also pops any subsequent LREs, RLEs, LROs, + or RLOs. */ + +/* LRI_⁦_LRI_⁦_RLE_‫_RLE_‫_RLE_‫_PDI_⁩*/ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +// LRI_⁦_RLE_‫_RLE_‫_RLE_‫_PDI_⁩ +// LRI_⁦_RLO_‮_RLE_‫_RLE_‫_PDI_⁩ +// LRI_⁦_RLO_‮_RLE_‫_PDI_⁩ +// FSI_⁨_RLO_‮_PDI_⁩ +// FSI_⁨_FSI_⁨_RLO_‮_PDI_⁩ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + +int LRI_\u2066_LRI_\u2066_LRE_\u202a_LRE_\u202a_LRE_\u202a_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int LRI_\u2066_LRI_\u2066_LRE_\u202a_LRE_\u202a_LRE_\u202a_PDI_\u2069_PDI_\u2069; +int LRI_\u2066_LRI_\u2066_LRI_\u2066_LRE_\u202a_LRE_\u202a_LRE_\u202a_PDI_\u2069_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int PDI_\u2069; +int LRI_\u2066_PDI_\u2069; +int RLI_\u2067_PDI_\u2069; +int LRE_\u202a_LRI_\u2066_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int LRI_\u2066_LRE_\u202a_PDF_\u202c_PDI_\u2069; +int LRI_\u2066_LRE_\u202a_LRE_\u202a_PDF_\u202c_PDI_\u2069; +int RLI_\u2067_LRI_\u2066_LRE_\u202a_LRE_\u202a_PDF_\u202c_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int FSI_\u2068_LRI_\u2066_LRE_\u202a_LRE_\u202a_PDF_\u202c_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int RLO_\u202e_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int RLI_\u2067_PDI_\u2069_RLI_\u2067; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int FSI_\u2068_PDF_\u202c_PDI_\u2069; +int FSI_\u2068_FSI_\u2068_PDF_\u202c_PDI_\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-15.c b/gcc/testsuite/c-c++-common/Wbidi-chars-15.c new file mode 100644 index 0000000..a0ce8ff --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-15.c @@ -0,0 +1,59 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=unpaired" } */ +/* Test unpaired bidi control chars in multiline comments. */ + +/* + * LRE‪ end + */ +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ +/* + * RLE‫ end + */ +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ +/* + * LRO‭ end + */ +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ +/* + * RLO‮ end + */ +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ +/* + * LRI⁦ end + */ +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ +/* + * RLI⁧ end + */ +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ +/* + * FSI⁨ end + */ +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ +/* LRE‪ + PDF‬ */ +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ +/* FSI⁨ + PDI⁩ */ +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ + +/* LRE<‪> + * + */ +/* { dg-warning "unpaired" "" { target *-*-* } .-3 } */ + +/* + * LRE<‪> + */ +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ + +/* + * + * LRE<‪> */ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + +/* RLI<⁧> */ /* PDI<⁩> */ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* LRE<‪> */ /* PDF<‬> */ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-16.c b/gcc/testsuite/c-c++-common/Wbidi-chars-16.c new file mode 100644 index 0000000..baa0159 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-16.c @@ -0,0 +1,26 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=any" } */ +/* Test LTR/RTL chars. */ + +/* LTR<‎> */ +/* { dg-warning "U\\+200E" "" { target *-*-* } .-1 } */ +// LTR<‎> +/* { dg-warning "U\\+200E" "" { target *-*-* } .-1 } */ +/* RTL<‏> */ +/* { dg-warning "U\\+200F" "" { target *-*-* } .-1 } */ +// RTL<‏> +/* { dg-warning "U\\+200F" "" { target *-*-* } .-1 } */ + +const char *s1 = "LTR<‎>"; +/* { dg-warning "U\\+200E" "" { target *-*-* } .-1 } */ +const char *s2 = "LTR\u200e"; +/* { dg-warning "U\\+200E" "" { target *-*-* } .-1 } */ +const char *s3 = "LTR\u200E"; +/* { dg-warning "U\\+200E" "" { target *-*-* } .-1 } */ +const char *s4 = "RTL<‏>"; +/* { dg-warning "U\\+200F" "" { target *-*-* } .-1 } */ +const char *s5 = "RTL\u200f"; +/* { dg-warning "U\\+200F" "" { target *-*-* } .-1 } */ +const char *s6 = "RTL\u200F"; +/* { dg-warning "U\\+200F" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-17.c b/gcc/testsuite/c-c++-common/Wbidi-chars-17.c new file mode 100644 index 0000000..07cb432 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-17.c @@ -0,0 +1,30 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=unpaired" } */ +/* Test LTR/RTL chars. */ + +/* LTR<‎> */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +// LTR<‎> +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +/* RTL<‏> */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +// RTL<‏> +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int ltr_\u200e; +/* { dg-error "universal character " "" { target *-*-* } .-1 } */ +int rtl_\u200f; +/* { dg-error "universal character " "" { target *-*-* } .-1 } */ + +const char *s1 = "LTR<‎>"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +const char *s2 = "LTR\u200e"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +const char *s3 = "LTR\u200E"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +const char *s4 = "RTL<‏>"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +const char *s5 = "RTL\u200f"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +const char *s6 = "RTL\u200F"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-2.c b/gcc/testsuite/c-c++-common/Wbidi-chars-2.c new file mode 100644 index 0000000..2340374 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-2.c @@ -0,0 +1,9 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ + +int main() { + /* Say hello; newline⁧/*/ return 0 ; +/* { dg-warning "bidirectional" "" { target *-*-* } .-1 } */ + __builtin_printf("Hello world.\n"); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-3.c b/gcc/testsuite/c-c++-common/Wbidi-chars-3.c new file mode 100644 index 0000000..9dc7edb --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-3.c @@ -0,0 +1,11 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ + +int main() { + const char* access_level = "user"; + if (__builtin_strcmp(access_level, "user‮ ⁦// Check if admin⁩ ⁦")) { +/* { dg-warning "bidirectional" "" { target *-*-* } .-1 } */ + __builtin_printf("You are an admin.\n"); + } + return 0; +} diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-4.c b/gcc/testsuite/c-c++-common/Wbidi-chars-4.c new file mode 100644 index 0000000..639e5c6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-4.c @@ -0,0 +1,188 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=any -Wno-multichar -Wno-overflow" } */ +/* Test all bidi chars in various contexts (identifiers, comments, + string literals, character constants), both UCN and UTF-8. The bidi + chars here are properly terminated, except for the character constants. */ + +/* a b c LRE‪ 1 2 3 PDF‬ x y z */ +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ +/* a b c RLE‫ 1 2 3 PDF‬ x y z */ +/* { dg-warning "U\\+202B" "" { target *-*-* } .-1 } */ +/* a b c LRO‭ 1 2 3 PDF‬ x y z */ +/* { dg-warning "U\\+202D" "" { target *-*-* } .-1 } */ +/* a b c RLO‮ 1 2 3 PDF‬ x y z */ +/* { dg-warning "U\\+202E" "" { target *-*-* } .-1 } */ +/* a b c LRI⁦ 1 2 3 PDI⁩ x y z */ +/* { dg-warning "U\\+2066" "" { target *-*-* } .-1 } */ +/* a b c RLI⁧ 1 2 3 PDI⁩ x y */ +/* { dg-warning "U\\+2067" "" { target *-*-* } .-1 } */ +/* a b c FSI⁨ 1 2 3 PDI⁩ x y z */ +/* { dg-warning "U\\+2068" "" { target *-*-* } .-1 } */ + +/* Same but C++ comments instead. */ +// a b c LRE‪ 1 2 3 PDF‬ x y z +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ +// a b c RLE‫ 1 2 3 PDF‬ x y z +/* { dg-warning "U\\+202B" "" { target *-*-* } .-1 } */ +// a b c LRO‭ 1 2 3 PDF‬ x y z +/* { dg-warning "U\\+202D" "" { target *-*-* } .-1 } */ +// a b c RLO‮ 1 2 3 PDF‬ x y z +/* { dg-warning "U\\+202E" "" { target *-*-* } .-1 } */ +// a b c LRI⁦ 1 2 3 PDI⁩ x y z +/* { dg-warning "U\\+2066" "" { target *-*-* } .-1 } */ +// a b c RLI⁧ 1 2 3 PDI⁩ x y +/* { dg-warning "U\\+2067" "" { target *-*-* } .-1 } */ +// a b c FSI⁨ 1 2 3 PDI⁩ x y z +/* { dg-warning "U\\+2068" "" { target *-*-* } .-1 } */ + +/* Here we're closing an unopened context, warn when =any. */ +/* a b c PDI⁩ x y z */ +/* { dg-warning "U\\+2069" "" { target *-*-* } .-1 } */ +/* a b c PDF‬ x y z */ +/* { dg-warning "U\\+202C" "" { target *-*-* } .-1 } */ +// a b c PDI⁩ x y z +/* { dg-warning "U\\+2069" "" { target *-*-* } .-1 } */ +// a b c PDF‬ x y z +/* { dg-warning "U\\+202C" "" { target *-*-* } .-1 } */ + +/* Multiline comments. */ +/* a b c PDI⁩ x y z + */ +/* { dg-warning "U\\+2069" "" { target *-*-* } .-2 } */ +/* a b c PDF‬ x y z + */ +/* { dg-warning "U\\+202C" "" { target *-*-* } .-2 } */ +/* first + a b c PDI⁩ x y z + */ +/* { dg-warning "U\\+2069" "" { target *-*-* } .-2 } */ +/* first + a b c PDF‬ x y z + */ +/* { dg-warning "U\\+202C" "" { target *-*-* } .-2 } */ +/* first + a b c PDI⁩ x y z */ +/* { dg-warning "U\\+2069" "" { target *-*-* } .-1 } */ +/* first + a b c PDF‬ x y z */ +/* { dg-warning "U\\+202C" "" { target *-*-* } .-1 } */ + +void +g1 () +{ + const char *s1 = "a b c LRE‪ 1 2 3 PDF‬ x y z"; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ + const char *s2 = "a b c RLE‫ 1 2 3 PDF‬ x y z"; +/* { dg-warning "U\\+202B" "" { target *-*-* } .-1 } */ + const char *s3 = "a b c LRO‭ 1 2 3 PDF‬ x y z"; +/* { dg-warning "U\\+202D" "" { target *-*-* } .-1 } */ + const char *s4 = "a b c RLO‮ 1 2 3 PDF‬ x y z"; +/* { dg-warning "U\\+202E" "" { target *-*-* } .-1 } */ + const char *s5 = "a b c LRI⁦ 1 2 3 PDI⁩ x y z"; +/* { dg-warning "U\\+2066" "" { target *-*-* } .-1 } */ + const char *s6 = "a b c RLI⁧ 1 2 3 PDI⁩ x y z"; +/* { dg-warning "U\\+2067" "" { target *-*-* } .-1 } */ + const char *s7 = "a b c FSI⁨ 1 2 3 PDI⁩ x y z"; +/* { dg-warning "U\\+2068" "" { target *-*-* } .-1 } */ + const char *s8 = "a b c PDI⁩ x y z"; +/* { dg-warning "U\\+2069" "" { target *-*-* } .-1 } */ + const char *s9 = "a b c PDF‬ x y z"; +/* { dg-warning "U\\+202C" "" { target *-*-* } .-1 } */ + + const char *s10 = "a b c LRE\u202a 1 2 3 PDF\u202c x y z"; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ + const char *s11 = "a b c LRE\u202A 1 2 3 PDF\u202c x y z"; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ + const char *s12 = "a b c RLE\u202b 1 2 3 PDF\u202c x y z"; +/* { dg-warning "U\\+202B" "" { target *-*-* } .-1 } */ + const char *s13 = "a b c RLE\u202B 1 2 3 PDF\u202c x y z"; +/* { dg-warning "U\\+202B" "" { target *-*-* } .-1 } */ + const char *s14 = "a b c LRO\u202d 1 2 3 PDF\u202c x y z"; +/* { dg-warning "U\\+202D" "" { target *-*-* } .-1 } */ + const char *s15 = "a b c LRO\u202D 1 2 3 PDF\u202c x y z"; +/* { dg-warning "U\\+202D" "" { target *-*-* } .-1 } */ + const char *s16 = "a b c RLO\u202e 1 2 3 PDF\u202c x y z"; +/* { dg-warning "U\\+202E" "" { target *-*-* } .-1 } */ + const char *s17 = "a b c RLO\u202E 1 2 3 PDF\u202c x y z"; +/* { dg-warning "U\\+202E" "" { target *-*-* } .-1 } */ + const char *s18 = "a b c LRI\u2066 1 2 3 PDI\u2069 x y z"; +/* { dg-warning "U\\+2066" "" { target *-*-* } .-1 } */ + const char *s19 = "a b c RLI\u2067 1 2 3 PDI\u2069 x y z"; +/* { dg-warning "U\\+2067" "" { target *-*-* } .-1 } */ + const char *s20 = "a b c FSI\u2068 1 2 3 PDI\u2069 x y z"; +/* { dg-warning "U\\+2068" "" { target *-*-* } .-1 } */ +} + +void +g2 () +{ + const char c1 = '\u202a'; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ + const char c2 = '\u202A'; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ + const char c3 = '\u202b'; +/* { dg-warning "U\\+202B" "" { target *-*-* } .-1 } */ + const char c4 = '\u202B'; +/* { dg-warning "U\\+202B" "" { target *-*-* } .-1 } */ + const char c5 = '\u202d'; +/* { dg-warning "U\\+202D" "" { target *-*-* } .-1 } */ + const char c6 = '\u202D'; +/* { dg-warning "U\\+202D" "" { target *-*-* } .-1 } */ + const char c7 = '\u202e'; +/* { dg-warning "U\\+202E" "" { target *-*-* } .-1 } */ + const char c8 = '\u202E'; +/* { dg-warning "U\\+202E" "" { target *-*-* } .-1 } */ + const char c9 = '\u2066'; +/* { dg-warning "U\\+2066" "" { target *-*-* } .-1 } */ + const char c10 = '\u2067'; +/* { dg-warning "U\\+2067" "" { target *-*-* } .-1 } */ + const char c11 = '\u2068'; +/* { dg-warning "U\\+2068" "" { target *-*-* } .-1 } */ +} + +int a‪b‬c; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ +int a‫b‬c; +/* { dg-warning "U\\+202B" "" { target *-*-* } .-1 } */ +int a‭b‬c; +/* { dg-warning "U\\+202D" "" { target *-*-* } .-1 } */ +int a‮b‬c; +/* { dg-warning "U\\+202E" "" { target *-*-* } .-1 } */ +int a⁦b⁩c; +/* { dg-warning "U\\+2066" "" { target *-*-* } .-1 } */ +int a⁧b⁩c; +/* { dg-warning "U\\+2067" "" { target *-*-* } .-1 } */ +int a⁨b⁩c; +/* { dg-warning "U\\+2068" "" { target *-*-* } .-1 } */ +int A‬X; +/* { dg-warning "U\\+202C" "" { target *-*-* } .-1 } */ +int A\u202cY; +/* { dg-warning "U\\+202C" "" { target *-*-* } .-1 } */ +int A\u202CY2; +/* { dg-warning "U\\+202C" "" { target *-*-* } .-1 } */ + +int d\u202ae\u202cf; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ +int d\u202Ae\u202cf2; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ +int d\u202be\u202cf; +/* { dg-warning "U\\+202B" "" { target *-*-* } .-1 } */ +int d\u202Be\u202cf2; +/* { dg-warning "U\\+202B" "" { target *-*-* } .-1 } */ +int d\u202de\u202cf; +/* { dg-warning "U\\+202D" "" { target *-*-* } .-1 } */ +int d\u202De\u202cf2; +/* { dg-warning "U\\+202D" "" { target *-*-* } .-1 } */ +int d\u202ee\u202cf; +/* { dg-warning "U\\+202E" "" { target *-*-* } .-1 } */ +int d\u202Ee\u202cf2; +/* { dg-warning "U\\+202E" "" { target *-*-* } .-1 } */ +int d\u2066e\u2069f; +/* { dg-warning "U\\+2066" "" { target *-*-* } .-1 } */ +int d\u2067e\u2069f; +/* { dg-warning "U\\+2067" "" { target *-*-* } .-1 } */ +int d\u2068e\u2069f; +/* { dg-warning "U\\+2068" "" { target *-*-* } .-1 } */ +int X\u2069; +/* { dg-warning "U\\+2069" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-5.c b/gcc/testsuite/c-c++-common/Wbidi-chars-5.c new file mode 100644 index 0000000..68cb053 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-5.c @@ -0,0 +1,188 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=unpaired -Wno-multichar -Wno-overflow" } */ +/* Test all bidi chars in various contexts (identifiers, comments, + string literals, character constants), both UCN and UTF-8. The bidi + chars here are properly terminated, except for the character constants. */ + +/* a b c LRE‪ 1 2 3 PDF‬ x y z */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +/* a b c RLE‫ 1 2 3 PDF‬ x y z */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +/* a b c LRO‭ 1 2 3 PDF‬ x y z */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +/* a b c RLO‮ 1 2 3 PDF‬ x y z */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +/* a b c LRI⁦ 1 2 3 PDI⁩ x y z */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +/* a b c RLI⁧ 1 2 3 PDI⁩ x y */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +/* a b c FSI⁨ 1 2 3 PDI⁩ x y z */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + +/* Same but C++ comments instead. */ +// a b c LRE‪ 1 2 3 PDF‬ x y z +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +// a b c RLE‫ 1 2 3 PDF‬ x y z +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +// a b c LRO‭ 1 2 3 PDF‬ x y z +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +// a b c RLO‮ 1 2 3 PDF‬ x y z +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +// a b c LRI⁦ 1 2 3 PDI⁩ x y z +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +// a b c RLI⁧ 1 2 3 PDI⁩ x y +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +// a b c FSI⁨ 1 2 3 PDI⁩ x y z +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + +/* Here we're closing an unopened context, warn when =any. */ +/* a b c PDI⁩ x y z */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +/* a b c PDF‬ x y z */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +// a b c PDI⁩ x y z +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +// a b c PDF‬ x y z +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + +/* Multiline comments. */ +/* a b c PDI⁩ x y z + */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-2 } */ +/* a b c PDF‬ x y z + */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-2 } */ +/* first + a b c PDI⁩ x y z + */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-2 } */ +/* first + a b c PDF‬ x y z + */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-2 } */ +/* first + a b c PDI⁩ x y z */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +/* first + a b c PDF‬ x y z */ +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + +void +g1 () +{ + const char *s1 = "a b c LRE‪ 1 2 3 PDF‬ x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s2 = "a b c RLE‫ 1 2 3 PDF‬ x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s3 = "a b c LRO‭ 1 2 3 PDF‬ x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s4 = "a b c RLO‮ 1 2 3 PDF‬ x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s5 = "a b c LRI⁦ 1 2 3 PDI⁩ x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s6 = "a b c RLI⁧ 1 2 3 PDI⁩ x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s7 = "a b c FSI⁨ 1 2 3 PDI⁩ x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s8 = "a b c PDI⁩ x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s9 = "a b c PDF‬ x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + + const char *s10 = "a b c LRE\u202a 1 2 3 PDF\u202c x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s11 = "a b c LRE\u202A 1 2 3 PDF\u202c x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s12 = "a b c RLE\u202b 1 2 3 PDF\u202c x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s13 = "a b c RLE\u202B 1 2 3 PDF\u202c x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s14 = "a b c LRO\u202d 1 2 3 PDF\u202c x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s15 = "a b c LRO\u202D 1 2 3 PDF\u202c x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s16 = "a b c RLO\u202e 1 2 3 PDF\u202c x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s17 = "a b c RLO\u202E 1 2 3 PDF\u202c x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s18 = "a b c LRI\u2066 1 2 3 PDI\u2069 x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s19 = "a b c RLI\u2067 1 2 3 PDI\u2069 x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + const char *s20 = "a b c FSI\u2068 1 2 3 PDI\u2069 x y z"; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +} + +void +g2 () +{ + const char c1 = '\u202a'; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char c2 = '\u202A'; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char c3 = '\u202b'; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char c4 = '\u202B'; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char c5 = '\u202d'; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char c6 = '\u202D'; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char c7 = '\u202e'; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char c8 = '\u202E'; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char c9 = '\u2066'; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char c10 = '\u2067'; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char c11 = '\u2068'; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +} + +int a‪b‬c; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int a‫b‬c; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int a‭b‬c; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int a‮b‬c; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int a⁦b⁩c; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int a⁧b⁩c; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int a⁨b⁩c; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int A‬X; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int A\u202cY; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int A\u202CY2; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ + +int d\u202ae\u202cf; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int d\u202Ae\u202cf2; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int d\u202be\u202cf; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int d\u202Be\u202cf2; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int d\u202de\u202cf; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int d\u202De\u202cf2; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int d\u202ee\u202cf; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int d\u202Ee\u202cf2; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int d\u2066e\u2069f; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int d\u2067e\u2069f; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int d\u2068e\u2069f; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ +int X\u2069; +/* { dg-bogus "unpaired" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-6.c b/gcc/testsuite/c-c++-common/Wbidi-chars-6.c new file mode 100644 index 0000000..0ce6fff --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-6.c @@ -0,0 +1,155 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=unpaired" } */ +/* Test nesting of bidi chars in various contexts. */ + +/* Terminated by the wrong char: */ +/* a b c LRE‪ 1 2 3 PDI⁩ x y z */ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* a b c RLE‫ 1 2 3 PDI⁩ x y z*/ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* a b c LRO‭ 1 2 3 PDI⁩ x y z */ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* a b c RLO‮ 1 2 3 PDI⁩ x y z */ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* a b c LRI⁦ 1 2 3 PDF‬ x y z */ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* a b c RLI⁧ 1 2 3 PDF‬ x y z */ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* a b c FSI⁨ 1 2 3 PDF‬ x y z*/ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + +/* LRE‪ PDF‬ */ +/* LRE‪ LRE‪ PDF‬ PDF‬ */ +/* PDF‬ LRE‪ PDF‬ */ +/* LRE‪ PDF‬ LRE‪ PDF‬ */ +/* LRE‪ LRE‪ PDF‬ */ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* PDF‬ LRE‪ */ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + +// a b c LRE‪ 1 2 3 PDI⁩ x y z +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +// a b c RLE‫ 1 2 3 PDI⁩ x y z*/ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +// a b c LRO‭ 1 2 3 PDI⁩ x y z +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +// a b c RLO‮ 1 2 3 PDI⁩ x y z +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +// a b c LRI⁦ 1 2 3 PDF‬ x y z +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +// a b c RLI⁧ 1 2 3 PDF‬ x y z +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +// a b c FSI⁨ 1 2 3 PDF‬ x y z +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + +// LRE‪ PDF‬ +// LRE‪ LRE‪ PDF‬ PDF‬ +// PDF‬ LRE‪ PDF‬ +// LRE‪ PDF‬ LRE‪ PDF‬ +// LRE‪ LRE‪ PDF‬ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +// PDF‬ LRE‪ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + +void +g1 () +{ + const char *s1 = "a b c LRE‪ 1 2 3 PDI⁩ x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s2 = "a b c LRE\u202a 1 2 3 PDI\u2069 x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s3 = "a b c RLE‫ 1 2 3 PDI⁩ x y "; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s4 = "a b c RLE\u202b 1 2 3 PDI\u2069 x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s5 = "a b c LRO‭ 1 2 3 PDI⁩ x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s6 = "a b c LRO\u202d 1 2 3 PDI\u2069 x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s7 = "a b c RLO‮ 1 2 3 PDI⁩ x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s8 = "a b c RLO\u202e 1 2 3 PDI\u2069 x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s9 = "a b c LRI⁦ 1 2 3 PDF‬ x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s10 = "a b c LRI\u2066 1 2 3 PDF\u202c x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s11 = "a b c RLI⁧ 1 2 3 PDF‬ x y z\ + "; +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ + const char *s12 = "a b c RLI\u2067 1 2 3 PDF\u202c x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s13 = "a b c FSI⁨ 1 2 3 PDF‬ x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s14 = "a b c FSI\u2068 1 2 3 PDF\u202c x y z"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s15 = "PDF‬ LRE‪"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s16 = "PDF\u202c LRE\u202a"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s17 = "LRE‪ PDF‬"; + const char *s18 = "LRE\u202a PDF\u202c"; + const char *s19 = "LRE‪ LRE‪ PDF‬ PDF‬"; + const char *s20 = "LRE\u202a LRE\u202a PDF\u202c PDF\u202c"; + const char *s21 = "PDF‬ LRE‪ PDF‬"; + const char *s22 = "PDF\u202c LRE\u202a PDF\u202c"; + const char *s23 = "LRE‪ LRE‪ PDF‬"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s24 = "LRE\u202a LRE\u202a PDF\u202c"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s25 = "PDF‬ LRE‪"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s26 = "PDF\u202c LRE\u202a"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s27 = "PDF‬ LRE\u202a"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + const char *s28 = "PDF\u202c LRE‪"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +} + +int aLRE‪bPDI⁩; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int A\u202aB\u2069C; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int aRLE‫bPDI⁩; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int a\u202bB\u2069c; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int aLRO‭bPDI⁩; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int a\u202db\u2069c2; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int aRLO‮bPDI⁩; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int a\u202eb\u2069; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int aLRI⁦bPDF‬; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int a\u2066b\u202c; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int aRLI⁧bPDF‬c +; +/* { dg-warning "unpaired" "" { target *-*-* } .-2 } */ +int a\u2067b\u202c; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int aFSI⁨bPDF‬; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int a\u2068b\u202c; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int aFSI⁨bPD\u202C; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int aFSI\u2068bPDF‬_; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int aLRE‪bPDF‬b; +int A\u202aB\u202c; +int a_LRE‪_LRE‪_b_PDF‬_PDF‬; +int A\u202aA\u202aB\u202cB\u202c; +int aPDF‬bLREadPDF‬; +int a_\u202C_\u202a_\u202c; +int a_LRE‪_b_PDF‬_c_LRE‪_PDF‬; +int a_\u202a_\u202c_\u202a_\u202c_; +int a_LRE‪_b_PDF‬_c_LRE‪; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int a_\u202a_\u202c_\u202a_; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-7.c b/gcc/testsuite/c-c++-common/Wbidi-chars-7.c new file mode 100644 index 0000000..d012d42 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-7.c @@ -0,0 +1,9 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=any" } */ +/* Test we ignore UCNs in comments. */ + +// a b c \u202a 1 2 3 +// a b c \u202A 1 2 3 +/* a b c \u202a 1 2 3 */ +/* a b c \u202A 1 2 3 */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-8.c b/gcc/testsuite/c-c++-common/Wbidi-chars-8.c new file mode 100644 index 0000000..4f54c50 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-8.c @@ -0,0 +1,13 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=any" } */ +/* Test \u vs \U. */ + +int a_\u202A; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ +int a_\u202a_2; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ +int a_\U0000202A_3; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ +int a_\U0000202a_4; +/* { dg-warning "U\\+202A" "" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-9.c b/gcc/testsuite/c-c++-common/Wbidi-chars-9.c new file mode 100644 index 0000000..e2af1b1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-9.c @@ -0,0 +1,29 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=unpaired" } */ +/* Test that we properly separate bidi contexts (comment/identifier/character + constant/string literal). */ + +/* LRE ->‪<- */ int pdf_\u202c_1; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* RLE ->‫<- */ int pdf_\u202c_2; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* LRO ->‭<- */ int pdf_\u202c_3; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* RLO ->‮<- */ int pdf_\u202c_4; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* LRI ->⁦<-*/ int pdi_\u2069_1; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* RLI ->⁧<- */ int pdi_\u2069_12; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* FSI ->⁨<- */ int pdi_\u2069_3; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ + +const char *s1 = "LRE\u202a"; /* PDF ->‬<- */ +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +/* LRE ->‪<- */ const char *s2 = "PDF\u202c"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +const char *s3 = "LRE\u202a"; int pdf_\u202c_5; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ +int lre_\u202a; const char *s4 = "PDF\u202c"; +/* { dg-warning "unpaired" "" { target *-*-* } .-1 } */ -- cgit v1.1 From b8ce19bb1a0592051e8f9a4c3252d12ae605b256 Mon Sep 17 00:00:00 2001 From: Kewen Lin Date: Tue, 16 Nov 2021 23:55:01 -0600 Subject: visium: Fix non-robust split condition in define_insn_and_split This patch is to fix some non-robust split conditions in some define_insn_and_splits, to make each of them applied on top of the corresponding condition for define_insn part, otherwise the splitting could perform unexpectedly. gcc/ChangeLog: * config/visium/visium.md (*add3_insn, *addsi3_insn, *addi3_insn, *sub3_insn, *subsi3_insn, *subdi3_insn, *neg2_insn, *negdi2_insn, *and3_insn, *ior3_insn, *xor3_insn, *one_cmpl2_insn, *ashl3_insn, *ashr3_insn, *lshr3_insn, *trunchiqi2_insn, *truncsihi2_insn, *truncdisi2_insn, *extendqihi2_insn, *extendqisi2_insn, *extendhisi2_insn, *extendsidi2_insn, *zero_extendqihi2_insn, *zero_extendqisi2_insn, *zero_extendsidi2_insn): Fix split condition. --- gcc/config/visium/visium.md | 50 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'gcc') diff --git a/gcc/config/visium/visium.md b/gcc/config/visium/visium.md index 83ccf08..ca2234b 100644 --- a/gcc/config/visium/visium.md +++ b/gcc/config/visium/visium.md @@ -792,7 +792,7 @@ (match_operand:QHI 2 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, mode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (plus:QHI (match_dup 1) (match_dup 2))) (clobber (reg:CC R_FLAGS))])] @@ -850,7 +850,7 @@ (match_operand:SI 2 "add_operand" " L,r,J")))] "ok_for_simple_arith_logic_operands (operands, SImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) (clobber (reg:CC R_FLAGS))])] @@ -912,7 +912,7 @@ (match_operand:DI 2 "add_operand" " L,J, r")))] "ok_for_simple_arith_logic_operands (operands, DImode)" "#" - "reload_completed" + "&& reload_completed" [(const_int 0)] { visium_split_double_add (PLUS, operands[0], operands[1], operands[2]); @@ -1007,7 +1007,7 @@ (match_operand:QHI 2 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, mode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (minus:QHI (match_dup 1) (match_dup 2))) (clobber (reg:CC R_FLAGS))])] @@ -1064,7 +1064,7 @@ (match_operand:SI 2 "add_operand" " L,r, J")))] "ok_for_simple_arith_logic_operands (operands, SImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2))) (clobber (reg:CC R_FLAGS))])] @@ -1125,7 +1125,7 @@ (match_operand:DI 2 "add_operand" " L,J, r")))] "ok_for_simple_arith_logic_operands (operands, DImode)" "#" - "reload_completed" + "&& reload_completed" [(const_int 0)] { visium_split_double_add (MINUS, operands[0], operands[1], operands[2]); @@ -1209,7 +1209,7 @@ (neg:I (match_operand:I 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, mode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (neg:I (match_dup 1))) (clobber (reg:CC R_FLAGS))])] "" @@ -1253,7 +1253,7 @@ (neg:DI (match_operand:DI 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, DImode)" "#" - "reload_completed" + "&& reload_completed" [(const_int 0)] { visium_split_double_add (MINUS, operands[0], const0_rtx, operands[1]); @@ -1415,7 +1415,7 @@ (match_operand:I 2 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, mode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (and:I (match_dup 1) (match_dup 2))) (clobber (reg:CC R_FLAGS))])] @@ -1453,7 +1453,7 @@ (match_operand:I 2 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, mode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (ior:I (match_dup 1) (match_dup 2))) (clobber (reg:CC R_FLAGS))])] @@ -1491,7 +1491,7 @@ (match_operand:I 2 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, mode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (xor:I (match_dup 1) (match_dup 2))) (clobber (reg:CC R_FLAGS))])] @@ -1527,7 +1527,7 @@ (not:I (match_operand:I 1 "reg_or_0_operand" "rO")))] "ok_for_simple_arith_logic_operands (operands, mode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (not:I (match_dup 1))) (clobber (reg:CC R_FLAGS))])] "" @@ -1563,7 +1563,7 @@ (match_operand:QI 2 "reg_or_shift_operand" "r,K")))] "ok_for_simple_arith_logic_operands (operands, mode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (ashift:I (match_dup 1) (match_dup 2))) (clobber (reg:CC R_FLAGS))])] @@ -1622,7 +1622,7 @@ (match_operand:QI 2 "reg_or_shift_operand" "r,K")))] "ok_for_simple_arith_logic_operands (operands, mode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (ashiftrt:I (match_dup 1) (match_dup 2))) (clobber (reg:CC R_FLAGS))])] @@ -1683,7 +1683,7 @@ (match_operand:QI 2 "reg_or_shift_operand" "r,K")))] "ok_for_simple_arith_logic_operands (operands, mode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (lshiftrt:I (match_dup 1) (match_dup 2))) (clobber (reg:CC R_FLAGS))])] @@ -1740,7 +1740,7 @@ (truncate:QI (match_operand:HI 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, QImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (truncate:QI (match_dup 1))) (clobber (reg:CC R_FLAGS))])] "" @@ -1764,7 +1764,7 @@ (truncate:HI (match_operand:SI 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, HImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (truncate:HI (match_dup 1))) (clobber (reg:CC R_FLAGS))])] "" @@ -1788,7 +1788,7 @@ (truncate:SI (match_operand:DI 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, SImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (truncate:SI (match_dup 1))) (clobber (reg:CC R_FLAGS))])] "" @@ -1822,7 +1822,7 @@ (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, HImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (sign_extend:HI (match_dup 1))) (clobber (reg:CC R_FLAGS))])] "" @@ -1846,7 +1846,7 @@ (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, SImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (sign_extend:SI (match_dup 1))) (clobber (reg:CC R_FLAGS))])] "" @@ -1870,7 +1870,7 @@ (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, SImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_operand:SI 0 "register_operand" "") (sign_extend:SI (match_operand:HI 1 "register_operand" ""))) (clobber (reg:CC R_FLAGS))])] @@ -1895,7 +1895,7 @@ (sign_extend:DI (match_operand:SI 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, DImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 3) (match_dup 1)) (clobber (reg:CC R_FLAGS))]) (parallel [(set (match_dup 2) @@ -1931,7 +1931,7 @@ (zero_extend:HI (match_operand:QI 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, HImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (ashift:HI (match_dup 2) (const_int 8))) (clobber (reg:CC R_FLAGS))]) @@ -1953,7 +1953,7 @@ (zero_extend:SI (match_operand:QI 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, SImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 0) (ashift:SI (match_dup 2) (const_int 24))) (clobber (reg:CC R_FLAGS))]) @@ -1982,7 +1982,7 @@ (zero_extend:DI (match_operand:SI 1 "register_operand" "r")))] "ok_for_simple_arith_logic_operands (operands, DImode)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (match_dup 3) (match_dup 1)) (clobber (reg:CC R_FLAGS))]) (set (match_dup 2) (const_int 0))] -- cgit v1.1 From 1a15a91a0015208eafb797e4de1348c9877fd6d0 Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Tue, 16 Nov 2021 23:37:08 +0000 Subject: Fix PR 103288, ICE after PHI-OPT, move an assigment when still in use for another bb The problem is r12-5300-gf98f373dd822b35c allows phiopt to recognize more basic blocks but missed one location where phiopt could move an assignment from the middle block to the non-middle one. This patch fixes that. OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. PR tree-optimization/103288 gcc/ChangeLog: * tree-ssa-phiopt.c (value_replacement): Return early if middle block has more than one pred. gcc/testsuite/ChangeLog: * gcc.c-torture/compile/pr103288-1.c: New test. --- gcc/testsuite/gcc.c-torture/compile/pr103288-1.c | 6 ++++++ gcc/tree-ssa-phiopt.c | 3 +++ 2 files changed, 9 insertions(+) create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr103288-1.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.c-torture/compile/pr103288-1.c b/gcc/testsuite/gcc.c-torture/compile/pr103288-1.c new file mode 100644 index 0000000..88d1c67 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr103288-1.c @@ -0,0 +1,6 @@ + +int ui_5; +long func_14_uli_8; +void func_14() { + ui_5 &= (func_14_uli_8 ? 60 : ui_5) ? 5 : 0; +} diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index 6b22f6b..8984a5e 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -1381,6 +1381,9 @@ value_replacement (basic_block cond_bb, basic_block middle_bb, } } + if (!single_pred_p (middle_bb)) + return 0; + /* Now optimize (x != 0) ? x + y : y to just x + y. */ gsi = gsi_last_nondebug_bb (middle_bb); if (gsi_end_p (gsi)) -- cgit v1.1 From bf5f41e4fcc396b359f096231a37a3cb411cc9df Mon Sep 17 00:00:00 2001 From: Kewen Lin Date: Wed, 17 Nov 2021 04:02:20 -0600 Subject: i386: Fix non-robust split condition in define_insn_and_split This patch is to fix some non-robust split conditions in some define_insn_and_splits, to make each of them applied on top of the corresponding condition for define_insn part, otherwise the splitting could perform unexpectedly. gcc/ChangeLog: * config/i386/i386.md (*add3_doubleword, *addv4_doubleword, *addv4_doubleword_1, *sub3_doubleword, *subv4_doubleword, *subv4_doubleword_1, *add3_doubleword_cc_overflow_1, *divmodsi4_const, *neg2_doubleword, *tls_dynamic_gnu2_combine_64_): Fix split condition. --- gcc/config/i386/i386.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'gcc') diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 7394906..73d15de 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -5491,7 +5491,7 @@ (clobber (reg:CC FLAGS_REG))] "ix86_binary_operator_ok (PLUS, mode, operands)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (reg:CCC FLAGS_REG) (compare:CCC (plus:DWIH (match_dup 1) (match_dup 2)) @@ -6300,7 +6300,7 @@ (plus: (match_dup 1) (match_dup 2)))] "ix86_binary_operator_ok (PLUS, mode, operands)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (reg:CCC FLAGS_REG) (compare:CCC (plus:DWIH (match_dup 1) (match_dup 2)) @@ -6347,7 +6347,7 @@ && CONST_SCALAR_INT_P (operands[2]) && rtx_equal_p (operands[2], operands[3])" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (reg:CCC FLAGS_REG) (compare:CCC (plus:DWIH (match_dup 1) (match_dup 2)) @@ -6641,7 +6641,7 @@ (clobber (reg:CC FLAGS_REG))] "ix86_binary_operator_ok (MINUS, mode, operands)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (reg:CC FLAGS_REG) (compare:CC (match_dup 1) (match_dup 2))) (set (match_dup 0) @@ -6817,7 +6817,7 @@ (minus: (match_dup 1) (match_dup 2)))] "ix86_binary_operator_ok (MINUS, mode, operands)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (reg:CC FLAGS_REG) (compare:CC (match_dup 1) (match_dup 2))) (set (match_dup 0) @@ -6862,7 +6862,7 @@ && CONST_SCALAR_INT_P (operands[2]) && rtx_equal_p (operands[2], operands[3])" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (reg:CC FLAGS_REG) (compare:CC (match_dup 1) (match_dup 2))) (set (match_dup 0) @@ -7542,7 +7542,7 @@ (plus: (match_dup 1) (match_dup 2)))] "ix86_binary_operator_ok (PLUS, mode, operands)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (reg:CCC FLAGS_REG) (compare:CCC (plus:DWIH (match_dup 1) (match_dup 2)) @@ -9000,7 +9000,7 @@ (clobber (reg:CC FLAGS_REG))] "!optimize_function_for_size_p (cfun)" "#" - "reload_completed" + "&& reload_completed" [(set (match_dup 0) (match_dup 2)) (set (match_dup 1) (match_dup 4)) (parallel [(set (match_dup 0) @@ -10515,7 +10515,7 @@ (clobber (reg:CC FLAGS_REG))] "ix86_unary_operator_ok (NEG, mode, operands)" "#" - "reload_completed" + "&& reload_completed" [(parallel [(set (reg:CCC FLAGS_REG) (ne:CCC (match_dup 1) (const_int 0))) @@ -16908,7 +16908,7 @@ (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT && TARGET_GNU2_TLS" "#" - "" + "&& 1" [(set (match_dup 0) (match_dup 4))] { operands[4] = can_create_pseudo_p () ? gen_reg_rtx (ptr_mode) : operands[0]; -- cgit v1.1 From 7061300025188d57e715c1593b8dae598c87b3c5 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 17 Nov 2021 12:28:44 +0000 Subject: Add IFN_COND_FMIN/FMAX functions This patch adds conditional forms of FMAX and FMIN, following the pattern for existing conditional binary functions. gcc/ * doc/md.texi (cond_fmin@var{mode}, cond_fmax@var{mode}): Document. * optabs.def (cond_fmin_optab, cond_fmax_optab): New optabs. * internal-fn.def (COND_FMIN, COND_FMAX): New functions. * internal-fn.c (first_commutative_argument): Handle them. (FOR_EACH_COND_FN_PAIR): Likewise. * match.pd (UNCOND_BINARY, COND_BINARY): Likewise. * config/aarch64/aarch64-sve.md (cond_): New pattern. gcc/testsuite/ * gcc.target/aarch64/sve/cond_fmaxnm_5.c: New test. * gcc.target/aarch64/sve/cond_fmaxnm_5_run.c: Likewise. * gcc.target/aarch64/sve/cond_fmaxnm_6.c: Likewise. * gcc.target/aarch64/sve/cond_fmaxnm_6_run.c: Likewise. * gcc.target/aarch64/sve/cond_fmaxnm_7.c: Likewise. * gcc.target/aarch64/sve/cond_fmaxnm_7_run.c: Likewise. * gcc.target/aarch64/sve/cond_fmaxnm_8.c: Likewise. * gcc.target/aarch64/sve/cond_fmaxnm_8_run.c: Likewise. * gcc.target/aarch64/sve/cond_fminnm_5.c: Likewise. * gcc.target/aarch64/sve/cond_fminnm_5_run.c: Likewise. * gcc.target/aarch64/sve/cond_fminnm_6.c: Likewise. * gcc.target/aarch64/sve/cond_fminnm_6_run.c: Likewise. * gcc.target/aarch64/sve/cond_fminnm_7.c: Likewise. * gcc.target/aarch64/sve/cond_fminnm_7_run.c: Likewise. * gcc.target/aarch64/sve/cond_fminnm_8.c: Likewise. * gcc.target/aarch64/sve/cond_fminnm_8_run.c: Likewise. --- gcc/config/aarch64/aarch64-sve.md | 19 +++++++++++++- gcc/doc/md.texi | 4 +++ gcc/internal-fn.c | 4 +++ gcc/internal-fn.def | 2 ++ gcc/match.pd | 2 ++ gcc/optabs.def | 2 ++ .../gcc.target/aarch64/sve/cond_fmaxnm_5.c | 28 +++++++++++++++++++++ .../gcc.target/aarch64/sve/cond_fmaxnm_5_run.c | 4 +++ .../gcc.target/aarch64/sve/cond_fmaxnm_6.c | 22 ++++++++++++++++ .../gcc.target/aarch64/sve/cond_fmaxnm_6_run.c | 4 +++ .../gcc.target/aarch64/sve/cond_fmaxnm_7.c | 27 ++++++++++++++++++++ .../gcc.target/aarch64/sve/cond_fmaxnm_7_run.c | 4 +++ .../gcc.target/aarch64/sve/cond_fmaxnm_8.c | 26 +++++++++++++++++++ .../gcc.target/aarch64/sve/cond_fmaxnm_8_run.c | 4 +++ .../gcc.target/aarch64/sve/cond_fminnm_5.c | 29 ++++++++++++++++++++++ .../gcc.target/aarch64/sve/cond_fminnm_5_run.c | 4 +++ .../gcc.target/aarch64/sve/cond_fminnm_6.c | 23 +++++++++++++++++ .../gcc.target/aarch64/sve/cond_fminnm_6_run.c | 4 +++ .../gcc.target/aarch64/sve/cond_fminnm_7.c | 28 +++++++++++++++++++++ .../gcc.target/aarch64/sve/cond_fminnm_7_run.c | 4 +++ .../gcc.target/aarch64/sve/cond_fminnm_8.c | 27 ++++++++++++++++++++ .../gcc.target/aarch64/sve/cond_fminnm_8_run.c | 4 +++ 22 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_5.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_5_run.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_6.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_6_run.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_7.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_7_run.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_8.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_8_run.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_5.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_5_run.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_6.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_6_run.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_7.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_7_run.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_8.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_8_run.c (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index 5de479e..0f5bf5e 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -6287,7 +6287,7 @@ ;; ------------------------------------------------------------------------- ;; Unpredicated fmax/fmin (the libm functions). The optabs for the -;; smin/smax rtx codes are handled in the generic section above. +;; smax/smin rtx codes are handled in the generic section above. (define_expand "3" [(set (match_operand:SVE_FULL_F 0 "register_operand") (unspec:SVE_FULL_F @@ -6302,6 +6302,23 @@ } ) +;; Predicated fmax/fmin (the libm functions). The optabs for the +;; smax/smin rtx codes are handled in the generic section above. +(define_expand "cond_" + [(set (match_operand:SVE_FULL_F 0 "register_operand") + (unspec:SVE_FULL_F + [(match_operand: 1 "register_operand") + (unspec:SVE_FULL_F + [(match_dup 1) + (const_int SVE_RELAXED_GP) + (match_operand:SVE_FULL_F 2 "register_operand") + (match_operand:SVE_FULL_F 3 "aarch64_sve_float_maxmin_operand")] + SVE_COND_FP_MAXMIN_PUBLIC) + (match_operand:SVE_FULL_F 4 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +) + ;; Predicated floating-point maximum/minimum. (define_insn "@aarch64_pred_" [(set (match_operand:SVE_FULL_F 0 "register_operand" "=w, w, ?&w, ?&w") diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 41f1850..589f841 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -6930,6 +6930,8 @@ operand 0, otherwise (operand 2 + operand 3) is moved. @cindex @code{cond_smax@var{mode}} instruction pattern @cindex @code{cond_umin@var{mode}} instruction pattern @cindex @code{cond_umax@var{mode}} instruction pattern +@cindex @code{cond_fmin@var{mode}} instruction pattern +@cindex @code{cond_fmax@var{mode}} instruction pattern @cindex @code{cond_ashl@var{mode}} instruction pattern @cindex @code{cond_ashr@var{mode}} instruction pattern @cindex @code{cond_lshr@var{mode}} instruction pattern @@ -6947,6 +6949,8 @@ operand 0, otherwise (operand 2 + operand 3) is moved. @itemx @samp{cond_smax@var{mode}} @itemx @samp{cond_umin@var{mode}} @itemx @samp{cond_umax@var{mode}} +@itemx @samp{cond_fmin@var{mode}} +@itemx @samp{cond_fmax@var{mode}} @itemx @samp{cond_ashl@var{mode}} @itemx @samp{cond_ashr@var{mode}} @itemx @samp{cond_lshr@var{mode}} diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index e8fd16b..e5b85f0 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -3842,6 +3842,8 @@ first_commutative_argument (internal_fn fn) case IFN_COND_MUL: case IFN_COND_MIN: case IFN_COND_MAX: + case IFN_COND_FMIN: + case IFN_COND_FMAX: case IFN_COND_AND: case IFN_COND_IOR: case IFN_COND_XOR: @@ -3961,6 +3963,8 @@ conditional_internal_fn_code (internal_fn ifn) /* Invoke T(IFN) for each internal function IFN that also has an IFN_COND_* form. */ #define FOR_EACH_COND_FN_PAIR(T) \ + T (FMAX) \ + T (FMIN) \ T (FMA) \ T (FMS) \ T (FNMA) \ diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index bb13c6c..bb4d8ab 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -188,6 +188,8 @@ DEF_INTERNAL_SIGNED_OPTAB_FN (COND_MIN, ECF_CONST, first, cond_smin, cond_umin, cond_binary) DEF_INTERNAL_SIGNED_OPTAB_FN (COND_MAX, ECF_CONST, first, cond_smax, cond_umax, cond_binary) +DEF_INTERNAL_OPTAB_FN (COND_FMIN, ECF_CONST, cond_fmin, cond_binary) +DEF_INTERNAL_OPTAB_FN (COND_FMAX, ECF_CONST, cond_fmax, cond_binary) DEF_INTERNAL_OPTAB_FN (COND_AND, ECF_CONST | ECF_NOTHROW, cond_and, cond_binary) DEF_INTERNAL_OPTAB_FN (COND_IOR, ECF_CONST | ECF_NOTHROW, diff --git a/gcc/match.pd b/gcc/match.pd index 7f76925..89df7b2 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -90,12 +90,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) plus minus mult trunc_div trunc_mod rdiv min max + IFN_FMIN IFN_FMAX bit_and bit_ior bit_xor lshift rshift) (define_operator_list COND_BINARY IFN_COND_ADD IFN_COND_SUB IFN_COND_MUL IFN_COND_DIV IFN_COND_MOD IFN_COND_RDIV IFN_COND_MIN IFN_COND_MAX + IFN_COND_FMIN IFN_COND_FMAX IFN_COND_AND IFN_COND_IOR IFN_COND_XOR IFN_COND_SHL IFN_COND_SHR) diff --git a/gcc/optabs.def b/gcc/optabs.def index b889ad2..e25f4c9 100644 --- a/gcc/optabs.def +++ b/gcc/optabs.def @@ -241,6 +241,8 @@ OPTAB_D (cond_smin_optab, "cond_smin$a") OPTAB_D (cond_smax_optab, "cond_smax$a") OPTAB_D (cond_umin_optab, "cond_umin$a") OPTAB_D (cond_umax_optab, "cond_umax$a") +OPTAB_D (cond_fmin_optab, "cond_fmin$a") +OPTAB_D (cond_fmax_optab, "cond_fmax$a") OPTAB_D (cond_fma_optab, "cond_fma$a") OPTAB_D (cond_fms_optab, "cond_fms$a") OPTAB_D (cond_fnma_optab, "cond_fnma$a") diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_5.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_5.c new file mode 100644 index 0000000..4bae7e0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_5.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fmaxnm_1.c" + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #0\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #1\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #1\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.h, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.s, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.d, #2\.0} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, z[0-9]+\.d\n} 1 } } */ + +/* { dg-final { scan-assembler-not {\tmov\tz} } } */ +/* { dg-final { scan-assembler-not {\tmovprfx\t} } } */ +/* { dg-final { scan-assembler-not {\tsel\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_5_run.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_5_run.c new file mode 100644 index 0000000..1aa2eb4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_5_run.c @@ -0,0 +1,4 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fmaxnm_1_run.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_6.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_6.c new file mode 100644 index 0000000..912db00 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_6.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fmaxnm_2.c" + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #0\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #1\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.s, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.d, #2\.0} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, z[0-9]+\.d\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 3 } } */ +/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d\n} 3 } } */ + +/* { dg-final { scan-assembler-not {\tmov\tz} } } */ +/* { dg-final { scan-assembler-not {\tsel\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_6_run.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_6_run.c new file mode 100644 index 0000000..19f6edd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_6_run.c @@ -0,0 +1,4 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fmaxnm_2_run.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_7.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_7.c new file mode 100644 index 0000000..30f07f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_7.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fmaxnm_3.c" + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #0\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #1\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.h, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.s, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.d, #2\.0} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, z[0-9]+\.d\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tsel\tz[0-9]+\.h, p[0-7], z[0-9]+\.h, z[0-9]+\.h\n} 3 } } */ +/* { dg-final { scan-assembler-times {\tsel\tz[0-9]+\.h, p[0-7], z[0-9]+\.h, z[0-9]+\.h\n} 3 } } */ +/* { dg-final { scan-assembler-times {\tsel\tz[0-9]+\.h, p[0-7], z[0-9]+\.h, z[0-9]+\.h\n} 3 } } */ + +/* { dg-final { scan-assembler-not {\tmovprfx\t} } } */ +/* { dg-final { scan-assembler-not {\tmov\tz} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_7_run.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_7_run.c new file mode 100644 index 0000000..3e647ed --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_7_run.c @@ -0,0 +1,4 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fmaxnm_3_run.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_8.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_8.c new file mode 100644 index 0000000..a590d38 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_8.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fmaxnm_4.c" + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #0\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #1\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.h, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.s, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.d, #2\.0} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, z[0-9]+\.d\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/z, z[0-9]+\.s\n} 3 } } */ +/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.d, p[0-7]/z, z[0-9]+\.d\n} 3 } } */ + +/* { dg-final { scan-assembler-not {\tmov\tz} } } */ +/* { dg-final { scan-assembler-not {\tsel\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_8_run.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_8_run.c new file mode 100644 index 0000000..d421e54 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fmaxnm_8_run.c @@ -0,0 +1,4 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fmaxnm_4_run.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_5.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_5.c new file mode 100644 index 0000000..290c4be --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_5.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#define FN(X) __builtin_fmin##X +#include "cond_fmaxnm_1.c" + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #0\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #1\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #1\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.h, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.s, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.d, #2\.0} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, z[0-9]+\.d\n} 1 } } */ + +/* { dg-final { scan-assembler-not {\tmov\tz} } } */ +/* { dg-final { scan-assembler-not {\tmovprfx\t} } } */ +/* { dg-final { scan-assembler-not {\tsel\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_5_run.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_5_run.c new file mode 100644 index 0000000..76baf6a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_5_run.c @@ -0,0 +1,4 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fminnm_1_run.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_6.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_6.c new file mode 100644 index 0000000..cc9db99 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_6.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#define FN(X) __builtin_fmin##X +#include "cond_fmaxnm_2.c" + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #0\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #1\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.s, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.d, #2\.0} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, z[0-9]+\.d\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 3 } } */ +/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d\n} 3 } } */ + +/* { dg-final { scan-assembler-not {\tmov\tz} } } */ +/* { dg-final { scan-assembler-not {\tsel\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_6_run.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_6_run.c new file mode 100644 index 0000000..dbafea1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_6_run.c @@ -0,0 +1,4 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fminnm_2_run.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_7.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_7.c new file mode 100644 index 0000000..347a1a3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_7.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#define FN(X) __builtin_fmin##X +#include "cond_fmaxnm_3.c" + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #0\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #1\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.h, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.s, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.d, #2\.0} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, z[0-9]+\.d\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tsel\tz[0-9]+\.h, p[0-7], z[0-9]+\.h, z[0-9]+\.h\n} 3 } } */ +/* { dg-final { scan-assembler-times {\tsel\tz[0-9]+\.h, p[0-7], z[0-9]+\.h, z[0-9]+\.h\n} 3 } } */ +/* { dg-final { scan-assembler-times {\tsel\tz[0-9]+\.h, p[0-7], z[0-9]+\.h, z[0-9]+\.h\n} 3 } } */ + +/* { dg-final { scan-assembler-not {\tmovprfx\t} } } */ +/* { dg-final { scan-assembler-not {\tmov\tz} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_7_run.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_7_run.c new file mode 100644 index 0000000..6617095 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_7_run.c @@ -0,0 +1,4 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fminnm_3_run.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_8.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_8.c new file mode 100644 index 0000000..20d6cb5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_8.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#define FN(X) __builtin_fmin##X +#include "cond_fmaxnm_4.c" + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #0\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1\.0\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, #1\.0\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.h, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.s, #2\.0} 1 } } */ +/* { dg-final { scan-assembler-times {\tfmov\tz[0-9]+\.d, #2\.0} 1 } } */ + +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */ +/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.d, z[0-9]+\.d\n} 1 } } */ + +/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/z, z[0-9]+\.s\n} 3 } } */ +/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.d, p[0-7]/z, z[0-9]+\.d\n} 3 } } */ + +/* { dg-final { scan-assembler-not {\tmov\tz} } } */ +/* { dg-final { scan-assembler-not {\tsel\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_8_run.c b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_8_run.c new file mode 100644 index 0000000..4fb6497 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/cond_fminnm_8_run.c @@ -0,0 +1,4 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-O2 -ftree-vectorize" } */ + +#include "cond_fminnm_4_run.c" -- cgit v1.1 From c39cb6bf835ca12e590eaa6f90222e51be207c50 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 17 Nov 2021 13:45:53 +0100 Subject: ranger: Fix up fold_using_range::range_of_address [PR103255] If on &base->member the offset isn't constant or isn't zero and -fdelete-null-pointer-checks and not -fwrapv-pointer and base has a range that doesn't include NULL, we return the range of the base. Usually it isn't a big deal, because for most pointers we just use varying, range_zero and range_nonzero ranges and nothing beyond that, but if a pointer is initialized from a constant, we actually track the exact range and in that case this causes miscompilation. As discussed on IRC, I think doing something like: offset_int off2; if (off_cst && off.is_constant (&off2)) { tree cst = wide_int_to_tree (sizetype, off2 / BITS_PER_UNIT); // adjust range r with POINTER_PLUS_EXPR cst if (!range_includes_zero_p (&r)) return true; } // Fallback r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); return true; could work, given that most of the pointer ranges are just the simple ones perhaps it is too much for little benefit. 2021-11-17 Jakub Jelinek PR tree-optimization/103255 * gimple-range-fold.cc (fold_using_range::range_of_address): Return range_nonzero rather than unadjusted base's range. Formatting fixes. * gcc.c-torture/execute/pr103255.c: New test. --- gcc/gimple-range-fold.cc | 16 ++++++---- gcc/testsuite/gcc.c-torture/execute/pr103255.c | 41 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr103255.c (limited to 'gcc') diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index 608d98b..ec9690b 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -720,14 +720,20 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src) } /* If &X->a is equal to X, the range of X is the result. */ if (off_cst && known_eq (off, 0)) - return true; + return true; else if (flag_delete_null_pointer_checks && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr))) { - /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't - allow going from non-NULL pointer to NULL. */ - if(!range_includes_zero_p (&r)) - return true; + /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't + allow going from non-NULL pointer to NULL. */ + if (!range_includes_zero_p (&r)) + { + /* We could here instead adjust r by off >> LOG2_BITS_PER_UNIT + using POINTER_PLUS_EXPR if off_cst and just fall back to + this. */ + r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); + return true; + } } /* If MEM_REF has a "positive" offset, consider it non-NULL always, for -fdelete-null-pointer-checks also "negative" diff --git a/gcc/testsuite/gcc.c-torture/execute/pr103255.c b/gcc/testsuite/gcc.c-torture/execute/pr103255.c new file mode 100644 index 0000000..d74b054 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr103255.c @@ -0,0 +1,41 @@ +/* PR tree-optimization/103255 */ + +struct H +{ + unsigned a; + unsigned b; + unsigned c; +}; + +#if __SIZEOF_POINTER__ >= 4 +#define ADDR 0x400000 +#else +#define ADDR 0x4000 +#endif +#define OFF 0x20 + +int +main () +{ + struct H *h = 0; + unsigned long o; + volatile int t = 1; + + for (o = OFF; o <= OFF; o += 0x1000) + { + struct H *u; + u = (struct H *) (ADDR + o); + if (t) + { + h = u; + break; + } + } + + if (h == 0) + return 0; + unsigned *tt = &h->b; + if ((__SIZE_TYPE__) tt != (ADDR + OFF + __builtin_offsetof (struct H, b))) + __builtin_abort (); + return 0; +} -- cgit v1.1 From 077425c890927eefacb765ab5236060de9859e82 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 17 Nov 2021 14:18:42 +0100 Subject: lim: Reset flow sensitive info even for pointers [PR103192] Since 2014 is lim clearing SSA_NAME_RANGE_INFO for integral SSA_NAMEs if moving them from conditional contexts inside of a loop into unconditional before the loop, but as the miscompilation of gimplify.c shows, we need to treat pointers the same, even for them we need to reset whether the pointer can/can't be null or the recorded pointer alignment. This fixes -FAIL: libgomp.c/../libgomp.c-c++-common/target-in-reduction-2.c (internal compiler error) -FAIL: libgomp.c/../libgomp.c-c++-common/target-in-reduction-2.c (test for excess errors) -UNRESOLVED: libgomp.c/../libgomp.c-c++-common/target-in-reduction-2.c compilation failed to produce executable -FAIL: libgomp.c++/../libgomp.c-c++-common/target-in-reduction-2.c (internal compiler error) -FAIL: libgomp.c++/../libgomp.c-c++-common/target-in-reduction-2.c (test for excess errors) -UNRESOLVED: libgomp.c++/../libgomp.c-c++-common/target-in-reduction-2.c compilation failed to produce executable -FAIL: libgomp.c++/target-in-reduction-2.C (internal compiler error) -FAIL: libgomp.c++/target-in-reduction-2.C (test for excess errors) -UNRESOLVED: libgomp.c++/target-in-reduction-2.C compilation failed to produce executable on both x86_64 and i686. 2021-11-17 Jakub Jelinek PR tree-optimization/103192 * tree-ssa-loop-im.c (move_computations_worker): Use reset_flow_sensitive_info instead of manually clearing SSA_NAME_RANGE_INFO and do it for all SSA_NAMEs, not just ones with integral types. --- gcc/tree-ssa-loop-im.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c index 4b187c2..8a81aca 100644 --- a/gcc/tree-ssa-loop-im.c +++ b/gcc/tree-ssa-loop-im.c @@ -1183,14 +1183,10 @@ move_computations_worker (basic_block bb) COND_EXPR, t, arg0, arg1); todo |= TODO_cleanup_cfg; } - if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (new_stmt))) - && (!ALWAYS_EXECUTED_IN (bb) - || (ALWAYS_EXECUTED_IN (bb) != level - && !flow_loop_nested_p (ALWAYS_EXECUTED_IN (bb), level)))) - { - tree lhs = gimple_assign_lhs (new_stmt); - SSA_NAME_RANGE_INFO (lhs) = NULL; - } + if (!ALWAYS_EXECUTED_IN (bb) + || (ALWAYS_EXECUTED_IN (bb) != level + && !flow_loop_nested_p (ALWAYS_EXECUTED_IN (bb), level))) + reset_flow_sensitive_info (gimple_assign_lhs (new_stmt)); gsi_insert_on_edge (loop_preheader_edge (level), new_stmt); remove_phi_node (&bsi, false); } @@ -1253,14 +1249,10 @@ move_computations_worker (basic_block bb) gsi_remove (&bsi, false); if (gimple_has_lhs (stmt) && TREE_CODE (gimple_get_lhs (stmt)) == SSA_NAME - && INTEGRAL_TYPE_P (TREE_TYPE (gimple_get_lhs (stmt))) && (!ALWAYS_EXECUTED_IN (bb) || !(ALWAYS_EXECUTED_IN (bb) == level || flow_loop_nested_p (ALWAYS_EXECUTED_IN (bb), level)))) - { - tree lhs = gimple_get_lhs (stmt); - SSA_NAME_RANGE_INFO (lhs) = NULL; - } + reset_flow_sensitive_info (gimple_get_lhs (stmt)); /* In case this is a stmt that is not unconditionally executed when the target loop header is executed and the stmt may invoke undefined integer or pointer overflow rewrite it to -- cgit v1.1 From 4e6bf0b9dd5585df1a1472d6a93b9fff72fe2524 Mon Sep 17 00:00:00 2001 From: Martin Uecker Date: Wed, 17 Nov 2021 14:20:59 +0100 Subject: Fix ICE when mixing VLAs and statement expressions [PR91038] When returning VM-types from statement expressions, this can lead to an ICE when declarations from the statement expression are referred to later. Most of these issues can be addressed by gimplifying the base expression earlier in gimplify_compound_lval. Another issue is fixed by wrapping the pointer expression in pointer_int_sum. This fixes PR91038 and some of the test cases from PR29970 (structs with VLA members need further work). gcc/ PR c/91038 PR c/29970 * gimplify.c (gimplify_var_or_parm_decl): Update comment. (gimplify_compound_lval): Gimplify base expression first. (gimplify_target_expr): Add comment. gcc/c-family/ PR c/91038 PR c/29970 * c-common.c (pointer_int_sum): Make sure pointer expressions are evaluated first when the size expression depends on for variably-modified types. gcc/testsuite/ PR c/91038 PR c/29970 * gcc.dg/vla-stexp-3.c: New test. * gcc.dg/vla-stexp-4.c: New test. * gcc.dg/vla-stexp-5.c: New test. * gcc.dg/vla-stexp-6.c: New test. * gcc.dg/vla-stexp-7.c: New test. * gcc.dg/vla-stexp-8.c: New test. * gcc.dg/vla-stexp-9.c: New test. --- gcc/c-family/c-common.c | 14 +++++- gcc/gimplify.c | 79 +++++++++++++++----------------- gcc/testsuite/gcc.dg/vla-stexp-3.c | 11 +++++ gcc/testsuite/gcc.dg/vla-stexp-4.c | 94 ++++++++++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/vla-stexp-5.c | 30 ++++++++++++ gcc/testsuite/gcc.dg/vla-stexp-6.c | 94 ++++++++++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/vla-stexp-7.c | 44 ++++++++++++++++++ gcc/testsuite/gcc.dg/vla-stexp-8.c | 47 +++++++++++++++++++ gcc/testsuite/gcc.dg/vla-stexp-9.c | 53 +++++++++++++++++++++ 9 files changed, 422 insertions(+), 44 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vla-stexp-3.c create mode 100644 gcc/testsuite/gcc.dg/vla-stexp-4.c create mode 100644 gcc/testsuite/gcc.dg/vla-stexp-5.c create mode 100644 gcc/testsuite/gcc.dg/vla-stexp-6.c create mode 100644 gcc/testsuite/gcc.dg/vla-stexp-7.c create mode 100644 gcc/testsuite/gcc.dg/vla-stexp-8.c create mode 100644 gcc/testsuite/gcc.dg/vla-stexp-9.c (limited to 'gcc') diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 90e8ec8..ca7d69c 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -3306,7 +3306,19 @@ pointer_int_sum (location_t loc, enum tree_code resultcode, TREE_TYPE (result_type))) size_exp = integer_one_node; else - size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type)); + { + size_exp = size_in_bytes_loc (loc, TREE_TYPE (result_type)); + /* Wrap the pointer expression in a SAVE_EXPR to make sure it + is evaluated first when the size expression may depend + on it for VM types. */ + if (TREE_SIDE_EFFECTS (size_exp) + && TREE_SIDE_EFFECTS (ptrop) + && variably_modified_type_p (TREE_TYPE (ptrop), NULL)) + { + ptrop = save_expr (ptrop); + size_exp = build2 (COMPOUND_EXPR, TREE_TYPE (intop), ptrop, size_exp); + } + } /* We are manipulating pointer values, so we don't need to warn about relying on undefined signed overflow. We disable the diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 1602a62..467b135 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -2964,7 +2964,9 @@ gimplify_var_or_parm_decl (tree *expr_p) declaration, for which we've already issued an error. It would be really nice if the front end wouldn't leak these at all. Currently the only known culprit is C++ destructors, as seen - in g++.old-deja/g++.jason/binding.C. */ + in g++.old-deja/g++.jason/binding.C. + Another possible culpit are size expressions for variably modified + types which are lost in the FE or not gimplified correctly. */ if (VAR_P (decl) && !DECL_SEEN_IN_BIND_EXPR_P (decl) && !TREE_STATIC (decl) && !DECL_EXTERNAL (decl) @@ -3109,16 +3111,22 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, expression until we deal with any variable bounds, sizes, or positions in order to deal with PLACEHOLDER_EXPRs. - So we do this in three steps. First we deal with the annotations - for any variables in the components, then we gimplify the base, - then we gimplify any indices, from left to right. */ + The base expression may contain a statement expression that + has declarations used in size expressions, so has to be + gimplified before gimplifying the size expressions. + + So we do this in three steps. First we deal with variable + bounds, sizes, and positions, then we gimplify the base, + then we deal with the annotations for any variables in the + components and any indices, from left to right. */ + for (i = expr_stack.length () - 1; i >= 0; i--) { tree t = expr_stack[i]; if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF) { - /* Gimplify the low bound and element type size and put them into + /* Deal with the low bound and element type size and put them into the ARRAY_REF. If these values are set, they have already been gimplified. */ if (TREE_OPERAND (t, 2) == NULL_TREE) @@ -3127,18 +3135,8 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, if (!is_gimple_min_invariant (low)) { TREE_OPERAND (t, 2) = low; - tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, - post_p, is_gimple_reg, - fb_rvalue); - ret = MIN (ret, tret); } } - else - { - tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p, - is_gimple_reg, fb_rvalue); - ret = MIN (ret, tret); - } if (TREE_OPERAND (t, 3) == NULL_TREE) { @@ -3155,18 +3153,8 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, elmt_size, factor); TREE_OPERAND (t, 3) = elmt_size; - tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, - post_p, is_gimple_reg, - fb_rvalue); - ret = MIN (ret, tret); } } - else - { - tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p, - is_gimple_reg, fb_rvalue); - ret = MIN (ret, tret); - } } else if (TREE_CODE (t) == COMPONENT_REF) { @@ -3186,18 +3174,8 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, offset, factor); TREE_OPERAND (t, 2) = offset; - tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, - post_p, is_gimple_reg, - fb_rvalue); - ret = MIN (ret, tret); } } - else - { - tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p, - is_gimple_reg, fb_rvalue); - ret = MIN (ret, tret); - } } } @@ -3208,21 +3186,34 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, fallback | fb_lvalue); ret = MIN (ret, tret); - /* And finally, the indices and operands of ARRAY_REF. During this - loop we also remove any useless conversions. */ + /* Step 3: gimplify size expressions and the indices and operands of + ARRAY_REF. During this loop we also remove any useless conversions. */ + for (; expr_stack.length () > 0; ) { tree t = expr_stack.pop (); if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF) { + /* Gimplify the low bound and element type size. */ + tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p, + is_gimple_reg, fb_rvalue); + ret = MIN (ret, tret); + + tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p, + is_gimple_reg, fb_rvalue); + ret = MIN (ret, tret); + /* Gimplify the dimension. */ - if (!is_gimple_min_invariant (TREE_OPERAND (t, 1))) - { - tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p, - is_gimple_val, fb_rvalue); - ret = MIN (ret, tret); - } + tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p, + is_gimple_val, fb_rvalue); + ret = MIN (ret, tret); + } + else if (TREE_CODE (t) == COMPONENT_REF) + { + tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p, + is_gimple_reg, fb_rvalue); + ret = MIN (ret, tret); } STRIP_USELESS_TYPE_CONVERSION (TREE_OPERAND (t, 0)); @@ -6927,6 +6918,8 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) { if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (temp))) gimplify_type_sizes (TREE_TYPE (temp), pre_p); + /* FIXME: this is correct only when the size of the type does + not depend on expressions evaluated in init. */ gimplify_vla_decl (temp, pre_p); } else diff --git a/gcc/testsuite/gcc.dg/vla-stexp-3.c b/gcc/testsuite/gcc.dg/vla-stexp-3.c new file mode 100644 index 0000000..e663de1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-stexp-3.c @@ -0,0 +1,11 @@ +/* PR91038 */ +/* { dg-do compile } */ +/* { dg-options "" } */ + + +void bar(void) +{ + ({ int N = 2; int (*x)[9][N] = 0; x; })[1]; + ({ int N = 2; int (*x)[9][N] = 0; x; })[0]; // should not ice +} + diff --git a/gcc/testsuite/gcc.dg/vla-stexp-4.c b/gcc/testsuite/gcc.dg/vla-stexp-4.c new file mode 100644 index 0000000..612b5a8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-stexp-4.c @@ -0,0 +1,94 @@ +/* PR29970, PR91038 */ +/* { dg-do run } */ +/* { dg-options "-O0 -Wunused-variable" } */ + +int foo3b(void) // should not return 0 +{ + int n = 0; + return sizeof *({ n = 10; int x[n]; &x; }); +} + +int foo4(void) // should not ICE +{ + return (*({ + int n = 20; + char (*x)[n][n] = __builtin_malloc(n * n); + (*x)[12][1] = 1; + x; + }))[12][1]; +} + +int foo5(void) // should return 1, returns 0 +{ + int n = 0; + return (*({ + n = 20; + char (*x)[n][n] = __builtin_malloc(n * n); + (*x)[12][1] = 1; + (*x)[0][1] = 0; + x; + }))[12][1]; +} + +int foo5c(void) // should return 400 +{ + int n = 0; + return sizeof(*({ + n = 20; + char (*x)[n][n] = __builtin_malloc(n * n); + (*x)[12][1] = 1; + (*x)[0][1] = 0; + x; + })); +} + +int foo5b(void) // should return 1, returns 0 +{ + int n = 0; /* { dg-warning "unused variable" } */ + return (*({ + int n = 20; + char (*x)[n][n] = __builtin_malloc(n * n); + (*x)[12][1] = 1; + (*x)[0][1] = 0; + x; + }))[12][1]; +} + +int foo5a(void) // should return 1, returns 0 +{ + return (*({ + int n = 20; + char (*x)[n][n] = __builtin_malloc(n * n); + (*x)[12][1] = 1; + (*x)[0][1] = 0; + x; + }))[12][1]; +} + + + + +int main() +{ + if (sizeof(int[10]) != foo3b()) + __builtin_abort(); + + if (1 != foo4()) + __builtin_abort(); + + if (400 != foo5c()) + __builtin_abort(); + + if (1 != foo5a()) + __builtin_abort(); + + if (1 != foo5b()) // -O0 + __builtin_abort(); + + if (1 != foo5()) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/vla-stexp-5.c b/gcc/testsuite/gcc.dg/vla-stexp-5.c new file mode 100644 index 0000000..d6a7f2b --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-stexp-5.c @@ -0,0 +1,30 @@ +/* PR29970 */ +/* { dg-do run } */ +/* { dg-options "-Wunused-variable" } */ + + + + +int foo2a(void) // should not ICE +{ + return ({ int n = 20; struct { int x[n];} x; x.x[12] = 1; sizeof(x); }); +} + + +int foo2b(void) // should not ICE +{ + return sizeof *({ int n = 20; struct { int x[n];} x; x.x[12] = 1; &x; }); +} + +int main() +{ + if (sizeof(struct { int x[20]; }) != foo2a()) + __builtin_abort(); + + if (sizeof(struct { int x[20]; }) != foo2b()) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/vla-stexp-6.c b/gcc/testsuite/gcc.dg/vla-stexp-6.c new file mode 100644 index 0000000..3d96d38 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-stexp-6.c @@ -0,0 +1,94 @@ +/* PR29970, PR91038 */ +/* { dg-do run } */ +/* { dg-options "-O2 -Wunused-variable" } */ + +int foo3b(void) // should not return 0 +{ + int n = 0; + return sizeof *({ n = 10; int x[n]; &x; }); +} + +int foo4(void) // should not ICE +{ + return (*({ + int n = 20; + char (*x)[n][n] = __builtin_malloc(n * n); + (*x)[12][1] = 1; + x; + }))[12][1]; +} + +int foo5(void) // should return 1, returns 0 +{ + int n = 0; + return (*({ + n = 20; + char (*x)[n][n] = __builtin_malloc(n * n); + (*x)[12][1] = 1; + (*x)[0][1] = 0; + x; + }))[12][1]; +} + +int foo5c(void) // should return 400 +{ + int n = 0; + return sizeof(*({ + n = 20; + char (*x)[n][n] = __builtin_malloc(n * n); + (*x)[12][1] = 1; + (*x)[0][1] = 0; + x; + })); +} + +int foo5b(void) // should return 1, returns 0 +{ + int n = 0; /* { dg-warning "unused variable" } */ + return (*({ + int n = 20; + char (*x)[n][n] = __builtin_malloc(n * n); + (*x)[12][1] = 1; + (*x)[0][1] = 0; + x; + }))[12][1]; +} + +int foo5a(void) // should return 1, returns 0 +{ + return (*({ + int n = 20; + char (*x)[n][n] = __builtin_malloc(n * n); + (*x)[12][1] = 1; + (*x)[0][1] = 0; + x; + }))[12][1]; +} + + + + +int main() +{ + if (sizeof(int[10]) != foo3b()) + __builtin_abort(); + + if (1 != foo4()) + __builtin_abort(); + + if (400 != foo5c()) + __builtin_abort(); + + if (1 != foo5a()) + __builtin_abort(); + + if (1 != foo5b()) // -O0 + __builtin_abort(); + + if (1 != foo5()) + __builtin_abort(); + + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/vla-stexp-7.c b/gcc/testsuite/gcc.dg/vla-stexp-7.c new file mode 100644 index 0000000..3091b91 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-stexp-7.c @@ -0,0 +1,44 @@ +/* PR91038 */ +/* { dg-do run } */ +/* { dg-options "-O2 -Wunused-variable" } */ + + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +struct lbm { + + int D; + const int* DQ; + +} D2Q9 = { 2, + (const int*)&(const int[9][2]){ + { 0, 0 }, + { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 }, + { 1, 1 }, { -1, 1 }, { -1, -1 }, { 1, -1 }, + } +}; + +void zouhe_left(void) +{ + __auto_type xx = (*({ int N = 2; struct lbm __x = D2Q9; ((const int(*)[9][N])__x.DQ); })); + + if (1 != xx[1][0]) + __builtin_abort(); + + if (2 != ARRAY_SIZE(xx[1])) + __builtin_abort(); + + if (1 != (*({ int N = 2; struct lbm __x = D2Q9; ((const int(*)[9][N])__x.DQ); }))[1][0]) + __builtin_abort(); + + if (2 != ARRAY_SIZE(*({ int N = 2; struct lbm __x = D2Q9; ((const int(*)[9][N])__x.DQ); })[1])) + __builtin_abort(); +} + +int main() +{ + zouhe_left(); + return 0; +} + + diff --git a/gcc/testsuite/gcc.dg/vla-stexp-8.c b/gcc/testsuite/gcc.dg/vla-stexp-8.c new file mode 100644 index 0000000..5b475eb --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-stexp-8.c @@ -0,0 +1,47 @@ +/* PR29970, PR91038 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wunused-variable" } */ + + +int foo0(void) +{ + int c = *(*(*({ int n = 10; int (*x)[n][n] = __builtin_malloc(sizeof *x); x; }) + 5) + 5); + return c; +} + +int foo1(void) +{ + int c = *(5 + *(5 + *({ int n = 10; int (*x)[n][n] = __builtin_malloc(sizeof *x); x; }))); + return c; +} + +int bar2(void) +{ + int c = (*({ int n = 10; struct { int y[n]; int z; }* x = __builtin_malloc(sizeof *x); x; })).z; + return c; +} + +int bar3(void) +{ + int n = 2; /* { dg-warning "unused variable" } */ + int c = (*({ int n = 3; /* { dg-warning "unused variable" } */ + ({ int n = 10; int (*x)[n][n] = __builtin_malloc(sizeof *x); x; }); }))[5][5]; + return c; +} + +int bar3b(void) +{ + int n = 2; /* { dg-warning "unused variable" } */ + int c = (*({ int n = 3; /* { dg-warning "unused variable" } */ + ({ int n = 10; int (*x)[n][n] = __builtin_malloc(sizeof *x); x; }); }))[0][0]; + return c; +} + +int bar4(void) +{ + int n = 2; /* { dg-warning "unused variable" } */ + int c = *(5 + *( 5 + *({ int n = 3; /* { dg-warning "unused variable" } */ + ({ int n = 10; int (*x)[n][n] = __builtin_malloc(sizeof *x); x; }); }))); + return c; +} + diff --git a/gcc/testsuite/gcc.dg/vla-stexp-9.c b/gcc/testsuite/gcc.dg/vla-stexp-9.c new file mode 100644 index 0000000..3593a79 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-stexp-9.c @@ -0,0 +1,53 @@ +/* PR91038 */ +/* { dg-do run } */ +/* { dg-options "-O2 -Wunused-variable" } */ + + + +void foo(void) +{ + if (2 * sizeof(int) != sizeof((*({ int N = 2; int (*x)[9][N] = 0; x; })[1]))) + __builtin_abort(); +} + +void bar(void) +{ + if (2 * sizeof(int) != sizeof((*({ int N = 2; int (*x)[9][N] = 0; x; })[0]))) + __builtin_abort(); +} + +void bar0(void) +{ + if (2 * 9 * sizeof(int) != sizeof((*({ int N = 2; int (*x)[9][N] = 0; x; })))) + __builtin_abort(); +} + +void bar11(void) +{ + sizeof(*((*({ int N = 2; int (*x)[9][N] = 0; x; }) + 0))); +} + +void bar12(void) +{ + if (2 * sizeof(int) != sizeof(*((*({ int N = 2; int (*x)[9][N] = 0; x; }) )))) + __builtin_abort(); +} + +void bar1(void) +{ + if (2 * sizeof(int) != sizeof(*((*({ int N = 2; int (*x)[9][N] = 0; x; }) + 0)))) + __builtin_abort(); +} + + + + +int main() +{ + foo(); + bar0(); + bar12(); + bar1(); + bar(); +} + -- cgit v1.1 From dd159a4167ca19b5ff26e7156333c88e854943bf Mon Sep 17 00:00:00 2001 From: Przemyslaw Wirkus Date: Wed, 17 Nov 2021 13:38:24 +0000 Subject: aarch64: Add new vector mode V8DI This patch is adding new V8DI mode which will be used with new Armv8.7-A LS64 extension intrinsics. gcc/ChangeLog: * config/aarch64/aarch64-modes.def (VECTOR_MODE): New V8DI mode. * config/aarch64/aarch64.c (aarch64_hard_regno_mode_ok): Handle V8DImode. * config/aarch64/iterators.md (define_mode_attr nunits): Add entry for V8DI. --- gcc/config/aarch64/aarch64-modes.def | 5 +++++ gcc/config/aarch64/aarch64.c | 4 ++++ gcc/config/aarch64/iterators.md | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-modes.def b/gcc/config/aarch64/aarch64-modes.def index ac97d22..f0265bd 100644 --- a/gcc/config/aarch64/aarch64-modes.def +++ b/gcc/config/aarch64/aarch64-modes.def @@ -81,6 +81,11 @@ INT_MODE (OI, 32); INT_MODE (CI, 48); INT_MODE (XI, 64); +/* V8DI mode. */ +VECTOR_MODE_WITH_PREFIX (V, INT, DI, 8, 5); + +ADJUST_ALIGNMENT (V8DI, 8); + /* Define Advanced SIMD modes for structures of 2, 3 and 4 d-registers. */ #define ADV_SIMD_D_REG_STRUCT_MODES(NVECS, VB, VH, VS, VD) \ VECTOR_MODES_WITH_PREFIX (V##NVECS##x, INT, 8, 3); \ diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index d8410fc..7389b59 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -3394,6 +3394,10 @@ aarch64_hard_regno_nregs (unsigned regno, machine_mode mode) static bool aarch64_hard_regno_mode_ok (unsigned regno, machine_mode mode) { + if (mode == V8DImode) + return IN_RANGE (regno, R0_REGNUM, R23_REGNUM) + && multiple_p (regno - R0_REGNUM, 2); + if (GET_MODE_CLASS (mode) == MODE_CC) return regno == CC_REGNUM; diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index a9842b3..2c58d55 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -1062,7 +1062,7 @@ (define_mode_attr nunits [(V8QI "8") (V16QI "16") (V4HI "4") (V8HI "8") (V2SI "2") (V4SI "4") - (V2DI "2") + (V2DI "2") (V8DI "8") (V4HF "4") (V8HF "8") (V4BF "4") (V8BF "8") (V2SF "2") (V4SF "4") -- cgit v1.1 From 049f0efeaa77b43a508172161ca040feb6bb5622 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 17 Nov 2021 17:31:40 +0100 Subject: libcpp: Fix up handling of block comments in -fdirectives-only mode [PR103130] Normal preprocessing, -fdirectives-only preprocessing before the Nathan's rewrite, and all other compilers I've tried on godbolt treat even \*/ as end of a block comment, but the new -fdirectives-only handling doesn't. 2021-11-17 Jakub Jelinek PR preprocessor/103130 * lex.c (cpp_directive_only_process): Treat even \*/ as end of block comment. * c-c++-common/cpp/dir-only-9.c: New test. --- gcc/testsuite/c-c++-common/cpp/dir-only-9.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 gcc/testsuite/c-c++-common/cpp/dir-only-9.c (limited to 'gcc') diff --git a/gcc/testsuite/c-c++-common/cpp/dir-only-9.c b/gcc/testsuite/c-c++-common/cpp/dir-only-9.c new file mode 100644 index 0000000..d11cd97 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/dir-only-9.c @@ -0,0 +1,13 @@ +/* PR preprocessor/103130 */ +/* { dg-do preprocess } */ +/* { dg-options -fdirectives-only } */ + +/*\ + * this is a comment +\*/ + +int +main () +{ + return 0; +} -- cgit v1.1 From c70546482388951b5c9c19cff002ee6ab920b7f5 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Wed, 17 Nov 2021 11:55:50 -0500 Subject: Fix two mips target tests compromised by recent IPA work gcc/testsuite * gcc.target/mips/frame-header-1.c (bar): Add noipa attribute. * gcc.target/mips/frame-header-2.c (bar): Likewise. --- gcc/testsuite/gcc.target/mips/frame-header-1.c | 2 +- gcc/testsuite/gcc.target/mips/frame-header-2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/mips/frame-header-1.c b/gcc/testsuite/gcc.target/mips/frame-header-1.c index 971656d..55efc0b 100644 --- a/gcc/testsuite/gcc.target/mips/frame-header-1.c +++ b/gcc/testsuite/gcc.target/mips/frame-header-1.c @@ -8,7 +8,7 @@ /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */ /* { dg-final { scan-assembler "\taddiu\t\\\$sp,\\\$sp,-24" } } */ -NOMIPS16 void __attribute__((noinline)) +NOMIPS16 void __attribute__((noinline)) __attribute__((noipa)) bar (int* a) { *a = 1; diff --git a/gcc/testsuite/gcc.target/mips/frame-header-2.c b/gcc/testsuite/gcc.target/mips/frame-header-2.c index 0e86bc9..31aa27e 100644 --- a/gcc/testsuite/gcc.target/mips/frame-header-2.c +++ b/gcc/testsuite/gcc.target/mips/frame-header-2.c @@ -8,7 +8,7 @@ /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */ /* { dg-final { scan-assembler "\taddiu\t\\\$sp,\\\$sp,-8" } } */ -NOMIPS16 void __attribute__((noinline)) +NOMIPS16 void __attribute__((noinline)) __attribute__((noipa)) bar (int* a) { *a = 1; -- cgit v1.1 From d3a9082d7acc3ef443de6f14a16e7063d92844b1 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 17 Nov 2021 05:45:02 -0500 Subject: doc: document -fimplicit-constexpr I forgot this in the implementation patch. gcc/ChangeLog: * doc/invoke.texi (C++ Dialect Options): Document -fimplicit-constexpr. --- gcc/doc/invoke.texi | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index a22758d..bd6b9f6 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -3106,6 +3106,13 @@ word as an identifier. You can use the keyword @code{__typeof__} instead. This option is implied by the strict ISO C++ dialects: @option{-ansi}, @option{-std=c++98}, @option{-std=c++11}, etc. +@item -fimplicit-constexpr +@opindex fimplicit-constexpr +Make inline functions implicitly constexpr, if they satisfy the +requirements for a constexpr function. This option can be used in +C++14 mode or later. This can result in initialization changing from +dynamic to static and other optimizations. + @item -fno-implicit-templates @opindex fno-implicit-templates @opindex fimplicit-templates -- cgit v1.1 From 2c2148d8c144d7388abcb7c34b782be647fe81c9 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Wed, 17 Nov 2021 11:51:33 -0700 Subject: Handle folded nonconstant array bounds [PR101702] PR c/101702 - ICE: in handle_argspec_attribute, at c-family/c-attribs.c:3623 gcc/c/ChangeLog: PR c/101702 * c-decl.c (get_parm_array_spec): Strip casts earlier and fold array bounds before deciding if they're constant. gcc/testsuite/ChangeLog: PR c/101702 * gcc.dg/Warray-parameter-11.c: New test. --- gcc/c/c-decl.c | 10 ++++++---- gcc/testsuite/gcc.dg/Warray-parameter-11.c | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Warray-parameter-11.c (limited to 'gcc') diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 186fa16..63d806a 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -5866,6 +5866,12 @@ get_parm_array_spec (const struct c_parm *parm, tree attrs) if (pd->u.array.static_p) spec += 's'; + if (!INTEGRAL_TYPE_P (TREE_TYPE (nelts))) + /* Avoid invalid NELTS. */ + return attrs; + + STRIP_NOPS (nelts); + nelts = c_fully_fold (nelts, false, nullptr); if (TREE_CODE (nelts) == INTEGER_CST) { /* Skip all constant bounds except the most significant one. @@ -5883,13 +5889,9 @@ get_parm_array_spec (const struct c_parm *parm, tree attrs) spec += buf; break; } - else if (!INTEGRAL_TYPE_P (TREE_TYPE (nelts))) - /* Avoid invalid NELTS. */ - return attrs; /* Each variable VLA bound is represented by a dollar sign. */ spec += "$"; - STRIP_NOPS (nelts); vbchain = tree_cons (NULL_TREE, nelts, vbchain); } diff --git a/gcc/testsuite/gcc.dg/Warray-parameter-11.c b/gcc/testsuite/gcc.dg/Warray-parameter-11.c new file mode 100644 index 0000000..8ca1b55 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-parameter-11.c @@ -0,0 +1,24 @@ +/* PR c/101702 - ICE on invalid function redeclaration + { dg-do compile } + { dg-options "-Wall" } */ + +typedef __INTPTR_TYPE__ intptr_t; + +#define copysign(x, y) __builtin_copysign (x, y) + +void f0 (double[!copysign (~2, 3)]); + +void f1 (double[!copysign (~2, 3)]); +void f1 (double[1]); // { dg-warning "-Warray-parameter" } + +void f2 (int[(int)+1.0]); +void f2 (int[(int)+1.1]); + +/* Also verify that equivalent expressions don't needlessly cause false + positives or negatives. */ +struct S { int a[1]; }; +extern struct S *sp; + +void f3 (int[(intptr_t)((char*)sp->a - (char*)sp)]); +void f3 (int[(intptr_t)((char*)&sp->a[0] - (char*)sp)]); +void f3 (int[(intptr_t)((char*)&sp->a[1] - (char*)sp)]); // { dg-warning "-Warray-parameter" } -- cgit v1.1 From ef342b2d99e7947a15e72ed02173d235feaf35f0 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Wed, 17 Nov 2021 20:32:23 +0100 Subject: i386: Introduce LEGACY_SSE_REGNO_P predicate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce LEGACY_SSE_REGNO_P predicate to simplify a couple of places. No functional changes. 2021-11-17 Uroš Bizjak gcc/ChangeLog: * config/i386/i386.h (LEGACY_SSE_REGNO_P): New predicate. (SSE_REGNO_P): Use LEGACY_SSE_REGNO_P predicate. * config/i386/i386.c (zero_all_vector_registers): Use LEGACY_SSE_REGNO_P predicate. (ix86_register_priority): Use REX_INT_REGNO_P, REX_SSE_REGNO_P and EXT_REG_SSE_REGNO_P predicates. (ix86_hard_regno_call_part_clobbered): Use REX_SSE_REGNO_P and LEGACY_SSE_REGNO_P predicates. --- gcc/config/i386/i386.c | 19 ++++++++----------- gcc/config/i386/i386.h | 5 ++++- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'gcc') diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 73c4d51..0c5439d 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -3665,7 +3665,7 @@ zero_all_vector_registers (HARD_REG_SET need_zeroed_hardregs) return NULL; for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if ((IN_RANGE (regno, FIRST_SSE_REG, LAST_SSE_REG) + if ((LEGACY_SSE_REGNO_P (regno) || (TARGET_64BIT && (REX_SSE_REGNO_P (regno) || (TARGET_AVX512F && EXT_REX_SSE_REGNO_P (regno))))) @@ -19089,15 +19089,13 @@ ix86_register_priority (int hard_regno) return 0; if (hard_regno == BP_REG) return 1; - /* New x86-64 int registers result in bigger code size. Discourage - them. */ - if (IN_RANGE (hard_regno, FIRST_REX_INT_REG, LAST_REX_INT_REG)) + /* New x86-64 int registers result in bigger code size. Discourage them. */ + if (REX_INT_REGNO_P (hard_regno)) return 2; - /* New x86-64 SSE registers result in bigger code size. Discourage - them. */ - if (IN_RANGE (hard_regno, FIRST_REX_SSE_REG, LAST_REX_SSE_REG)) + /* New x86-64 SSE registers result in bigger code size. Discourage them. */ + if (REX_SSE_REGNO_P (hard_regno)) return 2; - if (IN_RANGE (hard_regno, FIRST_EXT_REX_SSE_REG, LAST_EXT_REX_SSE_REG)) + if (EXT_REX_SSE_REGNO_P (hard_regno)) return 1; /* Usage of AX register results in smaller code. Prefer it. */ if (hard_regno == AX_REG) @@ -19974,9 +19972,8 @@ ix86_hard_regno_call_part_clobbered (unsigned int abi_id, unsigned int regno, /* Special ABI for vzeroupper which only clobber higher part of sse regs. */ if (abi_id == ABI_VZEROUPPER) return (GET_MODE_SIZE (mode) > 16 - && ((TARGET_64BIT - && (IN_RANGE (regno, FIRST_REX_SSE_REG, LAST_REX_SSE_REG))) - || (IN_RANGE (regno, FIRST_SSE_REG, LAST_SSE_REG)))); + && ((TARGET_64BIT && REX_SSE_REGNO_P (regno)) + || LEGACY_SSE_REGNO_P (regno))); return SSE_REGNO_P (regno) && GET_MODE_SIZE (mode) > 16; } diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index e35c79c..2fda1e0 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1409,10 +1409,13 @@ enum reg_class #define SSE_REG_P(X) (REG_P (X) && SSE_REGNO_P (REGNO (X))) #define SSE_REGNO_P(N) \ - (IN_RANGE ((N), FIRST_SSE_REG, LAST_SSE_REG) \ + (LEGACY_SSE_REGNO_P (N) \ || REX_SSE_REGNO_P (N) \ || EXT_REX_SSE_REGNO_P (N)) +#define LEGACY_SSE_REGNO_P(N) \ + IN_RANGE ((N), FIRST_SSE_REG, LAST_SSE_REG) + #define REX_SSE_REGNO_P(N) \ IN_RANGE ((N), FIRST_REX_SSE_REG, LAST_REX_SSE_REG) -- cgit v1.1 From 74509b963ef64101ce601a497913c13021994f51 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 17 Nov 2021 20:40:44 +0100 Subject: Add very basic IPA part of modref-kill analysis gcc/ChangeLog: 2021-11-17 Jan Hubicka * ipa-modref-tree.c: Include cgraph.h and tree-streamer.h. (modref_access_node::stream_out): New member function. (modref_access_node::stream_in): New member function. * ipa-modref-tree.h (modref_access_node::stream_out, modref_access_node::stream_in): Declare. * ipa-modref.c (modref_summary_lto::useful_p): Free useless kills. (modref_summary_lto::dump): Dump kills. (analyze_store): Record kills for LTO (analyze_stmt): Likewise. (modref_summaries_lto::duplicate): Duplicate kills. (write_modref_records): Use new stream_out member function. (read_modref_records): Likewise. (modref_write): Stream out kills. (read_section): Stream in kills (remap_kills): New function. (update_signature): Use it. --- gcc/ipa-modref-tree.c | 46 +++++++++++++++++++ gcc/ipa-modref-tree.h | 4 ++ gcc/ipa-modref.c | 121 ++++++++++++++++++++++++++++---------------------- 3 files changed, 118 insertions(+), 53 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-modref-tree.c b/gcc/ipa-modref-tree.c index bbe23a5..e23d88d 100644 --- a/gcc/ipa-modref-tree.c +++ b/gcc/ipa-modref-tree.c @@ -27,6 +27,8 @@ along with GCC; see the file COPYING3. If not see #include "selftest.h" #include "tree-ssa-alias.h" #include "gimple.h" +#include "cgraph.h" +#include "tree-streamer.h" /* Return true if both accesses are the same. */ bool @@ -458,6 +460,50 @@ modref_access_node::try_merge_with (vec *&accesses, i++; } +/* Stream out to OB. */ + +void +modref_access_node::stream_out (struct output_block *ob) const +{ + streamer_write_hwi (ob, parm_index); + if (parm_index != MODREF_UNKNOWN_PARM) + { + streamer_write_uhwi (ob, parm_offset_known); + if (parm_offset_known) + { + streamer_write_poly_int64 (ob, parm_offset); + streamer_write_poly_int64 (ob, offset); + streamer_write_poly_int64 (ob, size); + streamer_write_poly_int64 (ob, max_size); + } + } +} + +modref_access_node +modref_access_node::stream_in (struct lto_input_block *ib) +{ + int parm_index = streamer_read_hwi (ib); + bool parm_offset_known = false; + poly_int64 parm_offset = 0; + poly_int64 offset = 0; + poly_int64 size = -1; + poly_int64 max_size = -1; + + if (parm_index != MODREF_UNKNOWN_PARM) + { + parm_offset_known = streamer_read_uhwi (ib); + if (parm_offset_known) + { + parm_offset = streamer_read_poly_int64 (ib); + offset = streamer_read_poly_int64 (ib); + size = streamer_read_poly_int64 (ib); + max_size = streamer_read_poly_int64 (ib); + } + } + return {offset, size, max_size, parm_offset, parm_index, + parm_offset_known, false}; +} + /* Insert access with OFFSET and SIZE. Collapse tree if it has more than MAX_ACCESSES entries. If RECORD_ADJUSTMENTs is true avoid too many interval extensions. diff --git a/gcc/ipa-modref-tree.h b/gcc/ipa-modref-tree.h index 1bf2aa8..0a09734 100644 --- a/gcc/ipa-modref-tree.h +++ b/gcc/ipa-modref-tree.h @@ -99,6 +99,10 @@ struct GTY(()) modref_access_node tree get_call_arg (const gcall *stmt) const; /* Build ao_ref corresponding to the access and return true if succesful. */ bool get_ao_ref (const gcall *stmt, class ao_ref *ref) const; + /* Stream access to OB. */ + void stream_out (struct output_block *ob) const; + /* Stream access in from IB. */ + static modref_access_node stream_in (struct lto_input_block *ib); /* Insert A into vector ACCESSES. Limit size of vector to MAX_ACCESSES and if RECORD_ADJUSTMENT is true keep track of adjustment counts. Return 0 if nothing changed, 1 is insertion suceeded and -1 if failed. */ diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 90cd1be..9ceecdd 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -410,6 +410,8 @@ modref_summary_lto::useful_p (int ecf_flags, bool check_flags) && (ecf_flags & ECF_LOOPING_CONST_OR_PURE)); if (loads && !loads->every_base) return true; + else + kills.release (); if (ecf_flags & ECF_PURE) return ((!side_effects || !nondeterministic) && (ecf_flags & ECF_LOOPING_CONST_OR_PURE)); @@ -634,6 +636,15 @@ modref_summary_lto::dump (FILE *out) dump_lto_records (loads, out); fprintf (out, " stores:\n"); dump_lto_records (stores, out); + if (kills.length ()) + { + fprintf (out, " kills:\n"); + for (auto kill : kills) + { + fprintf (out, " "); + kill.dump (out); + } + } if (writes_errno) fprintf (out, " Writes errno\n"); if (side_effects) @@ -1527,15 +1538,17 @@ analyze_store (gimple *stmt, tree, tree op, void *data) record_access (summary->stores, &r, a); if (summary_lto) record_access_lto (summary_lto->stores, &r, a); - if (summary - && ((summary_ptrs *)data)->always_executed + if (((summary_ptrs *)data)->always_executed && a.useful_for_kill_p () && (!cfun->can_throw_non_call_exceptions || !stmt_could_throw_p (cfun, stmt))) { if (dump_file) fprintf (dump_file, " - Recording kill\n"); - modref_access_node::insert_kill (summary->kills, a, false); + if (summary) + modref_access_node::insert_kill (summary->kills, a, false); + if (summary_lto) + modref_access_node::insert_kill (summary_lto->kills, a, false); } return false; } @@ -1554,8 +1567,7 @@ analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto, Similar logic is in ipa-pure-const.c. */ if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt)) { - if (summary - && always_executed && record_access_p (gimple_assign_lhs (stmt))) + if (always_executed && record_access_p (gimple_assign_lhs (stmt))) { ao_ref r; ao_ref_init (&r, gimple_assign_lhs (stmt)); @@ -1564,7 +1576,10 @@ analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto, { if (dump_file) fprintf (dump_file, " - Recording kill\n"); - modref_access_node::insert_kill (summary->kills, a, false); + if (summary) + modref_access_node::insert_kill (summary->kills, a, false); + if (summary_lto) + modref_access_node::insert_kill (summary_lto->kills, a, false); } } return true; @@ -3270,6 +3285,8 @@ modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *, src_data->loads->max_refs, src_data->loads->max_accesses); dst_data->loads->copy_from (src_data->loads); + dst_data->kills.reserve_exact (src_data->kills.length ()); + dst_data->kills.splice (src_data->kills); dst_data->writes_errno = src_data->writes_errno; dst_data->side_effects = src_data->side_effects; dst_data->nondeterministic = src_data->nondeterministic; @@ -3324,40 +3341,21 @@ write_modref_records (modref_records_lto *tt, struct output_block *ob) streamer_write_uhwi (ob, tt->every_base); streamer_write_uhwi (ob, vec_safe_length (tt->bases)); - size_t i; - modref_base_node *base_node; - FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node) + for (auto base_node : tt->bases) { stream_write_tree (ob, base_node->base, true); streamer_write_uhwi (ob, base_node->every_ref); streamer_write_uhwi (ob, vec_safe_length (base_node->refs)); - size_t j; - modref_ref_node *ref_node; - FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node) + for (auto ref_node : base_node->refs) { stream_write_tree (ob, ref_node->ref, true); streamer_write_uhwi (ob, ref_node->every_access); streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses)); - size_t k; - modref_access_node *access_node; - FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node) - { - streamer_write_hwi (ob, access_node->parm_index); - if (access_node->parm_index != -1) - { - streamer_write_uhwi (ob, access_node->parm_offset_known); - if (access_node->parm_offset_known) - { - streamer_write_poly_int64 (ob, access_node->parm_offset); - streamer_write_poly_int64 (ob, access_node->offset); - streamer_write_poly_int64 (ob, access_node->size); - streamer_write_poly_int64 (ob, access_node->max_size); - } - } - } + for (auto access_node : ref_node->accesses) + access_node.stream_out (ob); } } } @@ -3469,26 +3467,7 @@ read_modref_records (lto_input_block *ib, struct data_in *data_in, for (size_t k = 0; k < naccesses; k++) { - int parm_index = streamer_read_hwi (ib); - bool parm_offset_known = false; - poly_int64 parm_offset = 0; - poly_int64 offset = 0; - poly_int64 size = -1; - poly_int64 max_size = -1; - - if (parm_index != -1) - { - parm_offset_known = streamer_read_uhwi (ib); - if (parm_offset_known) - { - parm_offset = streamer_read_poly_int64 (ib); - offset = streamer_read_poly_int64 (ib); - size = streamer_read_poly_int64 (ib); - max_size = streamer_read_poly_int64 (ib); - } - } - modref_access_node a = {offset, size, max_size, parm_offset, - parm_index, parm_offset_known, false}; + modref_access_node a = modref_access_node::stream_in (ib); if (nolto_ref_node) nolto_ref_node->insert_access (a, max_accesses, false); if (lto_ref_node) @@ -3599,6 +3578,9 @@ modref_write () write_modref_records (r->loads, ob); write_modref_records (r->stores, ob); + streamer_write_uhwi (ob, r->kills.length ()); + for (auto kill : r->kills) + kill.stream_out (ob); struct bitpack_d bp = bitpack_create (ob->main_stream); bp_pack_value (&bp, r->writes_errno, 1); @@ -3723,6 +3705,20 @@ read_section (struct lto_file_decl_data *file_data, const char *data, read_modref_records (&ib, data_in, modref_sum ? &modref_sum->stores : NULL, modref_sum_lto ? &modref_sum_lto->stores : NULL); + int j = streamer_read_uhwi (&ib); + if (j && modref_sum) + modref_sum->kills.reserve_exact (j); + if (j && modref_sum_lto) + modref_sum_lto->kills.reserve_exact (j); + for (int k = 0; k < j; k++) + { + modref_access_node a = modref_access_node::stream_in (&ib); + + if (modref_sum) + modref_sum->kills.quick_push (a); + if (modref_sum_lto) + modref_sum_lto->kills.quick_push (a); + } struct bitpack_d bp = streamer_read_bitpack (&ib); if (bp_unpack_value (&bp, 1)) { @@ -3863,6 +3859,27 @@ remap_arg_flags (auto_vec &arg_flags, clone_info *info) } } +/* Update kills accrdoing to the parm map MAP. */ + +static void +remap_kills (vec &kills, const vec &map) +{ + for (size_t i = 0; i < kills.length ();) + if (kills[i].parm_index >= 0) + { + if (kills[i].parm_index < (int)map.length () + && map[kills[i].parm_index] != MODREF_UNKNOWN_PARM) + { + kills[i].parm_index = map[kills[i].parm_index]; + i++; + } + else + kills.unordered_remove (i); + } + else + i++; +} + /* If signature changed, update the summary. */ static void @@ -3913,8 +3930,7 @@ update_signature (struct cgraph_node *node) { r->loads->remap_params (&map); r->stores->remap_params (&map); - /* TODO: One we do IPA kills analysis, update the table here. */ - r->kills.release (); + remap_kills (r->kills, map); if (r->arg_flags.length ()) remap_arg_flags (r->arg_flags, info); } @@ -3922,8 +3938,7 @@ update_signature (struct cgraph_node *node) { r_lto->loads->remap_params (&map); r_lto->stores->remap_params (&map); - /* TODO: One we do IPA kills analysis, update the table here. */ - r_lto->kills.release (); + remap_kills (r_lto->kills, map); if (r_lto->arg_flags.length ()) remap_arg_flags (r_lto->arg_flags, info); } -- cgit v1.1 From 69a5b3ca5c8fdd074fbb26fec926fa25fbec77c1 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Wed, 17 Nov 2021 20:47:48 +0100 Subject: i386: Redefine indirect_thunks_used as HARD_REG_SET. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change indirect_thunks_used to HARD_REG_SET to avoid recalculations of correct register numbers and allow usage of SET/TEST_HARD_REG_BIT accessors. 2021-11-17 Uroš Bizjak gcc/ChangeLog: * config/i386/i386.c (indirect_thunks_used): Redefine as HARD_REG_SET. (ix86_code_end): Use TEST_HARD_REG_BIT on indirect_thunks_used. (ix86_output_indirect_branch_via_reg): Use SET_HARD_REG_BIT on indirect_thunks_used. (ix86_output_indirect_function_return): Ditto. --- gcc/config/i386/i386.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 0c5439d..c9129ae 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -5733,7 +5733,7 @@ static bool indirect_thunk_needed = false; /* Bit masks of integer registers, which contain branch target, used by call thunk functions. */ -static int indirect_thunks_used; +static HARD_REG_SET indirect_thunks_used; /* True if return thunk function is needed. */ static bool indirect_return_needed = false; @@ -6030,8 +6030,7 @@ ix86_code_end (void) for (regno = FIRST_REX_INT_REG; regno <= LAST_REX_INT_REG; regno++) { - unsigned int i = regno - FIRST_REX_INT_REG + LAST_INT_REG + 1; - if ((indirect_thunks_used & (1 << i))) + if (TEST_HARD_REG_BIT (indirect_thunks_used, regno)) output_indirect_thunk_function (indirect_thunk_prefix_none, regno, false); } @@ -6041,7 +6040,7 @@ ix86_code_end (void) char name[32]; tree decl; - if ((indirect_thunks_used & (1 << regno))) + if (TEST_HARD_REG_BIT (indirect_thunks_used, regno)) output_indirect_thunk_function (indirect_thunk_prefix_none, regno, false); @@ -16014,12 +16013,8 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p) != indirect_branch_thunk_inline) { if (cfun->machine->indirect_branch_type == indirect_branch_thunk) - { - int i = regno; - if (i >= FIRST_REX_INT_REG) - i -= (FIRST_REX_INT_REG - LAST_INT_REG - 1); - indirect_thunks_used |= 1 << i; - } + SET_HARD_REG_BIT (indirect_thunks_used, regno); + indirect_thunk_name (thunk_name_buf, regno, need_prefix, false); thunk_name = thunk_name_buf; } @@ -16307,7 +16302,7 @@ ix86_output_indirect_function_return (rtx ret_op) if (need_thunk) { indirect_return_via_cx = true; - indirect_thunks_used |= 1 << CX_REG; + SET_HARD_REG_BIT (indirect_thunks_used, CX_REG); } fprintf (asm_out_file, "\tjmp\t"); assemble_name (asm_out_file, thunk_name); -- cgit v1.1 From 425369bf3068a9f840d1c2f04a4d4c38e924d4dc Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 17 Nov 2021 22:04:26 +0100 Subject: Fix modref summary streaming Fixes bug in streaming in modref access tree that now cause a failure of gamess benchmark. The bug is quite old (present in GCC11 release) but it needs quite interesting series of events to manifest. In particular 1) At lto time ISRA turns some parameters passed by reference to scalar 2) At lto time modref computes summaries for old parameters and then updates them but does so quite stupidly believing that the load from parameters are now unkonwn loads (rather than optimized out). This renders summary not very useful since it thinks every memory aliasing int is now accssed (as opposed as parameter dereference) 3) At stream in we notice too early that summary is useless, set every_access flag and drop the list. However while reading rest of the summary we overwrite the flag back to 0 which makes us to lose part of summary. 4) right selection of partitions needs to be done to avoid late modref from recalculating and thus fixing the summary. This patch fixes the stream in bug, however we also should fix updating of summaries. gcc/ChangeLog: 2021-11-17 Jan Hubicka PR ipa/103246 * ipa-modref.c (read_modref_records): Fix streaminig in of every_access flag. --- gcc/ipa-modref.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 9ceecdd..c94f058 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -3460,10 +3460,10 @@ read_modref_records (lto_input_block *ib, struct data_in *data_in, size_t every_access = streamer_read_uhwi (ib); size_t naccesses = streamer_read_uhwi (ib); - if (nolto_ref_node) - nolto_ref_node->every_access = every_access; - if (lto_ref_node) - lto_ref_node->every_access = every_access; + if (nolto_ref_node && every_access) + nolto_ref_node->collapse (); + if (lto_ref_node && every_access) + lto_ref_node->collapse (); for (size_t k = 0; k < naccesses; k++) { -- cgit v1.1 From 8e410de43ce039bbe08f1e0195e3b6ec24f68cae Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 17 Nov 2021 11:41:12 -0800 Subject: x86: Remove "%!" before ret Before MPX was removed, "%!" was mapped to case '!': if (ix86_bnd_prefixed_insn_p (current_output_insn)) fputs ("bnd ", file); return; After CET was added and MPX was removed, "%!" was mapped to case '!': if (ix86_notrack_prefixed_insn_p (current_output_insn)) fputs ("notrack ", file); return; ix86_notrack_prefixed_insn_p always returns false on ret since the notrack prefix is only for indirect branches. Remove the unused "%!" before ret. PR target/103307 * config/i386/i386.c (ix86_code_end): Remove "%!" before ret. (ix86_output_function_return): Likewise. * config/i386/i386.md (simple_return_pop_internal): Likewise. --- gcc/config/i386/i386.c | 4 ++-- gcc/config/i386/i386.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index c9129ae..a5bfb9e 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -6115,7 +6115,7 @@ ix86_code_end (void) xops[0] = gen_rtx_REG (Pmode, regno); xops[1] = gen_rtx_MEM (Pmode, stack_pointer_rtx); output_asm_insn ("mov%z0\t{%1, %0|%0, %1}", xops); - output_asm_insn ("%!ret", NULL); + fputs ("\tret\n", asm_out_file); final_end_function (); init_insn_lengths (); free_after_compilation (cfun); @@ -16273,7 +16273,7 @@ ix86_output_function_return (bool long_p) } if (!long_p) - return "%!ret"; + return "ret"; return "rep%; ret"; } diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 73d15de..7b2de60 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -14705,7 +14705,7 @@ [(simple_return) (use (match_operand:SI 0 "const_int_operand"))] "reload_completed" - "%!ret\t%0" + "ret\t%0" "&& cfun->machine->function_return_type != indirect_branch_keep" [(const_int 0)] "ix86_split_simple_return_pop_internal (operands[0]); DONE;" -- cgit v1.1 From 53a643f8568067d7700a9f2facc8ba39974973d3 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 27 Oct 2021 07:48:54 -0700 Subject: x86: Add -mharden-sls=[none|all|return|indirect-branch] Add -mharden-sls= to mitigate against straight line speculation (SLS) for function return and indirect branch by adding an INT3 instruction after function return and indirect branch. gcc/ PR target/102952 * config/i386/i386-opts.h (harden_sls): New enum. * config/i386/i386.c (output_indirect_thunk): Mitigate against SLS for function return. (ix86_output_function_return): Likewise. (ix86_output_jmp_thunk_or_indirect): Mitigate against indirect branch. (ix86_output_indirect_jmp): Likewise. (ix86_output_call_insn): Likewise. * config/i386/i386.opt: Add -mharden-sls=. * doc/invoke.texi: Document -mharden-sls=. gcc/testsuite/ PR target/102952 * gcc.target/i386/harden-sls-1.c: New test. * gcc.target/i386/harden-sls-2.c: Likewise. * gcc.target/i386/harden-sls-3.c: Likewise. * gcc.target/i386/harden-sls-4.c: Likewise. * gcc.target/i386/harden-sls-5.c: Likewise. --- gcc/config/i386/i386-opts.h | 7 +++++++ gcc/config/i386/i386.c | 21 ++++++++++++++------- gcc/config/i386/i386.opt | 20 ++++++++++++++++++++ gcc/doc/invoke.texi | 10 +++++++++- gcc/testsuite/gcc.target/i386/harden-sls-1.c | 14 ++++++++++++++ gcc/testsuite/gcc.target/i386/harden-sls-2.c | 14 ++++++++++++++ gcc/testsuite/gcc.target/i386/harden-sls-3.c | 14 ++++++++++++++ gcc/testsuite/gcc.target/i386/harden-sls-4.c | 16 ++++++++++++++++ gcc/testsuite/gcc.target/i386/harden-sls-5.c | 17 +++++++++++++++++ 9 files changed, 125 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/harden-sls-1.c create mode 100644 gcc/testsuite/gcc.target/i386/harden-sls-2.c create mode 100644 gcc/testsuite/gcc.target/i386/harden-sls-3.c create mode 100644 gcc/testsuite/gcc.target/i386/harden-sls-4.c create mode 100644 gcc/testsuite/gcc.target/i386/harden-sls-5.c (limited to 'gcc') diff --git a/gcc/config/i386/i386-opts.h b/gcc/config/i386/i386-opts.h index 04e4ad6..171d310 100644 --- a/gcc/config/i386/i386-opts.h +++ b/gcc/config/i386/i386-opts.h @@ -121,4 +121,11 @@ enum instrument_return { instrument_return_nop5 }; +enum harden_sls { + harden_sls_none = 0, + harden_sls_return = 1 << 0, + harden_sls_indirect_branch = 1 << 1, + harden_sls_all = harden_sls_return | harden_sls_indirect_branch +}; + #endif diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index a5bfb9e..c246c87 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -5914,6 +5914,8 @@ output_indirect_thunk (unsigned int regno) } fputs ("\tret\n", asm_out_file); + if ((ix86_harden_sls & harden_sls_return)) + fputs ("\tint3\n", asm_out_file); } /* Output a funtion with a call and return thunk for indirect branch. @@ -15983,6 +15985,8 @@ ix86_output_jmp_thunk_or_indirect (const char *thunk_name, const int regno) fprintf (asm_out_file, "\tjmp\t"); assemble_name (asm_out_file, thunk_name); putc ('\n', asm_out_file); + if ((ix86_harden_sls & harden_sls_indirect_branch)) + fputs ("\tint3\n", asm_out_file); } else output_indirect_thunk (regno); @@ -16201,10 +16205,10 @@ ix86_output_indirect_jmp (rtx call_op) gcc_unreachable (); ix86_output_indirect_branch (call_op, "%0", true); - return ""; } else - return "%!jmp\t%A0"; + output_asm_insn ("%!jmp\t%A0", &call_op); + return (ix86_harden_sls & harden_sls_indirect_branch) ? "int3" : ""; } /* Output return instrumentation for current function if needed. */ @@ -16272,10 +16276,8 @@ ix86_output_function_return (bool long_p) return ""; } - if (!long_p) - return "ret"; - - return "rep%; ret"; + output_asm_insn (long_p ? "rep%; ret" : "ret", nullptr); + return (ix86_harden_sls & harden_sls_return) ? "int3" : ""; } /* Output indirect function return. RET_OP is the function return @@ -16370,7 +16372,12 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) if (output_indirect_p && !direct_p) ix86_output_indirect_branch (call_op, xasm, true); else - output_asm_insn (xasm, &call_op); + { + output_asm_insn (xasm, &call_op); + if (!direct_p + && (ix86_harden_sls & harden_sls_indirect_branch)) + return "int3"; + } return ""; } diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt index 46fad3c..2b6d8aa 100644 --- a/gcc/config/i386/i386.opt +++ b/gcc/config/i386/i386.opt @@ -1117,6 +1117,26 @@ mrecord-return Target Var(ix86_flag_record_return) Init(0) Generate a __return_loc section pointing to all return instrumentation code. +mharden-sls= +Target RejectNegative Joined Enum(harden_sls) Var(ix86_harden_sls) Init(harden_sls_none) +Generate code to mitigate against straight line speculation. + +Enum +Name(harden_sls) Type(enum harden_sls) +Known choices for mitigation against straight line speculation with -mharden-sls=: + +EnumValue +Enum(harden_sls) String(none) Value(harden_sls_none) + +EnumValue +Enum(harden_sls) String(return) Value(harden_sls_return) + +EnumValue +Enum(harden_sls) String(indirect-branch) Value(harden_sls_indirect_branch) + +EnumValue +Enum(harden_sls) String(all) Value(harden_sls_all) + mavx512bf16 Target Mask(ISA2_AVX512BF16) Var(ix86_isa_flags2) Save Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, AVX2, AVX512F and diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index bd6b9f6..d62ec08 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1427,7 +1427,7 @@ See RS/6000 and PowerPC Options. -mstack-protector-guard-symbol=@var{symbol} @gol -mgeneral-regs-only -mcall-ms2sysv-xlogues -mrelax-cmpxchg-loop @gol -mindirect-branch=@var{choice} -mfunction-return=@var{choice} @gol --mindirect-branch-register -mneeded} +-mindirect-branch-register -mharden-sls=@var{choice} -mneeded} @emph{x86 Windows Options} @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol @@ -32408,6 +32408,14 @@ not be reachable in the large code model. @opindex mindirect-branch-register Force indirect call and jump via register. +@item -mharden-sls=@var{choice} +@opindex mharden-sls +Generate code to mitigate against straight line speculation (SLS) with +@var{choice}. The default is @samp{none} which disables all SLS +hardening. @samp{return} enables SLS hardening for function return. +@samp{indirect-branch} enables SLS hardening for indirect branch. +@samp{all} enables all SLS hardening. + @end table These @samp{-m} switches are supported in addition to the above diff --git a/gcc/testsuite/gcc.target/i386/harden-sls-1.c b/gcc/testsuite/gcc.target/i386/harden-sls-1.c new file mode 100644 index 0000000..6f70dc9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/harden-sls-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -mharden-sls=all" } */ +/* { dg-additional-options "-fno-pic" { target { ! *-*-darwin* } } } */ + +extern void foo (void); + +void +bar (void) +{ + foo (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]+_?foo" } } */ +/* { dg-final { scan-assembler-not {int3} } } */ diff --git a/gcc/testsuite/gcc.target/i386/harden-sls-2.c b/gcc/testsuite/gcc.target/i386/harden-sls-2.c new file mode 100644 index 0000000..a7c5907 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/harden-sls-2.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk-extern -mharden-sls=all" } */ +/* { dg-additional-options "-fno-pic" { target { ! *-*-darwin* } } } */ + +extern void (*fptr) (void); + +void +foo (void) +{ + fptr (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]+_?__x86_indirect_thunk_(r|e)ax" } } */ +/* { dg-final { scan-assembler-times "int3" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/harden-sls-3.c b/gcc/testsuite/gcc.target/i386/harden-sls-3.c new file mode 100644 index 0000000..1a6056b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/harden-sls-3.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=thunk -mharden-sls=all" } */ +/* { dg-additional-options "-fno-pic" { target { ! *-*-darwin* } } } */ + +extern void (*fptr) (void); + +void +foo (void) +{ + fptr (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]+_?__x86_indirect_thunk_(r|e)ax" } } */ +/* { dg-final { scan-assembler-times "int3" 2 } } */ diff --git a/gcc/testsuite/gcc.target/i386/harden-sls-4.c b/gcc/testsuite/gcc.target/i386/harden-sls-4.c new file mode 100644 index 0000000..f70dd13 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/harden-sls-4.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mindirect-branch=keep -mharden-sls=all" } */ +/* { dg-additional-options "-fno-pic" { target { ! *-*-darwin* } } } */ + +extern void (*fptr) (void); + +void +foo (void) +{ + fptr (); +} + +/* { dg-final { scan-assembler "jmp\[ \t\]+\\*_?fptr" { target { ! x32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]+fptr\\(%rip\\), %eax" { target x32 } } } */ +/* { dg-final { scan-assembler "jmp\[ \t\]+\\*%rax" { target x32 } } } */ +/* { dg-final { scan-assembler-times "int3" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/harden-sls-5.c b/gcc/testsuite/gcc.target/i386/harden-sls-5.c new file mode 100644 index 0000000..613c44c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/harden-sls-5.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -mharden-sls=return" } */ +/* { dg-additional-options "-fno-pic" { target { ! *-*-darwin* } } } */ + +typedef void (*dispatch_t)(long offset); + +dispatch_t dispatch; + +int +male_indirect_jump (long offset) +{ + dispatch(offset); + return 0; +} + +/* { dg-final { scan-assembler-times "ret" 1 } } */ +/* { dg-final { scan-assembler-times "int3" 1 } } */ -- cgit v1.1 From ea9e0d6c27405d256b4888e9e860e469037c911d Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Wed, 17 Nov 2021 15:09:23 -0700 Subject: Avoid pathological function redeclarations when checking access sizes [PR102759]. Resolves: PR tree-optimization/102759 - ICE: Segmentation fault in maybe_check_access_sizes since r12-2976-gb48d4e6818674898 gcc/ChangeLog: PR tree-optimization/102759 * gimple-array-bounds.cc (build_printable_array_type): Move... * gimple-ssa-warn-access.cc (build_printable_array_type): Avoid pathological function redeclarations that remove a previously declared prototype. Improve formatting of function arguments in informational notes. * pointer-query.cc (build_printable_array_type): ...to here. * pointer-query.h (build_printable_array_type): Declared. gcc/testsuite/ChangeLog: PR tree-optimization/102759 * gcc.dg/Warray-parameter-10.c: New test. * gcc.dg/Wstringop-overflow-82.c: New test. --- gcc/gimple-array-bounds.cc | 25 --------------------- gcc/gimple-ssa-warn-access.cc | 33 +++++++++++++++++++--------- gcc/pointer-query.cc | 30 +++++++++++++++++++++++++ gcc/pointer-query.h | 3 +++ gcc/testsuite/gcc.dg/Warray-parameter-10.c | 20 +++++++++++++++++ gcc/testsuite/gcc.dg/Wstringop-overflow-82.c | 29 ++++++++++++++++++++++++ 6 files changed, 105 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Warray-parameter-10.c create mode 100644 gcc/testsuite/gcc.dg/Wstringop-overflow-82.c (limited to 'gcc') diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc index a353559..ddb99d2 100644 --- a/gcc/gimple-array-bounds.cc +++ b/gcc/gimple-array-bounds.cc @@ -372,31 +372,6 @@ array_bounds_checker::check_array_ref (location_t location, tree ref, return warned; } -/* Wrapper around build_array_type_nelts that makes sure the array - can be created at all and handles zero sized arrays specially. */ - -static tree -build_printable_array_type (tree eltype, unsigned HOST_WIDE_INT nelts) -{ - if (TYPE_SIZE_UNIT (eltype) - && TREE_CODE (TYPE_SIZE_UNIT (eltype)) == INTEGER_CST - && !integer_zerop (TYPE_SIZE_UNIT (eltype)) - && TYPE_ALIGN_UNIT (eltype) > 1 - && wi::zext (wi::to_wide (TYPE_SIZE_UNIT (eltype)), - ffs_hwi (TYPE_ALIGN_UNIT (eltype)) - 1) != 0) - eltype = TYPE_MAIN_VARIANT (eltype); - - if (nelts) - return build_array_type_nelts (eltype, nelts); - - tree idxtype = build_range_type (sizetype, size_zero_node, NULL_TREE); - tree arrtype = build_array_type (eltype, idxtype); - arrtype = build_distinct_type_copy (TYPE_MAIN_VARIANT (arrtype)); - TYPE_SIZE (arrtype) = bitsize_zero_node; - TYPE_SIZE_UNIT (arrtype) = size_zero_node; - return arrtype; -} - /* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds references to string constants. If VRP can determine that the array subscript is a constant, check if it is outside valid range. diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index 22c791d..48bf8aa 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -2978,10 +2978,16 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype, continue; tree ptrtype = fntype_argno_type (fntype, ptridx); + if (!ptrtype) + /* A function with a prototype was redeclared without one and + the protype has been lost. See pr102759. Avoid dealing + with this pathological case. */ + return; + tree argtype = TREE_TYPE (ptrtype); - /* The size of the access by the call. */ - tree access_size; + /* The size of the access by the call in elements. */ + tree access_nelts; if (sizidx == -1) { /* If only the pointer attribute operand was specified and @@ -2991,17 +2997,17 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype, if the pointer is also declared with attribute nonnull. */ if (access.second.minsize && access.second.minsize != HOST_WIDE_INT_M1U) - access_size = build_int_cstu (sizetype, access.second.minsize); + access_nelts = build_int_cstu (sizetype, access.second.minsize); else - access_size = size_one_node; + access_nelts = size_one_node; } else - access_size = rwm->get (sizidx)->size; + access_nelts = rwm->get (sizidx)->size; /* Format the value or range to avoid an explosion of messages. */ char sizstr[80]; tree sizrng[2] = { size_zero_node, build_all_ones_cst (sizetype) }; - if (get_size_range (m_ptr_qry.rvals, access_size, stmt, sizrng, 1)) + if (get_size_range (m_ptr_qry.rvals, access_nelts, stmt, sizrng, 1)) { char *s0 = print_generic_expr_to_str (sizrng[0]); if (tree_int_cst_equal (sizrng[0], sizrng[1])) @@ -3059,6 +3065,8 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype, } } + /* The size of the access by the call in bytes. */ + tree access_size = NULL_TREE; if (tree_int_cst_sgn (sizrng[0]) >= 0) { if (COMPLETE_TYPE_P (argtype)) @@ -3075,9 +3083,9 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype, access_size = wide_int_to_tree (sizetype, minsize); } } + else + access_size = access_nelts; } - else - access_size = NULL_TREE; if (integer_zerop (ptr)) { @@ -3172,8 +3180,13 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype, if (opt_warned != no_warning) { if (access.second.internal_p) - inform (loc, "referencing argument %u of type %qT", - ptridx + 1, ptrtype); + { + unsigned HOST_WIDE_INT nelts = + access_nelts ? access.second.minsize : HOST_WIDE_INT_M1U; + tree arrtype = build_printable_array_type (argtype, nelts); + inform (loc, "referencing argument %u of type %qT", + ptridx + 1, arrtype); + } else /* If check_access issued a warning above, append the relevant attribute to the string. */ diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index a0e4543..2ead027 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -2358,3 +2358,33 @@ array_elt_at_offset (tree artype, HOST_WIDE_INT off, return NULL_TREE; } + +/* Wrapper around build_array_type_nelts that makes sure the array + can be created at all and handles zero sized arrays specially. */ + +tree +build_printable_array_type (tree eltype, unsigned HOST_WIDE_INT nelts) +{ + if (TYPE_SIZE_UNIT (eltype) + && TREE_CODE (TYPE_SIZE_UNIT (eltype)) == INTEGER_CST + && !integer_zerop (TYPE_SIZE_UNIT (eltype)) + && TYPE_ALIGN_UNIT (eltype) > 1 + && wi::zext (wi::to_wide (TYPE_SIZE_UNIT (eltype)), + ffs_hwi (TYPE_ALIGN_UNIT (eltype)) - 1) != 0) + eltype = TYPE_MAIN_VARIANT (eltype); + + /* Consider excessive NELTS an array of unknown bound. */ + tree idxtype = NULL_TREE; + if (nelts < HOST_WIDE_INT_MAX) + { + if (nelts) + return build_array_type_nelts (eltype, nelts); + idxtype = build_range_type (sizetype, size_zero_node, NULL_TREE); + } + + tree arrtype = build_array_type (eltype, idxtype); + arrtype = build_distinct_type_copy (TYPE_MAIN_VARIANT (arrtype)); + TYPE_SIZE (arrtype) = bitsize_zero_node; + TYPE_SIZE_UNIT (arrtype) = size_zero_node; + return arrtype; +} diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h index c8215b6..fbea331 100644 --- a/gcc/pointer-query.h +++ b/gcc/pointer-query.h @@ -275,4 +275,7 @@ extern tree array_elt_at_offset (tree, HOST_WIDE_INT, HOST_WIDE_INT * = nullptr, HOST_WIDE_INT * = nullptr); +/* Helper to build an array type that can be printed. */ +extern tree build_printable_array_type (tree, unsigned HOST_WIDE_INT); + #endif // GCC_POINTER_QUERY_H diff --git a/gcc/testsuite/gcc.dg/Warray-parameter-10.c b/gcc/testsuite/gcc.dg/Warray-parameter-10.c new file mode 100644 index 0000000..378f8af --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-parameter-10.c @@ -0,0 +1,20 @@ +/* PR c/102759 - ICE calling a function taking an argument redeclared + without a prototype. + { dg-do compile } + { dg-options "-Wall" } */ + +void f (void) +{ + void gia (int[2]); + void g (); +} + +/* Redeclaring the g(int[]) above without a prototype loses it. */ +void gia (); +void g (int[2]); + +void h (void ) +{ + gia (gia); + gia (g); +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-82.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-82.c new file mode 100644 index 0000000..ee2693d --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-82.c @@ -0,0 +1,29 @@ +/* Verify that notes after warnings for array and VLA parameters show + the array form. + { dg-do compile } + { dg-options "-Wall" } */ + +void fia5 (int[5]); + +void gia3_fia5 (void) +{ + int a[3]; + fia5 (a); // { dg-warning "-Wstringop-overflow" } + // { dg-message "argument 1 of type 'int\\\[5]'" "note" { target *-*-* } .-1 } +} + + +/* The type of the argument would ideall be 'int[n]' but the variable + bound is lost/cleared by free-lang-data and never makes it into + the middle end. An (inferior) alternative would be 'int[*]' but + the pretty printer doesn't know how to format the star. A better + solution might be to introduce a new notation, like 'int[$1]', + where the $1 refers to the VLA argument bound. */ +void fvla (int n, int[n]); + +void gia3_fvla (void) +{ + int a[3]; + fvla (sizeof a, a); // { dg-warning "-Wstringop-overflow" } + // { dg-message "argument 2 of type 'int\\\[]'" "note" { target *-*-* } .-1 } +} -- cgit v1.1 From bef32d4a28595e933f24fef378cf052a30b674a7 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 2 Nov 2021 15:45:22 -0400 Subject: libcpp: capture and underline ranges in -Wbidi-chars= [PR103026] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch converts the bidi::vec to use a struct so that we can capture location_t values for the bidirectional control characters. Before: Wbidi-chars-1.c: In function ‘main’: Wbidi-chars-1.c:6:43: warning: unpaired UTF-8 bidirectional control character detected [-Wbidi-chars=] 6 | /* } if (isAdmin) begin admins only */ | ^ Wbidi-chars-1.c:9:28: warning: unpaired UTF-8 bidirectional control character detected [-Wbidi-chars=] 9 | /* end admins only { */ | ^ After: Wbidi-chars-1.c: In function ‘main’: Wbidi-chars-1.c:6:43: warning: unpaired UTF-8 bidirectional control characters detected [-Wbidi-chars=] 6 | /* } if (isAdmin) begin admins only */ | ~~~~~~~~ ~~~~~~~~ ^ | | | | | | | end of bidirectional context | U+202E (RIGHT-TO-LEFT OVERRIDE) U+2066 (LEFT-TO-RIGHT ISOLATE) Wbidi-chars-1.c:9:28: warning: unpaired UTF-8 bidirectional control characters detected [-Wbidi-chars=] 9 | /* end admins only { */ | ~~~~~~~~ ~~~~~~~~ ^ | | | | | | | end of bidirectional context | | U+2066 (LEFT-TO-RIGHT ISOLATE) | U+202E (RIGHT-TO-LEFT OVERRIDE) Signed-off-by: David Malcolm gcc/testsuite/ChangeLog: PR preprocessor/103026 * c-c++-common/Wbidi-chars-ranges.c: New test. libcpp/ChangeLog: PR preprocessor/103026 * lex.c (struct bidi::context): New. (bidi::vec): Convert to a vec of context rather than unsigned char. (bidi::ctx_at): Rename to... (bidi::pop_kind_at): ...this and reimplement for above change. (bidi::current_ctx): Update for change to vec. (bidi::current_ctx_ucn_p): Likewise. (bidi::current_ctx_loc): New. (bidi::on_char): Update for usage of context struct. Add "loc" param and pass it when pushing contexts. (get_location_for_byte_range_in_cur_line): New. (get_bidi_utf8): Rename to... (get_bidi_utf8_1): ...this, reintroducing... (get_bidi_utf8): ...as a wrapper, setting *OUT when the result is not NONE. (get_bidi_ucn): Rename to... (get_bidi_ucn_1): ...this, reintroducing... (get_bidi_ucn): ...as a wrapper, setting *OUT when the result is not NONE. (class unpaired_bidi_rich_location): New. (maybe_warn_bidi_on_close): Use unpaired_bidi_rich_location when reporting on unpaired bidi chars. Split into singular vs plural spellings. (maybe_warn_bidi_on_char): Pass in a location_t rather than a const uchar * and use it when emitting warnings, and when calling bidi::on_char. (_cpp_skip_block_comment): Capture location when kind is not NONE and pass it to maybe_warn_bidi_on_char. (skip_line_comment): Likewise. (forms_identifier_p): Likewise. (lex_raw_string): Likewise. (lex_string): Likewise. Signed-off-by: David Malcolm --- gcc/testsuite/c-c++-common/Wbidi-chars-ranges.c | 54 +++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 gcc/testsuite/c-c++-common/Wbidi-chars-ranges.c (limited to 'gcc') diff --git a/gcc/testsuite/c-c++-common/Wbidi-chars-ranges.c b/gcc/testsuite/c-c++-common/Wbidi-chars-ranges.c new file mode 100644 index 0000000..298750a --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wbidi-chars-ranges.c @@ -0,0 +1,54 @@ +/* PR preprocessor/103026 */ +/* { dg-do compile } */ +/* { dg-options "-Wbidi-chars=unpaired -fdiagnostics-show-caret" } */ +/* Verify that we escape and underline pertinent bidirectional + control characters when quoting the source. */ + +int test_unpaired_bidi () { + int isAdmin = 0; + /*‮ } ⁦if (isAdmin)⁩ ⁦ begin admins only */ +/* { dg-warning "bidirectional" "" { target *-*-* } .-1 } */ +#if 0 + { dg-begin-multiline-output "" } + /* } if (isAdmin) begin admins only */ + ~~~~~~~~ ~~~~~~~~ ^ + | | | + | | end of bidirectional context + U+202E (RIGHT-TO-LEFT OVERRIDE) U+2066 (LEFT-TO-RIGHT ISOLATE) + { dg-end-multiline-output "" } +#endif + + __builtin_printf("You are an admin.\n"); + /* end admins only ‮ { ⁦*/ +/* { dg-warning "bidirectional" "" { target *-*-* } .-1 } */ +#if 0 + { dg-begin-multiline-output "" } + /* end admins only { */ + ~~~~~~~~ ~~~~~~~~ ^ + | | | + | | end of bidirectional context + | U+2066 (LEFT-TO-RIGHT ISOLATE) + U+202E (RIGHT-TO-LEFT OVERRIDE) + { dg-end-multiline-output "" } +#endif + + return 0; +} + +int LRE_‪_PDF_\u202c; +/* { dg-warning "mismatch" "" { target *-*-* } .-1 } */ +#if 0 + { dg-begin-multiline-output "" } + int LRE__PDF_\u202c; + ~~~~~~~~ ^~~~~~ + { dg-end-multiline-output "" } +#endif + +const char *s1 = "LRE_‪_PDF_\u202c"; +/* { dg-warning "mismatch" "" { target *-*-* } .-1 } */ +#if 0 + { dg-begin-multiline-output "" } + const char *s1 = "LRE__PDF_\u202c"; + ~~~~~~~~ ^~~~~~ + { dg-end-multiline-output "" } +#endif -- cgit v1.1 From 32221357007666124409ec3ee0d3a1cf263ebc9e Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Mon, 15 Nov 2021 09:31:20 +0000 Subject: Fix PR tree-optimization/103228 and 103228: folding of (type) X op CST where type is a nop convert Currently we fold (type) X op CST into (type) (X op ((type-x) CST)) when the conversion widens but not when the conversion is a nop. For the same reason why we move the widening conversion (the possibility of removing an extra conversion), we should do the same if the conversion is a nop. Committed as approved with the comment change. PR tree-optimization/103228 PR tree-optimization/55177 gcc/ChangeLog: * match.pd ((type) X bitop CST): Also do this transformation for nop conversions. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr103228-1.c: New test. * gcc.dg/tree-ssa/pr55177-1.c: New test. --- gcc/match.pd | 6 ++++-- gcc/testsuite/gcc.dg/tree-ssa/pr103228-1.c | 11 +++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr55177-1.c | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr103228-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr55177-1.c (limited to 'gcc') diff --git a/gcc/match.pd b/gcc/match.pd index 89df7b2..77d848d 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1616,8 +1616,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) Restrict it to GIMPLE to avoid endless recursions. */ && (bitop != BIT_AND_EXPR || GIMPLE) && (/* That's a good idea if the conversion widens the operand, thus - after hoisting the conversion the operation will be narrower. */ - TYPE_PRECISION (TREE_TYPE (@0)) < TYPE_PRECISION (type) + after hoisting the conversion the operation will be narrower. + It is also a good if the conversion is a nop as moves the + conversion to one side; allowing for combining of the conversions. */ + TYPE_PRECISION (TREE_TYPE (@0)) <= TYPE_PRECISION (type) /* It's also a good idea if the conversion is to a non-integer mode. */ || GET_MODE_CLASS (TYPE_MODE (type)) != MODE_INT diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr103228-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr103228-1.c new file mode 100644 index 0000000..a753981 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr103228-1.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +int f(int a, int b) +{ + b|=1u; + b|=2; + return b; +} +/* { dg-final { scan-tree-dump-times "\\\| 3" 1 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "\\\| 1" 0 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "\\\| 2" 0 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr55177-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr55177-1.c new file mode 100644 index 0000000..de1a264 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr55177-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +extern int x; + +void foo(void) +{ + int a = __builtin_bswap32(x); + a &= 0x5a5b5c5d; + x = __builtin_bswap32(a); +} + +/* { dg-final { scan-tree-dump-times "__builtin_bswap32" 0 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "& 1566333786" 1 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "& 1515936861" 0 "optimized"} } */ -- cgit v1.1 From 280d2838c112f02cb24dd34a69edf112e84cfe12 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 18 Nov 2021 00:16:34 +0000 Subject: Daily bump. --- gcc/ChangeLog | 166 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 17 +++++ gcc/c-family/ChangeLog | 13 ++++ gcc/c/ChangeLog | 6 ++ gcc/testsuite/ChangeLog | 117 ++++++++++++++++++++++++++++++++++ 6 files changed, 320 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0fb2567..5e5a720 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,169 @@ +2021-11-17 Andrew Pinski + + PR tree-optimization/103228 + PR tree-optimization/55177 + * match.pd ((type) X bitop CST): Also do this + transformation for nop conversions. + +2021-11-17 Martin Sebor + + PR tree-optimization/102759 + * gimple-array-bounds.cc (build_printable_array_type): Move... + * gimple-ssa-warn-access.cc (build_printable_array_type): Avoid + pathological function redeclarations that remove a previously + declared prototype. + Improve formatting of function arguments in informational notes. + * pointer-query.cc (build_printable_array_type): ...to here. + * pointer-query.h (build_printable_array_type): Declared. + +2021-11-17 H.J. Lu + + PR target/102952 + * config/i386/i386-opts.h (harden_sls): New enum. + * config/i386/i386.c (output_indirect_thunk): Mitigate against + SLS for function return. + (ix86_output_function_return): Likewise. + (ix86_output_jmp_thunk_or_indirect): Mitigate against indirect + branch. + (ix86_output_indirect_jmp): Likewise. + (ix86_output_call_insn): Likewise. + * config/i386/i386.opt: Add -mharden-sls=. + * doc/invoke.texi: Document -mharden-sls=. + +2021-11-17 H.J. Lu + + PR target/103307 + * config/i386/i386.c (ix86_code_end): Remove "%!" before ret. + (ix86_output_function_return): Likewise. + * config/i386/i386.md (simple_return_pop_internal): Likewise. + +2021-11-17 Jan Hubicka + + PR ipa/103246 + * ipa-modref.c (read_modref_records): Fix streaminig in of every_access + flag. + +2021-11-17 Uroš Bizjak + + * config/i386/i386.c (indirect_thunks_used): Redefine as HARD_REG_SET. + (ix86_code_end): Use TEST_HARD_REG_BIT on indirect_thunks_used. + (ix86_output_indirect_branch_via_reg): Use SET_HARD_REG_BIT + on indirect_thunks_used. + (ix86_output_indirect_function_return): Ditto. + +2021-11-17 Jan Hubicka + + * ipa-modref-tree.c: Include cgraph.h and tree-streamer.h. + (modref_access_node::stream_out): New member function. + (modref_access_node::stream_in): New member function. + * ipa-modref-tree.h (modref_access_node::stream_out, + modref_access_node::stream_in): Declare. + * ipa-modref.c (modref_summary_lto::useful_p): Free useless kills. + (modref_summary_lto::dump): Dump kills. + (analyze_store): Record kills for LTO + (analyze_stmt): Likewise. + (modref_summaries_lto::duplicate): Duplicate kills. + (write_modref_records): Use new stream_out member function. + (read_modref_records): Likewise. + (modref_write): Stream out kills. + (read_section): Stream in kills + (remap_kills): New function. + (update_signature): Use it. + +2021-11-17 Uroš Bizjak + + * config/i386/i386.h (LEGACY_SSE_REGNO_P): New predicate. + (SSE_REGNO_P): Use LEGACY_SSE_REGNO_P predicate. + * config/i386/i386.c (zero_all_vector_registers): + Use LEGACY_SSE_REGNO_P predicate. + (ix86_register_priority): Use REX_INT_REGNO_P, REX_SSE_REGNO_P + and EXT_REG_SSE_REGNO_P predicates. + (ix86_hard_regno_call_part_clobbered): Use REX_SSE_REGNO_P + and LEGACY_SSE_REGNO_P predicates. + +2021-11-17 Jason Merrill + + * doc/invoke.texi (C++ Dialect Options): Document + -fimplicit-constexpr. + +2021-11-17 Przemyslaw Wirkus + + * config/aarch64/aarch64-modes.def (VECTOR_MODE): New V8DI mode. + * config/aarch64/aarch64.c (aarch64_hard_regno_mode_ok): Handle + V8DImode. + * config/aarch64/iterators.md (define_mode_attr nunits): Add entry + for V8DI. + +2021-11-17 Martin Uecker + + PR c/91038 + PR c/29970 + * gimplify.c (gimplify_var_or_parm_decl): Update comment. + (gimplify_compound_lval): Gimplify base expression first. + (gimplify_target_expr): Add comment. + +2021-11-17 Jakub Jelinek + + PR tree-optimization/103192 + * tree-ssa-loop-im.c (move_computations_worker): Use + reset_flow_sensitive_info instead of manually clearing + SSA_NAME_RANGE_INFO and do it for all SSA_NAMEs, not just ones + with integral types. + +2021-11-17 Jakub Jelinek + + PR tree-optimization/103255 + * gimple-range-fold.cc (fold_using_range::range_of_address): Return + range_nonzero rather than unadjusted base's range. Formatting fixes. + +2021-11-17 Richard Sandiford + + * doc/md.texi (cond_fmin@var{mode}, cond_fmax@var{mode}): Document. + * optabs.def (cond_fmin_optab, cond_fmax_optab): New optabs. + * internal-fn.def (COND_FMIN, COND_FMAX): New functions. + * internal-fn.c (first_commutative_argument): Handle them. + (FOR_EACH_COND_FN_PAIR): Likewise. + * match.pd (UNCOND_BINARY, COND_BINARY): Likewise. + * config/aarch64/aarch64-sve.md (cond_): New + pattern. + +2021-11-17 Kewen Lin + + * config/i386/i386.md (*add3_doubleword, *addv4_doubleword, + *addv4_doubleword_1, *sub3_doubleword, + *subv4_doubleword, *subv4_doubleword_1, + *add3_doubleword_cc_overflow_1, *divmodsi4_const, + *neg2_doubleword, *tls_dynamic_gnu2_combine_64_): Fix split + condition. + +2021-11-17 Andrew Pinski + + PR tree-optimization/103288 + * tree-ssa-phiopt.c (value_replacement): Return early if middle + block has more than one pred. + +2021-11-17 Kewen Lin + + * config/visium/visium.md (*add3_insn, *addsi3_insn, *addi3_insn, + *sub3_insn, *subsi3_insn, *subdi3_insn, *neg2_insn, + *negdi2_insn, *and3_insn, *ior3_insn, *xor3_insn, + *one_cmpl2_insn, *ashl3_insn, *ashr3_insn, + *lshr3_insn, *trunchiqi2_insn, *truncsihi2_insn, + *truncdisi2_insn, *extendqihi2_insn, *extendqisi2_insn, + *extendhisi2_insn, *extendsidi2_insn, *zero_extendqihi2_insn, + *zero_extendqisi2_insn, *zero_extendsidi2_insn): Fix split condition. + +2021-11-17 Marek Polacek + + PR preprocessor/103026 + * doc/invoke.texi: Document -Wbidi-chars. + +2021-11-17 Jan Hubicka + + PR ipa/103246 + * ipa-modref.c (ipa_merge_modref_summary_after_inlining): Fix clearing + of to_info_lto + 2021-11-16 Jan Hubicka * ipa-modref.c (get_modref_function_summary): Declare. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 530e4a5..15171a2 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20211117 +20211118 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index be7b286..d9fc37c 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,20 @@ +2021-11-17 David Malcolm + + PR analyzer/102695 + * region-model-impl-calls.cc (region_model::impl_call_strchr): New. + * region-model-manager.cc + (region_model_manager::maybe_fold_unaryop): Simplify cast to + pointer type of an existing pointer to a region. + * region-model.cc (region_model::on_call_pre): Handle + BUILT_IN_STRCHR and "strchr". + (write_to_const_diagnostic::emit): Add auto_diagnostic_group. Add + alternate wordings for functions and labels. + (write_to_const_diagnostic::describe_final_event): Add alternate + wordings for functions and labels. + (region_model::check_for_writable_region): Handle RK_FUNCTION and + RK_LABEL. + * region-model.h (region_model::impl_call_strchr): New decl. + 2021-11-16 David Malcolm PR analyzer/102662 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index c5ae8c1..21f153e 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,16 @@ +2021-11-17 Martin Uecker + + PR c/91038 + PR c/29970 + * c-common.c (pointer_int_sum): Make sure pointer expressions + are evaluated first when the size expression depends on for + variably-modified types. + +2021-11-17 Marek Polacek + + PR preprocessor/103026 + * c.opt (Wbidi-chars, Wbidi-chars=): New option. + 2021-11-16 Jason Merrill * c-common.c (release_tree_vector): Only cache vecs smaller than diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 3ce48f1..8dcd6be 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2021-11-17 Martin Sebor + + PR c/101702 + * c-decl.c (get_parm_array_spec): Strip casts earlier and fold array + bounds before deciding if they're constant. + 2021-11-15 Jakub Jelinek * c-parser.c (OMP_TARGET_CLAUSE_MASK): Add diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 566c571..594cc2c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,120 @@ +2021-11-17 Andrew Pinski + + PR tree-optimization/103228 + PR tree-optimization/55177 + * gcc.dg/tree-ssa/pr103228-1.c: New test. + * gcc.dg/tree-ssa/pr55177-1.c: New test. + +2021-11-17 David Malcolm + + PR preprocessor/103026 + * c-c++-common/Wbidi-chars-ranges.c: New test. + +2021-11-17 Martin Sebor + + PR tree-optimization/102759 + * gcc.dg/Warray-parameter-10.c: New test. + * gcc.dg/Wstringop-overflow-82.c: New test. + +2021-11-17 H.J. Lu + + PR target/102952 + * gcc.target/i386/harden-sls-1.c: New test. + * gcc.target/i386/harden-sls-2.c: Likewise. + * gcc.target/i386/harden-sls-3.c: Likewise. + * gcc.target/i386/harden-sls-4.c: Likewise. + * gcc.target/i386/harden-sls-5.c: Likewise. + +2021-11-17 Martin Sebor + + PR c/101702 + * gcc.dg/Warray-parameter-11.c: New test. + +2021-11-17 Jeff Law + + * gcc.target/mips/frame-header-1.c (bar): Add noipa attribute. + * gcc.target/mips/frame-header-2.c (bar): Likewise. + +2021-11-17 Jakub Jelinek + + PR preprocessor/103130 + * c-c++-common/cpp/dir-only-9.c: New test. + +2021-11-17 Martin Uecker + + PR c/91038 + PR c/29970 + * gcc.dg/vla-stexp-3.c: New test. + * gcc.dg/vla-stexp-4.c: New test. + * gcc.dg/vla-stexp-5.c: New test. + * gcc.dg/vla-stexp-6.c: New test. + * gcc.dg/vla-stexp-7.c: New test. + * gcc.dg/vla-stexp-8.c: New test. + * gcc.dg/vla-stexp-9.c: New test. + +2021-11-17 Jakub Jelinek + + PR tree-optimization/103255 + * gcc.c-torture/execute/pr103255.c: New test. + +2021-11-17 Richard Sandiford + + * gcc.target/aarch64/sve/cond_fmaxnm_5.c: New test. + * gcc.target/aarch64/sve/cond_fmaxnm_5_run.c: Likewise. + * gcc.target/aarch64/sve/cond_fmaxnm_6.c: Likewise. + * gcc.target/aarch64/sve/cond_fmaxnm_6_run.c: Likewise. + * gcc.target/aarch64/sve/cond_fmaxnm_7.c: Likewise. + * gcc.target/aarch64/sve/cond_fmaxnm_7_run.c: Likewise. + * gcc.target/aarch64/sve/cond_fmaxnm_8.c: Likewise. + * gcc.target/aarch64/sve/cond_fmaxnm_8_run.c: Likewise. + * gcc.target/aarch64/sve/cond_fminnm_5.c: Likewise. + * gcc.target/aarch64/sve/cond_fminnm_5_run.c: Likewise. + * gcc.target/aarch64/sve/cond_fminnm_6.c: Likewise. + * gcc.target/aarch64/sve/cond_fminnm_6_run.c: Likewise. + * gcc.target/aarch64/sve/cond_fminnm_7.c: Likewise. + * gcc.target/aarch64/sve/cond_fminnm_7_run.c: Likewise. + * gcc.target/aarch64/sve/cond_fminnm_8.c: Likewise. + * gcc.target/aarch64/sve/cond_fminnm_8_run.c: Likewise. + +2021-11-17 Andrew Pinski + + PR tree-optimization/103288 + * gcc.c-torture/compile/pr103288-1.c: New test. + +2021-11-17 Marek Polacek + + PR preprocessor/103026 + * c-c++-common/Wbidi-chars-1.c: New test. + * c-c++-common/Wbidi-chars-2.c: New test. + * c-c++-common/Wbidi-chars-3.c: New test. + * c-c++-common/Wbidi-chars-4.c: New test. + * c-c++-common/Wbidi-chars-5.c: New test. + * c-c++-common/Wbidi-chars-6.c: New test. + * c-c++-common/Wbidi-chars-7.c: New test. + * c-c++-common/Wbidi-chars-8.c: New test. + * c-c++-common/Wbidi-chars-9.c: New test. + * c-c++-common/Wbidi-chars-10.c: New test. + * c-c++-common/Wbidi-chars-11.c: New test. + * c-c++-common/Wbidi-chars-12.c: New test. + * c-c++-common/Wbidi-chars-13.c: New test. + * c-c++-common/Wbidi-chars-14.c: New test. + * c-c++-common/Wbidi-chars-15.c: New test. + * c-c++-common/Wbidi-chars-16.c: New test. + * c-c++-common/Wbidi-chars-17.c: New test. + +2021-11-17 David Malcolm + + PR analyzer/102695 + * gcc.dg/analyzer/pr102695.c: New test. + * gcc.dg/analyzer/strchr-1.c: New test. + +2021-11-17 David Malcolm + + PR analyzer/102779 + * gcc.dg/analyzer/capacity-1.c: Add dg-require-effective-target + alloca. Use __builtin_alloca rather than alloca. + * gcc.dg/analyzer/capacity-3.c: Likewise. + 2021-11-16 Jan Hubicka * gcc.dg/tree-ssa/modref-dse-4.c: New test. -- cgit v1.1 From a72b7a455c144b29609c8ecf4dff12dc9040cf2c Mon Sep 17 00:00:00 2001 From: konglin1 Date: Wed, 10 Nov 2021 15:31:04 +0800 Subject: i386: add alias for f*mul_*ch intrinsics gcc/ChangeLog: * config/i386/avx512fp16intrin.h (_mm512_mul_pch): Add alias for _mm512_fmul_pch. (_mm512_mask_mul_pch): Likewise. (_mm512_maskz_mul_pch): Likewise. (_mm512_mul_round_pch): Likewise. (_mm512_mask_mul_round_pch): Likewise. (_mm512_maskz_mul_round_pch): Likewise. (_mm512_cmul_pch): Likewise. (_mm512_mask_cmul_pch): Likewise. (_mm512_maskz_cmul_pch): Likewise. (_mm512_cmul_round_pch): Likewise. (_mm512_mask_cmul_round_pch): Likewise. (_mm512_maskz_cmul_round_pch): Likewise. (_mm_mul_sch): Likewise. (_mm_mask_mul_sch): Likewise. (_mm_maskz_mul_sch): Likewise. (_mm_mul_round_sch): Likewise. (_mm_mask_mul_round_sch): Likewise. (_mm_maskz_mul_round_sch): Likewise. (_mm_cmul_sch): Likewise. (_mm_mask_cmul_sch): Likewise. (_mm_maskz_cmul_sch): Likewise. (_mm_cmul_round_sch): Likewise. (_mm_mask_cmul_round_sch): Likewise. (_mm_maskz_cmul_round_sch): Likewise. * config/i386/avx512fp16vlintrin.h (_mm_mul_pch): Likewise. (_mm_mask_mul_pch): Likewise. (_mm_maskz_mul_pch): Likewise. (_mm256_mul_pch): Likewise. (_mm256_mask_mul_pch): Likewise. (_mm256_maskz_mul_pch): Likewise. (_mm_cmul_pch): Likewise. (_mm_mask_cmul_pch): Likewise. (_mm_maskz_cmul_pch): Likewise. (_mm256_cmul_pch): Likewise. (_mm256_mask_cmul_pch): Likewise. (_mm256_maskz_cmul_pch): Likewise. gcc/testsuite/ChangeLog: * gcc.target/i386/avx512fp16-vfcmulcph-1a.c: Add new test for alias. * gcc.target/i386/avx512fp16-vfcmulcsh-1a.c: Likewise. * gcc.target/i386/avx512fp16-vfmulcph-1a.c: Likewise. * gcc.target/i386/avx512fp16-vfmulcsh-1a.c: Likewise. * gcc.target/i386/avx512fp16vl-vfcmulcph-1a.c: Likewise. * gcc.target/i386/avx512fp16vl-vfmulcph-1a.c: Likewise. --- gcc/config/i386/avx512fp16intrin.h | 39 ++++++++++++++++++++++ gcc/config/i386/avx512fp16vlintrin.h | 17 ++++++++++ .../gcc.target/i386/avx512fp16-vfcmulcph-1a.c | 19 +++++++---- .../gcc.target/i386/avx512fp16-vfcmulcsh-1a.c | 19 +++++++---- .../gcc.target/i386/avx512fp16-vfmulcph-1a.c | 19 +++++++---- .../gcc.target/i386/avx512fp16-vfmulcsh-1a.c | 19 +++++++---- .../gcc.target/i386/avx512fp16vl-vfcmulcph-1a.c | 20 +++++++---- .../gcc.target/i386/avx512fp16vl-vfmulcph-1a.c | 20 +++++++---- 8 files changed, 136 insertions(+), 36 deletions(-) (limited to 'gcc') diff --git a/gcc/config/i386/avx512fp16intrin.h b/gcc/config/i386/avx512fp16intrin.h index 44c5e24..fe73e69 100644 --- a/gcc/config/i386/avx512fp16intrin.h +++ b/gcc/config/i386/avx512fp16intrin.h @@ -7162,6 +7162,45 @@ _mm512_set1_pch (_Float16 _Complex __A) return (__m512h) _mm512_set1_ps (u.b); } +// intrinsics below are alias for f*mul_*ch +#define _mm512_mul_pch(A, B) _mm512_fmul_pch ((A), (B)) +#define _mm512_mask_mul_pch(W, U, A, B) \ + _mm512_mask_fmul_pch ((W), (U), (A), (B)) +#define _mm512_maskz_mul_pch(U, A, B) _mm512_maskz_fmul_pch ((U), (A), (B)) +#define _mm512_mul_round_pch(A, B, R) _mm512_fmul_round_pch ((A), (B), (R)) +#define _mm512_mask_mul_round_pch(W, U, A, B, R) \ + _mm512_mask_fmul_round_pch ((W), (U), (A), (B), (R)) +#define _mm512_maskz_mul_round_pch(U, A, B, R) \ + _mm512_maskz_fmul_round_pch ((U), (A), (B), (R)) + +#define _mm512_cmul_pch(A, B) _mm512_fcmul_pch ((A), (B)) +#define _mm512_mask_cmul_pch(W, U, A, B) \ + _mm512_mask_fcmul_pch ((W), (U), (A), (B)) +#define _mm512_maskz_cmul_pch(U, A, B) _mm512_maskz_fcmul_pch ((U), (A), (B)) +#define _mm512_cmul_round_pch(A, B, R) _mm512_fcmul_round_pch ((A), (B), (R)) +#define _mm512_mask_cmul_round_pch(W, U, A, B, R) \ + _mm512_mask_fcmul_round_pch ((W), (U), (A), (B), (R)) +#define _mm512_maskz_cmul_round_pch(U, A, B, R) \ + _mm512_maskz_fcmul_round_pch ((U), (A), (B), (R)) + +#define _mm_mul_sch(A, B) _mm_fmul_sch ((A), (B)) +#define _mm_mask_mul_sch(W, U, A, B) _mm_mask_fmul_sch ((W), (U), (A), (B)) +#define _mm_maskz_mul_sch(U, A, B) _mm_maskz_fmul_sch ((U), (A), (B)) +#define _mm_mul_round_sch(A, B, R) _mm_fmul_round_sch ((A), (B), (R)) +#define _mm_mask_mul_round_sch(W, U, A, B, R) \ + _mm_mask_fmul_round_sch ((W), (U), (A), (B), (R)) +#define _mm_maskz_mul_round_sch(U, A, B, R) \ + _mm_maskz_fmul_round_sch ((U), (A), (B), (R)) + +#define _mm_cmul_sch(A, B) _mm_fcmul_sch ((A), (B)) +#define _mm_mask_cmul_sch(W, U, A, B) _mm_mask_fcmul_sch ((W), (U), (A), (B)) +#define _mm_maskz_cmul_sch(U, A, B) _mm_maskz_fcmul_sch ((U), (A), (B)) +#define _mm_cmul_round_sch(A, B, R) _mm_fcmul_round_sch ((A), (B), (R)) +#define _mm_mask_cmul_round_sch(W, U, A, B, R) \ + _mm_mask_fcmul_round_sch ((W), (U), (A), (B), (R)) +#define _mm_maskz_cmul_round_sch(U, A, B, R) \ + _mm_maskz_fcmul_round_sch ((U), (A), (B), (R)) + #ifdef __DISABLE_AVX512FP16__ #undef __DISABLE_AVX512FP16__ #pragma GCC pop_options diff --git a/gcc/config/i386/avx512fp16vlintrin.h b/gcc/config/i386/avx512fp16vlintrin.h index 11f34bb..fb6f692 100644 --- a/gcc/config/i386/avx512fp16vlintrin.h +++ b/gcc/config/i386/avx512fp16vlintrin.h @@ -3337,6 +3337,23 @@ _mm_set1_pch (_Float16 _Complex __A) return (__m128h) _mm_set1_ps (u.b); } +// intrinsics below are alias for f*mul_*ch +#define _mm_mul_pch(A, B) _mm_fmul_pch ((A), (B)) +#define _mm_mask_mul_pch(W, U, A, B) _mm_mask_fmul_pch ((W), (U), (A), (B)) +#define _mm_maskz_mul_pch(U, A, B) _mm_maskz_fmul_pch ((U), (A), (B)) +#define _mm256_mul_pch(A, B) _mm256_fmul_pch ((A), (B)) +#define _mm256_mask_mul_pch(W, U, A, B) \ + _mm256_mask_fmul_pch ((W), (U), (A), (B)) +#define _mm256_maskz_mul_pch(U, A, B) _mm256_maskz_fmul_pch ((U), (A), (B)) + +#define _mm_cmul_pch(A, B) _mm_fcmul_pch ((A), (B)) +#define _mm_mask_cmul_pch(W, U, A, B) _mm_mask_fcmul_pch ((W), (U), (A), (B)) +#define _mm_maskz_cmul_pch(U, A, B) _mm_maskz_fcmul_pch ((U), (A), (B)) +#define _mm256_cmul_pch(A, B) _mm256_fcmul_pch ((A), (B)) +#define _mm256_mask_cmul_pch(W, U, A, B) \ + _mm256_mask_fcmul_pch ((W), (U), (A), (B)) +#define _mm256_maskz_cmul_pch(U, A, B) _mm256_maskz_fcmul_pch((U), (A), (B)) + #ifdef __DISABLE_AVX512FP16VL__ #undef __DISABLE_AVX512FP16VL__ #pragma GCC pop_options diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfcmulcph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfcmulcph-1a.c index ca2f140..e228393 100644 --- a/gcc/testsuite/gcc.target/i386/avx512fp16-vfcmulcph-1a.c +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfcmulcph-1a.c @@ -1,11 +1,11 @@ /* { dg-do compile } */ /* { dg-options "-mavx512fp16 -O2" } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\[^\{\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\{rz-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\[^\{\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\{rz-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ #include @@ -22,4 +22,11 @@ avx512f_test (void) res = _mm512_fcmul_round_pch (x1, x2, 8); res1 = _mm512_mask_fcmul_round_pch (res1, m16, x1, x2, 8); res2 = _mm512_maskz_fcmul_round_pch (m16, x1, x2, 11); + + res = _mm512_cmul_pch (x1, x2); + res1 = _mm512_mask_cmul_pch (res1, m16, x1, x2); + res2 = _mm512_maskz_cmul_pch (m16, x1, x2); + res = _mm512_cmul_round_pch (x1, x2, 8); + res1 = _mm512_mask_cmul_round_pch (res1, m16, x1, x2, 8); + res2 = _mm512_maskz_cmul_round_pch (m16, x1, x2, 11); } diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfcmulcsh-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfcmulcsh-1a.c index 872d91a..92f58c5 100644 --- a/gcc/testsuite/gcc.target/i386/avx512fp16-vfcmulcsh-1a.c +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfcmulcsh-1a.c @@ -1,11 +1,11 @@ /* { dg-do compile } */ /* { dg-options "-mavx512fp16 -O2" } */ -/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\[^\{\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\{rz-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\[^\{\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcsh\[ \\t\]+\{rz-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ #include @@ -22,4 +22,11 @@ avx512f_test (void) res = _mm_fcmul_round_sch (x1, x2, 8); res1 = _mm_mask_fcmul_round_sch (res1, m8, x1, x2, 8); res2 = _mm_maskz_fcmul_round_sch (m8, x1, x2, 11); + + res = _mm_cmul_sch (x1, x2); + res1 = _mm_mask_cmul_sch (res1, m8, x1, x2); + res2 = _mm_maskz_cmul_sch (m8, x1, x2); + res = _mm_cmul_round_sch (x1, x2, 8); + res1 = _mm_mask_cmul_round_sch (res1, m8, x1, x2, 8); + res2 = _mm_maskz_cmul_round_sch (m8, x1, x2, 11); } diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmulcph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmulcph-1a.c index f31cbca..4135cd2 100644 --- a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmulcph-1a.c +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmulcph-1a.c @@ -1,11 +1,11 @@ /* { dg-do compile } */ /* { dg-options "-mavx512fp16 -O2" } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\[^\{\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\{rz-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\[^\{\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\{rz-sae\}\[^\{\n\]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\[^\n\r]*%zmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ #include @@ -22,4 +22,11 @@ avx512f_test (void) res = _mm512_fmul_round_pch (x1, x2, 8); res1 = _mm512_mask_fmul_round_pch (res1, m16, x1, x2, 8); res2 = _mm512_maskz_fmul_round_pch (m16, x1, x2, 11); + + res = _mm512_mul_pch (x1, x2); + res1 = _mm512_mask_mul_pch (res1, m16, x1, x2); + res2 = _mm512_maskz_mul_pch (m16, x1, x2); + res = _mm512_mul_round_pch (x1, x2, 8); + res1 = _mm512_mask_mul_round_pch (res1, m16, x1, x2, 8); + res2 = _mm512_maskz_mul_round_pch (m16, x1, x2, 11); } diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmulcsh-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmulcsh-1a.c index 5d48874..cdca385 100644 --- a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmulcsh-1a.c +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmulcsh-1a.c @@ -1,11 +1,11 @@ /* { dg-do compile } */ /* { dg-options "-mavx512fp16 -O2" } */ -/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\[^\{\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\{rz-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\[^\{\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcsh\[ \\t\]+\{rz-sae\}\[^\{\n\]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ #include @@ -22,4 +22,11 @@ avx512f_test (void) res = _mm_fmul_round_sch (x1, x2, 8); res1 = _mm_mask_fmul_round_sch (res1, m8, x1, x2, 8); res2 = _mm_maskz_fmul_round_sch (m8, x1, x2, 11); + + res = _mm_mul_sch (x1, x2); + res1 = _mm_mask_mul_sch (res1, m8, x1, x2); + res2 = _mm_maskz_mul_sch (m8, x1, x2); + res = _mm_mul_round_sch (x1, x2, 8); + res1 = _mm_mask_mul_round_sch (res1, m8, x1, x2, 8); + res2 = _mm_maskz_mul_round_sch (m8, x1, x2, 11); } diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfcmulcph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfcmulcph-1a.c index 4e48e9c..370f9ee 100644 --- a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfcmulcph-1a.c +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfcmulcph-1a.c @@ -1,11 +1,11 @@ /* { dg-do compile } */ /* { dg-options "-mavx512f -mavx512fp16 -mavx512vl -O2" } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\{%k\[0-9\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\{%k\[0-9\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfcmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ #include @@ -25,4 +25,12 @@ avx512f_test (void) res2 = _mm_fcmul_pch (x4, x5); res2 = _mm_mask_fcmul_pch (res2, m8, x4, x5); res2 = _mm_maskz_fcmul_pch (m8, x4, x5); + + res1 = _mm256_cmul_pch (x1, x2); + res1 = _mm256_mask_cmul_pch (res1, m8, x1, x2); + res1 = _mm256_maskz_cmul_pch (m8, x1, x2); + + res2 = _mm_cmul_pch (x4, x5); + res2 = _mm_mask_cmul_pch (res2, m8, x4, x5); + res2 = _mm_maskz_cmul_pch (m8, x4, x5); } diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmulcph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmulcph-1a.c index 54e58c6..dce9088 100644 --- a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmulcph-1a.c +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmulcph-1a.c @@ -1,11 +1,11 @@ /* { dg-do compile } */ /* { dg-options "-mavx512f -mavx512fp16 -mavx512vl -O2" } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\{%k\[0-9\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}(?:\n|\[ \\t\]+#)" 1 } } */ -/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\{%k\[0-9\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\[^\n\r]*%ymm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmulcph\[ \\t\]+%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\[^\n\r]*%xmm\[0-9\]+\{%k\[0-9\]\}\{z\}\[^\n\r]*(?:\n|\[ \\t\]+#)" 2 } } */ #include @@ -25,4 +25,12 @@ avx512f_test (void) res2 = _mm_fmul_pch (x4, x5); res2 = _mm_mask_fmul_pch (res2, m8, x4, x5); res2 = _mm_maskz_fmul_pch (m8, x4, x5); + + res1 = _mm256_mul_pch (x1, x2); + res1 = _mm256_mask_mul_pch (res1, m8, x1, x2); + res1 = _mm256_maskz_mul_pch (m8, x1, x2); + + res2 = _mm_mul_pch (x4, x5); + res2 = _mm_mask_mul_pch (res2, m8, x4, x5); + res2 = _mm_maskz_mul_pch (m8, x4, x5); } -- cgit v1.1 From 15f5e70cbb33b40c97325ef9d55557747a148d39 Mon Sep 17 00:00:00 2001 From: Hongyu Wang Date: Thu, 18 Nov 2021 14:45:23 +0800 Subject: i386: Fix wrong codegen for -mrelax-cmpxchg-loop For -mrelax-cmpxchg-loop introduced by PR 103069/r12-5265, it would produce infinite loop. The correct code should be .L84: movl (%rdi), %ecx movl %eax, %edx orl %esi, %edx cmpl %eax, %ecx jne .L82 lock cmpxchgl %edx, (%rdi) jne .L84 movl %r8d, %eax <<< retval is missing in previous impl ret .L82: rep nop jmp .L84 Adjust corresponding expander to fix such issue, and fix runtime test so the problem would be exposed. gcc/ChangeLog: * config/i386/i386-expand.c (ix86_expand_atomic_fetch_op_loop): Adjust generated cfg to avoid infinite loop. gcc/testsuite/ChangeLog: * gcc.target/i386/pr103069-2.c: Adjust. --- gcc/config/i386/i386-expand.c | 7 ++++++- gcc/testsuite/gcc.target/i386/pr103069-2.c | 11 ++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index 3e4de64..0d5d1a0 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -23143,13 +23143,14 @@ void ix86_expand_atomic_fetch_op_loop (rtx target, rtx mem, rtx val, bool doubleword) { rtx old_reg, new_reg, old_mem, success, oldval, new_mem; - rtx_code_label *loop_label, *pause_label; + rtx_code_label *loop_label, *pause_label, *done_label; machine_mode mode = GET_MODE (target); old_reg = gen_reg_rtx (mode); new_reg = old_reg; loop_label = gen_label_rtx (); pause_label = gen_label_rtx (); + done_label = gen_label_rtx (); old_mem = copy_to_reg (mem); emit_label (loop_label); emit_move_insn (old_reg, old_mem); @@ -23207,11 +23208,15 @@ void ix86_expand_atomic_fetch_op_loop (rtx target, rtx mem, rtx val, GET_MODE (success), 1, loop_label, profile_probability::guessed_never ()); + emit_jump_insn (gen_jump (done_label)); + emit_barrier (); + /* If mem is not expected, pause and loop back. */ emit_label (pause_label); emit_insn (gen_pause ()); emit_jump_insn (gen_jump (loop_label)); emit_barrier (); + emit_label (done_label); } #include "gt-i386-expand.h" diff --git a/gcc/testsuite/gcc.target/i386/pr103069-2.c b/gcc/testsuite/gcc.target/i386/pr103069-2.c index 8ac824c..b3f2235 100644 --- a/gcc/testsuite/gcc.target/i386/pr103069-2.c +++ b/gcc/testsuite/gcc.target/i386/pr103069-2.c @@ -1,5 +1,5 @@ -/* PR target/103068 */ -/* { dg-do compile } */ +/* PR target/103069 */ +/* { dg-do run } */ /* { dg-additional-options "-O2 -march=x86-64 -mtune=generic" } */ #include @@ -37,13 +37,14 @@ FUNC_ATOMIC_RELAX (char, xor) #define TEST_ATOMIC_FETCH_LOGIC(TYPE, OP) \ { \ TYPE a = 11, b = 101, res, exp; \ + TYPE c = 11, d = 101; \ res = relax_##TYPE##_##OP##_fetch (&a, b); \ - exp = f_##TYPE##_##OP##_fetch (&a, b); \ + exp = f_##TYPE##_##OP##_fetch (&c, d); \ if (res != exp) \ abort (); \ - a = 21, b = 92; \ + a = c = 21, b = d = 92; \ res = relax_##TYPE##_fetch_##OP (&a, b); \ - exp = f_##TYPE##_fetch_##OP (&a, b); \ + exp = f_##TYPE##_fetch_##OP (&c, d); \ if (res != exp) \ abort (); \ } -- cgit v1.1 From 8f9f5101d52fec12f0f18dfaf746d18cf1f230d0 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 18 Nov 2021 09:07:22 +0100 Subject: tree-optimization/103277 - do abnormal cleanup after call DSE We can now DSE calls in more cases which requires us to eventually purge dead abnormal edges. This implements this. 2021-11-18 Richard Biener PR tree-optimization/103277 * tree-ssa-dse.c (need_ab_cleanup): New. (dse_optimize_redundant_stores): Adjust. (delete_dead_or_redundant_assignment): Get extra need_ab_cleanup argument and set when abnormal cleanup is needed. (dse_optimize_call): Adjust. (dse_optimize_stmt): Likewise. (pass_dse::execute): Allocate and deallocate need_ab_cleanup. Perform abnormal cleanup. * tree-ssa-dse.h (delete_dead_or_redundant_assignment): Adjust. * gcc.dg/pr103277.c: New testcase. --- gcc/testsuite/gcc.dg/pr103277.c | 14 ++++++++++++++ gcc/tree-ssa-dse.c | 25 ++++++++++++++++++++----- gcc/tree-ssa-dse.h | 2 +- 3 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr103277.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/pr103277.c b/gcc/testsuite/gcc.dg/pr103277.c new file mode 100644 index 0000000..5c206f9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr103277.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fbranch-probabilities -fno-ipa-pure-const" } */ + +__attribute__ ((returns_twice)) void +bar (void) +{ +} + +void +foo (int cond) +{ + if (cond) + bar (); +} /* { dg-message "profile count data" } */ diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c index 231e827..9531d89 100644 --- a/gcc/tree-ssa-dse.c +++ b/gcc/tree-ssa-dse.c @@ -88,6 +88,7 @@ static void delete_dead_or_redundant_call (gimple_stmt_iterator *, const char *) /* Bitmap of blocks that have had EH statements cleaned. We should remove their dead edges eventually. */ 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. @@ -758,7 +759,8 @@ dse_optimize_redundant_stores (gimple *stmt) (ao_ref_base_alias_set (&lhs_ref), earlier_base_set))) delete_dead_or_redundant_assignment (&gsi, "redundant", - need_eh_cleanup); + need_eh_cleanup, + need_ab_cleanup); } else if (is_gimple_call (use_stmt)) { @@ -1027,8 +1029,10 @@ delete_dead_or_redundant_call (gimple_stmt_iterator *gsi, const char *type) /* Delete a dead store at GSI, which is a gimple assignment. */ void -delete_dead_or_redundant_assignment (gimple_stmt_iterator *gsi, const char *type, - bitmap need_eh_cleanup) +delete_dead_or_redundant_assignment (gimple_stmt_iterator *gsi, + const char *type, + bitmap need_eh_cleanup, + bitmap need_ab_cleanup) { gimple *stmt = gsi_stmt (*gsi); if (dump_file && (dump_flags & TDF_DETAILS)) @@ -1043,6 +1047,8 @@ delete_dead_or_redundant_assignment (gimple_stmt_iterator *gsi, const char *type /* Remove the dead store. */ basic_block bb = gimple_bb (stmt); + if (need_ab_cleanup && stmt_can_make_abnormal_goto (stmt)) + bitmap_set_bit (need_ab_cleanup, bb->index); if (gsi_remove (gsi, true) && need_eh_cleanup) bitmap_set_bit (need_eh_cleanup, bb->index); @@ -1132,7 +1138,8 @@ dse_optimize_call (gimple_stmt_iterator *gsi, sbitmap live_bytes) if (store_status != DSE_STORE_DEAD) return false; } - delete_dead_or_redundant_assignment (gsi, "dead", need_eh_cleanup); + delete_dead_or_redundant_assignment (gsi, "dead", need_eh_cleanup, + need_ab_cleanup); return true; } @@ -1296,7 +1303,8 @@ dse_optimize_stmt (function *fun, gimple_stmt_iterator *gsi, sbitmap live_bytes) update_stmt (stmt); } else - delete_dead_or_redundant_assignment (gsi, "dead", need_eh_cleanup); + delete_dead_or_redundant_assignment (gsi, "dead", need_eh_cleanup, + need_ab_cleanup); } namespace { @@ -1333,6 +1341,7 @@ pass_dse::execute (function *fun) { unsigned todo = 0; need_eh_cleanup = BITMAP_ALLOC (NULL); + need_ab_cleanup = BITMAP_ALLOC (NULL); auto_sbitmap live_bytes (param_dse_max_object_size); renumber_gimple_stmt_uids (fun); @@ -1410,8 +1419,14 @@ pass_dse::execute (function *fun) gimple_purge_all_dead_eh_edges (need_eh_cleanup); todo |= TODO_cleanup_cfg; } + if (!bitmap_empty_p (need_ab_cleanup)) + { + gimple_purge_all_dead_abnormal_call_edges (need_ab_cleanup); + todo |= TODO_cleanup_cfg; + } BITMAP_FREE (need_eh_cleanup); + BITMAP_FREE (need_ab_cleanup); return todo; } diff --git a/gcc/tree-ssa-dse.h b/gcc/tree-ssa-dse.h index 337579a..051620c 100644 --- a/gcc/tree-ssa-dse.h +++ b/gcc/tree-ssa-dse.h @@ -32,6 +32,6 @@ dse_store_status dse_classify_store (ao_ref *, gimple *, bool, sbitmap, bool * = NULL, tree = NULL); void delete_dead_or_redundant_assignment (gimple_stmt_iterator *, const char *, - bitmap = NULL); + bitmap = NULL, bitmap = NULL); #endif /* GCC_TREE_SSA_DSE_H */ -- cgit v1.1 From e28afbb90f8eca31d0a658e92e2007eb0db2a964 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 18 Nov 2021 09:49:38 +0100 Subject: testsuite/103278 - adjust gcc.dg/tree-ssa/if-to-switch-3.c Analysis shows that after the CD-DCE change we produce better code which makes if-to-switch run into case-values-threshold on some architectures, thus the switch is deemed to simple to be worth generating. The following statically provides --param case-values-threshold to make the testcase less target dependent. 2021-11-18 Richard Biener PR testsuite/103278 * gcc.dg/tree-ssa/if-to-switch-3.c: Supply --param case-values-threshold=4. --- gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-3.c b/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-3.c index 707e630..a55231b 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-3.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-to-switch-3.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-iftoswitch-optimized" } */ +/* Supplying case-values-threshold makes the testcase less target dependent. */ +/* { dg-options "-O2 -fdump-tree-iftoswitch-optimized --param case-values-threshold=4" } */ int IsMySuperRandomChar(int aChar) { -- cgit v1.1 From 206b22d021d94adbaa79e1d443c87415254b15de Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 15 Oct 2021 16:34:34 +0200 Subject: Remove MAY_HAVE_DEBUG_MARKER_STMTS and MAY_HAVE_DEBUG_BIND_STMTS. The macros correspond 1:1 to an option flags and make it harder to find all usages of the flags. gcc/c-family/ChangeLog: * c-gimplify.c (genericize_c_loop): Use option directly. gcc/c/ChangeLog: * c-parser.c (add_debug_begin_stmt): Use option directly. gcc/ChangeLog: * cfgexpand.c (pass_expand::execute): Use option directly. * function.c (allocate_struct_function): Likewise. * gimple-low.c (lower_function_body): Likewise. (lower_stmt): Likewise. * gimple-ssa-backprop.c (backprop::prepare_change): Likewise. * ipa-param-manipulation.c (ipa_param_adjustments::modify_call): Likewise. * ipa-split.c (split_function): Likewise. * lto-streamer-in.c (input_function): Likewise. * sese.c (sese_insert_phis_for_liveouts): Likewise. * ssa-iterators.h (num_imm_uses): Likewise. * tree-cfg.c (make_blocks): Likewise. (gimple_merge_blocks): Likewise. * tree-inline.c (tree_function_versioning): Likewise. * tree-loop-distribution.c (generate_loops_for_partition): Likewise. * tree-sra.c (analyze_access_subtree): Likewise. * tree-ssa-dce.c (remove_dead_stmt): Likewise. * tree-ssa-loop-ivopts.c (remove_unused_ivs): Likewise. * tree-ssa-phiopt.c (spaceship_replacement): Likewise. * tree-ssa-reassoc.c (reassoc_remove_stmt): Likewise. * tree-ssa-tail-merge.c (tail_merge_optimize): Likewise. * tree-ssa-threadedge.c (propagate_threaded_block_debug_into): Likewise. * tree-ssa.c (gimple_replace_ssa_lhs): Likewise. (target_for_debug_bind): Likewise. (insert_debug_temp_for_var_def): Likewise. (insert_debug_temps_for_defs): Likewise. (reset_debug_uses): Likewise. * tree-ssanames.c (release_ssa_name_fn): Likewise. * tree-vect-loop-manip.c (adjust_vec_debug_stmts): Likewise. (adjust_debug_stmts): Likewise. (adjust_phi_and_debug_stmts): Likewise. (vect_do_peeling): Likewise. * tree-vect-loop.c (vect_transform_loop_stmt): Likewise. (vect_transform_loop): Likewise. * tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Remove (MAY_HAVE_DEBUG_BIND_STMTS): Remove. (MAY_HAVE_DEBUG_STMTS): Use options directly. gcc/cp/ChangeLog: * parser.c (add_debug_begin_stmt): Use option directly. --- gcc/c-family/c-gimplify.c | 4 ++-- gcc/c/c-parser.c | 2 +- gcc/cfgexpand.c | 2 +- gcc/cp/parser.c | 2 +- gcc/function.c | 2 +- gcc/gimple-low.c | 4 ++-- gcc/gimple-ssa-backprop.c | 2 +- gcc/ipa-param-manipulation.c | 2 +- gcc/ipa-split.c | 6 +++--- gcc/lto-streamer-in.c | 4 ++-- gcc/sese.c | 2 +- gcc/ssa-iterators.h | 2 +- gcc/tree-cfg.c | 4 ++-- gcc/tree-inline.c | 2 +- gcc/tree-loop-distribution.c | 2 +- gcc/tree-sra.c | 2 +- gcc/tree-ssa-dce.c | 2 +- gcc/tree-ssa-loop-ivopts.c | 2 +- gcc/tree-ssa-phiopt.c | 2 +- gcc/tree-ssa-reassoc.c | 2 +- gcc/tree-ssa-tail-merge.c | 2 +- gcc/tree-ssa-threadedge.c | 2 +- gcc/tree-ssa.c | 10 +++++----- gcc/tree-ssanames.c | 2 +- gcc/tree-vect-loop-manip.c | 8 ++++---- gcc/tree-vect-loop.c | 4 ++-- gcc/tree.h | 7 +------ 27 files changed, 41 insertions(+), 46 deletions(-) (limited to 'gcc') diff --git a/gcc/c-family/c-gimplify.c b/gcc/c-family/c-gimplify.c index 0d38b70..d9cf051 100644 --- a/gcc/c-family/c-gimplify.c +++ b/gcc/c-family/c-gimplify.c @@ -295,7 +295,7 @@ genericize_c_loop (tree *stmt_p, location_t start_locus, tree cond, tree body, finish_bc_block (&stmt_list, bc_continue, clab); if (incr) { - if (MAY_HAVE_DEBUG_MARKER_STMTS && incr_locus != UNKNOWN_LOCATION) + if (debug_nonbind_markers_p && incr_locus != UNKNOWN_LOCATION) { tree d = build0 (DEBUG_BEGIN_STMT, void_type_node); SET_EXPR_LOCATION (d, expr_loc_or_loc (incr, start_locus)); @@ -305,7 +305,7 @@ genericize_c_loop (tree *stmt_p, location_t start_locus, tree cond, tree body, } append_to_statement_list (entry, &stmt_list); - if (MAY_HAVE_DEBUG_MARKER_STMTS && cond_locus != UNKNOWN_LOCATION) + if (debug_nonbind_markers_p && cond_locus != UNKNOWN_LOCATION) { tree d = build0 (DEBUG_BEGIN_STMT, void_type_node); SET_EXPR_LOCATION (d, cond_locus); diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 83e837c..40c46ec 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1791,7 +1791,7 @@ static void add_debug_begin_stmt (location_t loc) { /* Don't add DEBUG_BEGIN_STMTs outside of functions, see PR84721. */ - if (!MAY_HAVE_DEBUG_MARKER_STMTS || !building_stmt_list_p ()) + if (!debug_nonbind_markers_p || !building_stmt_list_p ()) return; tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node); diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index eb6466f..4e6f776 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -6587,7 +6587,7 @@ pass_expand::execute (function *fun) timevar_pop (TV_OUT_OF_SSA); SA.partition_to_pseudo = XCNEWVEC (rtx, SA.map->num_partitions); - if (MAY_HAVE_DEBUG_BIND_STMTS && flag_tree_ter) + if (flag_var_tracking_assignments && flag_tree_ter) { gimple_stmt_iterator gsi; FOR_EACH_BB_FN (bb, cfun) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e86e2b5..154b40e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11684,7 +11684,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) static void add_debug_begin_stmt (location_t loc) { - if (!MAY_HAVE_DEBUG_MARKER_STMTS) + if (!debug_nonbind_markers_p) return; if (DECL_DECLARED_CONCEPT_P (current_function_decl)) /* A concept is never expanded normally. */ diff --git a/gcc/function.c b/gcc/function.c index 61b3bd0..1bebe8a 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -4872,7 +4872,7 @@ allocate_struct_function (tree fndecl, bool abstract_p) disabled. The markers make little sense without the variable binding annotations among them. */ cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt - && MAY_HAVE_DEBUG_MARKER_STMTS; + && debug_nonbind_markers_p; } /* This is like allocate_struct_function, but pushes a new cfun for FNDECL diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 7e39c22..7d9b3df 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -114,7 +114,7 @@ lower_function_body (void) /* If we had begin stmt markers from e.g. PCH, but this compilation doesn't want them, lower_stmt will have cleaned them up; we can now clear the flag that indicates we had them. */ - if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers) + if (!debug_nonbind_markers_p && cfun->debug_nonbind_markers) { /* This counter needs not be exact, but before lowering it will most certainly be. */ @@ -316,7 +316,7 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) /* Propagate fallthruness. */ /* If the function (e.g. from PCH) had debug stmts, but they're disabled for this compilation, remove them. */ - if (!MAY_HAVE_DEBUG_MARKER_STMTS) + if (!debug_nonbind_markers_p) gsi_remove (gsi, true); else gsi_next (gsi); diff --git a/gcc/gimple-ssa-backprop.c b/gcc/gimple-ssa-backprop.c index 4b62bb9..3705c10 100644 --- a/gcc/gimple-ssa-backprop.c +++ b/gcc/gimple-ssa-backprop.c @@ -737,7 +737,7 @@ strip_sign_op (tree rhs) void backprop::prepare_change (tree var) { - if (MAY_HAVE_DEBUG_BIND_STMTS) + if (flag_var_tracking_assignments) insert_debug_temp_for_var_def (NULL, var); reset_flow_sensitive_info (var); } diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c index cec1dba..ba897bb 100644 --- a/gcc/ipa-param-manipulation.c +++ b/gcc/ipa-param-manipulation.c @@ -832,7 +832,7 @@ ipa_param_adjustments::modify_call (cgraph_edge *cs, vector to say for debug info that if parameter parm had been passed, it would have value parm_Y(D). */ tree old_decl = gimple_call_fndecl (stmt); - if (MAY_HAVE_DEBUG_BIND_STMTS && old_decl && callee_decl) + if (flag_var_tracking_assignments && old_decl && callee_decl) { vec **debug_args = NULL; unsigned i = 0; diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c index c68577d..6537767 100644 --- a/gcc/ipa-split.c +++ b/gcc/ipa-split.c @@ -1465,7 +1465,7 @@ split_function (basic_block return_bb, class split_point *split_point, { vec **debug_args = NULL; unsigned i = 0, len = 0; - if (MAY_HAVE_DEBUG_BIND_STMTS) + if (flag_var_tracking_assignments) { debug_args = decl_debug_args_lookup (node->decl); if (debug_args) @@ -1479,11 +1479,11 @@ split_function (basic_block return_bb, class split_point *split_point, gimple *def_temp; /* This needs to be done even without - MAY_HAVE_DEBUG_BIND_STMTS, otherwise if it didn't exist + flag_var_tracking_assignments, otherwise if it didn't exist before, we'd end up with different SSA_NAME_VERSIONs between -g and -g0. */ arg = get_or_create_ssa_default_def (cfun, parm); - if (!MAY_HAVE_DEBUG_BIND_STMTS || debug_args == NULL) + if (!flag_var_tracking_assignments || debug_args == NULL) continue; while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm)) diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c index eb8a7dc..4165892 100644 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@ -1454,8 +1454,8 @@ input_function (tree fn_decl, class data_in *data_in, { if (is_gimple_debug (stmt) && (gimple_debug_nonbind_marker_p (stmt) - ? !MAY_HAVE_DEBUG_MARKER_STMTS - : !MAY_HAVE_DEBUG_BIND_STMTS)) + ? !debug_nonbind_markers_p + : !flag_var_tracking_assignments)) remove = true; /* In case the linemap overflows locations can be dropped to zero. Thus do not keep nonsensical inline entry markers diff --git a/gcc/sese.c b/gcc/sese.c index ca88f9b..5ddbb0b 100644 --- a/gcc/sese.c +++ b/gcc/sese.c @@ -205,7 +205,7 @@ void sese_insert_phis_for_liveouts (sese_info_p region, basic_block bb, edge false_e, edge true_e) { - if (MAY_HAVE_DEBUG_BIND_STMTS) + if (flag_var_tracking_assignments) sese_reset_debug_liveouts (region); unsigned i; diff --git a/gcc/ssa-iterators.h b/gcc/ssa-iterators.h index f70b0a4..3e26ce0 100644 --- a/gcc/ssa-iterators.h +++ b/gcc/ssa-iterators.h @@ -456,7 +456,7 @@ num_imm_uses (const_tree var) const ssa_use_operand_t *ptr; unsigned int num = 0; - if (!MAY_HAVE_DEBUG_BIND_STMTS) + if (!flag_var_tracking_assignments) { for (ptr = start->next; ptr != start; ptr = ptr->next) if (USE_STMT (ptr)) diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 8ed8c69..cde606e 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -614,7 +614,7 @@ make_blocks (gimple_seq seq) latest (earliest we find) label, and moving debug stmts that are not separated from it by nondebug nonlabel stmts after the label. */ - if (MAY_HAVE_DEBUG_MARKER_STMTS) + if (debug_nonbind_markers_p) { gimple_stmt_iterator label = gsi_none (); @@ -2139,7 +2139,7 @@ gimple_merge_blocks (basic_block a, basic_block b) gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT); } /* Other user labels keep around in a form of a debug stmt. */ - else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_BIND_STMTS) + else if (!DECL_ARTIFICIAL (label) && flag_var_tracking_assignments) { gimple *dbg = gimple_build_debug_bind (label, integer_zero_node, diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 8c108d8..a483b9b 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -6432,7 +6432,7 @@ tree_function_versioning (tree old_decl, tree new_decl, } } - if (param_body_adjs && MAY_HAVE_DEBUG_BIND_STMTS) + if (param_body_adjs && flag_var_tracking_assignments) { vec **debug_args = NULL; unsigned int len = 0; diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c index 583c01a..1f2d032 100644 --- a/gcc/tree-loop-distribution.c +++ b/gcc/tree-loop-distribution.c @@ -1000,7 +1000,7 @@ generate_loops_for_partition (class loop *loop, partition *partition, /* Remove stmts not in the PARTITION bitmap. */ bbs = get_loop_body_in_dom_order (loop); - if (MAY_HAVE_DEBUG_BIND_STMTS) + if (flag_var_tracking_assignments) for (i = 0; i < loop->num_nodes; i++) { basic_block bb = bbs[i]; diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 76e3aae..10acd5e 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -2588,7 +2588,7 @@ analyze_access_subtree (struct access *root, struct access *parent, gcc_checking_assert (!root->grp_scalar_read && !root->grp_assignment_read); sth_created = true; - if (MAY_HAVE_DEBUG_BIND_STMTS) + if (flag_var_tracking_assignments) { root->grp_to_be_debug_replaced = 1; root->replacement_decl = create_access_replacement (root); diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index dbf02c4..27aa74f 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -1143,7 +1143,7 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb, /* If this is a store into a variable that is being optimized away, add a debug bind stmt if possible. */ - if (MAY_HAVE_DEBUG_BIND_STMTS + if (flag_var_tracking_assignments && gimple_assign_single_p (stmt) && is_gimple_val (gimple_assign_rhs1 (stmt))) { diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 5a7fd30..2dad54d 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -7670,7 +7670,7 @@ remove_unused_ivs (struct ivopts_data *data, bitmap toremove) tree def = info->iv->ssa_name; - if (MAY_HAVE_DEBUG_BIND_STMTS && SSA_NAME_DEF_STMT (def)) + if (flag_var_tracking_assignments && SSA_NAME_DEF_STMT (def)) { imm_use_iterator imm_iter; use_operand_p use_p; diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index 8984a5e..f043168 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -2403,7 +2403,7 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, } update_stmt (use_stmt); - if (MAY_HAVE_DEBUG_BIND_STMTS) + if (flag_var_tracking_assignments) { use_operand_p use_p; imm_use_iterator iter; diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index 6531622..5c748ad 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -233,7 +233,7 @@ reassoc_remove_stmt (gimple_stmt_iterator *gsi) { gimple *stmt = gsi_stmt (*gsi); - if (!MAY_HAVE_DEBUG_BIND_STMTS || gimple_code (stmt) == GIMPLE_PHI) + if (!flag_var_tracking_assignments || gimple_code (stmt) == GIMPLE_PHI) return gsi_remove (gsi, true); gimple_stmt_iterator prev = *gsi; diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c index 48f9421..5487679e0 100644 --- a/gcc/tree-ssa-tail-merge.c +++ b/gcc/tree-ssa-tail-merge.c @@ -1796,7 +1796,7 @@ tail_merge_optimize (unsigned int todo) if (nr_bbs_removed_total > 0) { - if (MAY_HAVE_DEBUG_BIND_STMTS) + if (flag_var_tracking_assignments) { calculate_dominance_info (CDI_DOMINATORS); update_debug_stmts (); diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 891c62a..813137e 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -645,7 +645,7 @@ jump_threader::simplify_control_stmt_condition_1 void propagate_threaded_block_debug_into (basic_block dest, basic_block src) { - if (!MAY_HAVE_DEBUG_BIND_STMTS) + if (!flag_var_tracking_assignments) return; if (!single_pred_p (dest)) diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 1565e21..ab5e915 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -220,7 +220,7 @@ flush_pending_stmts (edge e) void gimple_replace_ssa_lhs (gimple *stmt, tree nlhs) { - if (MAY_HAVE_DEBUG_BIND_STMTS) + if (flag_var_tracking_assignments) { tree lhs = gimple_get_lhs (stmt); @@ -242,7 +242,7 @@ gimple_replace_ssa_lhs (gimple *stmt, tree nlhs) tree target_for_debug_bind (tree var) { - if (!MAY_HAVE_DEBUG_BIND_STMTS) + if (!flag_var_tracking_assignments) return NULL_TREE; if (TREE_CODE (var) == SSA_NAME) @@ -307,7 +307,7 @@ insert_debug_temp_for_var_def (gimple_stmt_iterator *gsi, tree var) int usecount = 0; tree value = NULL; - if (!MAY_HAVE_DEBUG_BIND_STMTS) + if (!flag_var_tracking_assignments) return; /* If this name has already been registered for replacement, do nothing @@ -499,7 +499,7 @@ insert_debug_temps_for_defs (gimple_stmt_iterator *gsi) ssa_op_iter op_iter; def_operand_p def_p; - if (!MAY_HAVE_DEBUG_BIND_STMTS) + if (!flag_var_tracking_assignments) return; stmt = gsi_stmt (*gsi); @@ -525,7 +525,7 @@ reset_debug_uses (gimple *stmt) imm_use_iterator imm_iter; gimple *use_stmt; - if (!MAY_HAVE_DEBUG_BIND_STMTS) + if (!flag_var_tracking_assignments) return; FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, op_iter, SSA_OP_DEF) diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c index f427c5a..eceb51a 100644 --- a/gcc/tree-ssanames.c +++ b/gcc/tree-ssanames.c @@ -560,7 +560,7 @@ release_ssa_name_fn (struct function *fn, tree var) int saved_ssa_name_version = SSA_NAME_VERSION (var); use_operand_p imm = &(SSA_NAME_IMM_USE_NODE (var)); - if (MAY_HAVE_DEBUG_BIND_STMTS) + if (flag_var_tracking_assignments) insert_debug_temp_for_var_def (NULL, var); if (flag_checking) diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c index f788deb..6d13255 100644 --- a/gcc/tree-vect-loop-manip.c +++ b/gcc/tree-vect-loop-manip.c @@ -201,7 +201,7 @@ adjust_debug_stmts_now (adjust_info *ai) static void adjust_vec_debug_stmts (void) { - if (!MAY_HAVE_DEBUG_BIND_STMTS) + if (!flag_var_tracking_assignments) return; gcc_assert (adjust_vec.exists ()); @@ -223,7 +223,7 @@ adjust_debug_stmts (tree from, tree to, basic_block bb) { adjust_info ai; - if (MAY_HAVE_DEBUG_BIND_STMTS + if (flag_var_tracking_assignments && TREE_CODE (from) == SSA_NAME && ! SSA_NAME_IS_DEFAULT_DEF (from) && ! virtual_operand_p (from)) @@ -251,7 +251,7 @@ adjust_phi_and_debug_stmts (gimple *update_phi, edge e, tree new_def) SET_PHI_ARG_DEF (update_phi, e->dest_idx, new_def); - if (MAY_HAVE_DEBUG_BIND_STMTS) + if (flag_var_tracking_assignments) adjust_debug_stmts (orig_def, PHI_RESULT (update_phi), gimple_bb (update_phi)); } @@ -2696,7 +2696,7 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1, vop_to_rename = create_lcssa_for_virtual_phi (orig_loop); } - if (MAY_HAVE_DEBUG_BIND_STMTS) + if (flag_var_tracking_assignments) { gcc_assert (!adjust_vec.exists ()); adjust_vec.create (32); diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 73efdb9..f305d54 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -9228,7 +9228,7 @@ vect_transform_loop_stmt (loop_vec_info loop_vinfo, stmt_vec_info stmt_info, dump_printf_loc (MSG_NOTE, vect_location, "------>vectorizing statement: %G", stmt_info->stmt); - if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info)) + if (flag_var_tracking_assignments && !STMT_VINFO_LIVE_P (stmt_info)) vect_loop_kill_debug_uses (loop, stmt_info); if (!STMT_VINFO_RELEVANT_P (stmt_info) @@ -9602,7 +9602,7 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) if (!stmt_info) continue; - if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info)) + if (flag_var_tracking_assignments && !STMT_VINFO_LIVE_P (stmt_info)) vect_loop_kill_debug_uses (loop, stmt_info); if (!STMT_VINFO_RELEVANT_P (stmt_info) diff --git a/gcc/tree.h b/gcc/tree.h index 03719b18..76d96c3 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1174,14 +1174,9 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, #define VL_EXP_OPERAND_LENGTH(NODE) \ ((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0])) -/* Nonzero if gimple_debug_nonbind_marker_p() may possibly hold. */ -#define MAY_HAVE_DEBUG_MARKER_STMTS debug_nonbind_markers_p -/* Nonzero if gimple_debug_bind_p() (and thus - gimple_debug_source_bind_p()) may possibly hold. */ -#define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments /* Nonzero if is_gimple_debug() may possibly hold. */ #define MAY_HAVE_DEBUG_STMTS \ - (MAY_HAVE_DEBUG_MARKER_STMTS || MAY_HAVE_DEBUG_BIND_STMTS) + (debug_nonbind_markers_p || flag_var_tracking_assignments) /* In a LOOP_EXPR node. */ #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0) -- cgit v1.1 From efb7c51024ccad9df293e6caf134d78b3d00cf89 Mon Sep 17 00:00:00 2001 From: Matthias Kretz Date: Fri, 16 Jul 2021 10:46:24 +0200 Subject: c-family: Add __builtin_assoc_barrier New builtin to enable explicit use of PAREN_EXPR in C & C++ code. Signed-off-by: Matthias Kretz gcc/testsuite/ChangeLog: * c-c++-common/builtin-assoc-barrier-1.c: New test. gcc/cp/ChangeLog: * constexpr.c (cxx_eval_constant_expression): Handle PAREN_EXPR via cxx_eval_constant_expression. * cp-objcp-common.c (names_builtin_p): Handle RID_BUILTIN_ASSOC_BARRIER. * cp-tree.h: Adjust TREE_LANG_FLAG documentation to include PAREN_EXPR in REF_PARENTHESIZED_P. (REF_PARENTHESIZED_P): Add PAREN_EXPR. * parser.c (cp_parser_postfix_expression): Handle RID_BUILTIN_ASSOC_BARRIER. * pt.c (tsubst_copy_and_build): If the PAREN_EXPR is not a parenthesized initializer, build a new PAREN_EXPR. * semantics.c (force_paren_expr): Simplify conditionals. Set REF_PARENTHESIZED_P on PAREN_EXPR. (maybe_undo_parenthesized_ref): Test PAREN_EXPR for REF_PARENTHESIZED_P. gcc/c-family/ChangeLog: * c-common.c (c_common_reswords): Add __builtin_assoc_barrier. * c-common.h (enum rid): Add RID_BUILTIN_ASSOC_BARRIER. gcc/c/ChangeLog: * c-decl.c (names_builtin_p): Handle RID_BUILTIN_ASSOC_BARRIER. * c-parser.c (c_parser_postfix_expression): Likewise. gcc/ChangeLog: * doc/extend.texi: Document __builtin_assoc_barrier. --- gcc/c-family/c-common.c | 1 + gcc/c-family/c-common.h | 2 +- gcc/c/c-decl.c | 1 + gcc/c/c-parser.c | 20 ++++++ gcc/cp/constexpr.c | 8 +++ gcc/cp/cp-objcp-common.c | 1 + gcc/cp/cp-tree.h | 12 ++-- gcc/cp/parser.c | 14 +++++ gcc/cp/pt.c | 10 ++- gcc/cp/semantics.c | 23 +++---- gcc/doc/extend.texi | 18 ++++++ .../c-c++-common/builtin-assoc-barrier-1.c | 71 ++++++++++++++++++++++ 12 files changed, 158 insertions(+), 23 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c (limited to 'gcc') diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index ca7d69c..86c007f 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -384,6 +384,7 @@ const struct c_common_resword c_common_reswords[] = { "__builtin_convertvector", RID_BUILTIN_CONVERTVECTOR, 0 }, { "__builtin_has_attribute", RID_BUILTIN_HAS_ATTRIBUTE, 0 }, { "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY }, + { "__builtin_assoc_barrier", RID_BUILTIN_ASSOC_BARRIER, 0 }, { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 }, { "__builtin_shufflevector", RID_BUILTIN_SHUFFLEVECTOR, 0 }, { "__builtin_tgmath", RID_BUILTIN_TGMATH, D_CONLY }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index d5dad99..c089fda 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -108,7 +108,7 @@ enum rid RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE, RID_BUILTIN_SHUFFLEVECTOR, RID_BUILTIN_CONVERTVECTOR, RID_BUILTIN_TGMATH, - RID_BUILTIN_HAS_ATTRIBUTE, + RID_BUILTIN_HAS_ATTRIBUTE, RID_BUILTIN_ASSOC_BARRIER, RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, /* TS 18661-3 keywords, in the same sequence as the TI_* values. */ diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 63d806a..3e28a03 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -10621,6 +10621,7 @@ names_builtin_p (const char *name) case RID_BUILTIN_HAS_ATTRIBUTE: case RID_BUILTIN_SHUFFLE: case RID_BUILTIN_SHUFFLEVECTOR: + case RID_BUILTIN_ASSOC_BARRIER: case RID_CHOOSE_EXPR: case RID_OFFSETOF: case RID_TYPES_COMPATIBLE_P: diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 40c46ec..81eea18 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -8962,6 +8962,7 @@ c_parser_predefined_identifier (c_parser *parser) assignment-expression , assignment-expression, ) __builtin_convertvector ( assignment-expression , type-name ) + __builtin_assoc_barrier ( assignment-expression ) offsetof-member-designator: identifier @@ -10107,6 +10108,25 @@ c_parser_postfix_expression (c_parser *parser) } } break; + case RID_BUILTIN_ASSOC_BARRIER: + { + location_t start_loc = loc; + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + e1 = c_parser_expr_no_commas (parser, NULL); + mark_exp_read (e1.value); + location_t end_loc = c_parser_peek_token (parser)->get_finish (); + parens.skip_until_found_close (parser); + expr.value = build1_loc (loc, PAREN_EXPR, TREE_TYPE (e1.value), + e1.value); + set_c_expr_source_range (&expr, start_loc, end_loc); + } + break; case RID_AT_SELECTOR: { gcc_assert (c_dialect_objc ()); diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 69d9d3d..c8f9d5f 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -6901,6 +6901,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, non_constant_p, overflow_p); break; + case PAREN_EXPR: + gcc_assert (!REF_PARENTHESIZED_P (t)); + /* A PAREN_EXPR resulting from __builtin_assoc_barrier has no effect in + constant expressions since it's unaffected by -fassociative-math. */ + r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, + non_constant_p, overflow_p); + break; + case NOP_EXPR: if (REINTERPRET_CAST_P (t)) { diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 28f2d7b..38eae88 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -404,6 +404,7 @@ names_builtin_p (const char *name) case RID_BUILTIN_SHUFFLE: case RID_BUILTIN_SHUFFLEVECTOR: case RID_BUILTIN_LAUNDER: + case RID_BUILTIN_ASSOC_BARRIER: case RID_BUILTIN_BIT_CAST: case RID_OFFSETOF: case RID_HAS_NOTHROW_ASSIGN: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index acc98c9..3f56cb9 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -473,7 +473,8 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR) FNDECL_USED_AUTO (in FUNCTION_DECL) DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE) - REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF, SCOPE_REF, VIEW_CONVERT_EXPR) + REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF, SCOPE_REF, + VIEW_CONVERT_EXPR, PAREN_EXPR) AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR) CONSTRUCTOR_MUTABLE_POISON (in CONSTRUCTOR) OVL_HIDDEN_P (in OVERLOAD) @@ -4041,12 +4042,13 @@ struct GTY(()) lang_decl { #define PAREN_STRING_LITERAL_P(NODE) \ TREE_LANG_FLAG_0 (STRING_CST_CHECK (NODE)) -/* Indicates whether a COMPONENT_REF or a SCOPE_REF has been parenthesized, or - an INDIRECT_REF comes from parenthesizing a _DECL. Currently only set some - of the time in C++14 mode. */ +/* Indicates whether a COMPONENT_REF or a SCOPE_REF has been parenthesized, an + INDIRECT_REF comes from parenthesizing a _DECL, or a PAREN_EXPR identifies a + parenthesized initializer relevant for decltype(auto). Currently only set + some of the time in C++14 mode. */ #define REF_PARENTHESIZED_P(NODE) \ - TREE_LANG_FLAG_2 (TREE_CHECK4 ((NODE), COMPONENT_REF, INDIRECT_REF, SCOPE_REF, VIEW_CONVERT_EXPR)) + TREE_LANG_FLAG_2 (TREE_CHECK5 ((NODE), COMPONENT_REF, INDIRECT_REF, SCOPE_REF, VIEW_CONVERT_EXPR, PAREN_EXPR)) /* Nonzero if this AGGR_INIT_EXPR provides for initialization via a constructor call, rather than an ordinary function call. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 154b40e..65f0f11 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7354,6 +7354,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, case RID_BUILTIN_SHUFFLE: case RID_BUILTIN_SHUFFLEVECTOR: case RID_BUILTIN_LAUNDER: + case RID_BUILTIN_ASSOC_BARRIER: { vec *vec; @@ -7396,6 +7397,19 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, } break; + case RID_BUILTIN_ASSOC_BARRIER: + if (vec->length () == 1) + postfix_expression = build1_loc (loc, PAREN_EXPR, + TREE_TYPE ((*vec)[0]), + (*vec)[0]); + else + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_assoc_barrier%>"); + postfix_expression = error_mark_node; + } + break; + case RID_BUILTIN_SHUFFLE: if (vec->length () == 2) postfix_expression diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 82bf7dc..b27eea3 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -21010,7 +21010,15 @@ tsubst_copy_and_build (tree t, integral_constant_expression_p)); case PAREN_EXPR: - RETURN (finish_parenthesized_expr (RECUR (TREE_OPERAND (t, 0)))); + if (REF_PARENTHESIZED_P (t)) + RETURN (finish_parenthesized_expr (RECUR (TREE_OPERAND (t, 0)))); + else + /* Recreate the PAREN_EXPR from __builtin_assoc_barrier. */ + { + tree op0 = RECUR (TREE_OPERAND (t, 0)); + RETURN (build1_loc (input_location, PAREN_EXPR, + TREE_TYPE (op0), op0)); + } case VEC_PERM_EXPR: { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 1540442..8f79f04 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2048,24 +2048,17 @@ force_paren_expr (tree expr, bool even_uneval) if (cp_unevaluated_operand && !even_uneval) return expr; - if (!DECL_P (tree_strip_any_location_wrapper (expr)) - && TREE_CODE (expr) != COMPONENT_REF - && TREE_CODE (expr) != SCOPE_REF) - return expr; - - location_t loc = cp_expr_location (expr); - if (TREE_CODE (expr) == COMPONENT_REF || TREE_CODE (expr) == SCOPE_REF) REF_PARENTHESIZED_P (expr) = true; - else if (processing_template_decl) - expr = build1_loc (loc, PAREN_EXPR, TREE_TYPE (expr), expr); - else + else if (DECL_P (tree_strip_any_location_wrapper (expr))) { - expr = build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (expr), expr); + location_t loc = cp_expr_location (expr); + const tree_code code = processing_template_decl ? PAREN_EXPR + : VIEW_CONVERT_EXPR; + expr = build1_loc (loc, code, TREE_TYPE (expr), expr); REF_PARENTHESIZED_P (expr) = true; } - return expr; } @@ -2090,10 +2083,8 @@ maybe_undo_parenthesized_ref (tree t) || TREE_CODE (t) == STATIC_CAST_EXPR); t = TREE_OPERAND (t, 0); } - else if (TREE_CODE (t) == PAREN_EXPR) - t = TREE_OPERAND (t, 0); - else if (TREE_CODE (t) == VIEW_CONVERT_EXPR - && REF_PARENTHESIZED_P (t)) + else if ((TREE_CODE (t) == PAREN_EXPR || TREE_CODE (t) == VIEW_CONVERT_EXPR) + && REF_PARENTHESIZED_P (t)) t = TREE_OPERAND (t, 0); return t; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 6e6c580..ef654d7 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -14043,6 +14043,24 @@ int g (int c) @end deftypefn +@deftypefn {Built-in Function} @var{type} __builtin_assoc_barrier (@var{type} @var{expr}) +This built-in inhibits re-association of the floating-point expression +@var{expr} with expressions consuming the return value of the built-in. The +expression @var{expr} itself can be reordered, and the whole expression +@var{expr} can be reordered with operands after the barrier. The barrier is +only relevant when @code{-fassociative-math} is active, since otherwise +floating-point is not treated as associative. + +@smallexample +float x0 = a + b - b; +float x1 = __builtin_assoc_barrier(a + b) - b; +@end smallexample + +@noindent +means that, with @code{-fassociative-math}, @code{x0} can be optimized to +@code{x0 = a} but @code{x1} cannot. +@end deftypefn + @deftypefn {Built-in Function} {void *} __builtin_assume_aligned (const void *@var{exp}, size_t @var{align}, ...) This function returns its first argument, and allows the compiler to assume that the returned pointer is at least @var{align} bytes diff --git a/gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c b/gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c new file mode 100644 index 0000000..3ff3249 --- /dev/null +++ b/gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c @@ -0,0 +1,71 @@ +// { dg-options "-O2 -ffast-math" } +/* { dg-do run } */ + +float a = 1.f; +float b = 1.e20f; + +float +fast() +{ + return __builtin_assoc_barrier (a + b) - b; +} + +__attribute__((optimize("-fno-associative-math"))) +float +normal() +{ + return a + b - b; +} + +void test0() +{ + if (fast() != normal()) + __builtin_abort(); +} + +#ifdef __cplusplus +#ifdef __cpp_constexpr +constexpr float +pm(float x, float y) +{ + return __builtin_assoc_barrier(x + y) - y; +} + +template + constexpr int + f() + { + return x; + } +#endif + +template + T + pm(T x, T y) + { + return __builtin_assoc_barrier(x + y) - y; + } + +void test1() +{ + if (pm(a, b) != normal()) + __builtin_abort(); +#ifdef __cpp_constexpr + constexpr float x = pm(1.f, 1.e20f); + constexpr int y = f(); + if (x != normal()) + __builtin_abort(); + if (y != 0) + __builtin_abort(); +#endif +} +#else +void test1() {} +#endif + +int main() +{ + test0(); + test1(); + return 0; +} -- cgit v1.1 From 1a0bce98dcf84dd0a7b3ac67b51ac68758cc7ad0 Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Thu, 18 Nov 2021 11:22:11 +0000 Subject: middle-end: Fix FMA detection when inspecting gimple which have no LHS. convert_mult_to_fma assumes that all gimple_assigns have a LHS set. This assumption is however not true when an IFN is kept around just for the side-effects. In those situations you have just the IFN and lhs will be null. Since there's no LHS, there also can't be any ADD and such it can't be an FMA so it's correct to just return early if no LHS. gcc/ChangeLog: PR tree-optimization/103253 * tree-ssa-math-opts.c (convert_mult_to_fma): Check for LHS. gcc/testsuite/ChangeLog: PR tree-optimization/103253 * gcc.dg/vect/pr103253.c: New test. --- gcc/testsuite/gcc.dg/vect/pr103253.c | 16 ++++++++++++++++ gcc/tree-ssa-math-opts.c | 4 ++++ 2 files changed, 20 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/vect/pr103253.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/vect/pr103253.c b/gcc/testsuite/gcc.dg/vect/pr103253.c new file mode 100644 index 0000000..abe3f09 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr103253.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target fopenmp } */ +/* { dg-additional-options "-O2 -fexceptions -fopenmp -fno-delete-dead-exceptions -fno-trapping-math" } */ + +double +do_work (double do_work_pri) +{ + int i; + +#pragma omp simd + for (i = 0; i < 17; ++i) + do_work_pri = (!i ? 0.5 : i) * 2.0; + + return do_work_pri; +} + diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c index c4a6492..cc8496c 100644 --- a/gcc/tree-ssa-math-opts.c +++ b/gcc/tree-ssa-math-opts.c @@ -3224,6 +3224,10 @@ convert_mult_to_fma (gimple *mul_stmt, tree op1, tree op2, fma_deferring_state *state, tree mul_cond = NULL_TREE) { tree mul_result = gimple_get_lhs (mul_stmt); + /* If there isn't a LHS then this can't be an FMA. There can be no LHS + if the statement was left just for the side-effects. */ + if (!mul_result) + return false; tree type = TREE_TYPE (mul_result); gimple *use_stmt, *neguse_stmt; use_operand_p use_p; -- cgit v1.1 From e3dbd2e14020d5a4f3401fa60dd5792b99fae108 Mon Sep 17 00:00:00 2001 From: David Edelsohn Date: Wed, 17 Nov 2021 13:26:36 -0500 Subject: aix: detect power10 processor. For -mcpu=native, GCC needs to detect the processor. This patch adds the processor value for Power10. Suggested by Kevin Alder. * config/rs6000/driver-rs6000.c (detect_processor_aix): Add power10. --- gcc/config/rs6000/driver-rs6000.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gcc') diff --git a/gcc/config/rs6000/driver-rs6000.c b/gcc/config/rs6000/driver-rs6000.c index e23c445..4de373d 100644 --- a/gcc/config/rs6000/driver-rs6000.c +++ b/gcc/config/rs6000/driver-rs6000.c @@ -418,6 +418,9 @@ detect_processor_aix (void) case 0x20000: return "power9"; + case 0x40000: + return "power10"; + default: return "powerpc"; } -- cgit v1.1 From 6fa8e0896c6ec96eddcedb2b92502a7bbb525c03 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 18 Nov 2021 10:04:27 -0500 Subject: c++: unqual lookup performed twice w/ template-id ADL [PR102670] Here we're incorrectly performing unqualified lookup of 'adl' again at substitution time for the call adl(t) (for which name lookup at parse time found nothing) which causes us to reject the testcase because the second unqualified lookup finds the later-declared variable template 'adl', leading to confusion. Fixed thusly. The testcase concepts-recursive-sat1.C needed to be adjusted to use ADL proper instead of relying on this incorrect second unqualified lookup. PR c++/102670 gcc/cp/ChangeLog: * pt.c (tsubst_copy_and_build) : When looking for an identifier callee in the koenig_p case, also look through TEMPLATE_ID_EXPR. Use tsubst_copy to substitute through the template arguments of the template-id. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-recursive-sat1.C: Adjust to use ADL proper. * g++.dg/cpp2a/fn-template23.C: New test. --- gcc/cp/pt.c | 11 ++++++- .../g++.dg/cpp2a/concepts-recursive-sat1.C | 15 ++++++--- gcc/testsuite/g++.dg/cpp2a/fn-template23.C | 36 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/fn-template23.C (limited to 'gcc') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b27eea3..2e31663 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20267,7 +20267,10 @@ tsubst_copy_and_build (tree t, /*done=*/false, /*address_p=*/false); } - else if (koenig_p && identifier_p (function)) + else if (koenig_p + && (identifier_p (function) + || (TREE_CODE (function) == TEMPLATE_ID_EXPR + && identifier_p (TREE_OPERAND (function, 0))))) { /* Do nothing; calling tsubst_copy_and_build on an identifier would incorrectly perform unqualified lookup again. @@ -20280,6 +20283,12 @@ tsubst_copy_and_build (tree t, FIXME but doing that causes c++/15272, so we need to stop using IDENTIFIER_NODE in that situation. */ qualified_p = false; + + if (TREE_CODE (function) == TEMPLATE_ID_EXPR) + /* Use tsubst_copy to substitute through the template arguments + of the template-id without performing unqualified lookup of + the template name. */ + function = tsubst_copy (function, args, complain, in_decl); } else { diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-recursive-sat1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-recursive-sat1.C index 22696c3..0103e7a 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-recursive-sat1.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-recursive-sat1.C @@ -3,16 +3,21 @@ template concept Foo = requires(T t) { foo(t); }; // { dg-error "template instantiation depth" } -template - requires Foo -int foo(T t) +namespace ns { - return foo(t); + struct S { }; + + template + requires Foo + int foo(T t) + { + return foo(t); + } } int main(int, char**) { - return foo<1>(1); + return foo<1>(ns::S{}); } // { dg-prune-output "compilation terminated" } diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template23.C b/gcc/testsuite/g++.dg/cpp2a/fn-template23.C new file mode 100644 index 0000000..b85d4c9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/fn-template23.C @@ -0,0 +1,36 @@ +// PR c++/102670 +// { dg-do compile { target c++20 } } + +namespace ns { + struct S { }; + + template + constexpr int adl(const S &) { + return I; + } +} + +namespace redirect { + template + concept can_call_adl = requires(T t) { + adl(t); + }; + + template + struct adl_fn { + template T> + constexpr decltype(auto) operator()(T t) const { + return adl(t); + } + }; + + namespace { + template + constexpr inline adl_fn adl{}; + } +} + +int main() { + static_assert(redirect::can_call_adl); + redirect::adl<3>(ns::S{}); +} -- cgit v1.1 From 90de06a7b3ce6ae8381136e58a2dde91fbbb6eff Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 18 Nov 2021 10:05:13 -0500 Subject: c++: template-id ADL and partial instantiation [PR99911] Here when partially instantiating the call get(T{}) with T=N::A (for which earlier unqualified name lookup for 'get' found nothing) the arguments after substitution are no longer dependent but the callee still is, so perform_koenig_lookup postpones ADL. But then we go on to diagnose the unresolved template name anyway, as if ADL was already performed and failed. This patch fixes this by avoiding the error path in question when the template arguments of an unresolved template-id are still dependent, mirroring the dependence check in perform_koenig_lookup. PR c++/99911 gcc/cp/ChangeLog: * pt.c (tsubst_copy_and_build) : Don't diagnose name lookup failure if the arguments to an unresolved template name are still dependent. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/fn-template24.C: New test. --- gcc/cp/pt.c | 4 +++- gcc/testsuite/g++.dg/cpp2a/fn-template24.C | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/fn-template24.C (limited to 'gcc') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2e31663..ad51c07 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20434,7 +20434,9 @@ tsubst_copy_and_build (tree t, if (function != NULL_TREE && (identifier_p (function) || (TREE_CODE (function) == TEMPLATE_ID_EXPR - && identifier_p (TREE_OPERAND (function, 0)))) + && identifier_p (TREE_OPERAND (function, 0)) + && !any_dependent_template_arguments_p (TREE_OPERAND + (function, 1)))) && !any_type_dependent_arguments_p (call_args)) { if (TREE_CODE (function) == TEMPLATE_ID_EXPR) diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template24.C b/gcc/testsuite/g++.dg/cpp2a/fn-template24.C new file mode 100644 index 0000000..b444ac6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/fn-template24.C @@ -0,0 +1,16 @@ +// PR c++/99911 +// { dg-do compile { target c++20 } } + +namespace N { + struct A { }; + template void get(A); +}; + +template +auto f() { + return [](U) { get(T{}); }; +} + +int main() { + f()(0); +} -- cgit v1.1 From 16fab6d691b1410abdf794230246ab9753d183af Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Thu, 18 Nov 2021 10:47:21 -0500 Subject: Fix MIPS test after recent match.pd changes gcc/testsuite * gcc.target/mips/octeon-bbit-1.c (f3): Add noipa attribute. --- gcc/testsuite/gcc.target/mips/octeon-bbit-1.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/mips/octeon-bbit-1.c b/gcc/testsuite/gcc.target/mips/octeon-bbit-1.c index f91c68b..8adbb26 100644 --- a/gcc/testsuite/gcc.target/mips/octeon-bbit-1.c +++ b/gcc/testsuite/gcc.target/mips/octeon-bbit-1.c @@ -22,7 +22,9 @@ f2 (int i) foo (); } -NOMIPS16 void +/* f3 and f4 are equivalent and may be subject to ICF. The attribute + is supposed to prevent that. */ +NOMIPS16 void __attribute__ ((noipa)) f3 (int i) { if (i % 2) -- cgit v1.1 From 2196a681d7810ad8b227bf983f38ba716620545e Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 27 Oct 2021 06:27:15 -0700 Subject: x86: Add -mindirect-branch-cs-prefix Add -mindirect-branch-cs-prefix to add CS prefix to call and jmp to indirect thunk with branch target in r8-r15 registers so that the call and jmp instruction length is 6 bytes to allow them to be replaced with "lfence; call *%r8-r15" or "lfence; jmp *%r8-r15" at run-time. gcc/ PR target/102952 * config/i386/i386.c (ix86_output_jmp_thunk_or_indirect): Emit CS prefix for -mindirect-branch-cs-prefix. (ix86_output_indirect_branch_via_reg): Likewise. * config/i386/i386.opt: Add -mindirect-branch-cs-prefix. * doc/invoke.texi: Document -mindirect-branch-cs-prefix. gcc/testsuite/ PR target/102952 * gcc.target/i386/indirect-thunk-cs-prefix-1.c: New test. * gcc.target/i386/indirect-thunk-cs-prefix-2.c: Likewise. --- gcc/config/i386/i386.c | 6 ++++++ gcc/config/i386/i386.opt | 4 ++++ gcc/doc/invoke.texi | 10 +++++++++- .../gcc.target/i386/indirect-thunk-cs-prefix-1.c | 14 ++++++++++++++ .../gcc.target/i386/indirect-thunk-cs-prefix-2.c | 15 +++++++++++++++ 5 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-cs-prefix-1.c create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-cs-prefix-2.c (limited to 'gcc') diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index c246c87..7fe271b 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -15982,6 +15982,9 @@ ix86_output_jmp_thunk_or_indirect (const char *thunk_name, const int regno) { if (thunk_name != NULL) { + if (REX_INT_REGNO_P (regno) + && ix86_indirect_branch_cs_prefix) + fprintf (asm_out_file, "\tcs\n"); fprintf (asm_out_file, "\tjmp\t"); assemble_name (asm_out_file, thunk_name); putc ('\n', asm_out_file); @@ -16031,6 +16034,9 @@ ix86_output_indirect_branch_via_reg (rtx call_op, bool sibcall_p) { if (thunk_name != NULL) { + if (REX_INT_REGNO_P (regno) + && ix86_indirect_branch_cs_prefix) + fprintf (asm_out_file, "\tcs\n"); fprintf (asm_out_file, "\tcall\t"); assemble_name (asm_out_file, thunk_name); putc ('\n', asm_out_file); diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt index 2b6d8aa..3e67c53 100644 --- a/gcc/config/i386/i386.opt +++ b/gcc/config/i386/i386.opt @@ -1076,6 +1076,10 @@ Enum(indirect_branch) String(thunk-inline) Value(indirect_branch_thunk_inline) EnumValue Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern) +mindirect-branch-cs-prefix +Target Var(ix86_indirect_branch_cs_prefix) Init(0) +Add CS prefix to call and jmp to indirect thunk with branch target in r8-r15 registers. + mindirect-branch-register Target Var(ix86_indirect_branch_register) Init(0) Force indirect call and jump via register. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d62ec08..5fed1dd 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1427,7 +1427,8 @@ See RS/6000 and PowerPC Options. -mstack-protector-guard-symbol=@var{symbol} @gol -mgeneral-regs-only -mcall-ms2sysv-xlogues -mrelax-cmpxchg-loop @gol -mindirect-branch=@var{choice} -mfunction-return=@var{choice} @gol --mindirect-branch-register -mharden-sls=@var{choice} -mneeded} +-mindirect-branch-register -mharden-sls=@var{choice} @gol +-mindirect-branch-cs-prefix -mneeded} @emph{x86 Windows Options} @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll @gol @@ -32416,6 +32417,13 @@ hardening. @samp{return} enables SLS hardening for function return. @samp{indirect-branch} enables SLS hardening for indirect branch. @samp{all} enables all SLS hardening. +@item -mindirect-branch-cs-prefix +@opindex mindirect-branch-cs-prefix +Add CS prefix to call and jmp to indirect thunk with branch target in +r8-r15 registers so that the call and jmp instruction length is 6 bytes +to allow them to be replaced with @samp{lfence; call *%r8-r15} or +@samp{lfence; jmp *%r8-r15} at run-time. + @end table These @samp{-m} switches are supported in addition to the above diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-cs-prefix-1.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-cs-prefix-1.c new file mode 100644 index 0000000..db2f341 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-cs-prefix-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -ffixed-rax -ffixed-rbx -ffixed-rcx -ffixed-rdx -ffixed-rdi -ffixed-rsi -mindirect-branch-cs-prefix -mindirect-branch=thunk-extern" } */ +/* { dg-additional-options "-fno-pic" { target { ! *-*-darwin* } } } */ + +extern void (*fptr) (void); + +void +foo (void) +{ + fptr (); +} + +/* { dg-final { scan-assembler-times "jmp\[ \t\]+_?__x86_indirect_thunk_r\[0-9\]+" 1 } } */ +/* { dg-final { scan-assembler-times "\tcs" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-cs-prefix-2.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-cs-prefix-2.c new file mode 100644 index 0000000..adfc39a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-cs-prefix-2.c @@ -0,0 +1,15 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2 -ffixed-rax -ffixed-rbx -ffixed-rcx -ffixed-rdx -ffixed-rdi -ffixed-rsi -mindirect-branch-cs-prefix -mindirect-branch=thunk-extern" } */ +/* { dg-additional-options "-fno-pic" { target { ! *-*-darwin* } } } */ + +extern void (*bar) (void); + +int +foo (void) +{ + bar (); + return 0; +} + +/* { dg-final { scan-assembler-times "call\[ \t\]+_?__x86_indirect_thunk_r\[0-9\]+" 1 } } */ +/* { dg-final { scan-assembler-times "\tcs" 1 } } */ -- cgit v1.1 From 4f0a2f5a3ddb1024b885c066a18caae4d733bb6c Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Thu, 18 Nov 2021 17:10:36 +0000 Subject: middle-end: check that both sides of complex expression is a mul. Both sides of the VEC_PERM_EXPR need to be a MULT but the check was accidentally checking if both sides are a mul. The FMS case would be handled by the validate_multiplication but this makes the requirement more explicit and we exit earlier. gcc/ChangeLog: PR tree-optimization/103311 * tree-vect-slp-patterns.c (complex_mul_pattern::matches, complex_fms_pattern::matches): Check for multiplications. gcc/testsuite/ChangeLog: PR tree-optimization/103311 * gcc.target/aarch64/pr103311.c: New test. --- gcc/testsuite/gcc.target/aarch64/pr103311.c | 16 ++++++++++++++++ gcc/tree-vect-slp-patterns.c | 6 ++++-- 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/pr103311.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/aarch64/pr103311.c b/gcc/testsuite/gcc.target/aarch64/pr103311.c new file mode 100644 index 0000000..7bcc7db --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/pr103311.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_v8_3a_complex_neon_ok } */ +/* { dg-add-options arm_v8_3a_complex_neon } */ +/* { dg-additional-options "-std=c99" } */ + +_Complex double y; + +void +cbknu (_Complex double f) +{ + const _Complex double cone = 1.0e0; + + f = f * cone; + y = f * cone; +} + diff --git a/gcc/tree-vect-slp-patterns.c b/gcc/tree-vect-slp-patterns.c index 53fbe51..d916fc9c 100644 --- a/gcc/tree-vect-slp-patterns.c +++ b/gcc/tree-vect-slp-patterns.c @@ -949,7 +949,7 @@ complex_mul_pattern::matches (complex_operation_t op, bool mul0 = vect_match_expression_p (l0node[0], MULT_EXPR); bool mul1 = vect_match_expression_p (l0node[1], MULT_EXPR); - if (!mul0 && !mul1) + if (!mul0 || !mul1) return IFN_LAST; /* Now operand2+4 may lead to another expression. */ @@ -1204,7 +1204,9 @@ complex_fms_pattern::matches (complex_operation_t op, /* If these nodes don't have any children then they're not ones we're interested in. */ - if (left_op.length () != 2 || right_op.length () != 2) + if (left_op.length () != 2 + || right_op.length () != 2 + || !vect_match_expression_p (l0node[1], MULT_EXPR)) return IFN_LAST; bool is_neg = vect_normalize_conj_loc (left_op); -- cgit v1.1 From c331a75d49b6043399f5ccce72a02ccf3b0ddc56 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Thu, 18 Nov 2021 18:41:43 +0100 Subject: Fix modref wrt __builtin_assume_aligned __builtin_assume_aligned has bit contraictionary fnspec description "1cX " which means that parameter 1 is returned but also unused. PTA code takes precedence to parameter being returned, while modref takes the info that parameter is unused. This patch tweaks modref to follow PTA semantics (as suggested by Richard in the PR log) gcc/ChangeLog: 2021-11-18 Jan Hubicka PR ipa/103266 * ipa-modref.c (modref_eaf_analysis::merge_call_lhs_flags): Unused parameter may still be returned. (modref_eaf_analysis::analyze_ssa_name): Call merge_call_lhs_flags even for unused function args. gcc/testsuite/ChangeLog: 2021-11-18 Jan Hubicka PR ipa/103266 * g++.dg/torture/pr103266.C: New test. --- gcc/ipa-modref.c | 32 ++++++++++++++++++++++---------- gcc/testsuite/g++.dg/torture/pr103266.C | 23 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/pr103266.C (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index c94f058..e5d2b11 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -2033,10 +2033,7 @@ modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg, bool indirect) { int index = SSA_NAME_VERSION (name); - - /* If value is not returned at all, do nothing. */ - if (!direct && !indirect) - return; + bool returned_directly = false; /* If there is no return value, no flags are affected. */ if (!gimple_call_lhs (call)) @@ -2047,10 +2044,23 @@ modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg, if (arg >= 0) { int flags = gimple_call_return_flags (call); - if ((flags & ERF_RETURNS_ARG) - && (flags & ERF_RETURN_ARG_MASK) != arg) - return; + if (flags & ERF_RETURNS_ARG) + { + if ((flags & ERF_RETURN_ARG_MASK) == arg) + returned_directly = true; + else + return; + } + } + /* Make ERF_RETURNS_ARG overwrite EAF_UNUSED. */ + if (returned_directly) + { + direct = true; + indirect = false; } + /* If value is not returned at all, do nothing. */ + else if (!direct && !indirect) + return; /* If return value is SSA name determine its flags. */ if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME) @@ -2273,11 +2283,13 @@ modref_eaf_analysis::analyze_ssa_name (tree name) if (gimple_call_arg (call, i) == name) { int call_flags = gimple_call_arg_flags (call, i); - if (!ignore_retval && !(call_flags & EAF_UNUSED)) + if (!ignore_retval) merge_call_lhs_flags (call, i, name, - !(call_flags & EAF_NOT_RETURNED_DIRECTLY), - !(call_flags & EAF_NOT_RETURNED_INDIRECTLY)); + !(call_flags & (EAF_NOT_RETURNED_DIRECTLY + | EAF_UNUSED)), + !(call_flags & (EAF_NOT_RETURNED_INDIRECTLY + | EAF_UNUSED))); if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS))) { call_flags = callee_to_caller_flags diff --git a/gcc/testsuite/g++.dg/torture/pr103266.C b/gcc/testsuite/g++.dg/torture/pr103266.C new file mode 100644 index 0000000..d5c13f5 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr103266.C @@ -0,0 +1,23 @@ +// { dg-do run } +/* { dg-additional-options "-std=c++14" } */ + typedef unsigned int u32; + typedef unsigned char u8; + + static u32 pu8to32(const u8 * p8) __attribute__((noinline)); + static u32 pu8to32(const u8 * p8) { + u32 v; + + __builtin_memcpy(&v, __builtin_assume_aligned(p8, 1), sizeof(u32)); + + return v; + } + + int main(void) { + // dse1 throws this store away + u8 d[sizeof(u32)] = { + 0x07, 0x00, 0x00, 0x07, + }; + + if (pu8to32(d) != 0x07000007) + __builtin_trap(); + } -- cgit v1.1 From 75ac95f6647367783c4d65f6f686867ca425cb61 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Thu, 18 Nov 2021 18:42:35 +0100 Subject: Turn -fsemantic-interposition to optimization flag Turn flag_semantic_interposition to optimization option so it can be enabled with per-function granuality. This is done by adding the flag among visibility flags into the symbol table. gcc/ChangeLog: 2021-11-18 Jan Hubicka * cgraph.c (cgraph_node::get_availability): Update call of decl_replaceable_p. (cgraph_node::verify_node): Verify that semantic_interposition flag is set correclty. * cgraph.h: (symtab_node): Add semantic_interposition flag. * cgraphclones.c (set_new_clone_decl_and_node_flags): Clear semantic_interposition flag. * cgraphunit.c (cgraph_node::finalize_function): Set semantic_interposition flag. (cgraph_node::add_new_function): Likewise. (varpool_node::finalize_decl): Likewise. (cgraph_node::create_wrapper): Likewise. * common.opt (fsemantic-interposition): Turn to optimization node. * lto-cgraph.c (lto_output_node): Stream semantic_interposition. (lto_output_varpool_node): Likewise. (input_overwrite_node): Likewise. (input_varpool_node): Likewise. * symtab.c (symtab_node::dump_base): Dump new flag. * varasm.c (decl_replaceable_p): Add semantic_interposition_p parameter. * varasm.h (decl_replaceable_p): Update declaration. * varpool.c (varpool_node::ctor_useable_for_folding_p): Use semantic_interposition flag. (varpool_node::get_availability): Likewise. (varpool_node::create_alias): Copy semantic_interposition flag. gcc/cp/ChangeLog: 2021-11-18 Jan Hubicka * decl.c (finish_function): Update use of decl_replaceable_p. gcc/lto/ChangeLog: 2021-11-18 Jan Hubicka * lto-partition.c (promote_symbol): Clear semantic_interposition flag. gcc/testsuite/ChangeLog: 2021-11-18 Jan Hubicka * gcc.dg/lto/semantic-interposition-1_0.c: New test. * gcc.dg/lto/semantic-interposition-1_1.c: New test. --- gcc/cgraph.c | 10 +++++++++- gcc/cgraph.h | 3 +++ gcc/cgraphclones.c | 1 + gcc/cgraphunit.c | 7 +++++++ gcc/common.opt | 2 +- gcc/cp/decl.c | 3 ++- gcc/lto-cgraph.c | 4 ++++ gcc/lto/lto-partition.c | 1 + gcc/symtab.c | 2 ++ gcc/testsuite/gcc.dg/lto/semantic-interposition-1_0.c | 13 +++++++++++++ gcc/testsuite/gcc.dg/lto/semantic-interposition-1_1.c | 5 +++++ gcc/varasm.c | 6 ++++-- gcc/varasm.h | 2 +- gcc/varpool.c | 8 +++++--- 14 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/lto/semantic-interposition-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/semantic-interposition-1_1.c (limited to 'gcc') diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 466b66d..8e7c126 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -2390,7 +2390,8 @@ cgraph_node::get_availability (symtab_node *ref) to code cp_cannot_inline_tree_fn and probably shall be shared and the inlinability hooks completely eliminated). */ - else if (decl_replaceable_p (decl) && !DECL_EXTERNAL (decl)) + else if (decl_replaceable_p (decl, semantic_interposition) + && !DECL_EXTERNAL (decl)) avail = AVAIL_INTERPOSABLE; else avail = AVAIL_AVAILABLE; @@ -3486,6 +3487,13 @@ cgraph_node::verify_node (void) "returns a pointer"); error_found = true; } + if (definition && externally_visible + && semantic_interposition + != opt_for_fn (decl, flag_semantic_interposition)) + { + error ("semantic interposition mismatch"); + error_found = true; + } for (e = indirect_calls; e; e = e->next_callee) { if (e->aux) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index e42e305..dafdfd2 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -117,6 +117,7 @@ public: refuse_visibility_changes (false), externally_visible (false), no_reorder (false), force_output (false), forced_by_abi (false), unique_name (false), implicit_section (false), body_removed (false), + semantic_interposition (flag_semantic_interposition), used_from_other_partition (false), in_other_partition (false), address_taken (false), in_init_priority_hash (false), need_lto_streaming (false), offloadable (false), ifunc_resolver (false), @@ -557,6 +558,8 @@ public: /* True when body and other characteristics have been removed by symtab_remove_unreachable_nodes. */ unsigned body_removed : 1; + /* True when symbol should comply to -fsemantic-interposition flag. */ + unsigned semantic_interposition : 1; /*** WHOPR Partitioning flags. These flags are used at ltrans stage when only part of the callgraph is diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index ae91dcc..c997b82 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -172,6 +172,7 @@ set_new_clone_decl_and_node_flags (cgraph_node *new_node) new_node->externally_visible = 0; new_node->local = 1; new_node->lowered = true; + new_node->semantic_interposition = 0; } /* Duplicate thunk THUNK if necessary but make it to refer to NODE. diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 55cb034..1e58ffd 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -452,6 +452,7 @@ cgraph_node::finalize_function (tree decl, bool no_collect) node->definition = true; notice_global_symbol (decl); node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL; + node->semantic_interposition = opt_for_fn (decl, flag_semantic_interposition); if (!flag_toplevel_reorder) node->no_reorder = true; @@ -554,6 +555,8 @@ cgraph_node::add_new_function (tree fndecl, bool lowered) node = cgraph_node::get_create (fndecl); node->local = false; node->definition = true; + node->semantic_interposition = opt_for_fn (fndecl, + flag_semantic_interposition); node->force_output = true; if (TREE_PUBLIC (fndecl)) node->externally_visible = true; @@ -581,6 +584,8 @@ cgraph_node::add_new_function (tree fndecl, bool lowered) if (lowered) node->lowered = true; node->definition = true; + node->semantic_interposition = opt_for_fn (fndecl, + flag_semantic_interposition); node->analyze (); push_cfun (DECL_STRUCT_FUNCTION (fndecl)); gimple_register_cfg_hooks (); @@ -954,6 +959,7 @@ varpool_node::finalize_decl (tree decl) /* Set definition first before calling notice_global_symbol so that it is available to notice_global_symbol. */ node->definition = true; + node->semantic_interposition = flag_semantic_interposition; notice_global_symbol (decl); if (!flag_toplevel_reorder) node->no_reorder = true; @@ -2576,6 +2582,7 @@ cgraph_node::create_wrapper (cgraph_node *target) /* Turn alias into thunk and expand it into GIMPLE representation. */ definition = true; + semantic_interposition = opt_for_fn (decl, flag_semantic_interposition); /* Create empty thunk, but be sure we did not keep former thunk around. In that case we would need to preserve the info. */ diff --git a/gcc/common.opt b/gcc/common.opt index de9b848..db6010e 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2539,7 +2539,7 @@ Common Var(flag_sel_sched_reschedule_pipelined) Init(0) Optimization Reschedule pipelined regions without pipelining. fsemantic-interposition -Common Var(flag_semantic_interposition) Init(1) +Common Var(flag_semantic_interposition) Init(1) Optimization Allow interposing function (or variables) by ones with different semantics (or initializer) respectively by dynamic linker. ; sched_stalled_insns means that insns can be moved prematurely from the queue diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 2ddf0e4..9f68d1a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -17609,7 +17609,8 @@ finish_function (bool inline_p) if (!processing_template_decl && !cp_function_chain->can_throw && !flag_non_call_exceptions - && !decl_replaceable_p (fndecl)) + && !decl_replaceable_p (fndecl, + opt_for_fn (fndecl, flag_semantic_interposition))) TREE_NOTHROW (fndecl) = 1; /* This must come after expand_function_end because cleanups might diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 7c3e276..ef3c371 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -516,6 +516,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, bp_pack_value (&bp, node->forced_by_abi, 1); bp_pack_value (&bp, node->unique_name, 1); bp_pack_value (&bp, node->body_removed, 1); + bp_pack_value (&bp, node->semantic_interposition, 1); bp_pack_value (&bp, node->implicit_section, 1); bp_pack_value (&bp, node->address_taken, 1); bp_pack_value (&bp, tag == LTO_symtab_analyzed_node @@ -604,6 +605,7 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, varpool_node *node, node->body_removed || (!encode_initializer_p && !node->alias && node->definition), 1); + bp_pack_value (&bp, node->semantic_interposition, 1); bp_pack_value (&bp, node->implicit_section, 1); bp_pack_value (&bp, node->writeonly, 1); bp_pack_value (&bp, node->definition && (encode_initializer_p || node->alias), @@ -1167,6 +1169,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data, node->forced_by_abi = bp_unpack_value (bp, 1); node->unique_name = bp_unpack_value (bp, 1); node->body_removed = bp_unpack_value (bp, 1); + node->semantic_interposition = bp_unpack_value (bp, 1); node->implicit_section = bp_unpack_value (bp, 1); node->address_taken = bp_unpack_value (bp, 1); node->used_from_other_partition = bp_unpack_value (bp, 1); @@ -1373,6 +1376,7 @@ input_varpool_node (struct lto_file_decl_data *file_data, node->forced_by_abi = bp_unpack_value (&bp, 1); node->unique_name = bp_unpack_value (&bp, 1); node->body_removed = bp_unpack_value (&bp, 1); + node->semantic_interposition = bp_unpack_value (&bp, 1); node->implicit_section = bp_unpack_value (&bp, 1); node->writeonly = bp_unpack_value (&bp, 1); node->definition = bp_unpack_value (&bp, 1); diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c index bee4021..6d20555 100644 --- a/gcc/lto/lto-partition.c +++ b/gcc/lto/lto-partition.c @@ -1001,6 +1001,7 @@ promote_symbol (symtab_node *node) so it is prevailing. This is important to keep binds_to_current_def_p to work across partitions. */ node->resolution = LDPR_PREVAILING_DEF_IRONLY; + node->semantic_interposition = false; DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN; DECL_VISIBILITY_SPECIFIED (node->decl) = true; if (dump_file) diff --git a/gcc/symtab.c b/gcc/symtab.c index c7ea8ec..94b4e47 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -929,6 +929,8 @@ symtab_node::dump_base (FILE *f) fprintf (f, " forced_by_abi"); if (externally_visible) fprintf (f, " externally_visible"); + if (semantic_interposition) + fprintf (f, " semantic_interposition"); if (no_reorder) fprintf (f, " no_reorder"); if (resolution != LDPR_UNKNOWN) diff --git a/gcc/testsuite/gcc.dg/lto/semantic-interposition-1_0.c b/gcc/testsuite/gcc.dg/lto/semantic-interposition-1_0.c new file mode 100644 index 0000000..db84274 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/semantic-interposition-1_0.c @@ -0,0 +1,13 @@ +/* { dg-lto-do link } */ +/* { dg-require-effective-target shared } */ +/* { dg-extra-ld-options { -shared } } */ +/* { dg-lto-options {{-O2 -flto -fpic -fdump-ipa-inline-details --shared}} } */ +extern int ret1(); + +int +test() +{ + return ret1(); +} +/* { dg-final { scan-wpa-ipa-dump "Inlined 1 calls" "inline" } } */ + diff --git a/gcc/testsuite/gcc.dg/lto/semantic-interposition-1_1.c b/gcc/testsuite/gcc.dg/lto/semantic-interposition-1_1.c new file mode 100644 index 0000000..9a74177 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/semantic-interposition-1_1.c @@ -0,0 +1,5 @@ +/* { dg-options "-O2 -flto -fpic -fno-semantic-interposition" } */ +int ret1() +{ + return 1; +} diff --git a/gcc/varasm.c b/gcc/varasm.c index 09316c6..8c7aba2 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -7625,6 +7625,8 @@ decl_binds_to_current_def_p (const_tree decl) at link-time with an entirely different definition, provided that the replacement has the same type. For example, functions declared with __attribute__((weak)) on most systems are replaceable. + If SEMANTIC_INTERPOSITION_P is false allow interposition only on + symbols explicitly declared weak. COMDAT functions are not replaceable, since all definitions of the function must be equivalent. It is important that COMDAT functions @@ -7632,12 +7634,12 @@ decl_binds_to_current_def_p (const_tree decl) instantiations is not penalized. */ bool -decl_replaceable_p (tree decl) +decl_replaceable_p (tree decl, bool semantic_interposition_p) { gcc_assert (DECL_P (decl)); if (!TREE_PUBLIC (decl) || DECL_COMDAT (decl)) return false; - if (!flag_semantic_interposition + if (!semantic_interposition_p && !DECL_WEAK (decl)) return false; return !decl_binds_to_current_def_p (decl); diff --git a/gcc/varasm.h b/gcc/varasm.h index 442ca6a..4ab9dc5 100644 --- a/gcc/varasm.h +++ b/gcc/varasm.h @@ -38,7 +38,7 @@ extern void mark_decl_referenced (tree); extern void notice_global_symbol (tree); extern void set_user_assembler_name (tree, const char *); extern void process_pending_assemble_externals (void); -extern bool decl_replaceable_p (tree); +extern bool decl_replaceable_p (tree, bool); extern bool decl_binds_to_current_def_p (const_tree); extern enum tls_model decl_default_tls_model (const_tree); diff --git a/gcc/varpool.c b/gcc/varpool.c index 4830df5..fd0d53b 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -372,7 +372,8 @@ varpool_node::ctor_useable_for_folding_p (void) */ if ((!DECL_INITIAL (real_node->decl) || (DECL_WEAK (decl) && !DECL_COMDAT (decl))) - && (DECL_EXTERNAL (decl) || decl_replaceable_p (decl))) + && ((DECL_EXTERNAL (decl) && !in_other_partition) + || decl_replaceable_p (decl, semantic_interposition))) return false; /* Variables declared `const' with an initializer are considered @@ -511,8 +512,8 @@ varpool_node::get_availability (symtab_node *ref) /* If the variable can be overwritten, return OVERWRITABLE. Takes care of at least one notable extension - the COMDAT variables used to share template instantiations in C++. */ - if (decl_replaceable_p (decl) - || DECL_EXTERNAL (decl)) + if (decl_replaceable_p (decl, semantic_interposition) + || (DECL_EXTERNAL (decl) && !in_other_partition)) return AVAIL_INTERPOSABLE; return AVAIL_AVAILABLE; } @@ -779,6 +780,7 @@ varpool_node::create_alias (tree alias, tree decl) alias_node = varpool_node::get_create (alias); alias_node->alias = true; alias_node->definition = true; + alias_node->semantic_interposition = flag_semantic_interposition; alias_node->alias_target = decl; if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL) alias_node->weakref = alias_node->transparent_alias = true; -- cgit v1.1 From 53c964ad996a1bb22566b987eafb333b5899deab Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 18 Nov 2021 13:10:28 -0500 Subject: c++: error recovery during C++20 template-id ADL failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When diagnosing ADL failure we try to perform a second unqualified lookup for backwards compatibility with legacy code (via -fpermissive), and for better diagnostics. But for C++20 template-id ADL, the backwards compatibility code sometimes causes confusing subsequent diagnostics such as in the testcase below where we end up diagnosing deduction failure after emitting the helpful "no declarations were found by ADL". This happens because the code just discards the arguments of the template-id callee when replacing it with the later-declared template, which leads to overload resolution failure: : In instantiation of ‘void f() [with T = int]’: :12:22: required from here :5:9: error: ‘g’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive] :10:6: note: ‘template void g(int)’ declared here, later in the translation unit :5:9: error: no matching function for call to ‘g(int)’ :10:6: note: candidate: ‘template void g(int)’ :10:6: note: template argument deduction/substitution failed: :5:9: note: couldn’t deduce template parameter ‘T’ So for C++20 template-id ADL, this patch disables the backwards compatibility code while keeping the helpful "no declarations were found by ADL" diagnostic. gcc/cp/ChangeLog: * pt.c (tsubst_copy_and_build) : Disable the -fpermissive fallback for C++20 template-id ADL, but keep the diagnostic. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/fn-template25.C: New test. --- gcc/cp/pt.c | 20 +++++++++++--------- gcc/testsuite/g++.dg/cpp2a/fn-template25.C | 12 ++++++++++++ 2 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/fn-template25.C (limited to 'gcc') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ad51c07..71a771f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20439,7 +20439,8 @@ tsubst_copy_and_build (tree t, (function, 1)))) && !any_type_dependent_arguments_p (call_args)) { - if (TREE_CODE (function) == TEMPLATE_ID_EXPR) + bool template_id_p = (TREE_CODE (function) == TEMPLATE_ID_EXPR); + if (template_id_p) function = TREE_OPERAND (function, 0); if (koenig_p && (complain & tf_warning_or_error)) { @@ -20454,20 +20455,21 @@ tsubst_copy_and_build (tree t, if (unq != function) { - /* In a lambda fn, we have to be careful to not - introduce new this captures. Legacy code can't - be using lambdas anyway, so it's ok to be - stricter. */ - bool in_lambda = (current_class_type - && LAMBDA_TYPE_P (current_class_type)); char const *const msg = G_("%qD was not declared in this scope, " "and no declarations were found by " "argument-dependent lookup at the point " "of instantiation"); + bool in_lambda = (current_class_type + && LAMBDA_TYPE_P (current_class_type)); + /* In a lambda fn, we have to be careful to not + introduce new this captures. Legacy code can't + be using lambdas anyway, so it's ok to be + stricter. Be strict with C++20 template-id ADL too. */ + bool strict = in_lambda || template_id_p; bool diag = true; - if (in_lambda) + if (strict) error_at (cp_expr_loc_or_input_loc (t), msg, function); else @@ -20503,7 +20505,7 @@ tsubst_copy_and_build (tree t, inform (DECL_SOURCE_LOCATION (fn), "%qD declared here, later in the " "translation unit", fn); - if (in_lambda) + if (strict) RETURN (error_mark_node); } diff --git a/gcc/testsuite/g++.dg/cpp2a/fn-template25.C b/gcc/testsuite/g++.dg/cpp2a/fn-template25.C new file mode 100644 index 0000000..5da409c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/fn-template25.C @@ -0,0 +1,12 @@ +// { dg-do compile { target c++20 } } + +template +void f() { + g(T{}); // { dg-error "argument-dependent lookup" } + // { dg-bogus "no match" "" { target *-*-* } .-1 } +} + +template +void g(int); // { dg-message "declared here, later" } + +template void f(); -- cgit v1.1 From 616ca1024a79c6a1935ea152051b9016d2142fb6 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 18 Nov 2021 17:39:23 +0100 Subject: IPA: use cgraph_node instance gcc/ChangeLog: * ipa-modref.c (analyze_function): Use fnode instead of repeated cgraph_node::get (current_function_decl). --- gcc/ipa-modref.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index e5d2b11..2c507cc 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -2882,22 +2882,22 @@ analyze_function (function *f, bool ipa) { if (dump_file && (summary - = optimization_summaries->get (cgraph_node::get (f->decl))) + = optimization_summaries->get (fnode)) != NULL && summary->loads) { fprintf (dump_file, "Past summary:\n"); optimization_summaries->get - (cgraph_node::get (f->decl))->dump (dump_file); + (fnode)->dump (dump_file); past_flags.reserve_exact (summary->arg_flags.length ()); past_flags.splice (summary->arg_flags); past_retslot_flags = summary->retslot_flags; past_static_chain_flags = summary->static_chain_flags; past_flags_known = true; } - optimization_summaries->remove (cgraph_node::get (f->decl)); + optimization_summaries->remove (fnode); } - summary = optimization_summaries->get_create (cgraph_node::get (f->decl)); + summary = optimization_summaries->get_create (fnode); gcc_checking_assert (nolto && !lto); } /* In IPA mode we analyze every function precisely once. Assert that. */ @@ -2908,16 +2908,16 @@ analyze_function (function *f, bool ipa) if (!summaries) summaries = modref_summaries::create_ggc (symtab); else - summaries->remove (cgraph_node::get (f->decl)); - summary = summaries->get_create (cgraph_node::get (f->decl)); + summaries->remove (fnode); + summary = summaries->get_create (fnode); } if (lto) { if (!summaries_lto) summaries_lto = modref_summaries_lto::create_ggc (symtab); else - summaries_lto->remove (cgraph_node::get (f->decl)); - summary_lto = summaries_lto->get_create (cgraph_node::get (f->decl)); + summaries_lto->remove (fnode); + summary_lto = summaries_lto->get_create (fnode); } if (!fnspec_summaries) fnspec_summaries = new fnspec_summaries_t (symtab); @@ -3036,13 +3036,11 @@ analyze_function (function *f, bool ipa) { if (!summary->loads->every_base && !summary->loads->bases && !summary->calls_interposable) - fixup_cfg = ipa_make_function_const - (cgraph_node::get (current_function_decl), - summary->side_effects, true); + fixup_cfg = ipa_make_function_const (fnode, + summary->side_effects, true); else - fixup_cfg = ipa_make_function_pure - (cgraph_node::get (current_function_decl), - summary->side_effects, true); + fixup_cfg = ipa_make_function_pure (fnode, + summary->side_effects, true); } } if (summary && !summary->useful_p (ecf_flags)) -- cgit v1.1 From 22c242342e38ebffa6bbf7e86e7a1e4abdf0d686 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 18 Nov 2021 17:50:19 +0100 Subject: IPA: fix reproducibility in IPA MOD REF gcc/ChangeLog: * ipa-modref.c (analyze_function): Do not execute the code only if dump_file != NULL. --- gcc/ipa-modref.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 2c507cc..2133431 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -2880,15 +2880,15 @@ analyze_function (function *f, bool ipa) optimization_summaries = modref_summaries::create_ggc (symtab); else /* Remove existing summary if we are re-running the pass. */ { - if (dump_file - && (summary - = optimization_summaries->get (fnode)) - != NULL + summary = optimization_summaries->get (fnode); + if (summary != NULL && summary->loads) { - fprintf (dump_file, "Past summary:\n"); - optimization_summaries->get - (fnode)->dump (dump_file); + if (dump_file) + { + fprintf (dump_file, "Past summary:\n"); + optimization_summaries->get (fnode)->dump (dump_file); + } past_flags.reserve_exact (summary->arg_flags.length ()); past_flags.splice (summary->arg_flags); past_retslot_flags = summary->retslot_flags; -- cgit v1.1 From 3535be6c6f440909798d1c78e862a657f7adaf63 Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Wed, 17 Nov 2021 22:21:24 +0100 Subject: Fortran: NULL() is not interoperable gcc/fortran/ChangeLog: PR fortran/101329 * check.c (is_c_interoperable): Reject NULL() as it is not interoperable. gcc/testsuite/ChangeLog: PR fortran/101329 * gfortran.dg/pr101329.f90: New test. Co-authored-by: Steven G. Kargl --- gcc/fortran/check.c | 6 ++++++ gcc/testsuite/gfortran.dg/pr101329.f90 | 13 +++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/pr101329.f90 (limited to 'gcc') diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c index ffa07b5..5a5aca1 100644 --- a/gcc/fortran/check.c +++ b/gcc/fortran/check.c @@ -5223,6 +5223,12 @@ is_c_interoperable (gfc_expr *expr, const char **msg, bool c_loc, bool c_f_ptr) { *msg = NULL; + if (expr->expr_type == EXPR_NULL) + { + *msg = "NULL() is not interoperable"; + return false; + } + if (expr->ts.type == BT_CLASS) { *msg = "Expression is polymorphic"; diff --git a/gcc/testsuite/gfortran.dg/pr101329.f90 b/gcc/testsuite/gfortran.dg/pr101329.f90 new file mode 100644 index 0000000..b82210d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr101329.f90 @@ -0,0 +1,13 @@ +! { dg-do compile } +! PR fortran/101329 - ICE: Invalid expression in gfc_element_size + +program p + use iso_c_binding + implicit none + integer(c_int), pointer :: ip4 + integer(c_int64_t), pointer :: ip8 + print *, c_sizeof (c_null_ptr) ! valid + print *, c_sizeof (null ()) ! { dg-error "is not interoperable" } + print *, c_sizeof (null (ip4)) ! { dg-error "is not interoperable" } + print *, c_sizeof (null (ip8)) ! { dg-error "is not interoperable" } +end -- cgit v1.1 From 6f4ac4f81f89caac7e74127ed2e6db6bbb3d7426 Mon Sep 17 00:00:00 2001 From: David Edelsohn Date: Thu, 18 Nov 2021 13:43:22 -0500 Subject: Fix rs6000 predicates.md use of decl_replaceable_p gcc/ChangeLog: * config/rs6000/predicates.md (current_file_function_operand): Add flag_semantic_interposition to call of decl_replaceable_p. --- gcc/config/rs6000/predicates.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 956e42b..f216ffd 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -1086,7 +1086,9 @@ (match_test "(DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op)) && (SYMBOL_REF_LOCAL_P (op) || (op == XEXP (DECL_RTL (current_function_decl), 0) - && !decl_replaceable_p (current_function_decl))) + && !decl_replaceable_p (current_function_decl, + opt_for_fn (current_function_decl, + flag_semantic_interposition)))) && !((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2) && (SYMBOL_REF_EXTERNAL_P (op) -- cgit v1.1 From 93810fd673654db9ff16170624a6d36449eab241 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 3 Nov 2021 11:04:22 -0400 Subject: c++: Implement C++23 P0849R8 - auto(x) [PR103049] This patch implements P0849R8 which allows auto in a functional cast, the result of which is a prvalue. [expr.type.conv]/1 says that the type is determined by placeholder type deduction. We only accept 'auto', not 'decltype(auto)' -- that the type shall be auto comes from [dcl.type.auto.deduct]. Therefore the rules are like for [temp.deduct.call], deducing template arguments from a function call, so the result type will never be a reference, and we decay arrays/functions. PR c++/103049 gcc/cp/ChangeLog: * semantics.c (finish_compound_literal): Accept C++23 auto{x}. * typeck2.c (build_functional_cast_1): Accept C++23 auto(x). gcc/testsuite/ChangeLog: * g++.dg/cpp0x/auto25.C: Adjust dg-error. * g++.dg/cpp0x/auto9.C: Likewise. * g++.dg/cpp2a/concepts-pr84979-2.C: Likewise. * g++.dg/cpp2a/concepts-pr84979-3.C: Likewise. * g++.dg/cpp23/auto-fncast1.C: New test. * g++.dg/cpp23/auto-fncast2.C: New test. * g++.dg/cpp23/auto-fncast3.C: New test. * g++.dg/cpp23/auto-fncast4.C: New test. * g++.dg/cpp23/auto-fncast5.C: New test. * g++.dg/cpp23/auto-fncast6.C: New test. --- gcc/cp/semantics.c | 14 ++++++ gcc/cp/typeck2.c | 26 +++++++---- gcc/testsuite/g++.dg/cpp0x/auto25.C | 4 +- gcc/testsuite/g++.dg/cpp0x/auto9.C | 2 +- gcc/testsuite/g++.dg/cpp23/auto-fncast1.C | 14 ++++++ gcc/testsuite/g++.dg/cpp23/auto-fncast2.C | 62 +++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp23/auto-fncast3.C | 21 +++++++++ gcc/testsuite/g++.dg/cpp23/auto-fncast4.C | 26 +++++++++++ gcc/testsuite/g++.dg/cpp23/auto-fncast5.C | 39 ++++++++++++++++ gcc/testsuite/g++.dg/cpp23/auto-fncast6.C | 14 ++++++ gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C | 3 +- gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C | 3 +- 12 files changed, 215 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast1.C create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast2.C create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast3.C create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast4.C create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast5.C create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast6.C (limited to 'gcc') diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 8f79f04..d962b29 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3134,6 +3134,20 @@ finish_compound_literal (tree type, tree compound_literal, if (type == error_mark_node) return error_mark_node; } + /* C++23 auto{x}. */ + else if (is_auto (type) + && !AUTO_IS_DECLTYPE (type) + && CONSTRUCTOR_NELTS (compound_literal) == 1) + { + if (cxx_dialect < cxx23) + pedwarn (input_location, OPT_Wc__23_extensions, + "% only available with " + "%<-std=c++2b%> or %<-std=gnu++2b%>"); + type = do_auto_deduction (type, compound_literal, type, complain, + adc_variable_type); + if (type == error_mark_node) + return error_mark_node; + } /* Used to hold a copy of the compound literal in a template. */ tree orig_cl = NULL_TREE; diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index e98fbf7..3fb651a 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -2201,19 +2201,29 @@ build_functional_cast_1 (location_t loc, tree exp, tree parms, if (tree anode = type_uses_auto (type)) { - if (!CLASS_PLACEHOLDER_TEMPLATE (anode)) + tree init; + if (CLASS_PLACEHOLDER_TEMPLATE (anode)) + init = parms; + /* C++23 auto(x). */ + else if (!AUTO_IS_DECLTYPE (anode) + && list_length (parms) == 1) { - if (complain & tf_error) - error_at (loc, "invalid use of %qT", anode); - return error_mark_node; + init = TREE_VALUE (parms); + if (cxx_dialect < cxx23) + pedwarn (loc, OPT_Wc__23_extensions, + "% only available with " + "%<-std=c++2b%> or %<-std=gnu++2b%>"); } else { - type = do_auto_deduction (type, parms, anode, complain, - adc_variable_type); - if (type == error_mark_node) - return error_mark_node; + if (complain & tf_error) + error_at (loc, "invalid use of %qT", anode); + return error_mark_node; } + type = do_auto_deduction (type, init, anode, complain, + adc_variable_type); + if (type == error_mark_node) + return error_mark_node; } if (processing_template_decl) diff --git a/gcc/testsuite/g++.dg/cpp0x/auto25.C b/gcc/testsuite/g++.dg/cpp0x/auto25.C index 19d51bc..3af0899 100644 --- a/gcc/testsuite/g++.dg/cpp0x/auto25.C +++ b/gcc/testsuite/g++.dg/cpp0x/auto25.C @@ -3,10 +3,10 @@ template struct A { - int a[auto(1)]; // { dg-error "9:invalid use of" } + int a[auto(1)]; // { dg-error "9:only available" "" { target c++20_down } } }; template void foo() { - int a[auto(1)]; // { dg-error "9:invalid use of" } + int a[auto(1)]; // { dg-error "9:only available" "" { target c++20_down } } } diff --git a/gcc/testsuite/g++.dg/cpp0x/auto9.C b/gcc/testsuite/g++.dg/cpp0x/auto9.C index 0e80c30..a3a6caf 100644 --- a/gcc/testsuite/g++.dg/cpp0x/auto9.C +++ b/gcc/testsuite/g++.dg/cpp0x/auto9.C @@ -45,7 +45,7 @@ foo () C c; dynamic_cast (c); // { dg-error "auto" } reinterpret_cast (c); // { dg-error "auto" } - int i = auto (0); // { dg-error "auto" } + int i = auto (0); // { dg-error "auto" "" { target c++20_down } } auto p1 = new (auto); // { dg-error "auto" } auto p2 = new (auto) (42); // { dg-error "invalid use of|deduce" } offsetof (auto, fld); // { dg-error "auto" } diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast1.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast1.C new file mode 100644 index 0000000..25e53c4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast1.C @@ -0,0 +1,14 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++23 } } +// Testcase from P0849R8. + +struct A {}; +void f(A&) = delete; // #1 +void f(A&&); // #2 +A& g(); +void h() { +// f(g()); // calls #1 + f(A(g())); // calls #2 with a temporary object + f(auto(g())); // calls #2 with a temporary object +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast2.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast2.C new file mode 100644 index 0000000..327a448 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast2.C @@ -0,0 +1,62 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++23 } } + +struct X { }; +X& fn (); +X&& fnr (); + +void h() +{ + double v[] = { 1.2, 3.4 }; + +auto(v); + +auto{v}; + static_assert (__is_same_as (decltype (auto(v)), double *)); + static_assert (__is_same_as (decltype (auto{v}), double *)); + auto a1 = fn (); + static_assert (__is_same_as (decltype (auto(fn())), decltype (a1))); + static_assert (__is_same_as (decltype (auto{fn()}), decltype (a1))); + auto a2 = fnr (); + static_assert (__is_same_as (decltype (auto(fnr())), decltype (a2))); + static_assert (__is_same_as (decltype (auto{fnr()}), decltype (a2))); + +auto(1); + new auto(1); + +auto{1}; + new auto{1}; +} + +template +void baz (T t, const T &tr, T &&trr) +{ + +auto(t); + +auto{t}; + +auto(tr); + +auto{tr}; + +auto(trr); + +auto{trr}; + static_assert (__is_same_as (decltype (auto(t)), T)); + static_assert (__is_same_as (decltype (auto{t}), T)); + static_assert (__is_same_as (decltype (auto(tr)), T)); + static_assert (__is_same_as (decltype (auto{tr}), T)); + static_assert (__is_same_as (decltype (auto(trr)), T)); + static_assert (__is_same_as (decltype (auto{trr}), T)); +} + +template +void foo () +{ +} + +template +void bar () +{ +} + +void +g() +{ + foo<>(); + bar<>(); + int i = 42; + baz (1, i, 42); +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast3.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast3.C new file mode 100644 index 0000000..1204458 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast3.C @@ -0,0 +1,21 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++23 } } +// Test invalid use. + +void +f () +{ + char x[] = "foo"; + +decltype(auto){x}; // { dg-error "invalid use of .decltype\\(auto\\)." } + +decltype(auto)(x); // { dg-error "invalid use of .decltype\\(auto\\)." } + + +auto(); // { dg-error "invalid use of .auto." } + new auto(); // { dg-error "requires exactly one element" } + +auto{}; // { dg-error "invalid use of .auto." } + new auto{}; // { dg-error "requires exactly one element" } + +auto(1, 2); // { dg-error "invalid use of .auto." } + new auto(1, 2); // { dg-error "requires exactly one element" } + +auto{1, 2}; // { dg-error "too many initializers" } + new auto{1, 2}; // { dg-error "requires exactly one element" } +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast4.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast4.C new file mode 100644 index 0000000..0e26bf2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast4.C @@ -0,0 +1,26 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++23 } } + +class cmdline_parser +{ + public: + cmdline_parser(char const*); + + auto add_option(char const*, char const*) & -> cmdline_parser &; + auto add_option(char const*, char const*) && -> cmdline_parser &&; + + void parse(int, char**); +}; + +int main(int argc, char *argv[]) +{ + auto cmdline = cmdline_parser("driver"); + + cmdline.add_option("-h", "show help messages") + .add_option("-v", "show version"); + + auto internal = auto(cmdline).add_option("--logging-level", "set logging level to 1-3") + .add_option("--dump-full", "do not minimize dump"); + internal.parse(argc, argv); +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast5.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast5.C new file mode 100644 index 0000000..b29901f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast5.C @@ -0,0 +1,39 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++23 } } + +struct X { + X() = default; + X(const X&) = delete; +}; + +void +g () +{ + X x; + +X(x); // { dg-error "use of deleted function" } + +auto(x); // { dg-error "use of deleted function" } +} + +class A; +void f(A); + +class A { + int x; + +public: + A(); + + auto run() { + f(A(*this)); + f(auto(*this)); + } + +protected: + A(const A&); +}; + +void z () { + A a; + a.run (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast6.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast6.C new file mode 100644 index 0000000..6b7858d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast6.C @@ -0,0 +1,14 @@ +// PR c++/103049 +// P0849R8 - auto(x) +// { dg-do compile { target c++20 } } + +void f (int); + +void +g () +{ + auto a1 = auto(f); // { dg-error "only available with" "" { target c++20_only } } + auto a2 = auto{f}; // { dg-error "only available with" "" { target c++20_only } } + static_assert (__is_same_as (decltype (a1), void(*)(int))); + static_assert (__is_same_as (decltype (a2), void(*)(int))); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C index 290aaf8..025bbf3 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C @@ -6,7 +6,8 @@ void foo1(T& t) { typename T::template C tcv = t; typename T::template C u = tcv; // { dg-error "not permitted" "" { target c++20 } } T::template C::f (tcv, u); // { dg-error "incomplete|not permitted" } - (typename T::template D (t)); // { dg-error "invalid|not permitted" } + (typename T::template D (t)); // { dg-error "invalid|not permitted|unable" } +// { dg-warning "only available" "" { target c++17_down } .-1 } } struct T1 { diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C index d612327..80a3884 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C @@ -10,7 +10,8 @@ void foo1(T& t) { typename T::template C tcv = t; typename T::template C u = tcv; // { dg-error "not permitted" "" { target c++20 } } T::template C::f (tcv, u); // { dg-error "incomplete|not permitted" } - (typename T::template D (t)); // { dg-error "invalid|not permitted" } + (typename T::template D (t)); // { dg-error "invalid|not permitted|no class" } +// { dg-warning "only available" "" { target c++17_down } .-1 } } struct T1 { -- cgit v1.1 From d6ec661e3931773e2f571ed4f6dd8b0402d8687d Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Thu, 18 Nov 2021 22:43:40 +0100 Subject: d: Use HOST_WIDE_INT for type size temporaries. These variables are later used as the value for the format specifier `%wd`, which the expected type may not match dinteger_t, causing unnecessary -Wformat warnings. gcc/d/ChangeLog: * decl.cc (d_finish_decl): Use HOST_WIDE_INT for type size temporaries. --- gcc/d/decl.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 0d46ee1..9c9205f 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -1544,8 +1544,9 @@ d_finish_decl (tree decl) if (flag_checking && DECL_INITIAL (decl)) { /* Initializer must never be bigger than symbol size. */ - dinteger_t tsize = int_size_in_bytes (TREE_TYPE (decl)); - dinteger_t dtsize = int_size_in_bytes (TREE_TYPE (DECL_INITIAL (decl))); + HOST_WIDE_INT tsize = int_size_in_bytes (TREE_TYPE (decl)); + HOST_WIDE_INT dtsize = + int_size_in_bytes (TREE_TYPE (DECL_INITIAL (decl))); if (tsize < dtsize) { -- cgit v1.1 From 483092d3d996c52a16519261ecf4236ab1a2d99c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 19 Nov 2021 00:16:34 +0000 Subject: Daily bump. --- gcc/ChangeLog | 177 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c-family/ChangeLog | 9 +++ gcc/c/ChangeLog | 9 +++ gcc/cp/ChangeLog | 53 +++++++++++++++ gcc/d/ChangeLog | 5 ++ gcc/fortran/ChangeLog | 7 ++ gcc/lto/ChangeLog | 4 ++ gcc/testsuite/ChangeLog | 94 +++++++++++++++++++++++++ 9 files changed, 359 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5e5a720..6059931 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,180 @@ +2021-11-18 David Edelsohn + + * config/rs6000/predicates.md (current_file_function_operand): + Add flag_semantic_interposition to call of decl_replaceable_p. + +2021-11-18 Martin Liska + + * ipa-modref.c (analyze_function): Do not execute the code + only if dump_file != NULL. + +2021-11-18 Martin Liska + + * ipa-modref.c (analyze_function): Use fnode instead of repeated + cgraph_node::get (current_function_decl). + +2021-11-18 Jan Hubicka + + * cgraph.c (cgraph_node::get_availability): Update call of + decl_replaceable_p. + (cgraph_node::verify_node): Verify that semantic_interposition flag + is set correclty. + * cgraph.h: (symtab_node): Add semantic_interposition flag. + * cgraphclones.c (set_new_clone_decl_and_node_flags): Clear + semantic_interposition flag. + * cgraphunit.c (cgraph_node::finalize_function): Set + semantic_interposition flag. + (cgraph_node::add_new_function): Likewise. + (varpool_node::finalize_decl): Likewise. + (cgraph_node::create_wrapper): Likewise. + * common.opt (fsemantic-interposition): Turn to optimization node. + * lto-cgraph.c (lto_output_node): Stream semantic_interposition. + (lto_output_varpool_node): Likewise. + (input_overwrite_node): Likewise. + (input_varpool_node): Likewise. + * symtab.c (symtab_node::dump_base): Dump new flag. + * varasm.c (decl_replaceable_p): Add semantic_interposition_p + parameter. + * varasm.h (decl_replaceable_p): Update declaration. + * varpool.c (varpool_node::ctor_useable_for_folding_p): + Use semantic_interposition flag. + (varpool_node::get_availability): Likewise. + (varpool_node::create_alias): Copy semantic_interposition flag. + +2021-11-18 Jan Hubicka + + PR ipa/103266 + * ipa-modref.c (modref_eaf_analysis::merge_call_lhs_flags): Unused + parameter may still be returned. + (modref_eaf_analysis::analyze_ssa_name): Call merge_call_lhs_flags + even for unused function args. + +2021-11-18 Tamar Christina + + PR tree-optimization/103311 + * tree-vect-slp-patterns.c (complex_mul_pattern::matches, + complex_fms_pattern::matches): Check for multiplications. + +2021-11-18 H.J. Lu + + PR target/102952 + * config/i386/i386.c (ix86_output_jmp_thunk_or_indirect): Emit + CS prefix for -mindirect-branch-cs-prefix. + (ix86_output_indirect_branch_via_reg): Likewise. + * config/i386/i386.opt: Add -mindirect-branch-cs-prefix. + * doc/invoke.texi: Document -mindirect-branch-cs-prefix. + +2021-11-18 David Edelsohn + + * config/rs6000/driver-rs6000.c (detect_processor_aix): Add + power10. + +2021-11-18 Tamar Christina + + PR tree-optimization/103253 + * tree-ssa-math-opts.c (convert_mult_to_fma): Check for LHS. + +2021-11-18 Matthias Kretz + + * doc/extend.texi: Document __builtin_assoc_barrier. + +2021-11-18 Martin Liska + + * cfgexpand.c (pass_expand::execute): Use option directly. + * function.c (allocate_struct_function): Likewise. + * gimple-low.c (lower_function_body): Likewise. + (lower_stmt): Likewise. + * gimple-ssa-backprop.c (backprop::prepare_change): Likewise. + * ipa-param-manipulation.c (ipa_param_adjustments::modify_call): Likewise. + * ipa-split.c (split_function): Likewise. + * lto-streamer-in.c (input_function): Likewise. + * sese.c (sese_insert_phis_for_liveouts): Likewise. + * ssa-iterators.h (num_imm_uses): Likewise. + * tree-cfg.c (make_blocks): Likewise. + (gimple_merge_blocks): Likewise. + * tree-inline.c (tree_function_versioning): Likewise. + * tree-loop-distribution.c (generate_loops_for_partition): Likewise. + * tree-sra.c (analyze_access_subtree): Likewise. + * tree-ssa-dce.c (remove_dead_stmt): Likewise. + * tree-ssa-loop-ivopts.c (remove_unused_ivs): Likewise. + * tree-ssa-phiopt.c (spaceship_replacement): Likewise. + * tree-ssa-reassoc.c (reassoc_remove_stmt): Likewise. + * tree-ssa-tail-merge.c (tail_merge_optimize): Likewise. + * tree-ssa-threadedge.c (propagate_threaded_block_debug_into): Likewise. + * tree-ssa.c (gimple_replace_ssa_lhs): Likewise. + (target_for_debug_bind): Likewise. + (insert_debug_temp_for_var_def): Likewise. + (insert_debug_temps_for_defs): Likewise. + (reset_debug_uses): Likewise. + * tree-ssanames.c (release_ssa_name_fn): Likewise. + * tree-vect-loop-manip.c (adjust_vec_debug_stmts): Likewise. + (adjust_debug_stmts): Likewise. + (adjust_phi_and_debug_stmts): Likewise. + (vect_do_peeling): Likewise. + * tree-vect-loop.c (vect_transform_loop_stmt): Likewise. + (vect_transform_loop): Likewise. + * tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Remove + (MAY_HAVE_DEBUG_BIND_STMTS): Remove. + (MAY_HAVE_DEBUG_STMTS): Use options directly. + +2021-11-18 Richard Biener + + PR tree-optimization/103277 + * tree-ssa-dse.c (need_ab_cleanup): New. + (dse_optimize_redundant_stores): Adjust. + (delete_dead_or_redundant_assignment): Get extra + need_ab_cleanup argument and set when abnormal cleanup is + needed. + (dse_optimize_call): Adjust. + (dse_optimize_stmt): Likewise. + (pass_dse::execute): Allocate and deallocate need_ab_cleanup. + Perform abnormal cleanup. + * tree-ssa-dse.h (delete_dead_or_redundant_assignment): Adjust. + +2021-11-18 Hongyu Wang + + * config/i386/i386-expand.c (ix86_expand_atomic_fetch_op_loop): + Adjust generated cfg to avoid infinite loop. + +2021-11-18 konglin1 + + * config/i386/avx512fp16intrin.h (_mm512_mul_pch): Add alias for _mm512_fmul_pch. + (_mm512_mask_mul_pch): Likewise. + (_mm512_maskz_mul_pch): Likewise. + (_mm512_mul_round_pch): Likewise. + (_mm512_mask_mul_round_pch): Likewise. + (_mm512_maskz_mul_round_pch): Likewise. + (_mm512_cmul_pch): Likewise. + (_mm512_mask_cmul_pch): Likewise. + (_mm512_maskz_cmul_pch): Likewise. + (_mm512_cmul_round_pch): Likewise. + (_mm512_mask_cmul_round_pch): Likewise. + (_mm512_maskz_cmul_round_pch): Likewise. + (_mm_mul_sch): Likewise. + (_mm_mask_mul_sch): Likewise. + (_mm_maskz_mul_sch): Likewise. + (_mm_mul_round_sch): Likewise. + (_mm_mask_mul_round_sch): Likewise. + (_mm_maskz_mul_round_sch): Likewise. + (_mm_cmul_sch): Likewise. + (_mm_mask_cmul_sch): Likewise. + (_mm_maskz_cmul_sch): Likewise. + (_mm_cmul_round_sch): Likewise. + (_mm_mask_cmul_round_sch): Likewise. + (_mm_maskz_cmul_round_sch): Likewise. + * config/i386/avx512fp16vlintrin.h (_mm_mul_pch): Likewise. + (_mm_mask_mul_pch): Likewise. + (_mm_maskz_mul_pch): Likewise. + (_mm256_mul_pch): Likewise. + (_mm256_mask_mul_pch): Likewise. + (_mm256_maskz_mul_pch): Likewise. + (_mm_cmul_pch): Likewise. + (_mm_mask_cmul_pch): Likewise. + (_mm_maskz_cmul_pch): Likewise. + (_mm256_cmul_pch): Likewise. + (_mm256_mask_cmul_pch): Likewise. + (_mm256_maskz_cmul_pch): Likewise. + 2021-11-17 Andrew Pinski PR tree-optimization/103228 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 15171a2..f09aab3 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20211118 +20211119 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 21f153e..1c54782 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,12 @@ +2021-11-18 Matthias Kretz + + * c-common.c (c_common_reswords): Add __builtin_assoc_barrier. + * c-common.h (enum rid): Add RID_BUILTIN_ASSOC_BARRIER. + +2021-11-18 Martin Liska + + * c-gimplify.c (genericize_c_loop): Use option directly. + 2021-11-17 Martin Uecker PR c/91038 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 8dcd6be..2728c59 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,12 @@ +2021-11-18 Matthias Kretz + + * c-decl.c (names_builtin_p): Handle RID_BUILTIN_ASSOC_BARRIER. + * c-parser.c (c_parser_postfix_expression): Likewise. + +2021-11-18 Martin Liska + + * c-parser.c (add_debug_begin_stmt): Use option directly. + 2021-11-17 Martin Sebor PR c/101702 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ac52e3b..f07ae26 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,56 @@ +2021-11-18 Marek Polacek + + PR c++/103049 + * semantics.c (finish_compound_literal): Accept C++23 auto{x}. + * typeck2.c (build_functional_cast_1): Accept C++23 auto(x). + +2021-11-18 Patrick Palka + + * pt.c (tsubst_copy_and_build) : Disable the + -fpermissive fallback for C++20 template-id ADL, but keep the + diagnostic. + +2021-11-18 Jan Hubicka + + * decl.c (finish_function): Update use of decl_replaceable_p. + +2021-11-18 Patrick Palka + + PR c++/99911 + * pt.c (tsubst_copy_and_build) : Don't diagnose + name lookup failure if the arguments to an unresolved template + name are still dependent. + +2021-11-18 Patrick Palka + + PR c++/102670 + * pt.c (tsubst_copy_and_build) : When looking + for an identifier callee in the koenig_p case, also look through + TEMPLATE_ID_EXPR. Use tsubst_copy to substitute through the + template arguments of the template-id. + +2021-11-18 Matthias Kretz + + * constexpr.c (cxx_eval_constant_expression): Handle PAREN_EXPR + via cxx_eval_constant_expression. + * cp-objcp-common.c (names_builtin_p): Handle + RID_BUILTIN_ASSOC_BARRIER. + * cp-tree.h: Adjust TREE_LANG_FLAG documentation to include + PAREN_EXPR in REF_PARENTHESIZED_P. + (REF_PARENTHESIZED_P): Add PAREN_EXPR. + * parser.c (cp_parser_postfix_expression): Handle + RID_BUILTIN_ASSOC_BARRIER. + * pt.c (tsubst_copy_and_build): If the PAREN_EXPR is not a + parenthesized initializer, build a new PAREN_EXPR. + * semantics.c (force_paren_expr): Simplify conditionals. Set + REF_PARENTHESIZED_P on PAREN_EXPR. + (maybe_undo_parenthesized_ref): Test PAREN_EXPR for + REF_PARENTHESIZED_P. + +2021-11-18 Martin Liska + + * parser.c (add_debug_begin_stmt): Use option directly. + 2021-11-16 Jason Merrill * ptree.c (cxx_print_xnode): Handle PTRMEM_CST. diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index b752dd9..d04102a 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,8 @@ +2021-11-18 Iain Buclaw + + * decl.cc (d_finish_decl): Use HOST_WIDE_INT for type size + temporaries. + 2021-10-22 Eric Gallager PR other/102663 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f5abad9..de5d4de 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,10 @@ +2021-11-18 Harald Anlauf + Steven G. Kargl + + PR fortran/101329 + * check.c (is_c_interoperable): Reject NULL() as it is not + interoperable. + 2021-11-16 Harald Anlauf PR fortran/103286 diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 38350b3..580a631 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,7 @@ +2021-11-18 Jan Hubicka + + * lto-partition.c (promote_symbol): Clear semantic_interposition flag. + 2021-11-06 Jan Hubicka PR ipa/103070 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 594cc2c..18340f6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,97 @@ +2021-11-18 Marek Polacek + + PR c++/103049 + * g++.dg/cpp0x/auto25.C: Adjust dg-error. + * g++.dg/cpp0x/auto9.C: Likewise. + * g++.dg/cpp2a/concepts-pr84979-2.C: Likewise. + * g++.dg/cpp2a/concepts-pr84979-3.C: Likewise. + * g++.dg/cpp23/auto-fncast1.C: New test. + * g++.dg/cpp23/auto-fncast2.C: New test. + * g++.dg/cpp23/auto-fncast3.C: New test. + * g++.dg/cpp23/auto-fncast4.C: New test. + * g++.dg/cpp23/auto-fncast5.C: New test. + * g++.dg/cpp23/auto-fncast6.C: New test. + +2021-11-18 Harald Anlauf + Steven G. Kargl + + PR fortran/101329 + * gfortran.dg/pr101329.f90: New test. + +2021-11-18 Patrick Palka + + * g++.dg/cpp2a/fn-template25.C: New test. + +2021-11-18 Jan Hubicka + + * gcc.dg/lto/semantic-interposition-1_0.c: New test. + * gcc.dg/lto/semantic-interposition-1_1.c: New test. + +2021-11-18 Jan Hubicka + + PR ipa/103266 + * g++.dg/torture/pr103266.C: New test. + +2021-11-18 Tamar Christina + + PR tree-optimization/103311 + * gcc.target/aarch64/pr103311.c: New test. + +2021-11-18 H.J. Lu + + PR target/102952 + * gcc.target/i386/indirect-thunk-cs-prefix-1.c: New test. + * gcc.target/i386/indirect-thunk-cs-prefix-2.c: Likewise. + +2021-11-18 Jeff Law + + * gcc.target/mips/octeon-bbit-1.c (f3): Add noipa attribute. + +2021-11-18 Patrick Palka + + PR c++/99911 + * g++.dg/cpp2a/fn-template24.C: New test. + +2021-11-18 Patrick Palka + + PR c++/102670 + * g++.dg/cpp2a/concepts-recursive-sat1.C: Adjust to use ADL + proper. + * g++.dg/cpp2a/fn-template23.C: New test. + +2021-11-18 Tamar Christina + + PR tree-optimization/103253 + * gcc.dg/vect/pr103253.c: New test. + +2021-11-18 Matthias Kretz + + * c-c++-common/builtin-assoc-barrier-1.c: New test. + +2021-11-18 Richard Biener + + PR testsuite/103278 + * gcc.dg/tree-ssa/if-to-switch-3.c: Supply + --param case-values-threshold=4. + +2021-11-18 Richard Biener + + PR tree-optimization/103277 + * gcc.dg/pr103277.c: New testcase. + +2021-11-18 Hongyu Wang + + * gcc.target/i386/pr103069-2.c: Adjust. + +2021-11-18 konglin1 + + * gcc.target/i386/avx512fp16-vfcmulcph-1a.c: Add new test for alias. + * gcc.target/i386/avx512fp16-vfcmulcsh-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vfmulcph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vfmulcsh-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vfcmulcph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vfmulcph-1a.c: Likewise. + 2021-11-17 Andrew Pinski PR tree-optimization/103228 -- cgit v1.1 From 09c24fe42ff2cef3f3291f5a7540a5835c08430c Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 18 Nov 2021 19:32:22 -0500 Subject: c++: implicit dummy object in requires clause [PR103198] In the testcase below satisfaction misbehaves for f and g ultimately because find_template_parameters fails to notice that the constraint 'val.x' depends on the template parms of the class template. In contrast, satisfaction works just fine for h. The problem seems to come down to a difference in how any_template_parm_r handles 'this' vs a dummy object: it walks the TREE_TYPE of the former but not the latter, and this causes us to miss the tparm dependencies in f/g's constraints since in their case the implicit object parm through which we access 'val' is a dummy object. (For h, since we know it's a non-static member function when parsing its trailing constraints, the implicit object parm is 'this', not a dummy object.) This patch fixes this inconsistency by making any_template_parm_r walk into the TREE_TYPE of a dummy object, like it already does for 'this'. PR c++/103198 gcc/cp/ChangeLog: * pt.c (any_template_parm_r): Walk the TREE_TYPE of a dummy object. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-this1.C: New test. --- gcc/cp/pt.c | 5 +++++ gcc/testsuite/g++.dg/cpp2a/concepts-this1.C | 30 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-this1.C (limited to 'gcc') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 71a771f..6a2a937 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10766,6 +10766,11 @@ any_template_parm_r (tree t, void *data) WALK_SUBTREE (TREE_TYPE (t)); break; + case CONVERT_EXPR: + if (is_dummy_object (t)) + WALK_SUBTREE (TREE_TYPE (t)); + break; + default: break; } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-this1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-this1.C new file mode 100644 index 0000000..d717028 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-this1.C @@ -0,0 +1,30 @@ +// PR c++/103198 +// { dg-do compile { target c++20 } } + +template +struct A { + T val; + + template + requires requires { val.x; } + void f(U); + + static void g(int) + requires requires { val.x; }; + + void h(int) + requires requires { val.x; }; +}; + +struct B { int x; }; +struct C { }; + +int main() { + A().f(0); + A().g(0); + A().h(0); + + A().f(0); // { dg-error "no match" } + A().g(0); // { dg-error "no match" } + A().h(0); // { dg-error "no match" } +} -- cgit v1.1 From d3152981f71eef16e50246a94819c39ff1489c70 Mon Sep 17 00:00:00 2001 From: liuhongt Date: Sat, 9 Oct 2021 09:42:10 +0800 Subject: Reduce cost of aligned sse register store. Make them be equal to cost of unaligned ones to avoid odd alignment peeling. Impact for SPEC2017 on CLX: fprate: 503.bwaves_r BuildSame 507.cactuBSSN_r -0.22 508.namd_r -0.02 510.parest_r -0.28 511.povray_r -0.20 519.lbm_r BuildSame 521.wrf_r -0.58 526.blender_r -0.30 527.cam4_r 1.07 538.imagick_r 0.01 544.nab_r -0.09 549.fotonik3d_r BuildSame 554.roms_r BuildSame intrate: 500.perlbench_r -0.25 502.gcc_r -0.15 505.mcf_r BuildSame 520.omnetpp_r 1.03 523.xalancbmk_r -0.13 525.x264_r -0.05 531.deepsjeng_r -0.27 541.leela_r -0.24 548.exchange2_r -0.06 557.xz_r -0.10 999.specrand_ir 2.69 gcc/ChangeLog: PR target/102543 * config/i386/x86-tune-costs.h (skylake_cost): Reduce cost of storing 256/512-bit SSE register to be equal to cost of unaligned store to avoid odd alignment peeling. (icelake_cost): Ditto. gcc/testsuite/ChangeLog: * gcc.target/i386/pr102543.c: New test. --- gcc/config/i386/x86-tune-costs.h | 4 ++-- gcc/testsuite/gcc.target/i386/pr102543.c | 35 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr102543.c (limited to 'gcc') diff --git a/gcc/config/i386/x86-tune-costs.h b/gcc/config/i386/x86-tune-costs.h index dd5563d..60d50c9 100644 --- a/gcc/config/i386/x86-tune-costs.h +++ b/gcc/config/i386/x86-tune-costs.h @@ -1903,7 +1903,7 @@ struct processor_costs skylake_cost = { {6, 6, 6}, /* cost of storing integer registers */ {6, 6, 6, 10, 20}, /* cost of loading SSE register in 32bit, 64bit, 128bit, 256bit and 512bit */ - {8, 8, 8, 12, 24}, /* cost of storing SSE register + {8, 8, 8, 8, 16}, /* cost of storing SSE register in 32bit, 64bit, 128bit, 256bit and 512bit */ {6, 6, 6, 10, 20}, /* cost of unaligned loads. */ {8, 8, 8, 8, 16}, /* cost of unaligned stores. */ @@ -2029,7 +2029,7 @@ struct processor_costs icelake_cost = { {6, 6, 6}, /* cost of storing integer registers */ {6, 6, 6, 10, 20}, /* cost of loading SSE register in 32bit, 64bit, 128bit, 256bit and 512bit */ - {8, 8, 8, 12, 24}, /* cost of storing SSE register + {8, 8, 8, 8, 16}, /* cost of storing SSE register in 32bit, 64bit, 128bit, 256bit and 512bit */ {6, 6, 6, 10, 20}, /* cost of unaligned loads. */ {8, 8, 8, 8, 16}, /* cost of unaligned stores. */ diff --git a/gcc/testsuite/gcc.target/i386/pr102543.c b/gcc/testsuite/gcc.target/i386/pr102543.c new file mode 100644 index 0000000..893eb9a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr102543.c @@ -0,0 +1,35 @@ +/* PR target/102543 */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -march=skylake-avx512 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-not "MEM\\\[" "optimized" } } */ + +struct a +{ + int a[100]; +}; +typedef struct a misaligned_t __attribute__ ((aligned (8))); +typedef struct a aligned_t __attribute__ ((aligned (32))); + +__attribute__ ((used)) +__attribute__ ((noinline)) +void +t(void *a, int misaligned, aligned_t *d) +{ + int i,v; + for (i=0;i<100;i++) + { + if (misaligned) + v=((misaligned_t *)a)->a[i]; + else + v=((aligned_t *)a)->a[i]; + d->a[i]+=v; + } +} +struct b {int v; misaligned_t m;aligned_t aa;} b; +aligned_t d; +int +main() +{ + t(&b.m, 1, &d); + return 0; +} -- cgit v1.1 From 0790c8aacdfb4fd096aa580dae0fe49172c43ab2 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 10 Nov 2020 20:07:24 -0500 Subject: c++: Implement -Wuninitialized for mem-initializers (redux) [PR19808] 2021 update: Last year I posted a version of this patch: but it didn't make it in. The main objection seemed to be that the patch tried to do too much, and overlapped with the ME uninitialized warnings. Since the patch used walk_tree without any data flow info, it issued false positives for things like a(0 ? b : 42) and similar. I'll admit I've been dreading resurrecting this because of the lack of clarity about where we should warn about what. On the other hand, I think we really should do something about this. So I've simplified the original patch as much as it seemed reasonable. For instance, it doesn't even attempt to handle cases like "a((b = 42)), c(b)" -- for these I simply give up for the whole mem-initializer (but who writes code like that, anyway?). I also give up when a member is initialized with a function call, because we don't know what the call could do. See Wuninitialized-17.C, for which clang emits a false positive but we don't. I remember having a hard time dealing with initializer lists in my previous patch, so now I only handle simple a{b} cases, but no more. It turned out that this abridged version still warns about 90% cases where users would expect a warning. More complicated cases are left for the ME, which, for unused inline functions, will only warn with -fkeep-inline-functions, but so be it. (This is bug 21678.) This patch implements the long-desired -Wuninitialized warning for member initializer lists, so that the front end can detect bugs like struct A { int a; int b; A() : b(1), a(b) { } }; where the field 'b' is used uninitialized because the order of member initializers in the member initializer list is irrelevant; what matters is the order of declarations in the class definition. I've implemented this by keeping a hash set holding fields that are not initialized yet, so at first it will be {a, b}, and after initializing 'a' it will be {b} and so on. Then I use walk_tree to walk the initializer and if we see that an uninitialized object is used, we warn. Of course, when we use the address of the object, we may not warn: struct B { int &r; int *p; int a; B() : r(a), p(&a), a(1) { } // ok }; Likewise, don't warn in unevaluated contexts such as sizeof. Classes without an explicit initializer may still be initialized by their default constructors; whether or not something is considered initialized is handled in perform_member_init, see member_initialized_p. PR c++/19808 PR c++/96121 gcc/cp/ChangeLog: * init.c (perform_member_init): Remove a forward declaration. Walk the initializer using find_uninit_fields_r. New parameter to track uninitialized fields. If a member is initialized, remove it from the hash set. (perform_target_ctor): Return the initializer. (struct find_uninit_data): New class. (find_uninit_fields_r): New function. (find_uninit_fields): New function. (emit_mem_initializers): Keep and initialize a set holding fields that are not initialized. When handling delegating constructors, walk the constructor tree using find_uninit_fields_r. Also when initializing base clases. Pass uninitialized down to perform_member_init. gcc/ChangeLog: * doc/invoke.texi: Update documentation for -Wuninitialized. * tree.c (stabilize_reference): Set location. gcc/testsuite/ChangeLog: * g++.dg/warn/Wuninitialized-14.C: New test. * g++.dg/warn/Wuninitialized-15.C: New test. * g++.dg/warn/Wuninitialized-16.C: New test. * g++.dg/warn/Wuninitialized-17.C: New test. * g++.dg/warn/Wuninitialized-18.C: New test. * g++.dg/warn/Wuninitialized-19.C: New test. * g++.dg/warn/Wuninitialized-20.C: New test. * g++.dg/warn/Wuninitialized-21.C: New test. * g++.dg/warn/Wuninitialized-22.C: New test. * g++.dg/warn/Wuninitialized-23.C: New test. * g++.dg/warn/Wuninitialized-24.C: New test. * g++.dg/warn/Wuninitialized-25.C: New test. * g++.dg/warn/Wuninitialized-26.C: New test. * g++.dg/warn/Wuninitialized-27.C: New test. * g++.dg/warn/Wuninitialized-28.C: New test. * g++.dg/warn/Wuninitialized-29.C: New test. * g++.dg/warn/Wuninitialized-30.C: New test. --- gcc/cp/init.c | 194 ++++++++++++++++++++++++-- gcc/doc/invoke.texi | 12 ++ gcc/testsuite/g++.dg/warn/Wuninitialized-14.C | 31 ++++ gcc/testsuite/g++.dg/warn/Wuninitialized-15.C | 118 ++++++++++++++++ gcc/testsuite/g++.dg/warn/Wuninitialized-16.C | 12 ++ gcc/testsuite/g++.dg/warn/Wuninitialized-17.C | 33 +++++ gcc/testsuite/g++.dg/warn/Wuninitialized-18.C | 22 +++ gcc/testsuite/g++.dg/warn/Wuninitialized-19.C | 50 +++++++ gcc/testsuite/g++.dg/warn/Wuninitialized-20.C | 16 +++ gcc/testsuite/g++.dg/warn/Wuninitialized-21.C | 20 +++ gcc/testsuite/g++.dg/warn/Wuninitialized-22.C | 37 +++++ gcc/testsuite/g++.dg/warn/Wuninitialized-23.C | 24 ++++ gcc/testsuite/g++.dg/warn/Wuninitialized-24.C | 89 ++++++++++++ gcc/testsuite/g++.dg/warn/Wuninitialized-25.C | 12 ++ gcc/testsuite/g++.dg/warn/Wuninitialized-26.C | 22 +++ gcc/testsuite/g++.dg/warn/Wuninitialized-27.C | 20 +++ gcc/testsuite/g++.dg/warn/Wuninitialized-28.C | 59 ++++++++ gcc/testsuite/g++.dg/warn/Wuninitialized-29.C | 59 ++++++++ gcc/testsuite/g++.dg/warn/Wuninitialized-30.C | 13 ++ gcc/tree.c | 1 + 20 files changed, 831 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-14.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-15.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-16.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-17.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-18.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-19.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-20.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-21.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-22.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-23.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-24.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-25.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-26.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-27.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-28.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-29.C create mode 100644 gcc/testsuite/g++.dg/warn/Wuninitialized-30.C (limited to 'gcc') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 3ba2e3b..975f2ed 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -41,7 +41,6 @@ static tree finish_init_stmts (bool, tree, tree); static void construct_virtual_base (tree, tree); static bool expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t); static bool expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t); -static void perform_member_init (tree, tree); static int member_init_ok_or_else (tree, tree, tree); static void expand_virtual_init (tree, tree); static tree sort_mem_initializers (tree, tree); @@ -525,19 +524,19 @@ build_value_init_noctor (tree type, tsubst_flags_t complain) return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false); } -/* Initialize current class with INIT, a TREE_LIST of - arguments for a target constructor. If TREE_LIST is void_type_node, - an empty initializer list was given. */ +/* Initialize current class with INIT, a TREE_LIST of arguments for + a target constructor. If TREE_LIST is void_type_node, an empty + initializer list was given. Return the target constructor. */ -static void +static tree perform_target_ctor (tree init) { tree decl = current_class_ref; tree type = current_class_type; - finish_expr_stmt (build_aggr_init (decl, init, - LOOKUP_NORMAL|LOOKUP_DELEGATING_CONS, - tf_warning_or_error)); + init = build_aggr_init (decl, init, LOOKUP_NORMAL|LOOKUP_DELEGATING_CONS, + tf_warning_or_error); + finish_expr_stmt (init); if (type_build_dtor_call (type)) { tree expr = build_delete (input_location, @@ -550,6 +549,7 @@ perform_target_ctor (tree init) && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) finish_eh_cleanup (expr); } + return init; } /* Return the non-static data initializer for FIELD_DECL MEMBER. */ @@ -775,12 +775,148 @@ maybe_warn_list_ctor (tree member, tree init) "of the underlying array", member, begin); } +/* Data structure for find_uninit_fields_r, below. */ + +struct find_uninit_data { + /* The set tracking the yet-uninitialized members. */ + hash_set *uninitialized; + /* The data member we are currently initializing. It can be either + a type (initializing a base class/delegating constructors), or + a COMPONENT_REF. */ + tree member; +}; + +/* walk_tree callback that warns about using uninitialized data in + a member-initializer-list. */ + +static tree +find_uninit_fields_r (tree *tp, int *walk_subtrees, void *data) +{ + find_uninit_data *d = static_cast(data); + hash_set *uninitialized = d->uninitialized; + tree init = *tp; + const tree_code code = TREE_CODE (init); + + /* No need to look into types or unevaluated operands. */ + if (TYPE_P (init) || unevaluated_p (code)) + { + *walk_subtrees = false; + return NULL_TREE; + } + + switch (code) + { + /* We'd need data flow info to avoid false positives. */ + case COND_EXPR: + case VEC_COND_EXPR: + case BIND_EXPR: + /* We might see a MODIFY_EXPR in cases like S() : a((b = 42)), c(b) { } + where the initializer for 'a' surreptitiously initializes 'b'. Let's + not bother with these complicated scenarios in the front end. */ + case MODIFY_EXPR: + /* Don't attempt to handle statement-expressions, either. */ + case STATEMENT_LIST: + uninitialized->empty (); + gcc_fallthrough (); + /* If we're just taking the address of an object, it doesn't matter + whether it's been initialized. */ + case ADDR_EXPR: + *walk_subtrees = false; + return NULL_TREE; + default: + break; + } + + /* We'd need data flow info to avoid false positives. */ + if (truth_value_p (code)) + goto give_up; + /* Attempt to handle a simple a{b}, but no more. */ + else if (BRACE_ENCLOSED_INITIALIZER_P (init)) + { + if (CONSTRUCTOR_NELTS (init) == 1 + && !BRACE_ENCLOSED_INITIALIZER_P (CONSTRUCTOR_ELT (init, 0)->value)) + init = CONSTRUCTOR_ELT (init, 0)->value; + else + goto give_up; + } + /* Warn about uninitialized 'this'. */ + else if (code == CALL_EXPR) + { + tree fn = get_callee_fndecl (init); + if (fn && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + { + tree op = CALL_EXPR_ARG (init, 0); + if (TREE_CODE (op) == ADDR_EXPR) + op = TREE_OPERAND (op, 0); + temp_override ovr (d->member, DECL_ARGUMENTS (fn)); + cp_walk_tree_without_duplicates (&op, find_uninit_fields_r, data); + } + /* Functions (whether static or nonstatic member) may have side effects + and initialize other members; it's not the front end's job to try to + figure it out. But don't give up for constructors: we still want to + warn when initializing base classes: + + struct D : public B { + int x; + D() : B(x) {} + }; + + so carry on to detect that 'x' is used uninitialized. */ + if (!fn || !DECL_CONSTRUCTOR_P (fn)) + goto give_up; + } + + /* If we find FIELD in the uninitialized set, we warn. */ + if (code == COMPONENT_REF) + { + tree field = TREE_OPERAND (init, 1); + tree type = TYPE_P (d->member) ? d->member : TREE_TYPE (d->member); + + /* We're initializing a reference member with itself. */ + if (TYPE_REF_P (type) && cp_tree_equal (d->member, init)) + warning_at (EXPR_LOCATION (init), OPT_Winit_self, + "%qD is initialized with itself", field); + else if (cp_tree_equal (TREE_OPERAND (init, 0), current_class_ref) + && uninitialized->contains (field)) + { + if (TYPE_REF_P (TREE_TYPE (field))) + warning_at (EXPR_LOCATION (init), OPT_Wuninitialized, + "reference %qD is not yet bound to a value when used " + "here", field); + else if (!INDIRECT_TYPE_P (type) || is_this_parameter (d->member)) + warning_at (EXPR_LOCATION (init), OPT_Wuninitialized, + "member %qD is used uninitialized", field); + *walk_subtrees = false; + } + } + + return NULL_TREE; + +give_up: + *walk_subtrees = false; + uninitialized->empty (); + return integer_zero_node; +} + +/* Wrapper around find_uninit_fields_r above. */ + +static void +find_uninit_fields (tree *t, hash_set *uninitialized, tree member) +{ + if (!uninitialized->is_empty ()) + { + find_uninit_data data = { uninitialized, member }; + cp_walk_tree_without_duplicates (t, find_uninit_fields_r, &data); + } +} + /* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of arguments. If TREE_LIST is void_type_node, an empty initializer - list was given; if NULL_TREE no initializer was given. */ + list was given; if NULL_TREE no initializer was given. UNINITIALIZED + is the hash set that tracks uninitialized fields. */ static void -perform_member_init (tree member, tree init) +perform_member_init (tree member, tree init, hash_set &uninitialized) { tree decl; tree type = TREE_TYPE (member); @@ -808,7 +944,9 @@ perform_member_init (tree member, tree init) if (decl == error_mark_node) return; - if (warn_init_self && init && TREE_CODE (init) == TREE_LIST + if ((warn_init_self || warn_uninitialized) + && init + && TREE_CODE (init) == TREE_LIST && TREE_CHAIN (init) == NULL_TREE) { tree val = TREE_VALUE (init); @@ -820,6 +958,8 @@ perform_member_init (tree member, tree init) warning_at (DECL_SOURCE_LOCATION (current_function_decl), OPT_Winit_self, "%qD is initialized with itself", member); + else + find_uninit_fields (&val, &uninitialized, decl); } if (array_of_unknown_bound_p (type)) @@ -848,6 +988,9 @@ perform_member_init (tree member, tree init) do aggregate-initialization. */ } + /* Assume we are initializing the member. */ + bool member_initialized_p = true; + if (init == void_type_node) { /* mem() means value-initialization. */ @@ -988,6 +1131,9 @@ perform_member_init (tree member, tree init) diagnose_uninitialized_cst_or_ref_member (core_type, /*using_new=*/false, /*complain=*/true); + + /* We left the member uninitialized. */ + member_initialized_p = false; } maybe_warn_list_ctor (member, init); @@ -998,6 +1144,11 @@ perform_member_init (tree member, tree init) tf_warning_or_error)); } + if (member_initialized_p && warn_uninitialized) + /* This member is now initialized, remove it from the uninitialized + set. */ + uninitialized.remove (member); + if (type_build_dtor_call (type)) { tree expr; @@ -1311,13 +1462,25 @@ emit_mem_initializers (tree mem_inits) if (!COMPLETE_TYPE_P (current_class_type)) return; + /* Keep a set holding fields that are not initialized. */ + hash_set uninitialized; + + /* Initially that is all of them. */ + if (warn_uninitialized) + for (tree f = next_initializable_field (TYPE_FIELDS (current_class_type)); + f != NULL_TREE; + f = next_initializable_field (DECL_CHAIN (f))) + if (!DECL_ARTIFICIAL (f)) + uninitialized.add (f); + if (mem_inits && TYPE_P (TREE_PURPOSE (mem_inits)) && same_type_p (TREE_PURPOSE (mem_inits), current_class_type)) { /* Delegating constructor. */ gcc_assert (TREE_CHAIN (mem_inits) == NULL_TREE); - perform_target_ctor (TREE_VALUE (mem_inits)); + tree ctor = perform_target_ctor (TREE_VALUE (mem_inits)); + find_uninit_fields (&ctor, &uninitialized, current_class_type); return; } @@ -1378,6 +1541,9 @@ emit_mem_initializers (tree mem_inits) flags, tf_warning_or_error); expand_cleanup_for_base (subobject, NULL_TREE); + if (STATEMENT_LIST_TAIL (cur_stmt_list)) + find_uninit_fields (&STATEMENT_LIST_TAIL (cur_stmt_list)->stmt, + &uninitialized, BINFO_TYPE (subobject)); } else if (!ABSTRACT_CLASS_TYPE_P (current_class_type)) /* C++14 DR1658 Means we do not have to construct vbases of @@ -1405,7 +1571,9 @@ emit_mem_initializers (tree mem_inits) iloc_sentinel ils (EXPR_LOCATION (TREE_TYPE (mem_inits))); perform_member_init (TREE_PURPOSE (mem_inits), - TREE_VALUE (mem_inits)); + TREE_VALUE (mem_inits), + uninitialized); + mem_inits = TREE_CHAIN (mem_inits); } } diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 5fed1dd..1b02ea0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -6996,6 +6996,18 @@ to compute a value that itself is never used, because such computations may be deleted by data flow analysis before the warnings are printed. +In C++, this warning also warns about using uninitialized objects in +member-initializer-lists. For example, GCC warns about @code{b} being +uninitialized in the following snippet: + +@smallexample +struct A @{ + int a; + int b; + A() : a(b) @{ @} +@}; +@end smallexample + @item -Wno-invalid-memory-model @opindex Winvalid-memory-model @opindex Wno-invalid-memory-model diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-14.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-14.C new file mode 100644 index 0000000..cebadf1 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-14.C @@ -0,0 +1,31 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized" } + +struct A { + int m; + int get() const { return m; } + + A() : m{} { } + A(int) { } + A(const A &) { } + A(A *) { } +}; + +struct S { + A a, b; + + S(int (*)[1]) : a() {} + S(int (*)[2]) : b(a.get()) {} + S(int (*)[3]) : b(a) {} + S(int (*)[4]) : a(&a) {} +}; + +struct R { + A a, b; + + R(int (*)[1]) : a{} {} + R(int (*)[2]) : b{a.get()} {} + R(int (*)[3]) : b{a} {} + R(int (*)[4]) : a{&a} {} +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-15.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-15.C new file mode 100644 index 0000000..89e9066 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-15.C @@ -0,0 +1,118 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized -Winit-self" } +// Largely copied from clang's test/SemaCXX/uninitialized.cpp. + +int x; +struct U { + U() : b(a) { } + int &a = x; + int &b; +}; + +struct T { + T() : a(b), b(a) { } // { dg-warning "reference .T::b. is not yet bound" } + int &a, &b; +}; + +struct S { + S() : a(a) { } // { dg-warning ".S::a. is initialized with itself" } + int &a; +}; + +struct A { + int a; + int b; + A() { } + A(int (*)[1]) : b(a) { } // { dg-warning ".A::a. is used uninitialized" } + A(int (*)[2]) : a(b) { } // { dg-warning ".A::b. is used uninitialized" } +}; + +struct D { + int a; + int &b; + int &c = a; + int d = b; + D() : b(a) { } +}; + +struct E { + int a; + int get(); + static int num(); + E() { } + E(int) { } +}; + +struct F { + int a; + E e; + int b; + F(int (*)[1]) : a(e.get()) { } // { dg-warning "member .F::e. is used uninitialized" } + F(int (*)[2]) : a(e.num()) { } + F(int (*)[3]) : e(a) { } // { dg-warning "member .F::a. is used uninitialized" } + F(int (*)[4]) : a(4), e(a) { } + F(int (*)[5]) : e(b) { } // { dg-warning "member .F::b. is used uninitialized" } + F(int (*)[6]) : e(b), b(4) { } // { dg-warning "member .F::b. is used uninitialized" } +}; + +struct G { + G(const A&) { }; +}; + +struct H { + A a1; + G g; + A a2; + H() : g(a1) { } + // ??? clang++ doesn't warn here + H(int) : g(a2) { } // { dg-warning "member .H::a2. is used uninitialized" } +}; + +struct I { + I(int *) { } +}; + +struct J : I { + int *a; + int *b; + int c; + J() : I((a = new int(5))), b(a), c(*a) { } +}; + +struct M { }; + +struct N : public M { + int a; + int b; + N() : b(a) { } // { dg-warning "member .N::a. is used uninitialized" } +}; + +struct O { + int x = 42; + int get() { return x; } +}; + +struct P { + O o; + int x = o.get(); + P() : x(o.get()) { } +}; + +struct Q { + int a; + int b; + int &c; + Q() : + a(c = 5), // "reference .Q::c. is not yet bound" but too complex for the FE + b(c), // "reference .Q::c. is not yet bound" but too complex for the FE + c(a) { } +}; + +struct R { + int a; + int b; + int c; + int d = a + b + c; + R() : a(c = 5), b(c), c(a) { } +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-16.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-16.C new file mode 100644 index 0000000..38f587b --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-16.C @@ -0,0 +1,12 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized" } + +struct S { + int a; + int b; + int c; + S() : a((b = 42)), c(b) { } + S(int) : a(((1, b) = 42)), c(b) { } + S(char) : a(((c++, b) = 42)), c(b) { } // "field .S::c. is used uninitialized" but too complex for the FE +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-17.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-17.C new file mode 100644 index 0000000..80c37ac --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-17.C @@ -0,0 +1,33 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized -Winit-self" } + +int +foo (int *p) +{ + *p = 42; + return 5; +} + +struct S { + int x; + int y; + int z; + S() : x(foo (&y)), z(y) { } // { dg-bogus "uninitialized" } +}; + +struct T { + int x; + int y; + int z; + T() : x(({ y = 30; 42; })), z(y) { } // { dg-bogus "uninitialized" } +}; + +struct A { + int x, y, z; + int f () { y = 1; return 2; } + A (): + x (f ()), + z (y) // { dg-bogus "uninitialized" } + { } +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-18.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-18.C new file mode 100644 index 0000000..29ae77a --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-18.C @@ -0,0 +1,22 @@ +// PR c++/96121 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized" } + +struct A { + A(); + int i; +}; +struct B { + B(A); + int i; +}; + +struct composed2 { + B b_; + A a_; + composed2() : b_(a_) {} // { dg-warning "member .composed2::a_. is used uninitialized" } +}; + +composed2 test() { + return composed2{}; +} diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-19.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-19.C new file mode 100644 index 0000000..e4d53d4 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-19.C @@ -0,0 +1,50 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized" } +// Test we warn when initializing a base class. + +struct A { + A(int) { } +}; + +struct B : public A { + int x; + B() : A(x) { } // { dg-warning "member .B::x. is used uninitialized" } +}; + +struct C : public A { + int x; + int y; + C() : A(y = 4), x(y) { } +}; + +struct D : public A { + int x; + D() : A{x} { } // { dg-warning "member .D::x. is used uninitialized" } +}; + +struct E : public A { + int x; + int y; + E() : A{y = 4}, x(y) { } +}; + +struct F { + F(int&) { } +}; + +struct G : F { + int x; + G() : F(x) { } +}; + +struct H { + H(int *) { } +}; + +struct I : H { + int x; + int arr[2]; + I() : H(&x) { } + I(int) : H(arr) { } +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-20.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-20.C new file mode 100644 index 0000000..867c4da --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-20.C @@ -0,0 +1,16 @@ +// PR c++/96121 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized" } +// Test we warn with delegating constructors. + +struct A { + A(int); + A(int &, int); + A(int (*)[1]) : A(x) { } // { dg-warning "21:member .A::x. is used uninitialized" } + A(int (*)[2]) : A(x, x) { } // { dg-warning "24:member .A::x. is used uninitialized" } + A(int (*)[3]) : A(x, 0) { } + A(int (*)[4]) : A{x} { } // { dg-warning "21:member .A::x. is used uninitialized" } + A(int (*)[5]) : A{x, x} { } // { dg-warning "24:member .A::x. is used uninitialized" } + A(int (*)[6]) : A{x, 0} { } + int x; +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-21.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-21.C new file mode 100644 index 0000000..57ca00a --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-21.C @@ -0,0 +1,20 @@ +// PR c++/19808 +// { dg-do compile } +// { dg-options "-Wuninitialized" } + +struct A { + int a; + int b; + A(int) {} +}; + +struct S { + A a; + A a2; + S() : + /* We don't warn here, because we consider partial initialization + as initializing the whole object. */ + a((a2.a = 42)), + a2(a2.a) + { } +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-22.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-22.C new file mode 100644 index 0000000..89686a0 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-22.C @@ -0,0 +1,37 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized -Winit-self" } +// Test that we don't warn when initializing a reference, unless it's +// self-init. + +struct R { + int &r; +}; + +struct S { + R r; + int a; + int &b; + int c; +}; + +struct X { + S s; + X() : s{ { s.a }, 1, s.c, 3} { } +}; + +struct A { + int &r; + A() : r{r} { } // { dg-warning ".A::r. is initialized with itself" } +}; + +struct B { + int &r; + int a; + B() : r{a} { } +}; + +struct C { + R x; + C() : x{x.r} { } // { dg-warning "member .C::x. is used uninitialized" } +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-23.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-23.C new file mode 100644 index 0000000..7cb2a9e --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-23.C @@ -0,0 +1,24 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized" } +// Test that we don't warn in an uninstantiated template. + +struct A { + int *fn() { return nullptr; } +}; + +template +struct B { + B() : p(a->fn()) { } + A *a; + int *p; +}; + +template +struct C { + C() : p(a->fn()) { } // { dg-warning "member .C::a. is used uninitialized" } + A *a; + int *p; +}; + +C c; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-24.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-24.C new file mode 100644 index 0000000..e5dd429 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-24.C @@ -0,0 +1,89 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized -Winit-self" } + +int fint(int); +int fintp(int *); +int fintr(int &); +int fintcr(const int &); + +int arr[10]; + +struct S { + int x; + int y; + const int z = 42; + int *p; + + S(int (*)[1]) : x(x) { } // { dg-warning "initialized with itself" } + S(int (*)[2]) : x(x + x) { } // { dg-warning "member .S::x. is used uninitialized" } + S(int (*)[3]) : x(static_cast(y)) { } // { dg-warning "member .S::y. is used uninitialized" } + S(int (*)[4]) : x(static_cast(x)) { } // { dg-warning "member .S::x. is used uninitialized" } + S(int (*)[5]) : x(fint(x)) { } + S(int (*)[6]) : x(fint(y)) { } + + S(int (*)[7]) : x(sizeof(x)) { } + S(int (*)[8]) : x(sizeof(y)) { } + S(int (*)[9]) : p(&x) { } + S(int (*)[10]) : x(fintp(&y)) { } + S(int (*)[11]) : x(fintr(y)) { } + S(int (*)[12]) : x(fintcr(y)) { } + S(int (*)[26]) : x(((void)(__typeof(y)) 1, 1)) { } + S(int (*)[27]) : x(((void)(decltype(y)) 1, 1)) { } + S(int (*)[28]) : x(__alignof__(y)) { } + S(int (*)[29]) : x(noexcept(y)) { } + + S(int (*)[13]) : x(0), y(x ? y : y) { } + S(int (*)[14]) : x(0), y(1 + (x ? y : y)) { } + S(int (*)[15]) : x(-y) { } // { dg-warning "member .S::y. is used uninitialized" } + S(int (*)[16]) : x(1 << y) { } // { dg-warning "member .S::y. is used uninitialized" } + S(int (*)[17]) : x(this->y) { } // { dg-warning "member .S::y. is used uninitialized" } + S(int (*)[18]) : x(arr[y]) { } // { dg-warning "member .S::y. is used uninitialized" } + S(int (*)[19]) : x(0), y(x ? x : y) { } + S(int (*)[20]) : x(0), y(y ? x : y) { } + S(int (*)[21]) : x(0), y(y ? x : x) { } + S(int (*)[22]) : x(0), y((fint(y), x)) { } + S(int (*)[23]) : x(0), y(x += y) { } // "member .S::y. is used uninitialized" but too complex for the FE + S(int (*)[24]) : x(y += 10) { } // "member .S::y. is used uninitialized" but too complex for the FE + S(int (*)[25]) : x(y++) { } // { dg-warning "member .S::y. is used uninitialized" } +}; + +// Same, but { }. +struct R { + int x; + int y; + const int z = 42; + int *p; + + R(int (*)[1]) : x{x} { } // { dg-warning "member .R::x. is used uninitialized" } + R(int (*)[2]) : x{x + x} { } // { dg-warning "member .R::x. is used uninitialized" } + R(int (*)[3]) : x{static_cast(y)} { } // { dg-warning "member .R::y. is used uninitialized" } + R(int (*)[4]) : x{static_cast(x)} { } // { dg-warning "member .R::x. is used uninitialized" } + R(int (*)[5]) : x{fint(x)} { } + R(int (*)[6]) : x{fint(y)} { } + + R(int (*)[7]) : x{sizeof(x)} { } + R(int (*)[8]) : x{sizeof(y)} { } + R(int (*)[9]) : p{&x} { } + R(int (*)[10]) : x{fintp(&y)} { } + R(int (*)[11]) : x{fintr(y)} { } + R(int (*)[12]) : x{fintcr(y)} { } + R(int (*)[26]) : x{((void)(__typeof(y)) 1, 1)} { } + R(int (*)[27]) : x{((void)(decltype(y)) 1, 1)} { } + R(int (*)[28]) : x{__alignof__(y)} { } + R(int (*)[29]) : x{noexcept(y)} { } + + R(int (*)[13]) : x{0}, y{x ? y : y} { } + R(int (*)[14]) : x{0}, y{1 + (x ? y : y)} { } + R(int (*)[15]) : x{-y} { } // { dg-warning "member .R::y. is used uninitialized" } + R(int (*)[16]) : x{1 << y} { } // { dg-warning "member .R::y. is used uninitialized" } + R(int (*)[17]) : x{this->y} { } // { dg-warning "member .R::y. is used uninitialized" } + R(int (*)[18]) : x{arr[y]} { } // { dg-warning "member .R::y. is used uninitialized" } + R(int (*)[19]) : x{0}, y{x ? x : y} { } + R(int (*)[20]) : x{0}, y{y ? x : y} { } + R(int (*)[21]) : x{0}, y{y ? x : x} { } + R(int (*)[22]) : x{0}, y{(fint(y), x)} { } + R(int (*)[23]) : x{0}, y{x += y} { } // "member .R::y. is used uninitialized" but too complex for the FE + R(int (*)[24]) : x{y += 10} { } // "member .R::y. is used uninitialized" but too complex for the FE + R(int (*)[25]) : x{y++} { } // { dg-warning "member .R::y. is used uninitialized" } +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-25.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-25.C new file mode 100644 index 0000000..fb652f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-25.C @@ -0,0 +1,12 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wall" } + +struct A { + A *a; +}; + +struct B : A { + int i; + B() : A{a} {} +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-26.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-26.C new file mode 100644 index 0000000..a887d12 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-26.C @@ -0,0 +1,22 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized" } +// Anonymous union/struct. +// ??? The diagnostic should be improved to say 'b' instead of +// "". + +struct S { + __extension__ struct { + int a; + int b; + }; + S() : a(b) { } // { dg-warning "is used uninitialized" } +}; + +struct U { + union { + int a; + int b; + }; + U() : a(b) { } // { dg-warning "is used uninitialized" } +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-27.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-27.C new file mode 100644 index 0000000..24e6b9b --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-27.C @@ -0,0 +1,20 @@ +// PR c++/19808 +// { dg-do compile } +// { dg-options "-Wall" } + +enum E { red }; + +struct C { + C(int *, unsigned); +}; + +template struct D : C { + D(int, int, E) : C(e, U) {} + int e[2]; +}; + +void +g () +{ + D<1>(0, 0, red); +} diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-28.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-28.C new file mode 100644 index 0000000..7dbbf87 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-28.C @@ -0,0 +1,59 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized" } + +struct S { + int i, j, k, l; + S() : i(j), // { dg-warning "member .S::j. is used uninitialized" } + j(1), + k(l + 1), // { dg-warning "member .S::l. is used uninitialized" } + l(2) { } +}; + +struct A { + int a, b, c; + A() : a(b // { dg-warning "member .A::b. is used uninitialized" } + + c) { } // { dg-warning "member .A::c. is used uninitialized" } +}; + +struct B { + int &r; + int *p; + int a; + B() : r(a), p(&a), a(1) { } +}; + +struct C { + const int &r1, &r2; + C () : r1(r2), // { dg-warning "reference .C::r2. is not yet bound to a value when used here" } + r2(r1) { } +}; + +struct D { + int a = 1; + int b = 2; + D() : a(b + 1), b(a + 1) { } // { dg-warning "member .D::b. is used uninitialized" } +}; + +struct E { + int a = 1; + E() : a(a + 1) { } // { dg-warning "member .E::a. is used uninitialized" } +}; + +struct F { + int a = 1; + int b; + F() : b(a + 1) { } +}; + +struct bar { + bar() {} + bar(bar&) {} +}; + +class foo { + bar first; + bar second; +public: + foo() : first(second) {} // { dg-warning "member .foo::second. is used uninitialized" } +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-29.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-29.C new file mode 100644 index 0000000..bc74299 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-29.C @@ -0,0 +1,59 @@ +// PR c++/19808 +// { dg-do compile { target c++11 } } +// { dg-options "-Wuninitialized" } + +struct S { + int i, j, k, l; + S() : i{j}, // { dg-warning "member .S::j. is used uninitialized" } + j{1}, + k{l + 1}, // { dg-warning "member .S::l. is used uninitialized" } + l{2} { } +}; + +struct A { + int a, b, c; + A() : a{b // { dg-warning "member .A::b. is used uninitialized" } + + c} { } // { dg-warning "member .A::c. is used uninitialized" } +}; + +struct B { + int &r; + int *p; + int a; + B() : r{a}, p{&a}, a{1} { } +}; + +struct C { + const int &r1, &r2; + C () : r1{r2}, // { dg-warning "reference .C::r2. is not yet bound to a value when used here" } + r2{r1} { } +}; + +struct D { + int a = 1; + int b = 2; + D() : a{b + 1}, b{a + 1} { } // { dg-warning "member .D::b. is used uninitialized" } +}; + +struct E { + int a = 1; + E() : a{a + 1} { } // { dg-warning "member .E::a. is used uninitialized" } +}; + +struct F { + int a = 1; + int b; + F() : b{a + 1} { } +}; + +struct bar { + bar() {} + bar(bar&) {} +}; + +class foo { + bar first; + bar second; +public: + foo() : first{second} {} // { dg-warning "member .foo::second. is used uninitialized" } +}; diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-30.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-30.C new file mode 100644 index 0000000..ba0f76e --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-30.C @@ -0,0 +1,13 @@ +// PR c++/19808 +// { dg-do compile } +// { dg-options "-Wuninitialized" } + +class diagnostic_event { +public: + virtual int get_stack_depth(); +}; +struct event_range { + event_range(diagnostic_event &initial_event) + : m_stack_depth(initial_event.get_stack_depth()) {} + int m_stack_depth; +}; diff --git a/gcc/tree.c b/gcc/tree.c index f2c829f..62d9d78 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -4781,6 +4781,7 @@ stabilize_reference (tree ref) TREE_READONLY (result) = TREE_READONLY (ref); TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (ref); TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref); + protected_set_expr_location (result, EXPR_LOCATION (ref)); return result; } -- cgit v1.1 From 527e54a431473cc497204226a21f2831d2375e66 Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Tue, 16 Nov 2021 04:46:21 +0000 Subject: Fix tree-optimization/103257: Missed jump threading due too early conversion of bool*A into bool?A:0 So like many optimizations on the gimple level, sometimes it makes sense to do the optimization early or later. In this case, creating a cond expression early causes other optimizations to be missed. So just disable it until canonicalize_math_p () is false. OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. PR tree-optimization/103257 gcc/ChangeLog: * match.pd ((m1 >/=/<= m2) * d -> (m1 >/=/<= m2) ? d : 0): Disable until !canonicalize_math_p (). gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/vrp116.c: Check optimized instead of vrp1. * gcc.dg/tree-ssa/pr103257-1.c: New test. --- gcc/match.pd | 8 ++++---- gcc/testsuite/gcc.dg/tree-ssa/pr103257-1.c | 11 +++++++++++ gcc/testsuite/gcc.dg/tree-ssa/vrp116.c | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr103257-1.c (limited to 'gcc') diff --git a/gcc/match.pd b/gcc/match.pd index 77d848d..4042b53 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1785,10 +1785,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (convert (bit_and (bit_not @1) @0)))) /* (m1 CMP m2) * d -> (m1 CMP m2) ? d : 0 */ -(for cmp (gt lt ge le) -(simplify - (mult (convert (cmp @0 @1)) @2) - (if (GIMPLE || !TREE_SIDE_EFFECTS (@2)) +(if (!canonicalize_math_p ()) + (for cmp (gt lt ge le) + (simplify + (mult (convert (cmp @0 @1)) @2) (cond (cmp @0 @1) @2 { build_zero_cst (type); })))) /* For integral types with undefined overflow and C != 0 fold diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr103257-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr103257-1.c new file mode 100644 index 0000000..89f4f44 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr103257-1.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +void link_error(void); +unsigned b, c; +static short a(short e, short f) { return e * f; } +int main() { + if (a(1 ^ ((0, 0) ^ 1 && b) <= b, c)) + link_error (); + c = 0; +} +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp116.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp116.c index d9d7b23..9e68a77 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp116.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp116.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-tree-vrp1" } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ int f (int m1, int m2, int c) @@ -9,4 +9,4 @@ f (int m1, int m2, int c) return e ? m1 : m2; } -/* { dg-final { scan-tree-dump-times "\\? c_\[0-9\]\\(D\\) : 0" 1 "vrp1" } } */ +/* { dg-final { scan-tree-dump-times "\\? c_\[0-9\]\\(D\\) : 0" 1 "optimized" } } */ -- cgit v1.1 From 09d462146b3107c665265b11ad925c61a91c6efb Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Thu, 18 Nov 2021 23:38:30 +0000 Subject: Fix PR 103317, ICE after PHI-OPT, minmax_replacement producing invalid SSA The problem is r12-5300-gf98f373dd822b35c allows phiopt to recognize more basic blocks but missed one location where the basic block does not need to be empty but still needs to have a single predecessor. This patch fixes that over sight. OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. PR tree-optimization/103317 gcc/ChangeLog: * tree-ssa-phiopt.c (minmax_replacement): For the non empty middle bb case, check to make sure it has a single predecessor. gcc/testsuite/ChangeLog: * gcc.c-torture/compile/pr103317-1.c: New test. --- gcc/testsuite/gcc.c-torture/compile/pr103317-1.c | 13 +++++++++++++ gcc/tree-ssa-phiopt.c | 3 +++ 2 files changed, 16 insertions(+) create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr103317-1.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.c-torture/compile/pr103317-1.c b/gcc/testsuite/gcc.c-torture/compile/pr103317-1.c new file mode 100644 index 0000000..f9d145e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr103317-1.c @@ -0,0 +1,13 @@ +int a, b; +char c; +void +d (void) +{ + char e = c; + if (b) + if (c < 16 - 11) + e = 16 - 11; + if (e > 8) + e = 8; + a = e; +} diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index f043168..1abc4ea 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -1780,6 +1780,9 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, gimple *assign = last_and_only_stmt (middle_bb); tree lhs, op0, op1, bound; + if (!single_pred_p (middle_bb)) + return false; + if (!assign || gimple_code (assign) != GIMPLE_ASSIGN) return false; -- cgit v1.1 From 0fc859f5efcb4624a8b4ffdbf34d63972af179a8 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 18 Nov 2021 13:40:32 +0100 Subject: tree-optimization/102436 - restore loop store motion This restores a case of conditional store motion we fail to handle after the rewrite. We can recognize the special case of all stores in a loop happening in a single conditionally executed block which ensures stores are not re-ordered by executing them in different loop iterations. Separating out the case avoids complicating the already complex main path. 2021-11-18 Richard Biener PR tree-optimization/102436 * tree-ssa-loop-im.c (execute_sm_if_changed): Add mode to just create the if structure and return the then block. (execute_sm): Add flag to indicate the var will re-use another flag var. (hoist_memory_references): Support a single conditional block with all stores as special case. * gcc.dg/torture/20211118-1.c: New testcase. * gcc.dg/tree-ssa/ssa-lim-18.c: Likewise. --- gcc/testsuite/gcc.dg/torture/20211118-1.c | 27 +++++ gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-18.c | 19 ++++ gcc/tree-ssa-loop-im.c | 162 +++++++++++++++++++++++++++-- 3 files changed, 199 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/20211118-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-18.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/torture/20211118-1.c b/gcc/testsuite/gcc.dg/torture/20211118-1.c new file mode 100644 index 0000000..67ef684 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/20211118-1.c @@ -0,0 +1,27 @@ +/* { dg-do run } */ + +unsigned p[3]; +void __attribute__((noipa)) +bar (float *q, int n, int m) +{ + for (int i = 0; i < m; ++i) + { + if (i == n) + { + unsigned a = p[1]; + p[1] = a + 1; + *q = 1.; + } + q++; + } +} + +int main() +{ +#if __SIZEOF_FLOAT__ == __SIZEOF_INT__ + bar ((float *)p, 1, 3); + if (((float *)p)[1] != 1.) + __builtin_abort (); +#endif + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-18.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-18.c new file mode 100644 index 0000000..da19806 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-18.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fstrict-aliasing -fdump-tree-lim2-details" } */ + +unsigned p; + +void foo (float *q) +{ + for (int i = 0; i < 256; ++i) + { + if (p) + { + unsigned a = p; + *(q++) = 1.; + p = a + 1; + } + } +} + +/* { dg-final { scan-tree-dump-times "Executing store motion" 1 "lim2" } } */ diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c index 8a81aca..682406d 100644 --- a/gcc/tree-ssa-loop-im.c +++ b/gcc/tree-ssa-loop-im.c @@ -1911,10 +1911,13 @@ first_mem_ref_loc (class loop *loop, im_mem_ref *ref) } } if (lsm_flag) <-- - MEM = lsm; <-- + MEM = lsm; <-- (X) + + In case MEM and TMP_VAR are NULL the function will return the then + block so the caller can insert (X) and other related stmts. */ -static void +static basic_block execute_sm_if_changed (edge ex, tree mem, tree tmp_var, tree flag, edge preheader, hash_set *flag_bbs, edge &append_cond_position, edge &last_cond_fallthru) @@ -2009,10 +2012,13 @@ execute_sm_if_changed (edge ex, tree mem, tree tmp_var, tree flag, NULL_TREE, NULL_TREE); gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); - gsi = gsi_start_bb (then_bb); /* Insert actual store. */ - stmt = gimple_build_assign (unshare_expr (mem), tmp_var); - gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + if (mem) + { + gsi = gsi_start_bb (then_bb); + stmt = gimple_build_assign (unshare_expr (mem), tmp_var); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + } edge e1 = single_succ_edge (new_bb); edge e2 = make_edge (new_bb, then_bb, @@ -2060,6 +2066,8 @@ execute_sm_if_changed (edge ex, tree mem, tree tmp_var, tree flag, update_stmt (phi); } } + + return then_bb; } /* When REF is set on the location, set flag indicating the store. */ @@ -2117,7 +2125,8 @@ struct sm_aux static void execute_sm (class loop *loop, im_mem_ref *ref, - hash_map &aux_map, bool maybe_mt) + hash_map &aux_map, bool maybe_mt, + bool use_other_flag_var) { gassign *load; struct fmt_data fmt_data; @@ -2146,7 +2155,7 @@ execute_sm (class loop *loop, im_mem_ref *ref, || (! flag_store_data_races && ! always_stored))) multi_threaded_model_p = true; - if (multi_threaded_model_p) + if (multi_threaded_model_p && !use_other_flag_var) aux->store_flag = execute_sm_if_changed_flag_set (loop, ref, &aux->flag_bbs); else @@ -2182,7 +2191,7 @@ execute_sm (class loop *loop, im_mem_ref *ref, lim_data->tgt_loop = loop; gsi_insert_before (&gsi, load, GSI_SAME_STMT); - if (multi_threaded_model_p) + if (aux->store_flag) { load = gimple_build_assign (aux->store_flag, boolean_false_node); lim_data = init_lim_data (load); @@ -2555,6 +2564,140 @@ hoist_memory_references (class loop *loop, bitmap mem_refs, unsigned i; bitmap_iterator bi; + /* There's a special case we can use ordered re-materialization for + conditionally excuted stores which is when all stores in the loop + happen in the same basic-block. In that case we know we'll reach + all stores and thus can simply process that BB and emit a single + conditional block of ordered materializations. See PR102436. */ + basic_block single_store_bb = NULL; + EXECUTE_IF_SET_IN_BITMAP (&memory_accesses.all_refs_stored_in_loop[loop->num], + 0, i, bi) + { + bool fail = false; + ref = memory_accesses.refs_list[i]; + for (auto loc : ref->accesses_in_loop) + if (!gimple_vdef (loc.stmt)) + ; + else if (!single_store_bb) + { + single_store_bb = gimple_bb (loc.stmt); + bool conditional = false; + for (edge e : exits) + if (!dominated_by_p (CDI_DOMINATORS, e->src, single_store_bb)) + { + /* Conditional as seen from e. */ + conditional = true; + break; + } + if (!conditional) + { + fail = true; + break; + } + } + else if (single_store_bb != gimple_bb (loc.stmt)) + { + fail = true; + break; + } + if (fail) + { + single_store_bb = NULL; + break; + } + } + if (single_store_bb) + { + /* Analyze the single block with stores. */ + auto_bitmap fully_visited; + auto_bitmap refs_not_supported; + auto_bitmap refs_not_in_seq; + auto_vec seq; + bitmap_copy (refs_not_in_seq, mem_refs); + int res = sm_seq_valid_bb (loop, single_store_bb, NULL_TREE, + seq, refs_not_in_seq, refs_not_supported, + false, fully_visited); + if (res != 1) + { + /* Unhandled refs can still fail this. */ + bitmap_clear (mem_refs); + return; + } + + /* We cannot handle sm_other since we neither remember the + stored location nor the value at the point we execute them. */ + for (unsigned i = 0; i < seq.length (); ++i) + { + unsigned new_i; + if (seq[i].second == sm_other + && seq[i].from != NULL_TREE) + seq[i].from = NULL_TREE; + else if ((seq[i].second == sm_ord + || (seq[i].second == sm_other + && seq[i].from != NULL_TREE)) + && !sm_seq_push_down (seq, i, &new_i)) + { + bitmap_set_bit (refs_not_supported, seq[new_i].first); + seq[new_i].second = sm_other; + seq[new_i].from = NULL_TREE; + } + } + bitmap_and_compl_into (mem_refs, refs_not_supported); + if (bitmap_empty_p (mem_refs)) + return; + + /* Prune seq. */ + while (seq.last ().second == sm_other + && seq.last ().from == NULL_TREE) + seq.pop (); + + hash_map aux_map; + + /* Execute SM but delay the store materialization for ordered + sequences on exit. */ + bool first_p = true; + EXECUTE_IF_SET_IN_BITMAP (mem_refs, 0, i, bi) + { + ref = memory_accesses.refs_list[i]; + execute_sm (loop, ref, aux_map, true, !first_p); + first_p = false; + } + + /* Get at the single flag variable we eventually produced. */ + im_mem_ref *ref + = memory_accesses.refs_list[bitmap_first_set_bit (mem_refs)]; + sm_aux *aux = *aux_map.get (ref); + + /* Materialize ordered store sequences on exits. */ + edge e; + FOR_EACH_VEC_ELT (exits, i, e) + { + edge append_cond_position = NULL; + edge last_cond_fallthru = NULL; + edge insert_e = e; + /* Construct the single flag variable control flow and insert + the ordered seq of stores in the then block. With + -fstore-data-races we can do the stores unconditionally. */ + if (aux->store_flag) + insert_e + = single_pred_edge + (execute_sm_if_changed (e, NULL_TREE, NULL_TREE, + aux->store_flag, + loop_preheader_edge (loop), + &aux->flag_bbs, append_cond_position, + last_cond_fallthru)); + execute_sm_exit (loop, insert_e, seq, aux_map, sm_ord, + append_cond_position, last_cond_fallthru); + gsi_commit_one_edge_insert (insert_e, NULL); + } + + for (hash_map::iterator iter = aux_map.begin (); + iter != aux_map.end (); ++iter) + delete (*iter).second; + + return; + } + /* To address PR57359 before actually applying store-motion check the candidates found for validity with regards to reordering relative to other stores which we until here disambiguated using @@ -2693,7 +2836,8 @@ hoist_memory_references (class loop *loop, bitmap mem_refs, EXECUTE_IF_SET_IN_BITMAP (mem_refs, 0, i, bi) { ref = memory_accesses.refs_list[i]; - execute_sm (loop, ref, aux_map, bitmap_bit_p (refs_not_supported, i)); + execute_sm (loop, ref, aux_map, bitmap_bit_p (refs_not_supported, i), + false); } /* Materialize ordered store sequences on exits. */ -- cgit v1.1 From fb15abdc9b61a0b7fa24a37f85d19dc449cfd5bf Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 16 Nov 2021 11:47:26 +0100 Subject: middle-end/103248 - fix RDIV_EXPR handling with fixed point This fixes the previous adjustment to operation_could_trap_helper_p where I failed to realize that RDIV_EXPR is also used for fixed-point types. It also fixes that handling by properly checking for a fixed_zerop divisor. 2021-11-16 Richard Biener PR middle-end/103248 * tree-eh.c (operation_could_trap_helper_p): Properly handle fixed-point RDIV_EXPR. * gcc.dg/pr103248.c: New testcase. --- gcc/testsuite/gcc.dg/pr103248.c | 8 ++++++++ gcc/tree-eh.c | 12 +++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr103248.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/pr103248.c b/gcc/testsuite/gcc.dg/pr103248.c new file mode 100644 index 0000000..da6232d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr103248.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target fixed_point } */ +/* { dg-options "-fnon-call-exceptions" } */ + +_Accum sa; +int c; + +void div_csa() { c /= sa; } diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 3eff07f..916da85 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -2474,10 +2474,16 @@ operation_could_trap_helper_p (enum tree_code op, return false; case RDIV_EXPR: - if (honor_snans) + if (fp_operation) + { + if (honor_snans) + return true; + return flag_trapping_math; + } + /* Fixed point operations also use RDIV_EXPR. */ + if (!TREE_CONSTANT (divisor) || fixed_zerop (divisor)) return true; - gcc_assert (fp_operation); - return flag_trapping_math; + return false; case LT_EXPR: case LE_EXPR: -- cgit v1.1 From a84177aff7ca86f501d6aa5ef407fac5e71f56fb Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 19 Nov 2021 10:05:01 +0100 Subject: c++: Fix up -fstrong-eval-order handling of call arguments [PR70796] For -fstrong-eval-order (default for C++17 and later) we make sure to gimplify arguments in the right order, but as the following testcase shows that is not enough. The problem is that some lvalues can satisfy the is_gimple_val / fb_rvalue predicate used by gimplify_arg for is_gimple_reg_type typed expressions, or is_gimple_lvalue / fb_either used for other types. E.g. in foo we have: C::C (&p, ++i, ++i) before gimplification where i is an automatic int variable and without this patch gimplify that as: i = i + 1; i = i + 1; C::C (&p, i, i); which means that the ctor is called with the original i value incremented by 2 in both arguments, while because the call is CALL_EXPR_ORDERED_ARGS the first argument should be different. Similarly in qux we have: B::B (&p, TARGET_EXPR , TARGET_EXPR ) and gimplify it as: _1 = A::operator++ (&i); _2 = A::operator++ (&i); B::B (&p, MEM[(const struct A &)_1], MEM[(const struct A &)_2]); but because A::operator++ returns the passed in argument, again we have the same value in both cases due to gimplify_arg doing: /* Also strip a TARGET_EXPR that would force an extra copy. */ if (TREE_CODE (*arg_p) == TARGET_EXPR) { tree init = TARGET_EXPR_INITIAL (*arg_p); if (init && !VOID_TYPE_P (TREE_TYPE (init))) *arg_p = init; } which is perfectly fine optimization for calls with unordered arguments, but breaks the ordered ones. Lastly, in corge, we have before gimplification: D::foo (NON_LVALUE_EXPR

, 3, ++p) and gimplify it as p = p + 4; D::foo (p, 3, p); which is again wrong, because the this argument isn't before the side-effects but after it. The following patch adds cp_gimplify_arg wrapper, which if ordered and is_gimple_reg_type forces non-SSA_NAME is_gimple_variable result into a temporary, and if ordered, not is_gimple_reg_type and argument is TARGET_EXPR bypasses the gimplify_arg optimization. So, in foo with this patch we gimplify it as: i = i + 1; i.0_1 = i; i = i + 1; C::C (&p, i.0_1, i); in qux as: _1 = A::operator++ (&i); D.2312 = MEM[(const struct A &)_1]; _2 = A::operator++ (&i); B::B (&p, D.2312, MEM[(const struct A &)_2]); where D.2312 is a temporary and in corge as: p.9_1 = p; p = p + 4; D::foo (p.9_1, 3, p); The is_gimple_reg_type forcing into a temporary should be really cheap (I think even at -O0 it should be optimized if there is no modification in between), the aggregate copies might be more expensive but I think e.g. SRA or FRE should be able to deal with those if there are no intervening changes. But still, the patch tries to avoid those when it is cheaply provable that nothing bad happens (if no argument following it in the strong evaluation order doesn't have TREE_SIDE_EFFECTS, then even VAR_DECLs etc. shouldn't be modified after it). There is also an optimization to avoid doing that for this or for arguments with reference types as nothing can modify the parameter values during evaluation of other argument's side-effects. I've tried if e.g. int i = 1; return i << ++i; doesn't suffer from this problem as well, but it doesn't, the FE uses SAVE_EXPR , SAVE_EXPR << ++i; in that case which gimplifies the way we want (temporary in the first operand). 2021-11-19 Jakub Jelinek PR c++/70796 * cp-gimplify.c (cp_gimplify_arg): New function. (cp_gimplify_expr): Use cp_gimplify_arg instead of gimplify_arg, pass true as last argument to it if there are any following arguments in strong evaluation order with side-effects. * g++.dg/cpp1z/eval-order11.C: New test. --- gcc/cp/cp-gimplify.c | 65 ++++++++++++++++++++-- gcc/testsuite/g++.dg/cpp1z/eval-order11.C | 89 +++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/eval-order11.C (limited to 'gcc') diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index c86a5fe..c1691c3 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -398,6 +398,47 @@ gimplify_to_rvalue (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, return t; } +/* Like gimplify_arg, but if ORDERED is set (which should be set if + any of the arguments this argument is sequenced before has + TREE_SIDE_EFFECTS set, make sure expressions with is_gimple_reg_type type + are gimplified into SSA_NAME or a fresh temporary and for + non-is_gimple_reg_type we don't optimize away TARGET_EXPRs. */ + +static enum gimplify_status +cp_gimplify_arg (tree *arg_p, gimple_seq *pre_p, location_t call_location, + bool ordered) +{ + enum gimplify_status t; + if (ordered + && !is_gimple_reg_type (TREE_TYPE (*arg_p)) + && TREE_CODE (*arg_p) == TARGET_EXPR) + { + /* gimplify_arg would strip away the TARGET_EXPR, but + that can mean we don't copy the argument and some following + argument with side-effect could modify it. */ + protected_set_expr_location (*arg_p, call_location); + return gimplify_expr (arg_p, pre_p, NULL, is_gimple_lvalue, fb_either); + } + else + { + t = gimplify_arg (arg_p, pre_p, call_location); + if (t == GS_ERROR) + return GS_ERROR; + else if (ordered + && is_gimple_reg_type (TREE_TYPE (*arg_p)) + && is_gimple_variable (*arg_p) + && TREE_CODE (*arg_p) != SSA_NAME + /* No need to force references into register, references + can't be modified. */ + && !TYPE_REF_P (TREE_TYPE (*arg_p)) + /* And this can't be modified either. */ + && *arg_p != current_class_ptr) + *arg_p = get_initialized_tmp_var (*arg_p, pre_p); + return t; + } + +} + /* Do C++-specific gimplification. Args are as for gimplify_expr. */ int @@ -613,7 +654,8 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) gcc_assert (call_expr_nargs (*expr_p) == 2); gcc_assert (!CALL_EXPR_ORDERED_ARGS (*expr_p)); enum gimplify_status t - = gimplify_arg (&CALL_EXPR_ARG (*expr_p, 1), pre_p, loc); + = cp_gimplify_arg (&CALL_EXPR_ARG (*expr_p, 1), pre_p, loc, + TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, 0))); if (t == GS_ERROR) ret = GS_ERROR; } @@ -622,10 +664,18 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) /* Leave the last argument for gimplify_call_expr, to avoid problems with __builtin_va_arg_pack(). */ int nargs = call_expr_nargs (*expr_p) - 1; + int last_side_effects_arg = -1; + for (int i = nargs; i > 0; --i) + if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, i))) + { + last_side_effects_arg = i; + break; + } for (int i = 0; i < nargs; ++i) { enum gimplify_status t - = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p, loc); + = cp_gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p, loc, + i < last_side_effects_arg); if (t == GS_ERROR) ret = GS_ERROR; } @@ -639,8 +689,17 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) fntype = TREE_TYPE (fntype); if (TREE_CODE (fntype) == METHOD_TYPE) { + int nargs = call_expr_nargs (*expr_p); + bool side_effects = false; + for (int i = 1; i < nargs; ++i) + if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, i))) + { + side_effects = true; + break; + } enum gimplify_status t - = gimplify_arg (&CALL_EXPR_ARG (*expr_p, 0), pre_p, loc); + = cp_gimplify_arg (&CALL_EXPR_ARG (*expr_p, 0), pre_p, loc, + side_effects); if (t == GS_ERROR) ret = GS_ERROR; } diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order11.C b/gcc/testsuite/g++.dg/cpp1z/eval-order11.C new file mode 100644 index 0000000..19a24c8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/eval-order11.C @@ -0,0 +1,89 @@ +// PR c++/70796 +// { dg-do run { target c++11 } } +// { dg-options "-fstrong-eval-order" { target c++14_down } } + +struct A +{ + int x = 0; + A & operator ++ () { ++x; return *this; } +}; +struct B +{ + A first, second; + B (A x, A y) : first{x}, second{y} {} +}; +struct C +{ + int first, second; + C (int x, int y) : first{x}, second{y} {} +}; +struct D +{ + int d; + void foo (int x, D *y) + { + if (y != this + 1) + __builtin_abort (); + d = x; + } +}; +D d[2] = { { 1 }, { 2 } }; + +void +foo () +{ + int i = 0; + C p{++i, ++i}; + if (p.first != 1 || p.second != 2) + __builtin_abort (); +} + +void +bar () +{ + int i = 0; + C p{++i, ++i}; + if (p.first != 1 || p.second != 2) + __builtin_abort (); + int &j = i; + C q{++j, ++j}; + if (q.first != 3 || q.second != 4) + __builtin_abort (); +} + +void +baz () +{ + int i = 0; + C p{(int &) ++i, (int &) ++i}; + if (p.first != 1 || p.second != 2) + __builtin_abort (); +} + +void +qux () +{ + A i; + B p{++i, ++i}; + if (p.first.x != 1 || p.second.x != 2) + __builtin_abort (); +} + +void +corge () +{ + D *p = &d[0]; + p->foo (3, ++p); + if (d[0].d != 3 || d[1].d != 2) + __builtin_abort (); +} + +int +main () +{ + bar (); + baz (); + foo (); + qux (); + corge (); +} -- cgit v1.1 From dd85c42c36a5d4e00b41ed40bca98598a2fb57c5 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 19 Nov 2021 08:54:18 +0100 Subject: c++/103326 - fix ICE in tsubst with VECTOR_CST This adds missing handling of VECTOR_CST. 2021-11-19 Richard Biener PR c++/103326 * pt.c (tsubst_copy): Handle VECTOR_CST. * g++.dg/pr103326.C: New testcase. --- gcc/cp/pt.c | 1 + gcc/testsuite/g++.dg/pr103326.C | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 gcc/testsuite/g++.dg/pr103326.C (limited to 'gcc') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 6a2a937..22798b9 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17254,6 +17254,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) case INTEGER_CST: case REAL_CST: case COMPLEX_CST: + case VECTOR_CST: { /* Instantiate any typedefs in the type. */ tree type = tsubst (TREE_TYPE (t), args, complain, in_decl); diff --git a/gcc/testsuite/g++.dg/pr103326.C b/gcc/testsuite/g++.dg/pr103326.C new file mode 100644 index 0000000..260e7da --- /dev/null +++ b/gcc/testsuite/g++.dg/pr103326.C @@ -0,0 +1,15 @@ +// { dg-do compile } +// { dg-require-effective-target c++11 } + +using x86_64_v16qi [[gnu::__vector_size__ (16)]] = char; + +template +void foo() +{ + constexpr x86_64_v16qi zero{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +} + +void foo2() +{ + foo(); +} -- cgit v1.1 From 74a4ece02df1b1b6f396fd0e24dbbf8b0897858a Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 18 Nov 2021 13:14:25 +0100 Subject: Fix IPA modref ubsan. modref_tree::merge(modref_tree*, vec*, modref_parm_map*, bool) is called with modref_parm_map chain_map; The variable has uninitialized m.parm_offset_known and it is accessed here: gcc/ipa-modref-tree.h:572 a.parm_offset_known &= m.parm_offset_known; PR ipa/103230 gcc/ChangeLog: * ipa-modref-tree.h (struct modref_parm_map): Add default constructor. * ipa-modref.c (ipa_merge_modref_summary_after_inlining): Use it. --- gcc/ipa-modref-tree.h | 5 +++++ gcc/ipa-modref.c | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-modref-tree.h b/gcc/ipa-modref-tree.h index 0a09734..6796e6e 100644 --- a/gcc/ipa-modref-tree.h +++ b/gcc/ipa-modref-tree.h @@ -287,6 +287,11 @@ struct GTY((user)) modref_base_node struct modref_parm_map { + /* Default constructor. */ + modref_parm_map () + : parm_index (MODREF_UNKNOWN_PARM), parm_offset_known (false), parm_offset () + {} + /* Index of parameter we translate to. Values from special_params enum are permitted too. */ int parm_index; diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 2133431..57e2aa5 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -5030,8 +5030,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) auto_vec parm_map; modref_parm_map chain_map; /* TODO: Once we get jump functions for static chains we could - compute this. */ - chain_map.parm_index = MODREF_UNKNOWN_PARM; + compute parm_index. */ compute_parm_map (edge, &parm_map); -- cgit v1.1 From ea2954df43d4162af23a20c84f4c5485463977ac Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Fri, 19 Nov 2021 01:42:41 +0000 Subject: Fix tree-optimization/103314 : Limit folding of (type) X op CST where type is a nop convert to gimple There is some re-association code in fold_binary which conflicts with this optimization due keeping around some "constants" which are not INTEGER_CST (1 << -1) so we end up in an infinite loop because of that. So we need to limit this case to GIMPLE level only. OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. PR tree-optimization/103314 gcc/ChangeLog: * match.pd ((type) X op CST): Restrict the equal TYPE_PRECISION case to GIMPLE only. gcc/testsuite/ChangeLog: * gcc.c-torture/compile/pr103314-1.c: New test. --- gcc/match.pd | 6 +++++- gcc/testsuite/gcc.c-torture/compile/pr103314-1.c | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr103314-1.c (limited to 'gcc') diff --git a/gcc/match.pd b/gcc/match.pd index 4042b53..e5985de 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1619,7 +1619,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) after hoisting the conversion the operation will be narrower. It is also a good if the conversion is a nop as moves the conversion to one side; allowing for combining of the conversions. */ - TYPE_PRECISION (TREE_TYPE (@0)) <= TYPE_PRECISION (type) + TYPE_PRECISION (TREE_TYPE (@0)) < TYPE_PRECISION (type) + /* The conversion check for being a nop can only be done at the gimple + level as fold_binary has some re-association code which can conflict + with this if there is a "constant" which is not a full INTEGER_CST. */ + || (GIMPLE && TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (type)) /* It's also a good idea if the conversion is to a non-integer mode. */ || GET_MODE_CLASS (TYPE_MODE (type)) != MODE_INT diff --git a/gcc/testsuite/gcc.c-torture/compile/pr103314-1.c b/gcc/testsuite/gcc.c-torture/compile/pr103314-1.c new file mode 100644 index 0000000..f4a6313 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr103314-1.c @@ -0,0 +1,6 @@ +/* { dg-options "" } */ +int main() { + int t = 1; + unsigned c = 0, d1 = t ? 1 ^ c ^ 1 >> (-1) : 0; /* { dg-warning "is negative" } */ + return d1; +} -- cgit v1.1 From fd740165e54151ea794fca34904f5c2e2ea1dcda Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 19 Nov 2021 08:54:25 -0500 Subject: c++: nested lambda capturing a capture proxy [PR94376] Here when determining the type of the FIELD_DECL for the by-value capture of 'i' in the inner lambda, we incorrectly give it the type const int instead of int since the effective initializer is the proxy for the outer capture, and this proxy is const since the outer lambda is non-mutable. This patch fixes this by making lambda_capture_field_type handle by-value capturing of capture proxies specially, namely we instead consider the type of their FIELD_DECL which unlike the proxy has the true cv-quals of the captured entity. PR c++/94376 gcc/cp/ChangeLog: * lambda.c (lambda_capture_field_type): Simplify by handling the is_this case first. When capturing by-value a capture proxy, consider the type of the corresponding field instead. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/lambda/lambda-nested9.C: New test. --- gcc/cp/lambda.c | 19 +++++++--- gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C | 41 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C (limited to 'gcc') diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index f68c68c..c39a2bc 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -195,7 +195,9 @@ lambda_capture_field_type (tree expr, bool explicit_init_p, tree type; bool is_this = is_this_parameter (tree_strip_nop_conversions (expr)); - if (!is_this && explicit_init_p) + if (is_this) + type = TREE_TYPE (expr); + else if (explicit_init_p) { tree auto_node = make_auto (); @@ -209,7 +211,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p, else type = do_auto_deduction (type, expr, auto_node); } - else if (!is_this && type_dependent_expression_p (expr)) + else if (type_dependent_expression_p (expr)) { type = cxx_make_type (DECLTYPE_TYPE); DECLTYPE_TYPE_EXPR (type) = expr; @@ -219,10 +221,19 @@ lambda_capture_field_type (tree expr, bool explicit_init_p, } else { + if (!by_reference_p && is_capture_proxy (expr)) + { + /* When capturing by-value another capture proxy from an enclosing + lambda, consider the type of the corresponding field instead, + as the proxy may be additionally const-qualifed if the enclosing + lambda is non-mutable (PR94376). */ + gcc_assert (TREE_CODE (DECL_VALUE_EXPR (expr)) == COMPONENT_REF); + expr = TREE_OPERAND (DECL_VALUE_EXPR (expr), 1); + } + type = non_reference (unlowered_expr_type (expr)); - if (!is_this - && (by_reference_p || TREE_CODE (type) == FUNCTION_TYPE)) + if (by_reference_p || TREE_CODE (type) == FUNCTION_TYPE) type = build_reference_type (type); } diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C new file mode 100644 index 0000000..ff7da3b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C @@ -0,0 +1,41 @@ +// PR c++/94376 +// { dg-do compile { target c++11 } } + +int main() { + // We used to incorrectly reject the first two cases. + int i = 0; + [=] () { + [=] () mutable { + ++i; + }; + }; + +#if __cpp_init_captures + [j=0] () { + [=] () mutable { + ++j; + }; + }; +#endif + + [=] () { + [&] () mutable { + ++i; // { dg-error "read-only" } + }; + }; + + const int j = 0; + [=] () { + [=] () mutable { + ++j; // { dg-error "read-only" } + }; + }; + +#if __cpp_init_captures + [j=0] () { + [&] () mutable { + ++j; // { dg-error "read-only" } + }; + }; +#endif +} -- cgit v1.1 From cb09215ad0bbc96fd67aac16004d2131739df096 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 19 Nov 2021 09:01:09 -0500 Subject: c++: cp_walk_subtrees simplification for *_CAST_EXPR Let walk_tree_1 do the operand walking for us. gcc/cp/ChangeLog: * tree.c (cp_walk_subtrees) : Don't explicitly walk the operands. --- gcc/cp/tree.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 32ddf83..7050a53 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -5352,13 +5352,6 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, case BIT_CAST_EXPR: if (TREE_TYPE (*tp)) WALK_SUBTREE (TREE_TYPE (*tp)); - - { - int i; - for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (*tp)); ++i) - WALK_SUBTREE (TREE_OPERAND (*tp, i)); - } - *walk_subtrees_p = 0; break; case CONSTRUCTOR: -- cgit v1.1 From c7381debe4c5dd7878338f38db98face1cfa6f90 Mon Sep 17 00:00:00 2001 From: Giuliano Belinassi Date: Tue, 16 Nov 2021 13:25:32 -0300 Subject: Do not abort compilation when dump file is /dev/* The `configure` scripts generated with autoconf often tests compiler features by setting output to `/dev/null`, which then sets the dump folder as being /dev/* and the compilation halts with an error because GCC cannot create files in /dev/. This is a problem when configure is testing for compiler features because it cannot tell if the failure was due to unsupported features or any other problem, and disable it even if it is working. As an example, running configure overriding CFLAGS="-fdump-ipa-clones" will result in several compiler-features as being disabled because of gcc halting with an error creating files in /dev/*. This commit fixes this issue by checking if the output file is /dev/null or /dev/zero. In this case we use the current working directory for dump output instead of the directory of the output file because we cannot write to /dev/*. gcc/ChangeLog 2021-11-16 Giuliano Belinassi * gcc.c (process_command): Skip dumpdir override if file is a not_actual_file_p. * doc/invoke.texi: Update -dumpdir documentation. gcc/testsuite/ChangeLog 2021-11-16 Giuliano Belinassi * gcc.dg/devnull-dump.c: New. Signed-off-by: Giuliano Belinassi --- gcc/doc/invoke.texi | 3 ++- gcc/gcc.c | 3 ++- gcc/testsuite/gcc.dg/devnull-dump.c | 7 +++++++ 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/devnull-dump.c (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 1b02ea0..49c8bef 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1880,7 +1880,8 @@ named @file{dir/bar.*}, combining the given @var{dumppfx} with the default @var{dumpbase} derived from the primary output name. Dump outputs also take the input name suffix: @file{dir/bar.c.*}. -It defaults to the location of the output file; options +It defaults to the location of the output file, unless the output +file is a special file like @code{/dev/null}. Options @option{-save-temps=cwd} and @option{-save-temps=obj} override this default, just like an explicit @option{-dumpdir} option. In case multiple such options are given, the last one prevails: diff --git a/gcc/gcc.c b/gcc/gcc.c index 506c2ac..6ff2278 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -5098,7 +5098,8 @@ process_command (unsigned int decoded_options_count, bool explicit_dumpdir = dumpdir; - if (!save_temps_overrides_dumpdir && explicit_dumpdir) + if ((!save_temps_overrides_dumpdir && explicit_dumpdir) + || (output_file && not_actual_file_p (output_file))) { /* Do nothing. */ } diff --git a/gcc/testsuite/gcc.dg/devnull-dump.c b/gcc/testsuite/gcc.dg/devnull-dump.c new file mode 100644 index 0000000..378e090 --- /dev/null +++ b/gcc/testsuite/gcc.dg/devnull-dump.c @@ -0,0 +1,7 @@ +/* { dg-do assemble } */ +/* { dg-options "-fdump-ipa-clones -o /dev/null" } */ + +int main() +{ + return 0; +} -- cgit v1.1 From 79e9f721d1a6f370ce0534745baeeb5a56da948e Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 19 Nov 2021 15:29:35 +0100 Subject: Revert "Remove MAY_HAVE_DEBUG_MARKER_STMTS and MAY_HAVE_DEBUG_BIND_STMTS." This reverts commit 206b22d021d94adbaa79e1d443c87415254b15de. --- gcc/c-family/c-gimplify.c | 4 ++-- gcc/c/c-parser.c | 2 +- gcc/cfgexpand.c | 2 +- gcc/cp/parser.c | 2 +- gcc/function.c | 2 +- gcc/gimple-low.c | 4 ++-- gcc/gimple-ssa-backprop.c | 2 +- gcc/ipa-param-manipulation.c | 2 +- gcc/ipa-split.c | 6 +++--- gcc/lto-streamer-in.c | 4 ++-- gcc/sese.c | 2 +- gcc/ssa-iterators.h | 2 +- gcc/tree-cfg.c | 4 ++-- gcc/tree-inline.c | 2 +- gcc/tree-loop-distribution.c | 2 +- gcc/tree-sra.c | 2 +- gcc/tree-ssa-dce.c | 2 +- gcc/tree-ssa-loop-ivopts.c | 2 +- gcc/tree-ssa-phiopt.c | 2 +- gcc/tree-ssa-reassoc.c | 2 +- gcc/tree-ssa-tail-merge.c | 2 +- gcc/tree-ssa-threadedge.c | 2 +- gcc/tree-ssa.c | 10 +++++----- gcc/tree-ssanames.c | 2 +- gcc/tree-vect-loop-manip.c | 8 ++++---- gcc/tree-vect-loop.c | 4 ++-- gcc/tree.h | 7 ++++++- 27 files changed, 46 insertions(+), 41 deletions(-) (limited to 'gcc') diff --git a/gcc/c-family/c-gimplify.c b/gcc/c-family/c-gimplify.c index d9cf051..0d38b70 100644 --- a/gcc/c-family/c-gimplify.c +++ b/gcc/c-family/c-gimplify.c @@ -295,7 +295,7 @@ genericize_c_loop (tree *stmt_p, location_t start_locus, tree cond, tree body, finish_bc_block (&stmt_list, bc_continue, clab); if (incr) { - if (debug_nonbind_markers_p && incr_locus != UNKNOWN_LOCATION) + if (MAY_HAVE_DEBUG_MARKER_STMTS && incr_locus != UNKNOWN_LOCATION) { tree d = build0 (DEBUG_BEGIN_STMT, void_type_node); SET_EXPR_LOCATION (d, expr_loc_or_loc (incr, start_locus)); @@ -305,7 +305,7 @@ genericize_c_loop (tree *stmt_p, location_t start_locus, tree cond, tree body, } append_to_statement_list (entry, &stmt_list); - if (debug_nonbind_markers_p && cond_locus != UNKNOWN_LOCATION) + if (MAY_HAVE_DEBUG_MARKER_STMTS && cond_locus != UNKNOWN_LOCATION) { tree d = build0 (DEBUG_BEGIN_STMT, void_type_node); SET_EXPR_LOCATION (d, cond_locus); diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 81eea18..f312630 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1791,7 +1791,7 @@ static void add_debug_begin_stmt (location_t loc) { /* Don't add DEBUG_BEGIN_STMTs outside of functions, see PR84721. */ - if (!debug_nonbind_markers_p || !building_stmt_list_p ()) + if (!MAY_HAVE_DEBUG_MARKER_STMTS || !building_stmt_list_p ()) return; tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node); diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 4e6f776..eb6466f 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -6587,7 +6587,7 @@ pass_expand::execute (function *fun) timevar_pop (TV_OUT_OF_SSA); SA.partition_to_pseudo = XCNEWVEC (rtx, SA.map->num_partitions); - if (flag_var_tracking_assignments && flag_tree_ter) + if (MAY_HAVE_DEBUG_BIND_STMTS && flag_tree_ter) { gimple_stmt_iterator gsi; FOR_EACH_BB_FN (bb, cfun) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 65f0f11..aa7f0e4 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11698,7 +11698,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) static void add_debug_begin_stmt (location_t loc) { - if (!debug_nonbind_markers_p) + if (!MAY_HAVE_DEBUG_MARKER_STMTS) return; if (DECL_DECLARED_CONCEPT_P (current_function_decl)) /* A concept is never expanded normally. */ diff --git a/gcc/function.c b/gcc/function.c index 1bebe8a..61b3bd0 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -4872,7 +4872,7 @@ allocate_struct_function (tree fndecl, bool abstract_p) disabled. The markers make little sense without the variable binding annotations among them. */ cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt - && debug_nonbind_markers_p; + && MAY_HAVE_DEBUG_MARKER_STMTS; } /* This is like allocate_struct_function, but pushes a new cfun for FNDECL diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 7d9b3df..7e39c22 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -114,7 +114,7 @@ lower_function_body (void) /* If we had begin stmt markers from e.g. PCH, but this compilation doesn't want them, lower_stmt will have cleaned them up; we can now clear the flag that indicates we had them. */ - if (!debug_nonbind_markers_p && cfun->debug_nonbind_markers) + if (!MAY_HAVE_DEBUG_MARKER_STMTS && cfun->debug_nonbind_markers) { /* This counter needs not be exact, but before lowering it will most certainly be. */ @@ -316,7 +316,7 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) /* Propagate fallthruness. */ /* If the function (e.g. from PCH) had debug stmts, but they're disabled for this compilation, remove them. */ - if (!debug_nonbind_markers_p) + if (!MAY_HAVE_DEBUG_MARKER_STMTS) gsi_remove (gsi, true); else gsi_next (gsi); diff --git a/gcc/gimple-ssa-backprop.c b/gcc/gimple-ssa-backprop.c index 3705c10..4b62bb9 100644 --- a/gcc/gimple-ssa-backprop.c +++ b/gcc/gimple-ssa-backprop.c @@ -737,7 +737,7 @@ strip_sign_op (tree rhs) void backprop::prepare_change (tree var) { - if (flag_var_tracking_assignments) + if (MAY_HAVE_DEBUG_BIND_STMTS) insert_debug_temp_for_var_def (NULL, var); reset_flow_sensitive_info (var); } diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c index ba897bb..cec1dba 100644 --- a/gcc/ipa-param-manipulation.c +++ b/gcc/ipa-param-manipulation.c @@ -832,7 +832,7 @@ ipa_param_adjustments::modify_call (cgraph_edge *cs, vector to say for debug info that if parameter parm had been passed, it would have value parm_Y(D). */ tree old_decl = gimple_call_fndecl (stmt); - if (flag_var_tracking_assignments && old_decl && callee_decl) + if (MAY_HAVE_DEBUG_BIND_STMTS && old_decl && callee_decl) { vec **debug_args = NULL; unsigned i = 0; diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c index 6537767..c68577d 100644 --- a/gcc/ipa-split.c +++ b/gcc/ipa-split.c @@ -1465,7 +1465,7 @@ split_function (basic_block return_bb, class split_point *split_point, { vec **debug_args = NULL; unsigned i = 0, len = 0; - if (flag_var_tracking_assignments) + if (MAY_HAVE_DEBUG_BIND_STMTS) { debug_args = decl_debug_args_lookup (node->decl); if (debug_args) @@ -1479,11 +1479,11 @@ split_function (basic_block return_bb, class split_point *split_point, gimple *def_temp; /* This needs to be done even without - flag_var_tracking_assignments, otherwise if it didn't exist + MAY_HAVE_DEBUG_BIND_STMTS, otherwise if it didn't exist before, we'd end up with different SSA_NAME_VERSIONs between -g and -g0. */ arg = get_or_create_ssa_default_def (cfun, parm); - if (!flag_var_tracking_assignments || debug_args == NULL) + if (!MAY_HAVE_DEBUG_BIND_STMTS || debug_args == NULL) continue; while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm)) diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c index 4165892..eb8a7dc 100644 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@ -1454,8 +1454,8 @@ input_function (tree fn_decl, class data_in *data_in, { if (is_gimple_debug (stmt) && (gimple_debug_nonbind_marker_p (stmt) - ? !debug_nonbind_markers_p - : !flag_var_tracking_assignments)) + ? !MAY_HAVE_DEBUG_MARKER_STMTS + : !MAY_HAVE_DEBUG_BIND_STMTS)) remove = true; /* In case the linemap overflows locations can be dropped to zero. Thus do not keep nonsensical inline entry markers diff --git a/gcc/sese.c b/gcc/sese.c index 5ddbb0b..ca88f9b 100644 --- a/gcc/sese.c +++ b/gcc/sese.c @@ -205,7 +205,7 @@ void sese_insert_phis_for_liveouts (sese_info_p region, basic_block bb, edge false_e, edge true_e) { - if (flag_var_tracking_assignments) + if (MAY_HAVE_DEBUG_BIND_STMTS) sese_reset_debug_liveouts (region); unsigned i; diff --git a/gcc/ssa-iterators.h b/gcc/ssa-iterators.h index 3e26ce0..f70b0a4 100644 --- a/gcc/ssa-iterators.h +++ b/gcc/ssa-iterators.h @@ -456,7 +456,7 @@ num_imm_uses (const_tree var) const ssa_use_operand_t *ptr; unsigned int num = 0; - if (!flag_var_tracking_assignments) + if (!MAY_HAVE_DEBUG_BIND_STMTS) { for (ptr = start->next; ptr != start; ptr = ptr->next) if (USE_STMT (ptr)) diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index cde606e..8ed8c69 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -614,7 +614,7 @@ make_blocks (gimple_seq seq) latest (earliest we find) label, and moving debug stmts that are not separated from it by nondebug nonlabel stmts after the label. */ - if (debug_nonbind_markers_p) + if (MAY_HAVE_DEBUG_MARKER_STMTS) { gimple_stmt_iterator label = gsi_none (); @@ -2139,7 +2139,7 @@ gimple_merge_blocks (basic_block a, basic_block b) gsi_insert_before (&dest_gsi, stmt, GSI_NEW_STMT); } /* Other user labels keep around in a form of a debug stmt. */ - else if (!DECL_ARTIFICIAL (label) && flag_var_tracking_assignments) + else if (!DECL_ARTIFICIAL (label) && MAY_HAVE_DEBUG_BIND_STMTS) { gimple *dbg = gimple_build_debug_bind (label, integer_zero_node, diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index a483b9b..8c108d8 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -6432,7 +6432,7 @@ tree_function_versioning (tree old_decl, tree new_decl, } } - if (param_body_adjs && flag_var_tracking_assignments) + if (param_body_adjs && MAY_HAVE_DEBUG_BIND_STMTS) { vec **debug_args = NULL; unsigned int len = 0; diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c index 1f2d032..583c01a 100644 --- a/gcc/tree-loop-distribution.c +++ b/gcc/tree-loop-distribution.c @@ -1000,7 +1000,7 @@ generate_loops_for_partition (class loop *loop, partition *partition, /* Remove stmts not in the PARTITION bitmap. */ bbs = get_loop_body_in_dom_order (loop); - if (flag_var_tracking_assignments) + if (MAY_HAVE_DEBUG_BIND_STMTS) for (i = 0; i < loop->num_nodes; i++) { basic_block bb = bbs[i]; diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 10acd5e..76e3aae 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -2588,7 +2588,7 @@ analyze_access_subtree (struct access *root, struct access *parent, gcc_checking_assert (!root->grp_scalar_read && !root->grp_assignment_read); sth_created = true; - if (flag_var_tracking_assignments) + if (MAY_HAVE_DEBUG_BIND_STMTS) { root->grp_to_be_debug_replaced = 1; root->replacement_decl = create_access_replacement (root); diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index 27aa74f..dbf02c4 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -1143,7 +1143,7 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb, /* If this is a store into a variable that is being optimized away, add a debug bind stmt if possible. */ - if (flag_var_tracking_assignments + if (MAY_HAVE_DEBUG_BIND_STMTS && gimple_assign_single_p (stmt) && is_gimple_val (gimple_assign_rhs1 (stmt))) { diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 2dad54d..5a7fd30 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -7670,7 +7670,7 @@ remove_unused_ivs (struct ivopts_data *data, bitmap toremove) tree def = info->iv->ssa_name; - if (flag_var_tracking_assignments && SSA_NAME_DEF_STMT (def)) + if (MAY_HAVE_DEBUG_BIND_STMTS && SSA_NAME_DEF_STMT (def)) { imm_use_iterator imm_iter; use_operand_p use_p; diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index 1abc4ea..2fa7069 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -2406,7 +2406,7 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, } update_stmt (use_stmt); - if (flag_var_tracking_assignments) + if (MAY_HAVE_DEBUG_BIND_STMTS) { use_operand_p use_p; imm_use_iterator iter; diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index 5c748ad..6531622 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -233,7 +233,7 @@ reassoc_remove_stmt (gimple_stmt_iterator *gsi) { gimple *stmt = gsi_stmt (*gsi); - if (!flag_var_tracking_assignments || gimple_code (stmt) == GIMPLE_PHI) + if (!MAY_HAVE_DEBUG_BIND_STMTS || gimple_code (stmt) == GIMPLE_PHI) return gsi_remove (gsi, true); gimple_stmt_iterator prev = *gsi; diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c index 5487679e0..48f9421 100644 --- a/gcc/tree-ssa-tail-merge.c +++ b/gcc/tree-ssa-tail-merge.c @@ -1796,7 +1796,7 @@ tail_merge_optimize (unsigned int todo) if (nr_bbs_removed_total > 0) { - if (flag_var_tracking_assignments) + if (MAY_HAVE_DEBUG_BIND_STMTS) { calculate_dominance_info (CDI_DOMINATORS); update_debug_stmts (); diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 813137e..891c62a 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -645,7 +645,7 @@ jump_threader::simplify_control_stmt_condition_1 void propagate_threaded_block_debug_into (basic_block dest, basic_block src) { - if (!flag_var_tracking_assignments) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return; if (!single_pred_p (dest)) diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index ab5e915..1565e21 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -220,7 +220,7 @@ flush_pending_stmts (edge e) void gimple_replace_ssa_lhs (gimple *stmt, tree nlhs) { - if (flag_var_tracking_assignments) + if (MAY_HAVE_DEBUG_BIND_STMTS) { tree lhs = gimple_get_lhs (stmt); @@ -242,7 +242,7 @@ gimple_replace_ssa_lhs (gimple *stmt, tree nlhs) tree target_for_debug_bind (tree var) { - if (!flag_var_tracking_assignments) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return NULL_TREE; if (TREE_CODE (var) == SSA_NAME) @@ -307,7 +307,7 @@ insert_debug_temp_for_var_def (gimple_stmt_iterator *gsi, tree var) int usecount = 0; tree value = NULL; - if (!flag_var_tracking_assignments) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return; /* If this name has already been registered for replacement, do nothing @@ -499,7 +499,7 @@ insert_debug_temps_for_defs (gimple_stmt_iterator *gsi) ssa_op_iter op_iter; def_operand_p def_p; - if (!flag_var_tracking_assignments) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return; stmt = gsi_stmt (*gsi); @@ -525,7 +525,7 @@ reset_debug_uses (gimple *stmt) imm_use_iterator imm_iter; gimple *use_stmt; - if (!flag_var_tracking_assignments) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return; FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, op_iter, SSA_OP_DEF) diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c index eceb51a..f427c5a 100644 --- a/gcc/tree-ssanames.c +++ b/gcc/tree-ssanames.c @@ -560,7 +560,7 @@ release_ssa_name_fn (struct function *fn, tree var) int saved_ssa_name_version = SSA_NAME_VERSION (var); use_operand_p imm = &(SSA_NAME_IMM_USE_NODE (var)); - if (flag_var_tracking_assignments) + if (MAY_HAVE_DEBUG_BIND_STMTS) insert_debug_temp_for_var_def (NULL, var); if (flag_checking) diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c index 6d13255..f788deb 100644 --- a/gcc/tree-vect-loop-manip.c +++ b/gcc/tree-vect-loop-manip.c @@ -201,7 +201,7 @@ adjust_debug_stmts_now (adjust_info *ai) static void adjust_vec_debug_stmts (void) { - if (!flag_var_tracking_assignments) + if (!MAY_HAVE_DEBUG_BIND_STMTS) return; gcc_assert (adjust_vec.exists ()); @@ -223,7 +223,7 @@ adjust_debug_stmts (tree from, tree to, basic_block bb) { adjust_info ai; - if (flag_var_tracking_assignments + if (MAY_HAVE_DEBUG_BIND_STMTS && TREE_CODE (from) == SSA_NAME && ! SSA_NAME_IS_DEFAULT_DEF (from) && ! virtual_operand_p (from)) @@ -251,7 +251,7 @@ adjust_phi_and_debug_stmts (gimple *update_phi, edge e, tree new_def) SET_PHI_ARG_DEF (update_phi, e->dest_idx, new_def); - if (flag_var_tracking_assignments) + if (MAY_HAVE_DEBUG_BIND_STMTS) adjust_debug_stmts (orig_def, PHI_RESULT (update_phi), gimple_bb (update_phi)); } @@ -2696,7 +2696,7 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1, vop_to_rename = create_lcssa_for_virtual_phi (orig_loop); } - if (flag_var_tracking_assignments) + if (MAY_HAVE_DEBUG_BIND_STMTS) { gcc_assert (!adjust_vec.exists ()); adjust_vec.create (32); diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index f305d54..73efdb9 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -9228,7 +9228,7 @@ vect_transform_loop_stmt (loop_vec_info loop_vinfo, stmt_vec_info stmt_info, dump_printf_loc (MSG_NOTE, vect_location, "------>vectorizing statement: %G", stmt_info->stmt); - if (flag_var_tracking_assignments && !STMT_VINFO_LIVE_P (stmt_info)) + if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info)) vect_loop_kill_debug_uses (loop, stmt_info); if (!STMT_VINFO_RELEVANT_P (stmt_info) @@ -9602,7 +9602,7 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call) if (!stmt_info) continue; - if (flag_var_tracking_assignments && !STMT_VINFO_LIVE_P (stmt_info)) + if (MAY_HAVE_DEBUG_BIND_STMTS && !STMT_VINFO_LIVE_P (stmt_info)) vect_loop_kill_debug_uses (loop, stmt_info); if (!STMT_VINFO_RELEVANT_P (stmt_info) diff --git a/gcc/tree.h b/gcc/tree.h index 76d96c3..03719b18 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1174,9 +1174,14 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, #define VL_EXP_OPERAND_LENGTH(NODE) \ ((int)TREE_INT_CST_LOW (VL_EXP_CHECK (NODE)->exp.operands[0])) +/* Nonzero if gimple_debug_nonbind_marker_p() may possibly hold. */ +#define MAY_HAVE_DEBUG_MARKER_STMTS debug_nonbind_markers_p +/* Nonzero if gimple_debug_bind_p() (and thus + gimple_debug_source_bind_p()) may possibly hold. */ +#define MAY_HAVE_DEBUG_BIND_STMTS flag_var_tracking_assignments /* Nonzero if is_gimple_debug() may possibly hold. */ #define MAY_HAVE_DEBUG_STMTS \ - (debug_nonbind_markers_p || flag_var_tracking_assignments) + (MAY_HAVE_DEBUG_MARKER_STMTS || MAY_HAVE_DEBUG_BIND_STMTS) /* In a LOOP_EXPR node. */ #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0) -- cgit v1.1 From 487d604b6fa0f0a981eadc216d9e481d08ed7e7b Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Fri, 19 Nov 2021 15:12:38 +0000 Subject: middle-end: Handle FMA_CONJ correctly after SLP layout update. Apologies, I got dinged by the i386 regressions bot for a test I didn't have in my tree at the time I made the previous patch. The bot was telling me that FMA stopped working after I strengthened the FMA check in the previous patch. The reason is that the check is slightly early. The first check can indeed only exit early when either node isn't a mult. However we need to delay till we know if the node is a MUL or FMA before enforcing that both nodes must be a MULT since the node to inspect is different if the operation is a MUL or FMA. Also with the update patch for GCC 11 tree layout update to the new GCC 12 one I had missed that the difference in which node is conjucated is not symmetrical. So the test for it can just be testing the inverse order. It was Currently no detecting when the first node was conjucated instead of the second one. This also made me wonder why my own test didn't detect this. It turns out that the tests, being copied from the _Float16 ones were incorrectly marked as xfail. The _Float16 ones are marked as xfail since C doesn't have a conj operation for _Float16, which means you get extra type-casts in between. While you could use the GCC _Complex extension here I opted to mark them xfail since I wanted to include detection over the widenings next year. Secondly the double tests were being skipped because Adv. SIMD was missing from targets supporting Complex Double vectorization. With these changes all other tests run and pass and only XFAIL ones are correctly the _Float16 ones. Sorry for missing this before, testing should now cover all cases. gcc/ChangeLog: PR tree-optimization/103311 PR target/103330 * tree-vect-slp-patterns.c (vect_validate_multiplication): Fix CONJ test to new codegen. (complex_mul_pattern::matches): Move check downwards. gcc/testsuite/ChangeLog: PR tree-optimization/103311 PR target/103330 * gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-double.c: Fix it. * gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-float.c: Likewise. * gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-double.c: Likewise. * gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-float.c: Likewise. * gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-double.c: Likewise. * gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-float.c: Likewise. * lib/target-supports.exp (check_effective_target_vect_complex_add_double): Add Adv. SIMD. --- .../complex/fast-math-bb-slp-complex-mla-double.c | 5 +++-- .../complex/fast-math-bb-slp-complex-mla-float.c | 6 +++--- .../complex/fast-math-bb-slp-complex-mls-double.c | 7 +++---- .../complex/fast-math-bb-slp-complex-mls-float.c | 6 +++--- .../complex/fast-math-bb-slp-complex-mul-double.c | 5 +++-- .../complex/fast-math-bb-slp-complex-mul-float.c | 4 ++-- gcc/testsuite/lib/target-supports.exp | 6 ++++-- gcc/tree-vect-slp-patterns.c | 24 ++++++++++++++-------- 8 files changed, 37 insertions(+), 26 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-double.c b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-double.c index 462063a..b77c847 100644 --- a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-double.c +++ b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-double.c @@ -1,10 +1,11 @@ /* { dg-do compile } */ /* { dg-require-effective-target vect_complex_add_double } */ /* { dg-add-options arm_v8_3a_complex_neon } */ +/* { dg-additional-options "-fdump-tree-vect-details" } */ #define TYPE double #define N 16 #include "complex-mla-template.c" -/* { dg-final { scan-tree-dump "Found COMPLEX_FMA_CONJ" "slp1" } } */ -/* { dg-final { scan-tree-dump "Found COMPLEX_FMA" "slp1" } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_FMA_CONJ" "vect" } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_FMA" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-float.c b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-float.c index a88adc8..cd68fd1 100644 --- a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-float.c +++ b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-float.c @@ -1,10 +1,10 @@ /* { dg-do compile } */ /* { dg-require-effective-target vect_complex_add_float } */ -/* { dg-additional-options "-fno-tree-loop-vectorize" } */ +/* { dg-additional-options "-fdump-tree-vect-details" } */ /* { dg-add-options arm_v8_3a_fp16_complex_neon } */ #define TYPE float #define N 16 #include "complex-mla-template.c" -/* { dg-final { scan-tree-dump "Found COMPLEX_FMA_CONJ" "slp1" { xfail *-*-* } } } */ -/* { dg-final { scan-tree-dump "Found COMPLEX_FMA" "slp1" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_FMA_CONJ" "vect" } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_FMA" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-double.c b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-double.c index a434fd1..9d98394 100644 --- a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-double.c +++ b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-double.c @@ -1,12 +1,11 @@ /* { dg-do compile } */ /* { dg-require-effective-target vect_complex_add_double } */ /* { dg-add-options arm_v8_3a_complex_neon } */ +/* { dg-additional-options "-fdump-tree-vect-details" } */ #define TYPE double #define N 16 #include "complex-mls-template.c" -/* { dg-final { scan-tree-dump "Found COMPLEX_ADD_ROT270" "slp1" } } */ -/* { dg-final { scan-tree-dump "Found COMPLEX_FMA" "slp1" } } */ -/* { dg-final { scan-tree-dump "Found COMPLEX_FMS_CONJ" "slp1" } } */ -/* { dg-final { scan-tree-dump "Found COMPLEX_FMS" "slp1" } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_FMS_CONJ" "vect" } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_FMS" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-float.c b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-float.c index b7ccbbd..cf540a0 100644 --- a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-float.c +++ b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-float.c @@ -1,11 +1,11 @@ /* { dg-do compile } */ /* { dg-require-effective-target vect_complex_add_float } */ -/* { dg-additional-options "-fno-tree-loop-vectorize" } */ +/* { dg-additional-options "-fdump-tree-vect-details" } */ /* { dg-add-options arm_v8_3a_complex_neon } */ #define TYPE float #define N 16 #include "complex-mls-template.c" -/* { dg-final { scan-tree-dump "Found COMPLEX_FMS_CONJ" "slp1" { xfail *-*-* } } } */ -/* { dg-final { scan-tree-dump "Found COMPLEX_FMS" "slp1" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_FMS_CONJ" "vect" } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_FMS" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-double.c b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-double.c index f7e9386..dcac519 100644 --- a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-double.c +++ b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-double.c @@ -1,10 +1,11 @@ /* { dg-do compile } */ /* { dg-require-effective-target vect_complex_add_double } */ /* { dg-add-options arm_v8_3a_complex_neon } */ +/* { dg-additional-options "-fdump-tree-vect-details" } */ #define TYPE double #define N 16 #include "complex-mul-template.c" -/* { dg-final { scan-tree-dump "Found COMPLEX_MUL_CONJ" "slp1" } } */ -/* { dg-final { scan-tree-dump "Found COMPLEX_MUL" slp1" } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_MUL_CONJ" "vect" } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_MUL" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-float.c b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-float.c index 0dc9c52..27280ae 100644 --- a/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-float.c +++ b/gcc/testsuite/gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-float.c @@ -7,5 +7,5 @@ #define N 16 #include "complex-mul-template.c" -/* { dg-final { scan-tree-dump "Found COMPLEX_MUL_CONJ" "slp1" { xfail *-*-* } } } */ -/* { dg-final { scan-tree-dump "Found COMPLEX_MUL" "slp1" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_MUL_CONJ" "slp1" } } */ +/* { dg-final { scan-tree-dump "Found COMPLEX_MUL" "slp1" } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index c928d99..155034c 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -3632,8 +3632,10 @@ proc check_effective_target_vect_complex_add_float { } { proc check_effective_target_vect_complex_add_double { } { return [check_cached_effective_target_indexed vect_complex_add_double { expr { - ([check_effective_target_aarch64_sve2] - && [check_effective_target_aarch64_little_endian]) + (([check_effective_target_arm_v8_3a_complex_neon_ok] + && [check_effective_target_aarch64_little_endian]) + || ([check_effective_target_aarch64_sve2] + && [check_effective_target_aarch64_little_endian])) }}] } diff --git a/gcc/tree-vect-slp-patterns.c b/gcc/tree-vect-slp-patterns.c index d916fc9c..0350441 100644 --- a/gcc/tree-vect-slp-patterns.c +++ b/gcc/tree-vect-slp-patterns.c @@ -809,14 +809,20 @@ vect_validate_multiplication (slp_tree_to_load_perm_map_t *perm_cache, if (linear_loads_p (perm_cache, left_op[index2]) == PERM_EVENODD) return true; } - else if (kind == PERM_EVENODD) + else if (kind == PERM_EVENODD && !neg_first) { - if ((kind = linear_loads_p (perm_cache, left_op[index2])) == PERM_EVENODD) + if ((kind = linear_loads_p (perm_cache, left_op[index2])) != PERM_EVENEVEN) return false; return true; } - else if (!neg_first) - *conj_first_operand = true; + else if (kind == PERM_EVENEVEN && neg_first) + { + if ((kind = linear_loads_p (perm_cache, left_op[index2])) != PERM_EVENODD) + return false; + + *conj_first_operand = true; + return true; + } else return false; @@ -949,7 +955,7 @@ complex_mul_pattern::matches (complex_operation_t op, bool mul0 = vect_match_expression_p (l0node[0], MULT_EXPR); bool mul1 = vect_match_expression_p (l0node[1], MULT_EXPR); - if (!mul0 || !mul1) + if (!mul0 && !mul1) return IFN_LAST; /* Now operand2+4 may lead to another expression. */ @@ -962,7 +968,7 @@ complex_mul_pattern::matches (complex_operation_t op, { auto vals = SLP_TREE_CHILDREN (l0node[0]); /* Check if it's a multiply, otherwise no idea what this is. */ - if (!vect_match_expression_p (vals[1], MULT_EXPR)) + if (!(mul0 = vect_match_expression_p (vals[1], MULT_EXPR))) return IFN_LAST; /* Check if the ADD is linear, otherwise it's not valid complex FMA. */ @@ -979,6 +985,8 @@ complex_mul_pattern::matches (complex_operation_t op, if (left_op.length () != 2 || right_op.length () != 2 + || !mul0 + || !mul1 || linear_loads_p (perm_cache, left_op[1]) == PERM_ODDEVEN) return IFN_LAST; @@ -993,7 +1001,7 @@ complex_mul_pattern::matches (complex_operation_t op, if (!vect_validate_multiplication (perm_cache, left_op, PERM_EVENEVEN) || vect_normalize_conj_loc (left_op)) return IFN_LAST; - if (!mul0) + if (add0) ifn = IFN_COMPLEX_FMA; else ifn = IFN_COMPLEX_MUL; @@ -1005,7 +1013,7 @@ complex_mul_pattern::matches (complex_operation_t op, false)) return IFN_LAST; - if(!mul0) + if(add0) ifn = IFN_COMPLEX_FMA_CONJ; else ifn = IFN_COMPLEX_MUL_CONJ; -- cgit v1.1 From f47870e6a272dfe740a38422030c6c68e0fc7ff8 Mon Sep 17 00:00:00 2001 From: Stefan Schulze Frielinghaus Date: Fri, 19 Nov 2021 16:56:56 +0100 Subject: IBM Z: Fix load-and-test peephole2 condition For a peephole2 condition variable insn points to the first matched insn. In order to refer to the second matched insn use peep2_next_insn(1) instead. gcc/ChangeLog: * config/s390/s390.md (define_peephole2): Variable insn points to the first matched insn. Use peep2_next_insn(1) to refer to the second matched insn. gcc/testsuite/ChangeLog: * gcc.target/s390/20211119.c: New test. --- gcc/config/s390/s390.md | 2 +- gcc/testsuite/gcc.target/s390/20211119.c | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/s390/20211119.c (limited to 'gcc') diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index 4debdcd..c4f92bd 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -1003,7 +1003,7 @@ (match_operand:GPR 2 "memory_operand")) (set (reg CC_REGNUM) (compare (match_dup 0) (match_operand:GPR 1 "const0_operand")))] - "s390_match_ccmode(insn, CCSmode) && TARGET_EXTIMM + "s390_match_ccmode (peep2_next_insn (1), CCSmode) && TARGET_EXTIMM && GENERAL_REG_P (operands[0]) && satisfies_constraint_T (operands[2]) && !contains_constant_pool_address_p (operands[2])" diff --git a/gcc/testsuite/gcc.target/s390/20211119.c b/gcc/testsuite/gcc.target/s390/20211119.c new file mode 100644 index 0000000..b9d2163 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/20211119.c @@ -0,0 +1,12 @@ +/* { dg-do run { target { s390_useable_hw } } } */ +/* { dg-options "-Os -march=z10" } */ +signed char a; +int b = -925974181, c; +unsigned *d = &b; +int *e = &c; +int main() { + *e = ((217 ^ a) > 585) < *d; + if (c != 1) + __builtin_abort(); + return 0; +} -- cgit v1.1 From ee448a523d377f9ed882dac806d2f5001bfa2432 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Wed, 17 Nov 2021 14:14:06 -0500 Subject: Limit depth for all GORI expressions. Apply the logical_depth limit ranger uses to all stmts with multiple ssa-names to avoid excessive outgoing calculations. gcc/ PR tree-optimization/103254 * gimple-range-gori.cc (range_def_chain::get_def_chain): Limit the depth for all statements with multple ssa names. gcc/testsuite/ * gcc.dg/pr103254.c: New. --- gcc/gimple-range-gori.cc | 20 +++++++++----------- gcc/testsuite/gcc.dg/pr103254.c | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr103254.c (limited to 'gcc') diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index fb2d571..911d7ac 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -331,7 +331,6 @@ range_def_chain::get_def_chain (tree name) { tree ssa1, ssa2, ssa3; unsigned v = SSA_NAME_VERSION (name); - bool is_logical = false; // If it has already been processed, just return the cached value. if (has_def_chain (name)) @@ -348,15 +347,6 @@ range_def_chain::get_def_chain (tree name) gimple *stmt = SSA_NAME_DEF_STMT (name); if (gimple_range_handler (stmt)) { - is_logical = is_gimple_logical_p (stmt); - // Terminate the def chains if we see too many cascading logical stmts. - if (is_logical) - { - if (m_logical_depth == param_ranger_logical_depth) - return NULL; - m_logical_depth++; - } - ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt)); ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt)); ssa3 = NULL_TREE; @@ -376,6 +366,14 @@ range_def_chain::get_def_chain (tree name) return NULL; } + // Terminate the def chains if we see too many cascading stmts. + if (m_logical_depth == param_ranger_logical_depth) + return NULL; + + // Increase the depth if we have a pair of ssa-names. + if (ssa1 && ssa2) + m_logical_depth++; + register_dependency (name, ssa1, gimple_bb (stmt)); register_dependency (name, ssa2, gimple_bb (stmt)); register_dependency (name, ssa3, gimple_bb (stmt)); @@ -383,7 +381,7 @@ range_def_chain::get_def_chain (tree name) if (!ssa1 && !ssa2 & !ssa3) set_import (m_def_chain[v], name, NULL); - if (is_logical) + if (ssa1 && ssa2) m_logical_depth--; return m_def_chain[v].bm; diff --git a/gcc/testsuite/gcc.dg/pr103254.c b/gcc/testsuite/gcc.dg/pr103254.c new file mode 100644 index 0000000..62d2415 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr103254.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O3" } */ +/* { dg-timeout 10 } */ + +short int i; + +void +foo (void) +{ + for (i = 1; i < 2; i += 4) + { + int j; + + for (j = 0; j < 5; j += 4) + { + int k; + + for (k = 0; k < 68; k += 4) + { + i &= j; + j &= i; + } + } + } +} -- cgit v1.1 From 16137fbb9256ef365dd498d39024eb33de1a4cd8 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Fri, 19 Nov 2021 09:44:31 -0700 Subject: Restore ancient -Waddress for weak symbols [PR33925]. Resolves: PR c/33925 - gcc -Waddress lost some useful warnings PR c/102867 - -Waddress from macro expansion in readelf.c gcc/c-family/ChangeLog: PR c++/33925 PR c/102867 * c-common.c (decl_with_nonnull_addr_p): Call maybe_nonzero_address and improve handling tof defined symbols. gcc/c/ChangeLog: PR c++/33925 PR c/102867 * c-typeck.c (maybe_warn_for_null_address): Suppress warnings for code resulting from macro expansion. gcc/cp/ChangeLog: PR c++/33925 PR c/102867 * typeck.c (warn_for_null_address): Suppress warnings for code resulting from macro expansion. gcc/ChangeLog: PR c++/33925 PR c/102867 * doc/invoke.texi (-Waddress): Update. gcc/testsuite/ChangeLog: PR c++/33925 PR c/102867 * g++.dg/warn/Walways-true-2.C: Adjust to avoid a valid warning. * c-c++-common/Waddress-5.c: New test. * c-c++-common/Waddress-6.c: New test. * g++.dg/warn/Waddress-7.C: New test. * gcc.dg/Walways-true-2.c: Adjust to avoid a valid warning. * gcc.dg/weak/weak-3.c: Expect a warning. --- gcc/c-family/c-common.c | 39 +++++++-- gcc/c/c-typeck.c | 5 +- gcc/cp/typeck.c | 2 + gcc/doc/invoke.texi | 2 + gcc/testsuite/c-c++-common/Waddress-5.c | 133 +++++++++++++++++++++++++++++ gcc/testsuite/c-c++-common/Waddress-6.c | 32 +++++++ gcc/testsuite/g++.dg/warn/Waddress-7.C | 76 +++++++++++++++++ gcc/testsuite/g++.dg/warn/Walways-true-2.C | 2 +- gcc/testsuite/gcc.dg/Walways-true-2.c | 2 +- gcc/testsuite/gcc.dg/weak/weak-3.c | 6 +- 10 files changed, 288 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/Waddress-5.c create mode 100644 gcc/testsuite/c-c++-common/Waddress-6.c create mode 100644 gcc/testsuite/g++.dg/warn/Waddress-7.C (limited to 'gcc') diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 86c007f..a25d59f 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -3413,16 +3413,43 @@ c_wrap_maybe_const (tree expr, bool non_const) /* Return whether EXPR is a declaration whose address can never be NULL. The address of the first struct member could be NULL only if it were - accessed through a NULL pointer, and such an access would be invalid. */ + accessed through a NULL pointer, and such an access would be invalid. + The address of a weak symbol may be null unless it has a definition. */ bool decl_with_nonnull_addr_p (const_tree expr) { - return (DECL_P (expr) - && (TREE_CODE (expr) == FIELD_DECL - || TREE_CODE (expr) == PARM_DECL - || TREE_CODE (expr) == LABEL_DECL - || !DECL_WEAK (expr))); + if (!DECL_P (expr)) + return false; + + if (TREE_CODE (expr) == FIELD_DECL + || TREE_CODE (expr) == PARM_DECL + || TREE_CODE (expr) == LABEL_DECL) + return true; + + if (!VAR_OR_FUNCTION_DECL_P (expr)) + return false; + + if (!DECL_WEAK (expr)) + /* Ordinary (non-weak) symbols have nonnull addresses. */ + return true; + + if (DECL_INITIAL (expr) && DECL_INITIAL (expr) != error_mark_node) + /* Initialized weak symbols have nonnull addresses. */ + return true; + + if (DECL_EXTERNAL (expr) || !TREE_STATIC (expr)) + /* Uninitialized extern weak symbols and weak symbols with no + allocated storage might have a null address. */ + return false; + + tree attribs = DECL_ATTRIBUTES (expr); + if (lookup_attribute ("weakref", attribs)) + /* Weakref symbols might have a null address unless their referent + is known not to. Don't bother following weakref targets here. */ + return false; + + return true; } /* Prepare expr to be an argument of a TRUTH_NOT_EXPR, diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 782414f..50d7010 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -11588,7 +11588,10 @@ build_vec_cmp (tree_code code, tree type, static void maybe_warn_for_null_address (location_t loc, tree op, tree_code code) { - if (!warn_address || warning_suppressed_p (op, OPT_Waddress)) + /* Prevent warnings issued for macro expansion. */ + if (!warn_address + || warning_suppressed_p (op, OPT_Waddress) + || from_macro_expansion_at (loc)) return; if (TREE_CODE (op) == NOP_EXPR) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index cb20329..58919aa 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -4594,9 +4594,11 @@ build_vec_cmp (tree_code code, tree type, static void warn_for_null_address (location_t location, tree op, tsubst_flags_t complain) { + /* Prevent warnings issued for macro expansion. */ if (!warn_address || (complain & tf_warning) == 0 || c_inhibit_evaluation_warnings != 0 + || from_macro_expansion_at (location) || warning_suppressed_p (op, OPT_Waddress)) return; diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 49c8bef..11ef797 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -8689,6 +8689,8 @@ suppressed by casting the pointer operand to an integer type such as @code{inptr_t} or @code{uinptr_t}. Comparisons against string literals result in unspecified behavior and are not portable, and suggest the intent was to call @code{strcmp}. +The warning is suppressed if the suspicious expression is the result +of macro expansion. @option{-Waddress} warning is enabled by @option{-Wall}. @item -Wno-address-of-packed-member diff --git a/gcc/testsuite/c-c++-common/Waddress-5.c b/gcc/testsuite/c-c++-common/Waddress-5.c new file mode 100644 index 0000000..5d63c7d --- /dev/null +++ b/gcc/testsuite/c-c++-common/Waddress-5.c @@ -0,0 +1,133 @@ +/* PR c/33925 - missing -Waddress with the address of an inline function + { dg-do compile } + { dg-options "-Wall" } + { dg-require-weak "" } */ + +extern inline int eifn (void); +extern inline int eifn_def (void) { return 0; } + +static inline int sifn (void); +static inline int sifn_def (void) { return 0; } + +inline int ifn (void); +inline int ifn_def (void) { return 0; } + +extern __attribute__ ((weak)) int ewfn (void); +extern __attribute__ ((weak)) int ewfn_def (void) { return 0; } + +__attribute__ ((weak)) int wfn (void); +__attribute__ ((weak)) int wfn_def (void) { return 0; } + +static __attribute__((weakref ("ewfn"))) int swrfn (void); + +void test_function_eqz (int *p) +{ + *p++ = eifn == 0; // { dg-warning "-Waddress" } + *p++ = eifn_def == 0; // { dg-warning "-Waddress" } + *p++ = sifn == 0; // { dg-warning "-Waddress" } + *p++ = sifn_def == 0; // { dg-warning "-Waddress" } + *p++ = ifn == 0; // { dg-warning "-Waddress" } + *p++ = ifn_def == 0; // { dg-warning "-Waddress" } + *p++ = ewfn == 0; + *p++ = ewfn_def == 0; // { dg-warning "-Waddress" } + *p++ = wfn == 0; + *p++ = wfn_def == 0; // { dg-warning "-Waddress" } + *p++ = swrfn == 0; +} + + +int test_function_if (int i) +{ + if (eifn) // { dg-warning "-Waddress" } + i++; + if (eifn_def) // { dg-warning "-Waddress" } + i++; + if (sifn) // { dg-warning "-Waddress" } + i++; + if (sifn_def) // { dg-warning "-Waddress" } + i++; + if (ifn) // { dg-warning "-Waddress" } + i++; + if (ifn_def) // { dg-warning "-Waddress" } + i++; + if (ewfn) + i++; + if (ewfn_def) // { dg-warning "-Waddress" } + i++; + if (wfn) + i++; + if(wfn_def) // { dg-warning "-Waddress" } + i++; + if (swrfn) + i++; + return i; +} + + +extern int ei; +extern int ei_def = 1; + +static int si; +static int si_def = 1; + +int i; +int i_def = 1; + +extern __attribute__ ((weak)) int ewi; // declaration (may be null) +extern __attribute__ ((weak)) int ewi_def = 1; + +__attribute__ ((weak)) int wi; // definition (cannot be bull) +__attribute__ ((weak)) int wi_def = 1; + +static __attribute__((weakref ("ewi"))) int swri; + +void test_scalar (int *p) +{ + *p++ = &ei == 0; // { dg-warning "-Waddress" } + *p++ = &ei_def == 0; // { dg-warning "-Waddress" } + *p++ = &si == 0; // { dg-warning "-Waddress" } + *p++ = &si_def == 0; // { dg-warning "-Waddress" } + *p++ = &i == 0; // { dg-warning "-Waddress" } + *p++ = &i_def == 0; // { dg-warning "-Waddress" } + *p++ = &ewi == 0; + *p++ = &ewi_def == 0; // { dg-warning "-Waddress" } + *p++ = &wi == 0; // { dg-warning "-Waddress" } + *p++ = &wi_def == 0; // { dg-warning "-Waddress" } + *p++ = &swri == 0; +} + + +extern int eia[]; +extern int eia_def[] = { 1 }; + +static int sia[1]; +static int sia_def[1] = { 1 }; + +int ia[1]; +int ia_def[] = { 1 }; + +extern __attribute__ ((weak)) int ewia[]; +extern __attribute__ ((weak)) int ewia_def[] = { 1 }; + +__attribute__ ((weak)) int wia[1]; // definition (cannot be null) +__attribute__ ((weak)) int wia_def[] = { 1 }; + +static __attribute__((weakref ("ewia"))) int swria[1]; + +void test_array (int *p) +{ + *p++ = eia == 0; // { dg-warning "-Waddress" } + *p++ = eia_def == 0; // { dg-warning "-Waddress" } + *p++ = sia == 0; // { dg-warning "-Waddress" } + *p++ = sia_def == 0; // { dg-warning "-Waddress" } + *p++ = ia == 0; // { dg-warning "-Waddress" } + *p++ = ia_def == 0; // { dg-warning "-Waddress" } + *p++ = ewia == 0; + *p++ = ewia_def == 0; // { dg-warning "-Waddress" } + *p++ = wia == 0; // { dg-warning "-Waddress" } + *p++ = wia_def == 0; // { dg-warning "-Waddress" } + *p++ = swria == 0; +} + +/* { dg-prune-output "never defined" } + { dg-prune-output "initialized and declared 'extern'" } */ diff --git a/gcc/testsuite/c-c++-common/Waddress-6.c b/gcc/testsuite/c-c++-common/Waddress-6.c new file mode 100644 index 0000000..e66e6e4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Waddress-6.c @@ -0,0 +1,32 @@ +/* PR c/102867 - -Waddress from macro expansion in readelf.c + { dg-do compile } + { dg-options "-Wall" } */ + +#define F(x) ((&x) != 0) + +int warn_nomacro (int *p, int i) +{ + return &p[i] != 0; // { dg-warning "-Waddress" } +} + +int nowarn_macro_expansion (int *p, int i) +{ + // Verify that -Waddress isn't issued for code from macro expansion. + return F (p[i]); // { dg-bogus "-Waddress" } +} + +#define G(x, i) ((&x) + i) + +int warn_function_macro_expansion (int *p, int i) +{ + /* Verify that -Waddress is issued for code involving macro expansion + where the comparison takes place outside the macro. */ + return G (*p, i) != 0; // { dg-warning "-Waddress" } +} + +#define malloc __builtin_malloc + +int warn_object_macro_expansion (int *p, int i) +{ + return malloc != 0; // { dg-warning "-Waddress" } +} diff --git a/gcc/testsuite/g++.dg/warn/Waddress-7.C b/gcc/testsuite/g++.dg/warn/Waddress-7.C new file mode 100644 index 0000000..efdafa5 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Waddress-7.C @@ -0,0 +1,76 @@ +/* PR c/33925 - missing -Waddress with the address of an inline function + { dg-do compile } + { dg-options "-Wall" } */ + +struct A +{ + int mf (); + int mf_def () { return 0; } + + static int smf (); + static int smf_def () { return 0; } + + int mi; + static int smi; + static int smi_def; + + __attribute__ ((weak)) static int wsmi; + __attribute__ ((weak)) static int wsmi_def; + + int mia[]; + static int smia[]; + static int smia_def[]; + + __attribute__ ((weak)) static int wsmia[]; + __attribute__ ((weak)) static int wsmia_def[]; + + void test_waddress (bool*); +}; + + +/* __attribute__ ((weak)) static */ int A::smi_def = 0; +/* __attribute__ ((weak)) static */ int A::smia_def[] = { 0 }; + +/* __attribute__ ((weak)) static */ int A::wsmi_def = 0; +/* __attribute__ ((weak)) static */ int A::wsmia_def[] = { 0 }; + + + +void A::test_waddress (bool *p) +{ + if (mf) // { dg-error "cannot convert" } + p++; + if (mf_def) // { dg-error "cannot convert" } + p++; + + if (smf) // { dg-warning "-Waddress" } + p++; + if (smf_def) // { dg-warning "-Waddress" } + p++; + + if (&mi) // { dg-warning "-Waddress" } + p++; + if (&smi) // { dg-warning "-Waddress" } + p++; + if (&smi_def) // { dg-warning "-Waddress" } + p++; + + if (&wsmi) + p++; + + if (&wsmi_def) // { dg-warning "-Waddress" } + p++; + + if (mia) // { dg-warning "-Waddress" } + p++; + if (smia) // { dg-warning "-Waddress" } + p++; + if (smia_def) // { dg-warning "-Waddress" } + p++; + + if (wsmia) + p++; + + if (wsmia_def) // { dg-warning "-Waddress" } + p++; +} diff --git a/gcc/testsuite/g++.dg/warn/Walways-true-2.C b/gcc/testsuite/g++.dg/warn/Walways-true-2.C index 29a80e5..e951e95 100644 --- a/gcc/testsuite/g++.dg/warn/Walways-true-2.C +++ b/gcc/testsuite/g++.dg/warn/Walways-true-2.C @@ -9,7 +9,7 @@ extern int foo (int) __attribute__ ((weak)); -int i __attribute__ ((weak)); +extern int i __attribute__ ((weak)); void bar (int a) diff --git a/gcc/testsuite/gcc.dg/Walways-true-2.c b/gcc/testsuite/gcc.dg/Walways-true-2.c index 7f0bb7b..ae3262b 100644 --- a/gcc/testsuite/gcc.dg/Walways-true-2.c +++ b/gcc/testsuite/gcc.dg/Walways-true-2.c @@ -9,7 +9,7 @@ extern int foo (int) __attribute__ ((weak)); -int i __attribute__ ((weak)); +extern int i __attribute__ ((weak)); void bar (int a) diff --git a/gcc/testsuite/gcc.dg/weak/weak-3.c b/gcc/testsuite/gcc.dg/weak/weak-3.c index a719848..5fdf029 100644 --- a/gcc/testsuite/gcc.dg/weak/weak-3.c +++ b/gcc/testsuite/gcc.dg/weak/weak-3.c @@ -55,7 +55,7 @@ void * foo1e (void) extern void * ffoo1f (void); void * foo1f (void) { - if (ffoo1f) /* { dg-warning "" } */ + if (ffoo1f) /* { dg-warning "-Waddress" } */ ffoo1f (); return 0; } @@ -68,7 +68,9 @@ void * ffoox1g (void) { return (void *)0; } extern void * ffoo1g (void) __attribute__((weak, alias ("ffoox1g"))); void * foo1g (void) { - if (ffoo1g) + /* ffoo1g is a weak alias for a symbol defined in this file, expect + a -Waddress for the test (which is folded to true). */ + if (ffoo1g) // { dg-warning "-Waddress" } ffoo1g (); return 0; } -- cgit v1.1 From ada63d56beb0e535d35b165b55f85e29a0b36929 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Fri, 19 Nov 2021 18:09:13 +0100 Subject: Use modref even for nested functions in ref_maybe_used_by_call_p_1 Remove test for function not having call chain guarding modref use in ref_maybe_used_by_call_p_1. It never made sense since modref treats call chain accesses explicitly. It was however copied from earlier check for ECF_CONST (which seems dubious too, but I would like to discuss it independelty). This enables us to detect that memory pointed to static chain (or parts of it) are unused by the function. lto-bootstrapped-regtested all lanugages on x86_64-linux. gcc/ChangeLog: 2021-11-19 Jan Hubicka * tree-ssa-alias.c (ref_maybe_used_by_call_p_1): Do not guard modref by !gimple_call_chain. gcc/testsuite/ChangeLog: 2021-11-19 Jan Hubicka * gcc.dg/tree-ssa/modref-dse-6.c: New test. --- gcc/testsuite/gcc.dg/tree-ssa/modref-dse-6.c | 23 +++++++++++++++++++++++ gcc/tree-ssa-alias.c | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/modref-dse-6.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-dse-6.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-dse-6.c new file mode 100644 index 0000000..d1e45a8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-dse-6.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +int +main() +{ + int a,b; + __attribute__ ((noinline)) + void kill_me() + { + a=1234; + b=2234; + } + a=0; + b=1234; + __attribute__ ((noinline)) + int reta() + { + return a; + } + return reta(); +} +/* { dg-final { scan-tree-dump-not "kill_me" "optimized" } } */ +/* { dg-final { scan-tree-dump-not "1234" "optimized" } } */ diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 02bbc87..cd6a0b2 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -2755,7 +2755,7 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p) callee = gimple_call_fndecl (call); - if (!gimple_call_chain (call) && callee != NULL_TREE) + if (callee != NULL_TREE) { struct cgraph_node *node = cgraph_node::get (callee); /* We can not safely optimize based on summary of calle if it does -- cgit v1.1 From 458d2c689963d8461d84670a3d8988cd6ecbfd81 Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Fri, 19 Nov 2021 18:46:00 +0100 Subject: options: Make -Ofast switch off -fsemantic-interposition Using -fno-semantic-interposition has been reported by various people to bring about considerable speed up at the cost of strict compliance to the ELF symbol interposition rules See for example https://fedoraproject.org/wiki/Changes/PythonNoSemanticInterpositionSpeedup As such I believe it should be implied by our -Ofast optimization level, not only so that benchmarks that can benefit run faster, but also so that people looking at -Ofast documentation for options that could speed their programs find it. gcc/ChangeLog: 2021-11-12 Martin Jambor * opts.c (default_options_table): Switch off flag_semantic_interposition at Ofast. * doc/invoke.texi (Optimize Options): Document that Ofast switches off -fsemantic-interposition. --- gcc/doc/invoke.texi | 1 + gcc/opts.c | 1 + 2 files changed, 2 insertions(+) (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 11ef797..1cfb702 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10677,6 +10677,7 @@ valid for all standard-compliant programs. It turns on @option{-ffast-math}, @option{-fallow-store-data-races} and the Fortran-specific @option{-fstack-arrays}, unless @option{-fmax-stack-var-size} is specified, and @option{-fno-protect-parens}. +It turns off @option {-fsemantic-interposition}. @item -Og @opindex Og diff --git a/gcc/opts.c b/gcc/opts.c index 175b463..b16497e 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -682,6 +682,7 @@ static const struct default_options default_options_table[] = /* -Ofast adds optimizations to -O3. */ { OPT_LEVELS_FAST, OPT_ffast_math, NULL, 1 }, { OPT_LEVELS_FAST, OPT_fallow_store_data_races, NULL, 1 }, + { OPT_LEVELS_FAST, OPT_fsemantic_interposition, NULL, 0 }, { OPT_LEVELS_NONE, 0, NULL, 0 } }; -- cgit v1.1 From d4943ce939d9654932624b9ece24c3a474ae4157 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Mon, 20 Sep 2021 18:41:56 +0100 Subject: Darwin: Rework handling for unwinder code in libgcc_s and specs [PR80556]. This addresses a long-standing problem where a work-around for an unwinder issue (also a regression) regresses other functionality. The patch replaces several work-arounds with a fix for PR80556 and a work-around for PR88590. * The fix for PR80556 requires a bump to the SO name for libgcc_s, since we need to remove the unwinder symbols from it. This would trigger PR88590 hence the work-around for that. * We weaken the symbols for emulated TLS support so that it is possible for a DSO linked with static-libgcc to interoperate with a DSO linked with libgcc_s. Likewise main exes. * We remove all the gcc-4.2.1 era stubs machinery and workarounds. * libgcc is always now linked ahead of libc, which avoids fails where the libc (libSystem) builtins implementations are not up to date. * The unwinder now always comes from the system - for Darwin9 from /usr/lib/libgcc_s.1.dylib - for Darwin10 from /usr/lib/libSystem.dylib - for Darwin11+ from /usr/lib/system/libunwind.dylib. We still insert a shim on Darwin10 to fix an omitted unwind function, but the underlying unwinder remains the system one. * The work-around for PR88590 has two parts (1) we always link libgcc from its convenience lib on affected system versions (avoiding the need to find the DSO path); (2) we add and export the emutls functions from DSOs - this makes a relatively small (20k) addition to a DSO. These can be backed out when a proper fix for PR88590 is committed. For distributions that wish to install a libgcc_s.1.dylib to satisfy linkage from exes that linked against the stubs can use a reexported libgcc_s.1.1 (since that contains all the symbols that were previously exported via the stubs). Signed-off-by: Iain Sandoe gcc/ChangeLog: PR target/80556 * config/darwin-driver.c (darwin_driver_init): Handle exported symbols and symbol lists (suppress automatic export of the TLS symbols). * config/darwin.c (darwin_rename_builtins): Remove workaround. * config/darwin.h (LINK_GCC_C_SEQUENCE_SPEC): Likewise. (REAL_LIBGCC_SPEC): Handle revised library uses. * config/darwin.opt (nodefaultexport): New. * config/i386/darwin.h (PR80556_WORKAROUND): Remove. * config/i386/darwin32-biarch.h (PR80556_WORKAROUND): Likewise. * config/i386/darwin64-biarch.h (PR80556_WORKAROUND): Likewise. libgcc/ChangeLog: * config.host: Add weak emutls crt to the extra_parts. * config/i386/darwin-lib.h (DECLARE_LIBRARY_RENAMES): Remove workaround. * config/libgcc-libsystem.ver: Add exclude list for the system- provided unwinder. * config/t-slibgcc-darwin: Bump SO version, remove stubs code. * config/i386/libgcc-darwin.10.4.ver: Removed. * config/i386/libgcc-darwin.10.5.ver: Removed. * config/rs6000/libgcc-darwin.10.4.ver: Removed. * config/rs6000/libgcc-darwin.10.5.ver: Removed. * config/t-darwin-noeh: New file. gcc/testsuite/ChangeLog: * gcc.dg/torture/fp-int-convert-timode-3.c: Remove XFAIL. * gcc.dg/torture/fp-int-convert-timode-4.c: Likewise. --- gcc/config/darwin-driver.c | 18 ++++ gcc/config/darwin.c | 24 ------ gcc/config/darwin.h | 98 ++++++++++++++-------- gcc/config/darwin.opt | 4 + gcc/config/i386/darwin.h | 31 ------- gcc/config/i386/darwin32-biarch.h | 13 --- gcc/config/i386/darwin64-biarch.h | 13 --- .../gcc.dg/torture/fp-int-convert-timode-3.c | 1 - .../gcc.dg/torture/fp-int-convert-timode-4.c | 1 - 9 files changed, 87 insertions(+), 116 deletions(-) (limited to 'gcc') diff --git a/gcc/config/darwin-driver.c b/gcc/config/darwin-driver.c index 4f0c6ba..7fa80ab 100644 --- a/gcc/config/darwin-driver.c +++ b/gcc/config/darwin-driver.c @@ -281,6 +281,7 @@ darwin_driver_init (unsigned int *decoded_options_count, const char *vers_string = NULL; bool seen_version_min = false; bool seen_sysroot_p = false; + bool noexport_p = true; for (i = 1; i < *decoded_options_count; i++) { @@ -349,6 +350,13 @@ darwin_driver_init (unsigned int *decoded_options_count, seen_sysroot_p = true; break; + case OPT_Xlinker: + case OPT_Wl_: + gcc_checking_assert ((*decoded_options)[i].arg); + if (startswith ((*decoded_options)[i].arg, "-exported_symbol")) + noexport_p = false; + break; + default: break; } @@ -474,4 +482,14 @@ darwin_driver_init (unsigned int *decoded_options_count, &(*decoded_options)[*decoded_options_count - 1]); } } + + if (noexport_p) + { + ++*decoded_options_count; + *decoded_options = XRESIZEVEC (struct cl_decoded_option, + *decoded_options, + *decoded_options_count); + generate_option (OPT_nodefaultexport, NULL, 1, CL_DRIVER, + &(*decoded_options)[*decoded_options_count - 1]); + } } diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index 204114c..c5ba792 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -3637,30 +3637,6 @@ darwin_fold_builtin (tree fndecl, int n_args, tree *argp, void darwin_rename_builtins (void) { - /* The system ___divdc3 routine in libSystem on darwin10 is not - accurate to 1ulp, ours is, so we avoid ever using the system name - for this routine and instead install a non-conflicting name that - is accurate. - - When -ffast-math or -funsafe-math-optimizations is given, we can - use the faster version. */ - if (!flag_unsafe_math_optimizations) - { - enum built_in_function dcode - = (enum built_in_function)(BUILT_IN_COMPLEX_DIV_MIN - + DCmode - MIN_MODE_COMPLEX_FLOAT); - tree fn = builtin_decl_explicit (dcode); - /* Fortran and c call TARGET_INIT_BUILTINS and - TARGET_INIT_LIBFUNCS at different times, so we have to put a - call into each to ensure that at least one of them is called - after build_common_builtin_nodes. A better fix is to add a - new hook to run after build_common_builtin_nodes runs. */ - if (fn) - set_user_assembler_name (fn, "___ieee_divdc3"); - fn = builtin_decl_implicit (dcode); - if (fn) - set_user_assembler_name (fn, "___ieee_divdc3"); - } } /* Implementation for the TARGET_LIBC_HAS_FUNCTION hook. */ diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index 7ed01ef..8d8d402 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -378,6 +378,16 @@ extern GTY(()) int darwin_ms_struct; %(link_ssp) \ %:version-compare(>< 10.6 10.7 mmacosx-version-min= -ld10-uwfef) \ %(link_gcc_c_sequence) \ + %{!nodefaultexport:%{dylib|dynamiclib|bundle: \ + %:version-compare(>= 10.11 asm_macosx_version_min= -U) \ + %:version-compare(>= 10.11 asm_macosx_version_min= ___emutls_get_address) \ + %:version-compare(>= 10.11 asm_macosx_version_min= -exported_symbol) \ + %:version-compare(>= 10.11 asm_macosx_version_min= ___emutls_get_address) \ + %:version-compare(>= 10.11 asm_macosx_version_min= -U) \ + %:version-compare(>= 10.11 asm_macosx_version_min= ___emutls_register_common) \ + %:version-compare(>= 10.11 asm_macosx_version_min= -exported_symbol) \ + %:version-compare(>= 10.11 asm_macosx_version_min= ___emutls_register_common) \ + }} \ }}}\ %{!r:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} %{F*} "\ DARWIN_PIE_SPEC \ @@ -404,14 +414,11 @@ extern GTY(()) int darwin_ms_struct; /* Tell collect2 to run dsymutil for us as necessary. */ #define COLLECT_RUN_DSYMUTIL 1 -/* Fix PR47558 by linking against libSystem ahead of libgcc. See also - PR 80556 and the fallout from this. */ - +/* We only want one instance of %G, since libSystem (Darwin's -lc) does not + depend on libgcc. */ #undef LINK_GCC_C_SEQUENCE_SPEC #define LINK_GCC_C_SEQUENCE_SPEC \ -"%{!static:%{!static-libgcc: \ - %:version-compare(>= 10.6 mmacosx-version-min= -lSystem) } } \ - %G %{!nolibc:%L}" + "%G %{!nolibc:%L} " /* ld64 supports a sysroot, it just has a different name and there's no easy way to check for it at config time. */ @@ -456,37 +463,62 @@ extern GTY(()) int darwin_ms_struct; #define LIB_SPEC "%{!static:-lSystem}" -/* Support -mmacosx-version-min by supplying different (stub) libgcc_s.dylib - libraries to link against, and by not linking against libgcc_s on - earlier-than-10.3.9. If we need exceptions, prior to 10.3.9, then we have - to link the static eh lib, since there's no shared version on the system. - - Note that by default, except as above, -lgcc_eh is not linked against. +/* + Note that by default, -lgcc_eh is not linked against. This is because,in general, we need to unwind through system libraries that are linked with the shared unwinder in libunwind (or libgcc_s for 10.4/5). - The static version of the current libgcc unwinder (which differs from the - implementation in libunwind.dylib on systems Darwin10 [10.6]+) can be used - by specifying -static-libgcc. - - If libgcc_eh is linked against, it has to be before -lgcc, because it might - need symbols from -lgcc. */ - + For -static-libgcc: < 10.6, use the unwinder in libgcc_eh (and find + the emultls impl. there too). + + For -static-libgcc: >= 10.6, the unwinder *still* comes from libSystem and + we find the emutls impl from lemutls_w. In either case, the builtins etc. + are linked from -lgcc. + + When we have specified shared-libgcc or any case that might require + exceptions, we pull the libgcc content (including emulated tls) from + -lgcc_s.1 in GCC and the unwinder from /usr/lib/libgcc_s.1 for < 10.6 and + libSystem for >= 10.6 respectively. + Otherwise, we just link the emutls/builtins from convenience libs. + + If we need exceptions, prior to 10.3.9, then we have to link the static + eh lib, since there's no shared version on the system. + + In all cases, libgcc_s.1 will be installed with the compiler, or any app + built using it, so we can link the builtins and emutls shared on all. + + We have to work around that DYLD_XXXX are disabled in macOS 10.11+ which + means that any bootstrap trying to use a shared libgcc with a bumped SO- + name will fail. This means that we do not accept shared libgcc for these + versions. + + For -static-libgcc: >= 10.6, the unwinder *still* comes from libSystem and + we find the emutls impl from lemutls_w. In either case, the builtins etc. + are linked from -lgcc. +> + Otherwise, we just link the shared version of gcc_s.1.1 and pick up + exceptions: + * Prior to 10.3.9, then we have to link the static eh lib, since there + is no shared version on the system. + * from 10.3.9 to 10.5, from /usr/lib/libgcc_s.1.dylib + * from 10.6 onwards, from libSystem.dylib + + In all cases, libgcc_s.1.1 will be installed with the compiler, or any app + built using it, so we can link the builtins and emutls shared on all. +*/ #undef REAL_LIBGCC_SPEC -#define REAL_LIBGCC_SPEC \ - "%{static-libgcc|static: -lgcc_eh -lgcc; \ - shared-libgcc|fexceptions|fobjc-exceptions|fgnu-runtime: \ - %:version-compare(!> 10.3.9 mmacosx-version-min= -lgcc_eh) \ - %:version-compare(>< 10.3.9 10.5 mmacosx-version-min= -lgcc_s.10.4) \ - %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5) \ - %:version-compare(>< 10.3.9 10.5 mmacosx-version-min= -lgcc_ext.10.4) \ - %:version-compare(>= 10.5 mmacosx-version-min= -lgcc_ext.10.5) \ - -lgcc ; \ - :%:version-compare(>< 10.3.9 10.5 mmacosx-version-min= -lgcc_s.10.4) \ - %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5) \ - %:version-compare(>< 10.3.9 10.5 mmacosx-version-min= -lgcc_ext.10.4) \ - %:version-compare(>= 10.5 mmacosx-version-min= -lgcc_ext.10.5) \ - -lgcc }" +#define REAL_LIBGCC_SPEC \ +"%{static-libgcc|static: \ + %:version-compare(!> 10.6 mmacosx-version-min= -lgcc_eh) \ + %:version-compare(>= 10.6 mmacosx-version-min= -lemutls_w); \ + shared-libgcc|fexceptions|fobjc-exceptions|fgnu-runtime: \ + %:version-compare(!> 10.11 mmacosx-version-min= -lgcc_s.1.1) \ + %:version-compare(>= 10.11 mmacosx-version-min= -lemutls_w) \ + %:version-compare(!> 10.3.9 mmacosx-version-min= -lgcc_eh) \ + %:version-compare(>< 10.3.9 10.5 mmacosx-version-min= -lgcc_s.10.4) \ + %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5); \ + : -lemutls_w \ + } -lgcc " /* We specify crt0.o as -lcrt0.o so that ld will search the library path. */ diff --git a/gcc/config/darwin.opt b/gcc/config/darwin.opt index d1d1f81..48d3aa9 100644 --- a/gcc/config/darwin.opt +++ b/gcc/config/darwin.opt @@ -233,6 +233,10 @@ no_dead_strip_inits_and_terms Driver RejectNegative (Obsolete) Current linkers never dead-strip these items, so the option is not needed. +nodefaultexport +Driver RejectNegative +Do not add a default symbol exports to modules or dynamic libraries. + nofixprebinding Driver RejectNegative (Obsolete after 10.3.9) Set MH_NOPREFIXBINDING, in an executable. diff --git a/gcc/config/i386/darwin.h b/gcc/config/i386/darwin.h index 741f29a..e946a8b 100644 --- a/gcc/config/i386/darwin.h +++ b/gcc/config/i386/darwin.h @@ -25,37 +25,6 @@ along with GCC; see the file COPYING3. If not see #undef DARWIN_X86 #define DARWIN_X86 1 -/* WORKAROUND pr80556: - For x86_64 Darwin10 and later, the unwinder is in libunwind (redirected - from libSystem). This doesn't use the keymgr (see keymgr.c) and therefore - the calls that libgcc makes to obtain the KEYMGR_GCC3_DW2_OBJ_LIST are not - updated to include new images, and might not even be valid for a single - image. - Therefore, for 64b exes at least, we must use the libunwind implementation, - even when static-libgcc is specified. We put libSystem first so that - unwinder symbols are satisfied from there. - We default to 64b for single-arch builds, so apply this unconditionally. */ -#ifndef PR80556_WORKAROUND -#define PR80556_WORKAROUND \ -" %:version-compare(>= 10.6 mmacosx-version-min= -lSystem) " -#endif -#undef REAL_LIBGCC_SPEC -#define REAL_LIBGCC_SPEC \ - "%{static-libgcc|static: " \ - PR80556_WORKAROUND \ - " -lgcc_eh -lgcc; \ - shared-libgcc|fexceptions|fgnu-runtime: \ - %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_s.10.4) \ - %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5) \ - %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_ext.10.4) \ - %:version-compare(>= 10.5 mmacosx-version-min= -lgcc_ext.10.5) \ - -lgcc ; \ - :%:version-compare(>< 10.3.9 10.5 mmacosx-version-min= -lgcc_s.10.4) \ - %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5) \ - %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_ext.10.4) \ - %:version-compare(>= 10.5 mmacosx-version-min= -lgcc_ext.10.5) \ - -lgcc }" - /* Size of the Obj-C jump buffer. */ #define OBJC_JBLEN ((TARGET_64BIT) ? ((9 * 2) + 3 + 16) : (18)) diff --git a/gcc/config/i386/darwin32-biarch.h b/gcc/config/i386/darwin32-biarch.h index 5470edf..ee15082 100644 --- a/gcc/config/i386/darwin32-biarch.h +++ b/gcc/config/i386/darwin32-biarch.h @@ -24,19 +24,6 @@ along with GCC; see the file COPYING3. If not see #define TARGET_64BIT_DEFAULT 0 #define TARGET_BI_ARCH 1 -/* WORKAROUND pr80556: - For x86_64 Darwin10 and later, the unwinder is in libunwind (redirected - from libSystem). This doesn't use the keymgr (see keymgr.c) and therefore - the calls that libgcc makes to obtain the KEYMGR_GCC3_DW2_OBJ_LIST are not - updated to include new images, and might not even be valid for a single - image. - Therefore, for 64b exes at least, we must use the libunwind implementation, - even when static-libgcc is specified. We put libSystem first so that - unwinder symbols are satisfied from there. */ -#undef PR80556_WORKAROUND -#define PR80556_WORKAROUND \ -" %{m64:%:version-compare(>= 10.6 mmacosx-version-min= -lSystem)} " - #undef DARWIN_SUBARCH_SPEC #define DARWIN_SUBARCH_SPEC DARWIN_ARCH_SPEC diff --git a/gcc/config/i386/darwin64-biarch.h b/gcc/config/i386/darwin64-biarch.h index f5bc3d6..d02f7fc 100644 --- a/gcc/config/i386/darwin64-biarch.h +++ b/gcc/config/i386/darwin64-biarch.h @@ -25,19 +25,6 @@ along with GCC; see the file COPYING3. If not see #define TARGET_64BIT_DEFAULT (OPTION_MASK_ISA_64BIT | OPTION_MASK_ABI_64) #define TARGET_BI_ARCH 1 -/* WORKAROUND pr80556: - For x86_64 Darwin10 and later, the unwinder is in libunwind (redirected - from libSystem). This doesn't use the keymgr (see keymgr.c) and therefore - the calls that libgcc makes to obtain the KEYMGR_GCC3_DW2_OBJ_LIST are not - updated to include new images, and might not even be valid for a single - image. - Therefore, for 64b exes at least, we must use the libunwind implementation, - even when static-libgcc is specified. We put libSystem first so that - unwinder symbols are satisfied from there. */ -#undef PR80556_WORKAROUND -#define PR80556_WORKAROUND \ -" %{!m32:%:version-compare(>= 10.6 mmacosx-version-min= -lSystem)} " - #undef DARWIN_SUBARCH_SPEC #define DARWIN_SUBARCH_SPEC DARWIN_ARCH_SPEC diff --git a/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode-3.c b/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode-3.c index 1070230..707d539 100644 --- a/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode-3.c +++ b/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode-3.c @@ -4,7 +4,6 @@ /* { dg-require-effective-target int128 } */ /* { dg-require-effective-target fenv } */ /* { dg-options "-frounding-math" } */ -/* { dg-xfail-run-if "see PR80556 c63" { x86_64-*-darwin* i68?-*-darwin* } { "*" } { "" } } */ #include #include diff --git a/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode-4.c b/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode-4.c index 3facf32..09600f9 100644 --- a/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode-4.c +++ b/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode-4.c @@ -4,7 +4,6 @@ /* { dg-require-effective-target int128 } */ /* { dg-require-effective-target fenv } */ /* { dg-options "-frounding-math" } */ -/* { dg-xfail-run-if "see PR80556 c63" { x86_64-*-darwin* i68?-*-darwin* } { "*" } { "" } } */ #include #include -- cgit v1.1 From b903e0f3adef830c4e2eef79040d213088e7332f Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 19 Nov 2021 14:54:18 -0500 Subject: c++: Fix cpp0x/lambda/lambda-nested9.C with C++11 Unfortunately dejagnu doesn't honor #if/#endif, so this test was failing with -std=c++11: FAIL: g++.dg/cpp0x/lambda/lambda-nested9.C -std=c++11 (test for errors, line 37) Fixed thus. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/lambda/lambda-nested9.C: Adjust dg-error. --- gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C index ff7da3b..8f67f22 100644 --- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested9.C @@ -34,7 +34,7 @@ int main() { #if __cpp_init_captures [j=0] () { [&] () mutable { - ++j; // { dg-error "read-only" } + ++j; // { dg-error "read-only" "" { target c++14 } } }; }; #endif -- cgit v1.1 From fc6c6f64ecff376902e7e1ef295f2d8518407ab5 Mon Sep 17 00:00:00 2001 From: "Paul A. Clarke" Date: Fri, 22 Oct 2021 12:09:43 -0500 Subject: rs6000: Add optimizations for _mm_sad_epu8 Power9 ISA added `vabsdub` instruction which is realized in the `vec_absd` instrinsic. Use `vec_absd` for `_mm_sad_epu8` compatibility intrinsic, when `_ARCH_PWR9`. Also, the realization of `vec_sum2s` on little-endian includes two rotates in order to position the input and output to match the semantics of `vec_sum2s`: - Rotate the second input vector left 12 bytes. In the current usage, that vector is `{0}`, so this shift is unnecessary, but is currently not eliminated under optimization. - Rotate the vector produced by the `vsum2sws` instruction left 4 bytes. The two words within each doubleword of this (rotated) result must then be explicitly swapped to match the semantics of `_mm_sad_epu8`, effectively reversing this rotate. So, this rotate (and a susequent swap) are unnecessary, but not currently removed under optimization. Using `__builtin_altivec_vsum2sws` retains both rotates, so is not an option for removing the rotates. For little-endian, use the `vsum2sws` instruction directly, and eliminate the explicit rotate (swap). 2021-11-19 Paul A. Clarke gcc * config/rs6000/emmintrin.h (_mm_sad_epu8): Use vec_absd when _ARCH_PWR9, optimize vec_sum2s when LE. --- gcc/config/rs6000/emmintrin.h | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/emmintrin.h b/gcc/config/rs6000/emmintrin.h index 32ad72b..4125b12 100644 --- a/gcc/config/rs6000/emmintrin.h +++ b/gcc/config/rs6000/emmintrin.h @@ -2189,27 +2189,37 @@ extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __arti _mm_sad_epu8 (__m128i __A, __m128i __B) { __v16qu a, b; - __v16qu vmin, vmax, vabsdiff; + __v16qu vabsdiff; __v4si vsum; const __v4su zero = { 0, 0, 0, 0 }; __v4si result; a = (__v16qu) __A; b = (__v16qu) __B; - vmin = vec_min (a, b); - vmax = vec_max (a, b); +#ifndef _ARCH_PWR9 + __v16qu vmin = vec_min (a, b); + __v16qu vmax = vec_max (a, b); vabsdiff = vec_sub (vmax, vmin); +#else + vabsdiff = vec_absd (a, b); +#endif /* Sum four groups of bytes into integers. */ vsum = (__vector signed int) vec_sum4s (vabsdiff, zero); +#ifdef __LITTLE_ENDIAN__ + /* Sum across four integers with two integer results. */ + asm ("vsum2sws %0,%1,%2" : "=v" (result) : "v" (vsum), "v" (zero)); + /* Note: vec_sum2s could be used here, but on little-endian, vector + shifts are added that are not needed for this use-case. + A vector shift to correctly position the 32-bit integer results + (currently at [0] and [2]) to [1] and [3] would then need to be + swapped back again since the desired results are two 64-bit + integers ([1]|[0] and [3]|[2]). Thus, no shift is performed. */ +#else /* Sum across four integers with two integer results. */ result = vec_sum2s (vsum, (__vector signed int) zero); /* Rotate the sums into the correct position. */ -#ifdef __LITTLE_ENDIAN__ - result = vec_sld (result, result, 4); -#else result = vec_sld (result, result, 6); #endif - /* Rotate the sums into the correct position. */ return (__m128i) result; } -- cgit v1.1 From f573d35147ca8433c102e1721d8c99fc432cb44b Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 18 Nov 2021 15:23:30 -0500 Subject: analyzer: fix false leak due to overeager state merging [PR103217] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR analyzer/103217 reports a false positive from -Wanalyzer-malloc-leak. The root cause is due to overzealous state merger, where the state-merging code decided to merge these two states by merging the stores: state A: clusters within frame: ‘main’@1 cluster for: one_3: CONJURED(val_4 = strdup (src_2(D));, val_4) cluster for: two_4: UNKNOWN(char *) cluster for: one_21: CONJURED(val_4 = strdup (src_2(D));, val_4) state B: clusters within frame: ‘main’@1 cluster for: one_3: UNKNOWN(char *) cluster for: two_4: CONJURED(val_4 = strdup (src_2(D));, val_4) cluster for: two_18: CONJURED(val_4 = strdup (src_2(D));, val_4) into: clusters within frame: ‘main’@1 cluster for: one_3: UNKNOWN(char *) cluster for: two_4: UNKNOWN(char *) cluster for: one_21: UNKNOWN(char *) cluster for: two_18: UNKNOWN(char *) despite "CONJURED(val_4 = strdup (src_2(D));, val_4)" having sm-state, in this case malloc:nonnull ({free}), thus leading to both references to the conjured svalue being lost at merger. This patch tweaks the state merger code so that it will not consider merging two different svalues for the value of a region if either svalue has non-purgable sm-state (in the above example, malloc:nonnull). This fixes the false leak report above. Doing so uncovered an issue with explode-2a.c in which the warnings moved from the correct location to the "while" stmt. This turned out to be a missing call to detect_leaks in phi-handling, which the patch also fixes (in the PK_BEFORE_SUPERNODE case in exploded_graph::process_node). Doing this fixed the regression in explode-2a.c and also fixed the location of the leak warning in explode-1.c. The other side effect of the change is that pr94858-1.c now emits a -Wanalyzer-too-complex warning, since pertinent state is no longer being thrown away. There doesn't seem to be a good way of avoiding this, so the patch also adds -Wno-analyzer-too-complex to that test case (restoring the default). gcc/analyzer/ChangeLog: PR analyzer/103217 * engine.cc (exploded_graph::get_or_create_node): Pass in m_ext_state to program_state::can_merge_with_p. (exploded_graph::process_worklist): Likewise. (exploded_graph::maybe_process_run_of_before_supernode_enodes): Likewise. (exploded_graph::process_node): Add missing call to detect_leaks when handling phi nodes. * program-state.cc (program_state::can_merge_with_p): Add "ext_state" param. Pass it and state ptrs to region_model::can_merge_with_p. (selftest::test_program_state_merging): Update for new ext_state param of program_state::can_merge_with_p. (selftest::test_program_state_merging_2): Likewise. * program-state.h (program_state::can_purge_p): Make const. (program_state::can_merge_with_p): Add "ext_state" param. * region-model.cc: Include "analyzer/program-state.h". (region_model::can_merge_with_p): Add params "ext_state", "state_a", and "state_b", use them when creating model_merger object. (model_merger::mergeable_svalue_p): New. * region-model.h (region_model::can_merge_with_p): Add params "ext_state", "state_a", and "state_b". (model_merger::model_merger) Likewise, initializing new fields. (model_merger::mergeable_svalue_p): New decl. (model_merger::m_ext_state): New field. (model_merger::m_state_a): New field. (model_merger::m_state_b): New field. * svalue.cc (svalue::can_merge_p): Call model_merger::mergeable_svalue_p on both states and reject the merger accordingly. gcc/testsuite/ChangeLog: PR analyzer/103217 * gcc.dg/analyzer/explode-1.c: Update for improvement to location of leak warning. * gcc.dg/analyzer/pr103217.c: New test. * gcc.dg/analyzer/pr94858-1.c: Add -Wno-analyzer-too-complex. Signed-off-by: David Malcolm --- gcc/analyzer/engine.cc | 10 +++++--- gcc/analyzer/program-state.cc | 9 ++++--- gcc/analyzer/program-state.h | 3 ++- gcc/analyzer/region-model.cc | 33 ++++++++++++++++++++++-- gcc/analyzer/region-model.h | 20 ++++++++++++--- gcc/analyzer/svalue.cc | 8 ++++++ gcc/testsuite/gcc.dg/analyzer/explode-1.c | 4 +-- gcc/testsuite/gcc.dg/analyzer/pr103217.c | 42 +++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/analyzer/pr94858-1.c | 2 ++ 9 files changed, 117 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr103217.c (limited to 'gcc') diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 096e219..e8a7cca 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -2417,7 +2417,7 @@ exploded_graph::get_or_create_node (const program_point &point, /* This merges successfully within the loop. */ program_state merged_state (m_ext_state); - if (pruned_state.can_merge_with_p (existing_state, point, + if (pruned_state.can_merge_with_p (existing_state, m_ext_state, point, &merged_state)) { merged_state.validate (m_ext_state); @@ -2717,7 +2717,8 @@ exploded_graph::process_worklist () gcc_assert (state != state_2); program_state merged_state (m_ext_state); - if (state.can_merge_with_p (state_2, point, &merged_state)) + if (state.can_merge_with_p (state_2, m_ext_state, + point, &merged_state)) { if (logger) logger->log ("merging EN: %i and EN: %i", @@ -2973,7 +2974,8 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode) { merged_state->validate (m_ext_state); program_state merge (m_ext_state); - if (it_state.can_merge_with_p (*merged_state, next_point, &merge)) + if (it_state.can_merge_with_p (*merged_state, m_ext_state, + next_point, &merge)) { *merged_state = merge; merged_state->validate (m_ext_state); @@ -3305,6 +3307,8 @@ exploded_graph::process_node (exploded_node *node) (node->get_supernode (), last_cfg_superedge, &ctxt); + program_state::detect_leaks (state, next_state, NULL, + get_ext_state (), &ctxt); } program_point next_point (point.get_next ()); diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index 1c87af0..47e4eca 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -1197,6 +1197,7 @@ program_state::get_representative_tree (const svalue *sval) const bool program_state::can_merge_with_p (const program_state &other, + const extrinsic_state &ext_state, const program_point &point, program_state *out) const { @@ -1213,7 +1214,9 @@ program_state::can_merge_with_p (const program_state &other, /* Attempt to merge the region_models. */ if (!m_region_model->can_merge_with_p (*other.m_region_model, point, - out->m_region_model)) + out->m_region_model, + &ext_state, + this, &other)) return false; /* Copy m_checker_states to OUT. */ @@ -1645,7 +1648,7 @@ test_program_state_merging () with the given sm-state. They ought to be mergeable, preserving the sm-state. */ program_state merged (ext_state); - ASSERT_TRUE (s0.can_merge_with_p (s1, point, &merged)); + ASSERT_TRUE (s0.can_merge_with_p (s1, ext_state, point, &merged)); merged.validate (ext_state); /* Verify that the merged state has the sm-state for "p". */ @@ -1703,7 +1706,7 @@ test_program_state_merging_2 () /* They ought to not be mergeable. */ program_state merged (ext_state); - ASSERT_FALSE (s0.can_merge_with_p (s1, point, &merged)); + ASSERT_FALSE (s0.can_merge_with_p (s1, ext_state, point, &merged)); } /* Run all of the selftests within this file. */ diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h index eb49006..4579e2a 100644 --- a/gcc/analyzer/program-state.h +++ b/gcc/analyzer/program-state.h @@ -242,7 +242,7 @@ public: tree get_representative_tree (const svalue *sval) const; bool can_purge_p (const extrinsic_state &ext_state, - const svalue *sval) + const svalue *sval) const { /* Don't purge vars that have non-purgeable sm state, to avoid generating false "leak" complaints. */ @@ -258,6 +258,7 @@ public: } bool can_merge_with_p (const program_state &other, + const extrinsic_state &ext_state, const program_point &point, program_state *out) const; diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index bbb15ab..dccf902 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -64,6 +64,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/pending-diagnostic.h" #include "analyzer/region-model-reachability.h" #include "analyzer/analyzer-selftests.h" +#include "analyzer/program-state.h" #include "stor-layout.h" #include "attribs.h" #include "tree-object-size.h" @@ -3683,7 +3684,10 @@ region_model::poison_any_pointers_to_descendents (const region *reg, bool region_model::can_merge_with_p (const region_model &other_model, const program_point &point, - region_model *out_model) const + region_model *out_model, + const extrinsic_state *ext_state, + const program_state *state_a, + const program_state *state_b) const { gcc_assert (out_model); gcc_assert (m_mgr == other_model.m_mgr); @@ -3693,7 +3697,8 @@ region_model::can_merge_with_p (const region_model &other_model, return false; out_model->m_current_frame = m_current_frame; - model_merger m (this, &other_model, point, out_model); + model_merger m (this, &other_model, point, out_model, + ext_state, state_a, state_b); if (!store::can_merge_p (&m_store, &other_model.m_store, &out_model->m_store, m_mgr->get_store_manager (), @@ -3897,6 +3902,30 @@ model_merger::dump (bool simple) const dump (stderr, simple); } +/* Return true if it's OK to merge SVAL with other svalues. */ + +bool +model_merger::mergeable_svalue_p (const svalue *sval) const +{ + if (m_ext_state) + { + /* Reject merging svalues that have non-purgable sm-state, + to avoid falsely reporting memory leaks by merging them + with something else. For example, given a local var "p", + reject the merger of a: + store_a mapping "p" to a malloc-ed ptr + with: + store_b mapping "p" to a NULL ptr. */ + if (m_state_a) + if (!m_state_a->can_purge_p (*m_ext_state, sval)) + return false; + if (m_state_b) + if (!m_state_b->can_purge_p (*m_ext_state, sval)) + return false; + } + return true; +} + } // namespace ana /* Dump RMODEL fully to stderr (i.e. without summarization). */ diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 5434011..bffbdf2 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -721,7 +721,10 @@ class region_model bool can_merge_with_p (const region_model &other_model, const program_point &point, - region_model *out_model) const; + region_model *out_model, + const extrinsic_state *ext_state = NULL, + const program_state *state_a = NULL, + const program_state *state_b = NULL) const; tree get_fndecl_for_call (const gcall *call, region_model_context *ctxt); @@ -987,10 +990,15 @@ struct model_merger model_merger (const region_model *model_a, const region_model *model_b, const program_point &point, - region_model *merged_model) + region_model *merged_model, + const extrinsic_state *ext_state, + const program_state *state_a, + const program_state *state_b) : m_model_a (model_a), m_model_b (model_b), m_point (point), - m_merged_model (merged_model) + m_merged_model (merged_model), + m_ext_state (ext_state), + m_state_a (state_a), m_state_b (state_b) { } @@ -1003,10 +1011,16 @@ struct model_merger return m_model_a->get_manager (); } + bool mergeable_svalue_p (const svalue *) const; + const region_model *m_model_a; const region_model *m_model_b; const program_point &m_point; region_model *m_merged_model; + + const extrinsic_state *m_ext_state; + const program_state *m_state_a; + const program_state *m_state_b; }; /* A record that can (optionally) be written out when diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc index 5f2fe4c..7cbcf0c 100644 --- a/gcc/analyzer/svalue.cc +++ b/gcc/analyzer/svalue.cc @@ -193,6 +193,14 @@ svalue::can_merge_p (const svalue *other, return NULL; } + /* Reject merging svalues that have non-purgable sm-state, + to avoid falsely reporting memory leaks by merging them + with something else. */ + if (!merger->mergeable_svalue_p (this)) + return NULL; + if (!merger->mergeable_svalue_p (other)) + return NULL; + /* Widening. */ /* Merge: (new_cst, existing_cst) -> widen (existing, new). */ if (maybe_get_constant () && other->maybe_get_constant ()) diff --git a/gcc/testsuite/gcc.dg/analyzer/explode-1.c b/gcc/testsuite/gcc.dg/analyzer/explode-1.c index f48408e..9b95afd 100644 --- a/gcc/testsuite/gcc.dg/analyzer/explode-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/explode-1.c @@ -12,7 +12,7 @@ void test (void) { void *p0, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8; void **pp; - while (get ()) /* { dg-warning "leak" } */ + while (get ()) { switch (get ()) { @@ -47,7 +47,7 @@ void test (void) { default: case 0: - *pp = malloc (16); + *pp = malloc (16); /* { dg-warning "leak" } */ break; case 1: free (*pp); diff --git a/gcc/testsuite/gcc.dg/analyzer/pr103217.c b/gcc/testsuite/gcc.dg/analyzer/pr103217.c new file mode 100644 index 0000000..a0ef8bf --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/pr103217.c @@ -0,0 +1,42 @@ +extern char *strdup (const char *__s) + __attribute__ ((__nothrow__ , __leaf__, __malloc__, __nonnull__ (1))); + +extern void abort (void) + __attribute__ ((__nothrow__ , __leaf__, __noreturn__)); + +extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) + __attribute__ ((__nothrow__ , __leaf__, __nonnull__ (2, 3))); +extern char *optarg; + +extern void free (void *__ptr) + __attribute__ ((__nothrow__ , __leaf__)); + +#define NULL ((void *)0) + +char *xstrdup(const char *src) { + char *val = strdup(src); + if (!val) + abort(); + return val; +} + +int main(int argc, char *argv[]) { + char *one = NULL, *two = NULL; + int rc; + + while ((rc = getopt(argc, argv, "a:b:")) != -1) { + switch (rc) { + case 'a': + free(one); + one = xstrdup(optarg); + break; + case 'b': + free(two); + two = xstrdup(optarg); + break; + } + } + free(one); + free(two); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/pr94858-1.c b/gcc/testsuite/gcc.dg/analyzer/pr94858-1.c index f7be1c6..d33c174 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr94858-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr94858-1.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-Wno-analyzer-too-complex" } */ + #include typedef short hashNx; -- cgit v1.1 From 16d1d97626cc542d0274aa998f4e584aeab44017 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Fri, 19 Nov 2021 20:15:35 +0000 Subject: gcc, doc: Fix Darwin bootstrap: Amend an @option command to elide a space. At least some version(s) of makeinfo (4.8) do not like @option {-xxxx} the brace has to follow the @option without any whitespace. makeinfo 4.8 is installed on Darwin systems and this breaks bootstrap. The amendment follows the style of the surrounding code. Signed-off-by: Iain Sandoe gcc/ChangeLog: * doc/invoke.texi: Remove whitespace after an @option. --- gcc/doc/invoke.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 1cfb702..4b1b583 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10677,7 +10677,7 @@ valid for all standard-compliant programs. It turns on @option{-ffast-math}, @option{-fallow-store-data-races} and the Fortran-specific @option{-fstack-arrays}, unless @option{-fmax-stack-var-size} is specified, and @option{-fno-protect-parens}. -It turns off @option {-fsemantic-interposition}. +It turns off @option{-fsemantic-interposition}. @item -Og @opindex Og -- cgit v1.1 From b751b225e4f02cf0c446e659e7c3e204096468bf Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 19 Nov 2021 22:09:01 +0100 Subject: c++: Avoid adding implicit attributes during apply_late_template_attributes [PR101180] decl_attributes and its caller cplus_decl_attributes sometimes add implicit attributes, e.g. optimize attribute if #pragma GCC optimize is active, target attribute if #pragma GCC target is active, or e.g. omp declare target attribute if in between #pragma omp declare target and #pragma omp end declare target. For templates that seems highly undesirable to me though, they should get those implicit attributes from the spot the templates were parsed (and they do get that), then tsubst through copy_node copies those attributes, but then apply_late_template_attributes can or does add a new set from the spot where they are instantiated, which can be pretty random point of first use of the template. Consider e.g. #pragma GCC push_options #pragma GCC target "avx" template inline void foo () { } #pragma GCC pop_options #pragma GCC push_options #pragma GCC target "crc32" void bar () { foo<0> (); } #pragma GCC pop_options testcase where the intention is that foo has avx target attribute and bar has crc32 target attribute, but we end up with __attribute__((target ("crc32"), target ("avx"))) on foo<0> (and due to yet another bug actually don't enable avx in foo<0>). In this particular case it is a regression caused by r12-299-ga0fdff3cf33f7284 which apparently calls cplus_decl_attributes even if attributes != NULL but late_attrs is NULL, before those changes we didn't call it in those cases. But, if there is at least one unrelated dependent attribute this would happen already in older releases. The following patch fixes that by temporarily overriding the variables that control the addition of the implicit attributes. Shall we also change the function so that it doesn't call cplus_decl_attributes if late_attrs is NULL, or was that change intentional? 2021-11-19 Jakub Jelinek PR c++/101180 * pt.c (apply_late_template_attributes): Temporarily override current_optimize_pragma, optimization_current_node, current_target_pragma and scope_chain->omp_declare_target_attribute, so that cplus_decl_attributes doesn't add implicit attributes. * g++.target/i386/pr101180.C: New test. --- gcc/cp/pt.c | 11 +++++++++++ gcc/testsuite/g++.target/i386/pr101180.C | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 gcc/testsuite/g++.target/i386/pr101180.C (limited to 'gcc') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 22798b9..c73e035 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11727,6 +11727,17 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, q = &TREE_CHAIN (*q); } + /* cplus_decl_attributes can add some attributes implicitly. For templates, + those attributes should have been added already when those templates were + parsed, and shouldn't be added based on from which context they are + first time instantiated. */ + auto o1 = make_temp_override (current_optimize_pragma, NULL_TREE); + auto o2 = make_temp_override (optimization_current_node, + optimization_default_node); + auto o3 = make_temp_override (current_target_pragma, NULL_TREE); + auto o4 = make_temp_override (scope_chain->omp_declare_target_attribute, + NULL); + cplus_decl_attributes (decl_p, late_attrs, attr_flags); return true; diff --git a/gcc/testsuite/g++.target/i386/pr101180.C b/gcc/testsuite/g++.target/i386/pr101180.C new file mode 100644 index 0000000..4830708 --- /dev/null +++ b/gcc/testsuite/g++.target/i386/pr101180.C @@ -0,0 +1,25 @@ +// PR c++/101180 +// { dg-do compile { target c++11 } } + +#pragma GCC target "avx" +template struct A {}; +#pragma GCC push_options +#pragma GCC target "avx,avx2,bmi,bmi2,fma,f16c" +template using B = A; +template struct C; +template <> struct C { + __attribute__((always_inline)) float operator()(long) { return .0f; } +}; +long d; +template void e(B) { + T{C()(d)}; +} +template void f(T d, FromT) { + e(d); +} +int g; +void h() { + A i; + f(i, g); +} +#pragma GCC pop_options -- cgit v1.1 From 9c0773984c8ec6dc1838f94177b4594b74650765 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 20 Nov 2021 00:16:35 +0000 Subject: Daily bump. --- gcc/ChangeLog | 166 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 34 ++++++++++ gcc/c-family/ChangeLog | 14 ++++ gcc/c/ChangeLog | 14 ++++ gcc/cp/ChangeLog | 71 +++++++++++++++++++++ gcc/testsuite/ChangeLog | 135 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 435 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6059931..6faa1bd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,169 @@ +2021-11-19 Iain Sandoe + + * doc/invoke.texi: Remove whitespace after an @option. + +2021-11-19 Paul A. Clarke + + * config/rs6000/emmintrin.h (_mm_sad_epu8): Use vec_absd when + _ARCH_PWR9, optimize vec_sum2s when LE. + +2021-11-19 Iain Sandoe + + PR target/80556 + * config/darwin-driver.c (darwin_driver_init): Handle exported + symbols and symbol lists (suppress automatic export of the TLS + symbols). + * config/darwin.c (darwin_rename_builtins): Remove workaround. + * config/darwin.h (LINK_GCC_C_SEQUENCE_SPEC): Likewise. + (REAL_LIBGCC_SPEC): Handle revised library uses. + * config/darwin.opt (nodefaultexport): New. + * config/i386/darwin.h (PR80556_WORKAROUND): Remove. + * config/i386/darwin32-biarch.h (PR80556_WORKAROUND): Likewise. + * config/i386/darwin64-biarch.h (PR80556_WORKAROUND): Likewise. + +2021-11-19 Martin Jambor + + * opts.c (default_options_table): Switch off + flag_semantic_interposition at Ofast. + * doc/invoke.texi (Optimize Options): Document that Ofast switches off + -fsemantic-interposition. + +2021-11-19 Jan Hubicka + + * tree-ssa-alias.c (ref_maybe_used_by_call_p_1): Do not guard modref + by !gimple_call_chain. + +2021-11-19 Martin Sebor + + PR c++/33925 + PR c/102867 + * doc/invoke.texi (-Waddress): Update. + +2021-11-19 Andrew MacLeod + + PR tree-optimization/103254 + * gimple-range-gori.cc (range_def_chain::get_def_chain): Limit the + depth for all statements with multple ssa names. + +2021-11-19 Stefan Schulze Frielinghaus + + * config/s390/s390.md (define_peephole2): Variable insn points + to the first matched insn. Use peep2_next_insn(1) to refer to + the second matched insn. + +2021-11-19 Tamar Christina + + PR tree-optimization/103311 + PR target/103330 + * tree-vect-slp-patterns.c (vect_validate_multiplication): Fix CONJ + test to new codegen. + (complex_mul_pattern::matches): Move check downwards. + +2021-11-19 Martin Liska + + Revert: + 2021-11-19 Martin Liska + + * cfgexpand.c (pass_expand::execute): Use option directly. + * function.c (allocate_struct_function): Likewise. + * gimple-low.c (lower_function_body): Likewise. + (lower_stmt): Likewise. + * gimple-ssa-backprop.c (backprop::prepare_change): Likewise. + * ipa-param-manipulation.c (ipa_param_adjustments::modify_call): Likewise. + * ipa-split.c (split_function): Likewise. + * lto-streamer-in.c (input_function): Likewise. + * sese.c (sese_insert_phis_for_liveouts): Likewise. + * ssa-iterators.h (num_imm_uses): Likewise. + * tree-cfg.c (make_blocks): Likewise. + (gimple_merge_blocks): Likewise. + * tree-inline.c (tree_function_versioning): Likewise. + * tree-loop-distribution.c (generate_loops_for_partition): Likewise. + * tree-sra.c (analyze_access_subtree): Likewise. + * tree-ssa-dce.c (remove_dead_stmt): Likewise. + * tree-ssa-loop-ivopts.c (remove_unused_ivs): Likewise. + * tree-ssa-phiopt.c (spaceship_replacement): Likewise. + * tree-ssa-reassoc.c (reassoc_remove_stmt): Likewise. + * tree-ssa-tail-merge.c (tail_merge_optimize): Likewise. + * tree-ssa-threadedge.c (propagate_threaded_block_debug_into): Likewise. + * tree-ssa.c (gimple_replace_ssa_lhs): Likewise. + (target_for_debug_bind): Likewise. + (insert_debug_temp_for_var_def): Likewise. + (insert_debug_temps_for_defs): Likewise. + (reset_debug_uses): Likewise. + * tree-ssanames.c (release_ssa_name_fn): Likewise. + * tree-vect-loop-manip.c (adjust_vec_debug_stmts): Likewise. + (adjust_debug_stmts): Likewise. + (adjust_phi_and_debug_stmts): Likewise. + (vect_do_peeling): Likewise. + * tree-vect-loop.c (vect_transform_loop_stmt): Likewise. + (vect_transform_loop): Likewise. + * tree.h (MAY_HAVE_DEBUG_MARKER_STMTS): Remove + (MAY_HAVE_DEBUG_BIND_STMTS): Remove. + (MAY_HAVE_DEBUG_STMTS): Use options directly. + +2021-11-19 Giuliano Belinassi + + * gcc.c (process_command): Skip dumpdir override if file is a + not_actual_file_p. + * doc/invoke.texi: Update -dumpdir documentation. + +2021-11-19 Andrew Pinski + + PR tree-optimization/103314 + * match.pd ((type) X op CST): Restrict the equal + TYPE_PRECISION case to GIMPLE only. + +2021-11-19 Martin Liska + + PR ipa/103230 + * ipa-modref-tree.h (struct modref_parm_map): Add default + constructor. + * ipa-modref.c (ipa_merge_modref_summary_after_inlining): Use it. + +2021-11-19 Richard Biener + + PR middle-end/103248 + * tree-eh.c (operation_could_trap_helper_p): Properly handle + fixed-point RDIV_EXPR. + +2021-11-19 Richard Biener + + PR tree-optimization/102436 + * tree-ssa-loop-im.c (execute_sm_if_changed): Add mode + to just create the if structure and return the then block. + (execute_sm): Add flag to indicate the var will re-use + another flag var. + (hoist_memory_references): Support a single conditional + block with all stores as special case. + +2021-11-19 Andrew Pinski + + PR tree-optimization/103317 + * tree-ssa-phiopt.c (minmax_replacement): For the non empty + middle bb case, check to make sure it has a single predecessor. + +2021-11-19 Andrew Pinski + + PR tree-optimization/103257 + * match.pd + ((m1 >/=/<= m2) * d -> (m1 >/=/<= m2) ? d : 0): + Disable until !canonicalize_math_p (). + +2021-11-19 Marek Polacek + + PR c++/19808 + PR c++/96121 + * doc/invoke.texi: Update documentation for -Wuninitialized. + * tree.c (stabilize_reference): Set location. + +2021-11-19 liuhongt + + PR target/102543 + * config/i386/x86-tune-costs.h (skylake_cost): Reduce cost of + storing 256/512-bit SSE register to be equal to cost of + unaligned store to avoid odd alignment peeling. + (icelake_cost): Ditto. + 2021-11-18 David Edelsohn * config/rs6000/predicates.md (current_file_function_operand): diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index f09aab3..9e0ed4c 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20211119 +20211120 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index d9fc37c..34a112d 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,37 @@ +2021-11-19 David Malcolm + + PR analyzer/103217 + * engine.cc (exploded_graph::get_or_create_node): Pass in + m_ext_state to program_state::can_merge_with_p. + (exploded_graph::process_worklist): Likewise. + (exploded_graph::maybe_process_run_of_before_supernode_enodes): + Likewise. + (exploded_graph::process_node): Add missing call to detect_leaks + when handling phi nodes. + * program-state.cc (program_state::can_merge_with_p): Add + "ext_state" param. Pass it and state ptrs to + region_model::can_merge_with_p. + (selftest::test_program_state_merging): Update for new ext_state + param of program_state::can_merge_with_p. + (selftest::test_program_state_merging_2): Likewise. + * program-state.h (program_state::can_purge_p): Make const. + (program_state::can_merge_with_p): Add "ext_state" param. + * region-model.cc: Include "analyzer/program-state.h". + (region_model::can_merge_with_p): Add params "ext_state", + "state_a", and "state_b", use them when creating model_merger + object. + (model_merger::mergeable_svalue_p): New. + * region-model.h (region_model::can_merge_with_p): Add params + "ext_state", "state_a", and "state_b". + (model_merger::model_merger) Likewise, initializing new fields. + (model_merger::mergeable_svalue_p): New decl. + (model_merger::m_ext_state): New field. + (model_merger::m_state_a): New field. + (model_merger::m_state_b): New field. + * svalue.cc (svalue::can_merge_p): Call + model_merger::mergeable_svalue_p on both states and reject the + merger accordingly. + 2021-11-17 David Malcolm PR analyzer/102695 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 1c54782..2e0b81d 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,17 @@ +2021-11-19 Martin Sebor + + PR c++/33925 + PR c/102867 + * c-common.c (decl_with_nonnull_addr_p): Call maybe_nonzero_address + and improve handling tof defined symbols. + +2021-11-19 Martin Liska + + Revert: + 2021-11-18 Martin Liska + + * c-gimplify.c (genericize_c_loop): Use option directly. + 2021-11-18 Matthias Kretz * c-common.c (c_common_reswords): Add __builtin_assoc_barrier. diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 2728c59..d42244d 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,17 @@ +2021-11-19 Martin Sebor + + PR c++/33925 + PR c/102867 + * c-typeck.c (maybe_warn_for_null_address): Suppress warnings for + code resulting from macro expansion. + +2021-11-19 Martin Liska + + Revert: + 2021-11-19 Martin Liska + + * c-parser.c (add_debug_begin_stmt): Use option directly. + 2021-11-18 Matthias Kretz * c-decl.c (names_builtin_p): Handle RID_BUILTIN_ASSOC_BARRIER. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f07ae26..205416f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,74 @@ +2021-11-19 Jakub Jelinek + + PR c++/101180 + * pt.c (apply_late_template_attributes): Temporarily override + current_optimize_pragma, optimization_current_node, + current_target_pragma and scope_chain->omp_declare_target_attribute, + so that cplus_decl_attributes doesn't add implicit attributes. + +2021-11-19 Martin Sebor + + PR c++/33925 + PR c/102867 + * typeck.c (warn_for_null_address): Suppress warnings for code + resulting from macro expansion. + +2021-11-19 Martin Liska + + Revert: + 2021-11-19 Martin Liska + + * parser.c (add_debug_begin_stmt): Use option directly. + +2021-11-19 Patrick Palka + + * tree.c (cp_walk_subtrees) : Don't explicitly + walk the operands. + +2021-11-19 Patrick Palka + + PR c++/94376 + * lambda.c (lambda_capture_field_type): Simplify by handling the + is_this case first. When capturing by-value a capture proxy, + consider the type of the corresponding field instead. + +2021-11-19 Richard Biener + + PR c++/103326 + * pt.c (tsubst_copy): Handle VECTOR_CST. + +2021-11-19 Jakub Jelinek + + PR c++/70796 + * cp-gimplify.c (cp_gimplify_arg): New function. + (cp_gimplify_expr): Use cp_gimplify_arg instead of gimplify_arg, + pass true as last argument to it if there are any following + arguments in strong evaluation order with side-effects. + +2021-11-19 Marek Polacek + + PR c++/19808 + PR c++/96121 + * init.c (perform_member_init): Remove a forward declaration. + Walk the initializer using find_uninit_fields_r. New parameter + to track uninitialized fields. If a member is initialized, + remove it from the hash set. + (perform_target_ctor): Return the initializer. + (struct find_uninit_data): New class. + (find_uninit_fields_r): New function. + (find_uninit_fields): New function. + (emit_mem_initializers): Keep and initialize a set holding fields + that are not initialized. When handling delegating constructors, + walk the constructor tree using find_uninit_fields_r. Also when + initializing base clases. Pass uninitialized down to + perform_member_init. + +2021-11-19 Patrick Palka + + PR c++/103198 + * pt.c (any_template_parm_r): Walk the TREE_TYPE of a dummy + object. + 2021-11-18 Marek Polacek PR c++/103049 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 18340f6..4bc2db5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,138 @@ +2021-11-19 Jakub Jelinek + + PR c++/101180 + * g++.target/i386/pr101180.C: New test. + +2021-11-19 David Malcolm + + PR analyzer/103217 + * gcc.dg/analyzer/explode-1.c: Update for improvement to location + of leak warning. + * gcc.dg/analyzer/pr103217.c: New test. + * gcc.dg/analyzer/pr94858-1.c: Add -Wno-analyzer-too-complex. + +2021-11-19 Marek Polacek + + * g++.dg/cpp0x/lambda/lambda-nested9.C: Adjust dg-error. + +2021-11-19 Iain Sandoe + + * gcc.dg/torture/fp-int-convert-timode-3.c: Remove XFAIL. + * gcc.dg/torture/fp-int-convert-timode-4.c: Likewise. + +2021-11-19 Jan Hubicka + + * gcc.dg/tree-ssa/modref-dse-6.c: New test. + +2021-11-19 Martin Sebor + + PR c++/33925 + PR c/102867 + * g++.dg/warn/Walways-true-2.C: Adjust to avoid a valid warning. + * c-c++-common/Waddress-5.c: New test. + * c-c++-common/Waddress-6.c: New test. + * g++.dg/warn/Waddress-7.C: New test. + * gcc.dg/Walways-true-2.c: Adjust to avoid a valid warning. + * gcc.dg/weak/weak-3.c: Expect a warning. + +2021-11-19 Andrew MacLeod + + * gcc.dg/pr103254.c: New. + +2021-11-19 Stefan Schulze Frielinghaus + + * gcc.target/s390/20211119.c: New test. + +2021-11-19 Tamar Christina + + PR tree-optimization/103311 + PR target/103330 + * gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-double.c: Fix it. + * gcc.dg/vect/complex/fast-math-bb-slp-complex-mla-float.c: Likewise. + * gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-double.c: Likewise. + * gcc.dg/vect/complex/fast-math-bb-slp-complex-mls-float.c: Likewise. + * gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-double.c: Likewise. + * gcc.dg/vect/complex/fast-math-bb-slp-complex-mul-float.c: Likewise. + * lib/target-supports.exp + (check_effective_target_vect_complex_add_double): Add Adv. SIMD. + +2021-11-19 Giuliano Belinassi + + * gcc.dg/devnull-dump.c: New. + +2021-11-19 Patrick Palka + + PR c++/94376 + * g++.dg/cpp0x/lambda/lambda-nested9.C: New test. + +2021-11-19 Andrew Pinski + + PR tree-optimization/103314 + * gcc.c-torture/compile/pr103314-1.c: New test. + +2021-11-19 Richard Biener + + PR c++/103326 + * g++.dg/pr103326.C: New testcase. + +2021-11-19 Jakub Jelinek + + PR c++/70796 + * g++.dg/cpp1z/eval-order11.C: New test. + +2021-11-19 Richard Biener + + PR middle-end/103248 + * gcc.dg/pr103248.c: New testcase. + +2021-11-19 Richard Biener + + PR tree-optimization/102436 + * gcc.dg/torture/20211118-1.c: New testcase. + * gcc.dg/tree-ssa/ssa-lim-18.c: Likewise. + +2021-11-19 Andrew Pinski + + PR tree-optimization/103317 + * gcc.c-torture/compile/pr103317-1.c: New test. + +2021-11-19 Andrew Pinski + + PR tree-optimization/103257 + * gcc.dg/tree-ssa/vrp116.c: Check optimized instead of vrp1. + * gcc.dg/tree-ssa/pr103257-1.c: New test. + +2021-11-19 Marek Polacek + + PR c++/19808 + PR c++/96121 + * g++.dg/warn/Wuninitialized-14.C: New test. + * g++.dg/warn/Wuninitialized-15.C: New test. + * g++.dg/warn/Wuninitialized-16.C: New test. + * g++.dg/warn/Wuninitialized-17.C: New test. + * g++.dg/warn/Wuninitialized-18.C: New test. + * g++.dg/warn/Wuninitialized-19.C: New test. + * g++.dg/warn/Wuninitialized-20.C: New test. + * g++.dg/warn/Wuninitialized-21.C: New test. + * g++.dg/warn/Wuninitialized-22.C: New test. + * g++.dg/warn/Wuninitialized-23.C: New test. + * g++.dg/warn/Wuninitialized-24.C: New test. + * g++.dg/warn/Wuninitialized-25.C: New test. + * g++.dg/warn/Wuninitialized-26.C: New test. + * g++.dg/warn/Wuninitialized-27.C: New test. + * g++.dg/warn/Wuninitialized-28.C: New test. + * g++.dg/warn/Wuninitialized-29.C: New test. + * g++.dg/warn/Wuninitialized-30.C: New test. + +2021-11-19 liuhongt + + * gcc.target/i386/pr102543.c: New test. + +2021-11-19 Patrick Palka + + PR c++/103198 + * g++.dg/cpp2a/concepts-this1.C: New test. + 2021-11-18 Marek Polacek PR c++/103049 -- cgit v1.1 From cfe8dbd9c08a5bce497646467c9d30942ec3efe0 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 19 Nov 2021 20:44:34 -0500 Subject: libgccjit: Add some reflection functions [PR96889] 2021-11-19 Antoni Boucher gcc/jit/ PR target/96889 * docs/topics/compatibility.rst (LIBGCCJIT_ABI_16): New ABI tag. * docs/topics/functions.rst: Add documentation for the functions gcc_jit_function_get_return_type and gcc_jit_function_get_param_count * docs/topics/types.rst: Add documentation for the functions gcc_jit_function_type_get_return_type, gcc_jit_function_type_get_param_count, gcc_jit_function_type_get_param_type, gcc_jit_type_unqualified, gcc_jit_type_dyncast_array, gcc_jit_type_is_bool, gcc_jit_type_dyncast_function_ptr_type, gcc_jit_type_is_integral, gcc_jit_type_is_pointer, gcc_jit_type_dyncast_vector, gcc_jit_vector_type_get_element_type, gcc_jit_vector_type_get_num_units, gcc_jit_struct_get_field, gcc_jit_type_is_struct, and gcc_jit_struct_get_field_count * libgccjit.c: (gcc_jit_function_get_return_type, gcc_jit_function_get_param_count, gcc_jit_function_type_get_return_type, gcc_jit_function_type_get_param_count, gcc_jit_function_type_get_param_type, gcc_jit_type_unqualified, gcc_jit_type_dyncast_array, gcc_jit_type_is_bool, gcc_jit_type_dyncast_function_ptr_type, gcc_jit_type_is_integral, gcc_jit_type_is_pointer, gcc_jit_type_dyncast_vector, gcc_jit_vector_type_get_element_type, gcc_jit_vector_type_get_num_units, gcc_jit_struct_get_field, gcc_jit_type_is_struct, gcc_jit_struct_get_field_count): New functions. (struct gcc_jit_function_type, struct gcc_jit_vector_type): New types. * libgccjit.h: (gcc_jit_function_get_return_type, gcc_jit_function_get_param_count, gcc_jit_function_type_get_return_type, gcc_jit_function_type_get_param_count, gcc_jit_function_type_get_param_type, gcc_jit_type_unqualified, gcc_jit_type_dyncast_array, gcc_jit_type_is_bool, gcc_jit_type_dyncast_function_ptr_type, gcc_jit_type_is_integral, gcc_jit_type_is_pointer, gcc_jit_type_dyncast_vector, gcc_jit_vector_type_get_element_type, gcc_jit_vector_type_get_num_units, gcc_jit_struct_get_field, gcc_jit_type_is_struct, gcc_jit_struct_get_field_count): New function declarations. (struct gcc_jit_function_type, struct gcc_jit_vector_type): New types. * jit-recording.h: New functions (is_struct and is_vector) * libgccjit.map (LIBGCCJIT_ABI_16): New ABI tag. gcc/testsuite/ PR target/96889 * jit.dg/all-non-failing-tests.h: Add test-reflection.c. * jit.dg/test-reflection.c: New test. --- gcc/jit/docs/topics/compatibility.rst | 43 ++++- gcc/jit/docs/topics/functions.rst | 26 +++ gcc/jit/docs/topics/types.rst | 122 +++++++++++++ gcc/jit/jit-recording.h | 7 + gcc/jit/libgccjit.c | 264 +++++++++++++++++++++++++++ gcc/jit/libgccjit.h | 89 +++++++++ gcc/jit/libgccjit.map | 21 +++ gcc/testsuite/jit.dg/all-non-failing-tests.h | 10 + gcc/testsuite/jit.dg/test-reflection.c | 95 ++++++++++ 9 files changed, 676 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/jit.dg/test-reflection.c (limited to 'gcc') diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index 239b6aa..52ee3f8 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -230,7 +230,7 @@ entrypoints: .. _LIBGCCJIT_ABI_15: ``LIBGCCJIT_ABI_15`` ------------------------ +-------------------- ``LIBGCCJIT_ABI_15`` covers the addition of API entrypoints for directly embedding assembler instructions: @@ -243,3 +243,44 @@ embedding assembler instructions: * :func:`gcc_jit_extended_asm_add_input_operand` * :func:`gcc_jit_extended_asm_add_clobber` * :func:`gcc_jit_context_add_top_level_asm` + +.. _LIBGCCJIT_ABI_16: + +``LIBGCCJIT_ABI_16`` +-------------------- +``LIBGCCJIT_ABI_16`` covers the addition of reflection functions via API +entrypoints: + + * :func:`gcc_jit_function_get_return_type` + + * :func:`gcc_jit_function_get_param_count` + + * :func:`gcc_jit_type_dyncast_array` + + * :func:`gcc_jit_type_is_bool` + + * :func:`gcc_jit_type_is_integral` + + * :func:`gcc_jit_type_is_pointer` + + * :func:`gcc_jit_type_is_struct` + + * :func:`gcc_jit_type_dyncast_vector` + + * :func:`gcc_jit_type_unqualified` + + * :func:`gcc_jit_type_dyncast_function_ptr_type` + + * :func:`gcc_jit_function_type_get_return_type` + + * :func:`gcc_jit_function_type_get_param_count` + + * :func:`gcc_jit_function_type_get_param_type` + + * :func:`gcc_jit_vector_type_get_num_units` + + * :func:`gcc_jit_vector_type_get_element_type` + + * :func:`gcc_jit_struct_get_field` + + * :func:`gcc_jit_struct_get_field_count` diff --git a/gcc/jit/docs/topics/functions.rst b/gcc/jit/docs/topics/functions.rst index b2d9239..8399345 100644 --- a/gcc/jit/docs/topics/functions.rst +++ b/gcc/jit/docs/topics/functions.rst @@ -171,6 +171,32 @@ Functions underlying string, so it is valid to pass in a pointer to an on-stack buffer. +.. function:: size_t \ + gcc_jit_function_get_param_count (gcc_jit_function *func) + + Get the number of parameters of the function. + +.. function:: gcc_jit_type *\ + gcc_jit_function_get_return_type (gcc_jit_function *func) + + Get the return type of the function. + + The API entrypoints relating to getting info about parameters and return + types: + + * :c:func:`gcc_jit_function_get_return_type` + + * :c:func:`gcc_jit_function_get_param_count` + + were added in :ref:`LIBGCCJIT_ABI_16`; you can test for their presence + using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_REFLECTION + + .. type:: gcc_jit_case + Blocks ------ .. type:: gcc_jit_block diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst index 831f11b..6260e9a 100644 --- a/gcc/jit/docs/topics/types.rst +++ b/gcc/jit/docs/topics/types.rst @@ -345,3 +345,125 @@ Function pointer types Function pointer types can be created using :c:func:`gcc_jit_context_new_function_ptr_type`. + +Reflection API +-------------- + +.. function:: gcc_jit_type *\ + gcc_jit_type_dyncast_array (gcc_jit_type *type) + + Get the element type of an array type or NULL if it's not an array. + +.. function:: int\ + gcc_jit_type_is_bool (gcc_jit_type *type) + + Return non-zero if the type is a bool. + +.. function:: gcc_jit_function_type *\ + gcc_jit_type_dyncast_function_ptr_type (gcc_jit_type *type) + + Return the function type if it is one or NULL. + +.. function:: gcc_jit_type *\ + gcc_jit_function_type_get_return_type (gcc_jit_function_type *function_type) + + Given a function type, return its return type. + +.. function:: size_t\ + gcc_jit_function_type_get_param_count (gcc_jit_function_type *function_type) + + Given a function type, return its number of parameters. + +.. function:: gcc_jit_type *\ + gcc_jit_function_type_get_param_type (gcc_jit_function_type *function_type, + size_t index) + + Given a function type, return the type of the specified parameter. + +.. function:: int\ + gcc_jit_type_is_integral (gcc_jit_type *type) + + Return non-zero if the type is an integral. + +.. function:: gcc_jit_type *\ + gcc_jit_type_is_pointer (gcc_jit_type *type) + + Return the type pointed by the pointer type or NULL if it's not a pointer. + +.. function:: gcc_jit_vector_type *\ + gcc_jit_type_dyncast_vector (gcc_jit_type *type) + + Given a type, return a dynamic cast to a vector type or NULL. + +.. function:: gcc_jit_struct *\ + gcc_jit_type_is_struct (gcc_jit_type *type) + + Given a type, return a dynamic cast to a struct type or NULL. + +.. function:: size_t\ + gcc_jit_vector_type_get_num_units (gcc_jit_vector_type *vector_type) + + Given a vector type, return the number of units it contains. + +.. function:: gcc_jit_type *\ + gcc_jit_vector_type_get_element_type (gcc_jit_vector_type * vector_type) + + Given a vector type, return the type of its elements. + +.. function:: gcc_jit_type *\ + gcc_jit_type_unqualified (gcc_jit_type *type) + + Given a type, return the unqualified type, removing "const", "volatile" and + alignment qualifiers. + +.. function:: gcc_jit_field *\ + gcc_jit_struct_get_field (gcc_jit_struct *struct_type, + size_t index) + + Get a struct field by index. + +.. function:: size_t\ + gcc_jit_struct_get_field_count (gcc_jit_struct *struct_type) + + Get the number of fields in the struct. + + The API entrypoints related to the reflection API: + + * :c:func:`gcc_jit_function_type_get_return_type` + + * :c:func:`gcc_jit_function_type_get_param_count` + + * :c:func:`gcc_jit_function_type_get_param_type` + + * :c:func:`gcc_jit_type_unqualified` + + * :c:func:`gcc_jit_type_dyncast_array` + + * :c:func:`gcc_jit_type_is_bool` + + * :c:func:`gcc_jit_type_dyncast_function_ptr_type` + + * :c:func:`gcc_jit_type_is_integral` + + * :c:func:`gcc_jit_type_is_pointer` + + * :c:func:`gcc_jit_type_dyncast_vector` + + * :c:func:`gcc_jit_vector_type_get_element_type` + + * :c:func:`gcc_jit_vector_type_get_num_units` + + * :c:func:`gcc_jit_struct_get_field` + + * :c:func:`gcc_jit_type_is_struct` + + * :c:func:`gcc_jit_struct_get_field_count` + + were added in :ref:`LIBGCCJIT_ABI_16`; you can test for their presence + using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_REFLECTION + + .. type:: gcc_jit_case diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 03fa116..4a994fe 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -546,7 +546,9 @@ public: virtual bool is_bool () const = 0; virtual type *is_pointer () = 0; virtual type *is_array () = 0; + virtual struct_ *is_struct () { return NULL; } virtual bool is_void () const { return false; } + virtual vector_type *is_vector () { return NULL; } virtual bool has_known_size () const { return true; } bool is_numeric () const @@ -663,6 +665,7 @@ public: bool is_bool () const FINAL OVERRIDE { return m_other_type->is_bool (); } type *is_pointer () FINAL OVERRIDE { return m_other_type->is_pointer (); } type *is_array () FINAL OVERRIDE { return m_other_type->is_array (); } + struct_ *is_struct () FINAL OVERRIDE { return m_other_type->is_struct (); } protected: type *m_other_type; @@ -745,6 +748,8 @@ public: void replay_into (replayer *) FINAL OVERRIDE; + vector_type *is_vector () FINAL OVERRIDE { return this; } + private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; @@ -951,6 +956,8 @@ public: const char *access_as_type (reproducer &r) FINAL OVERRIDE; + struct_ *is_struct () FINAL OVERRIDE { return this; } + private: string * make_debug_string () FINAL OVERRIDE; void write_reproducer (reproducer &r) FINAL OVERRIDE; diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 7fa9480..c744b63 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -60,6 +60,14 @@ struct gcc_jit_struct : public gcc::jit::recording::struct_ { }; +struct gcc_jit_function_type : public gcc::jit::recording::function_type +{ +}; + +struct gcc_jit_vector_type : public gcc::jit::recording::vector_type +{ +}; + struct gcc_jit_field : public gcc::jit::recording::field { }; @@ -518,6 +526,197 @@ gcc_jit_type_get_volatile (gcc_jit_type *type) /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the + gcc::jit::recording::type::is_array method, in + jit-recording.c. */ + +gcc_jit_type * +gcc_jit_type_dyncast_array (gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + + return (gcc_jit_type *)type->is_array (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::is_bool method, in + jit-recording.c. */ + +int +gcc_jit_type_is_bool (gcc_jit_type *type) +{ + RETURN_VAL_IF_FAIL (type, FALSE, NULL, NULL, "NULL type"); + + return type->is_bool (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::is_pointer method, in + jit-recording.c. */ + +gcc_jit_type * +gcc_jit_type_is_pointer (gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + + return (gcc_jit_type *)type->is_pointer (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::is_int method, in + jit-recording.c. */ + +int +gcc_jit_type_is_integral (gcc_jit_type *type) +{ + RETURN_VAL_IF_FAIL (type, FALSE, NULL, NULL, "NULL type"); + + return type->is_int (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::is_vector method, in + jit-recording.c. */ + +gcc_jit_vector_type * +gcc_jit_type_dyncast_vector (gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + gcc::jit::recording::vector_type *vector_type = type->is_vector (); + return (gcc_jit_vector_type *)vector_type; +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::is_struct method, in + jit-recording.c. */ + +gcc_jit_struct * +gcc_jit_type_is_struct (gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + gcc::jit::recording::struct_ *struct_type = type->is_struct (); + return (gcc_jit_struct *)struct_type; +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::vector_type::get_num_units method, in + jit-recording.c. */ + +size_t +gcc_jit_vector_type_get_num_units (gcc_jit_vector_type *vector_type) +{ + RETURN_VAL_IF_FAIL (vector_type, 0, NULL, NULL, "NULL vector_type"); + return vector_type->get_num_units (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::vector_type::get_element_type method, in + jit-recording.c. */ + +gcc_jit_type * +gcc_jit_vector_type_get_element_type (gcc_jit_vector_type *vector_type) +{ + RETURN_NULL_IF_FAIL (vector_type, NULL, NULL, "NULL vector_type"); + return (gcc_jit_type *)vector_type->get_element_type (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::unqualified method, in + jit-recording.c. */ + +gcc_jit_type * +gcc_jit_type_unqualified (gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + + return (gcc_jit_type *)type->unqualified (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::type::dyn_cast_function_type method, in + jit-recording.c. */ + +gcc_jit_function_type * +gcc_jit_type_dyncast_function_ptr_type (gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type"); + gcc::jit::recording::type *func_ptr_type = type->dereference (); + if (!func_ptr_type) + { + return NULL; + } + + return (gcc_jit_function_type *)func_ptr_type->dyn_cast_function_type (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::function_type::get_return_type method, in + jit-recording.c. */ + +gcc_jit_type * +gcc_jit_function_type_get_return_type (gcc_jit_function_type *function_type) +{ + RETURN_NULL_IF_FAIL (function_type, NULL, NULL, "NULL function_type"); + return (gcc_jit_type *)function_type->get_return_type (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::function_type::get_param_types method, in + jit-recording.c. */ + +size_t +gcc_jit_function_type_get_param_count (gcc_jit_function_type *function_type) +{ + RETURN_VAL_IF_FAIL (function_type, 0, NULL, NULL, "NULL function_type"); + return function_type->get_param_types ().length (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::function_type::get_param_types method, in + jit-recording.c. */ + +gcc_jit_type * +gcc_jit_function_type_get_param_type (gcc_jit_function_type *function_type, + size_t index) +{ + RETURN_NULL_IF_FAIL (function_type, NULL, NULL, "NULL function_type"); + size_t num_params = function_type->get_param_types ().length (); + gcc::jit::recording::context *ctxt = function_type->m_ctxt; + RETURN_NULL_IF_FAIL_PRINTF3 (index < num_params, + ctxt, NULL, + "index of %ld is too large (%s has %ld params)", + index, + function_type->get_debug_string (), + num_params); + return (gcc_jit_type *)function_type->get_param_types ()[index]; +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the gcc::jit::recording::context::new_array_type method, in jit-recording.c. */ @@ -736,6 +935,42 @@ gcc_jit_struct_set_fields (gcc_jit_struct *struct_type, (gcc::jit::recording::field **)fields); } + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::fields::get_field method in + jit-recording.c. */ +extern gcc_jit_field * +gcc_jit_struct_get_field (gcc_jit_struct *struct_type, + size_t index) +{ + RETURN_NULL_IF_FAIL (struct_type, NULL, NULL, "NULL struct type"); + RETURN_NULL_IF_FAIL (struct_type->get_fields (), NULL, NULL, + "NULL struct fields"); + size_t num_fields = struct_type->get_fields ()->length (); + RETURN_NULL_IF_FAIL_PRINTF3 (index < num_fields, + NULL, NULL, + "index of %ld is too large (%s has %ld fields)", + index, + struct_type->get_debug_string (), + num_fields); + return (gcc_jit_field *)struct_type->get_fields ()->get_field (index); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, this calls the trivial + gcc::jit::recording::struct_::get_fields method in + jit-recording.h. */ + +size_t +gcc_jit_struct_get_field_count (gcc_jit_struct *struct_type) +{ + RETURN_VAL_IF_FAIL (struct_type, 0, NULL, NULL, "NULL struct type"); + return struct_type->get_fields ()->length (); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the @@ -1020,6 +1255,35 @@ gcc_jit_function_get_param (gcc_jit_function *func, int index) /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the + gcc::jit::recording::function::get_params method, in + jit-recording.h. + */ + +size_t +gcc_jit_function_get_param_count (gcc_jit_function *func) +{ + RETURN_VAL_IF_FAIL (func, 0, NULL, NULL, "NULL function"); + gcc::jit::recording::context *ctxt = func->m_ctxt; + JIT_LOG_FUNC (ctxt->get_logger ()); + return func->get_params ().length (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::function::get_return_type method, in + jit-recording.h. */ + +gcc_jit_type * +gcc_jit_function_get_return_type (gcc_jit_function *func) +{ + RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function_type"); + return (gcc_jit_type *)func->get_return_type (); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the gcc::jit::recording::function::dump_to_dot method, in jit-recording.c. */ diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 5c722c2..a1c9436 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -61,6 +61,8 @@ typedef struct gcc_jit_result gcc_jit_result; +- gcc_jit_location +- gcc_jit_type +- gcc_jit_struct + +- gcc_jit_function_type + +- gcc_jit_vector_type +- gcc_jit_field +- gcc_jit_function +- gcc_jit_block @@ -97,6 +99,12 @@ typedef struct gcc_jit_field gcc_jit_field; the layout for, or an opaque type. */ typedef struct gcc_jit_struct gcc_jit_struct; +/* A gcc_jit_function_type encapsulates a function type. */ +typedef struct gcc_jit_function_type gcc_jit_function_type; + +/* A gcc_jit_vector_type encapsulates a vector type. */ +typedef struct gcc_jit_vector_type gcc_jit_vector_type; + /* A gcc_jit_function encapsulates a function: either one that you're creating yourself, or a reference to one that you're dynamically linking to within the rest of the process. */ @@ -654,6 +662,15 @@ gcc_jit_struct_set_fields (gcc_jit_struct *struct_type, int num_fields, gcc_jit_field **fields); +/* Get a field by index. */ +extern gcc_jit_field * +gcc_jit_struct_get_field (gcc_jit_struct *struct_type, + size_t index); + +/* Get the number of fields. */ +extern size_t +gcc_jit_struct_get_field_count (gcc_jit_struct *struct_type); + /* Unions work similarly to structs. */ extern gcc_jit_type * gcc_jit_context_new_union_type (gcc_jit_context *ctxt, @@ -1621,6 +1638,78 @@ gcc_jit_context_add_top_level_asm (gcc_jit_context *ctxt, gcc_jit_location *loc, const char *asm_stmts); +#define LIBGCCJIT_HAVE_REFLECTION + +/* Reflection functions to get the number of parameters, return type of + a function and whether a type is a bool from the C API. + + This API entrypoint was added in LIBGCCJIT_ABI_16; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_REFLECTION +*/ +/* Get the return type of a function. */ +extern gcc_jit_type * +gcc_jit_function_get_return_type (gcc_jit_function *func); + +/* Get the number of params of a function. */ +extern size_t +gcc_jit_function_get_param_count (gcc_jit_function *func); + +/* Get the element type of an array type or NULL if it's not an array. */ +extern gcc_jit_type * +gcc_jit_type_dyncast_array (gcc_jit_type *type); + +/* Return non-zero if the type is a bool. */ +extern int +gcc_jit_type_is_bool (gcc_jit_type *type); + +/* Return the function type if it is one or NULL. */ +extern gcc_jit_function_type * +gcc_jit_type_dyncast_function_ptr_type (gcc_jit_type *type); + +/* Given a function type, return its return type. */ +extern gcc_jit_type * +gcc_jit_function_type_get_return_type (gcc_jit_function_type *function_type); + +/* Given a function type, return its number of parameters. */ +extern size_t +gcc_jit_function_type_get_param_count (gcc_jit_function_type *function_type); + +/* Given a function type, return the type of the specified parameter. */ +extern gcc_jit_type * +gcc_jit_function_type_get_param_type (gcc_jit_function_type *function_type, + size_t index); + +/* Return non-zero if the type is an integral. */ +extern int +gcc_jit_type_is_integral (gcc_jit_type *type); + +/* Return the type pointed by the pointer type or NULL if it's not a + * pointer. */ +extern gcc_jit_type * +gcc_jit_type_is_pointer (gcc_jit_type *type); + +/* Given a type, return a dynamic cast to a vector type or NULL. */ +extern gcc_jit_vector_type * +gcc_jit_type_dyncast_vector (gcc_jit_type *type); + +/* Given a type, return a dynamic cast to a struct type or NULL. */ +extern gcc_jit_struct * +gcc_jit_type_is_struct (gcc_jit_type *type); + +/* Given a vector type, return the number of units it contains. */ +extern size_t +gcc_jit_vector_type_get_num_units (gcc_jit_vector_type *vector_type); + +/* Given a vector type, return the type of its elements. */ +extern gcc_jit_type * +gcc_jit_vector_type_get_element_type (gcc_jit_vector_type *vector_type); + +/* Given a type, return the unqualified type, removing "const", "volatile" + * and alignment qualifiers. */ +extern gcc_jit_type * +gcc_jit_type_unqualified (gcc_jit_type *type); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 337ea6c..64e7909 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -205,3 +205,24 @@ LIBGCCJIT_ABI_15 { gcc_jit_extended_asm_add_clobber; gcc_jit_context_add_top_level_asm; } LIBGCCJIT_ABI_14; + +LIBGCCJIT_ABI_16 { + global: + gcc_jit_function_get_return_type; + gcc_jit_function_get_param_count; + gcc_jit_function_type_get_return_type; + gcc_jit_function_type_get_param_count; + gcc_jit_function_type_get_param_type; + gcc_jit_type_unqualified; + gcc_jit_type_dyncast_array; + gcc_jit_type_is_bool; + gcc_jit_type_dyncast_function_ptr_type; + gcc_jit_type_is_integral; + gcc_jit_type_is_pointer; + gcc_jit_type_dyncast_vector; + gcc_jit_vector_type_get_element_type; + gcc_jit_vector_type_get_num_units; + gcc_jit_struct_get_field; + gcc_jit_type_is_struct; + gcc_jit_struct_get_field_count; +} LIBGCCJIT_ABI_15; diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 84ef54a..a7fddf9 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -265,6 +265,13 @@ #undef create_code #undef verify_code +/* test-reflection.c */ +#define create_code create_code_reflection +#define verify_code verify_code_reflection +#include "test-reflection.c" +#undef create_code +#undef verify_code + /* test-string-literal.c */ #define create_code create_code_string_literal #define verify_code verify_code_string_literal @@ -434,6 +441,9 @@ const struct testcase testcases[] = { {"reading_struct ", create_code_reading_struct , verify_code_reading_struct }, + {"reflection", + create_code_reflection , + verify_code_reflection }, {"string_literal", create_code_string_literal, verify_code_string_literal}, diff --git a/gcc/testsuite/jit.dg/test-reflection.c b/gcc/testsuite/jit.dg/test-reflection.c new file mode 100644 index 0000000..112a245 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-reflection.c @@ -0,0 +1,95 @@ +#include +#include + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Do nothing. */ +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Get the built-in functions. */ + gcc_jit_function *builtin_sin = + gcc_jit_context_get_builtin_function (ctxt, "sin"); + + CHECK_VALUE (gcc_jit_function_get_param_count(builtin_sin), 1); + + gcc_jit_type *double_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE); + CHECK_VALUE (gcc_jit_function_get_return_type(builtin_sin), double_type); + CHECK (!gcc_jit_type_is_integral(double_type)); + + gcc_jit_type *bool_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL); + CHECK (gcc_jit_type_is_bool(bool_type)); + CHECK (!gcc_jit_type_is_integral(bool_type)); + + gcc_jit_type *aligned_bool_type = + gcc_jit_type_get_aligned(gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL), 8); + CHECK (gcc_jit_type_is_bool(aligned_bool_type)); + CHECK (bool_type != aligned_bool_type); + CHECK_VALUE (gcc_jit_type_unqualified(aligned_bool_type), bool_type); + + CHECK_VALUE (gcc_jit_type_unqualified(gcc_jit_type_get_const(bool_type)), bool_type); + CHECK_VALUE (gcc_jit_type_unqualified(gcc_jit_type_get_volatile(bool_type)), bool_type); + + gcc_jit_type *int64 = + gcc_jit_context_get_int_type(ctxt, 8, 1); + CHECK (gcc_jit_type_is_integral(int64)); + gcc_jit_type *uint64 = + gcc_jit_context_get_int_type(ctxt, 8, 0); + CHECK (gcc_jit_type_is_integral(uint64)); + gcc_jit_type *int8 = + gcc_jit_context_get_int_type(ctxt, 1, 1); + CHECK (gcc_jit_type_is_integral(int8)); + gcc_jit_type *uint8 = + gcc_jit_context_get_int_type(ctxt, 1, 0); + CHECK (gcc_jit_type_is_integral(uint8)); + + CHECK (!gcc_jit_type_dyncast_vector(double_type)); + gcc_jit_type *vec_type = gcc_jit_type_get_vector (double_type, 4); + gcc_jit_vector_type *vector_type = gcc_jit_type_dyncast_vector(vec_type); + CHECK (vector_type); + CHECK (vec_type != double_type); + CHECK_VALUE (gcc_jit_vector_type_get_element_type(vector_type), double_type); + CHECK_VALUE (gcc_jit_vector_type_get_num_units(vector_type), 4); + + CHECK (!gcc_jit_type_is_pointer(double_type)); + CHECK_VALUE (gcc_jit_type_is_pointer(gcc_jit_type_get_pointer(double_type)), double_type); + + gcc_jit_type* params[2] = {int8, uint64}; + gcc_jit_type *function_ptr_type = gcc_jit_context_new_function_ptr_type(ctxt, NULL, int64, 2, params, 0); + CHECK (!gcc_jit_type_dyncast_function_ptr_type (int64)); + gcc_jit_function_type *function_type = gcc_jit_type_dyncast_function_ptr_type (function_ptr_type); + CHECK (function_type); + int param_count = gcc_jit_function_type_get_param_count(function_type); + CHECK_VALUE (param_count, 2); + gcc_jit_type *return_type = gcc_jit_function_type_get_return_type(function_type); + CHECK_VALUE (return_type, int64); + gcc_jit_type *param1 = gcc_jit_function_type_get_param_type(function_type, 0); + CHECK_VALUE (param1, int8); + gcc_jit_type *param2 = gcc_jit_function_type_get_param_type(function_type, 1); + CHECK_VALUE (param2, uint64); + + gcc_jit_field *field1 = gcc_jit_context_new_field (ctxt, NULL, uint64, "field1"); + gcc_jit_field *field2 = gcc_jit_context_new_field (ctxt, NULL, double_type, "field2"); + gcc_jit_field *fields[2] = { field1, field2 }; + gcc_jit_struct *struct_type = gcc_jit_context_new_struct_type (ctxt, NULL, "testStruct", 2, fields); + CHECK_VALUE (gcc_jit_struct_get_field_count(struct_type), 2); + CHECK_VALUE (gcc_jit_struct_get_field(struct_type, 0), field1); + CHECK_VALUE (gcc_jit_struct_get_field(struct_type, 1), field2); + CHECK (!gcc_jit_type_is_struct(double_type)); + gcc_jit_struct *struct_ty = gcc_jit_type_is_struct(gcc_jit_struct_as_type(struct_type)); + CHECK_VALUE (struct_ty, struct_type); + + CHECK (!gcc_jit_type_dyncast_array(double_type)); + gcc_jit_type* array_type = gcc_jit_context_new_array_type(ctxt, NULL, double_type, 1); + CHECK_VALUE (gcc_jit_type_dyncast_array(array_type), double_type); +} + -- cgit v1.1 From 38e4a361e79a459947540920db645f3d7fa7221a Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Sat, 20 Nov 2021 02:51:27 -0300 Subject: harden conds: detach without decls When we create copies of SSA_NAMEs to hold "detached" copies of the values for the hardening tests, we end up with assignments to SSA_NAMEs that refer to the same decls. That would be generally desirable, since it enables the variable to be recognized in dumps, and makes coalescing more likely if the original variable dies at that point. When the decl is a DECL_BY_REFERENCE, the SSA_NAME holds the address of a parm or result, and it's read-only, so we shouldn't create assignments to it. Gimple checkers flag at least the case of results. This patch arranges for us to avoid referencing the same decls, which cures the problem, but retaining the visible association between the SSA_NAMEs, by using the same identifier for the copy. for gcc/ChangeLog PR tree-optimization/102988 * gimple-harden-conditionals.cc (detach_value): Copy SSA_NAME without decl sharing. for gcc/testsuite/ChangeLog PR tree-optimization/102988 * g++.dg/pr102988.C: New. --- gcc/gimple-harden-conditionals.cc | 9 ++++++++- gcc/testsuite/g++.dg/pr102988.C | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/pr102988.C (limited to 'gcc') diff --git a/gcc/gimple-harden-conditionals.cc b/gcc/gimple-harden-conditionals.cc index 8916420..cfa2361 100644 --- a/gcc/gimple-harden-conditionals.cc +++ b/gcc/gimple-harden-conditionals.cc @@ -123,7 +123,14 @@ detach_value (location_t loc, gimple_stmt_iterator *gsip, tree val) return val; } - tree ret = copy_ssa_name (val); + /* Create a SSA "copy" of VAL. This could be an anonymous + temporary, but it's nice to have it named after the corresponding + variable. Alas, when VAL is a DECL_BY_REFERENCE RESULT_DECL, + setting (a copy of) it would be flagged by checking, so we don't + use copy_ssa_name: we create an anonymous SSA name, and then give + it the same identifier (rather than decl) as VAL. */ + tree ret = make_ssa_name (TREE_TYPE (val)); + SET_SSA_NAME_VAR_OR_IDENTIFIER (ret, SSA_NAME_IDENTIFIER (val)); /* Output asm ("" : "=g" (ret) : "0" (val)); */ vec *inputs = NULL; diff --git a/gcc/testsuite/g++.dg/pr102988.C b/gcc/testsuite/g++.dg/pr102988.C new file mode 100644 index 0000000..05a1a8f --- /dev/null +++ b/gcc/testsuite/g++.dg/pr102988.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fharden-conditional-branches -fchecking=1" } */ + +/* DECL_BY_REFERENCE RESULT_DECL is read-only, we can't create a copy + of its (address) default def and set it. */ + +void ll(); +struct k { + ~k(); +}; +k ice(k *a) +{ + k v; + if (&v!= a) + ll(); + return v; +} -- cgit v1.1 From 74faa9834a9ad208e34f67b08c854c20b0fcfe92 Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Sat, 20 Nov 2021 01:37:54 +0000 Subject: Fix tree-optimization/103220: Another missing folding of (type) X op CST where type is a nop convert The problem here is that int_fits_type_p will return false if we just change the sign of things like -2 (or 254) so we should accept the case where we just change the sign (and not the precision) of the type. OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. PR tree-optimization/103220 gcc/ChangeLog: * match.pd ((type) X bitop CST): Don't check if CST fits into the type if only the sign changes. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr103220-1.c: New test. * gcc.dg/tree-ssa/pr103220-2.c: New test. * gcc.dg/pr25530.c: Update test to check for 4294967294 in the case -2 is not matched. --- gcc/match.pd | 3 ++- gcc/testsuite/gcc.dg/pr25530.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/pr103220-1.c | 15 +++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr103220-2.c | 16 ++++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr103220-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr103220-2.c (limited to 'gcc') diff --git a/gcc/match.pd b/gcc/match.pd index e5985de..f059b47 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1607,7 +1607,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (bitop (convert@2 @0) (convert?@3 @1)) (if (((TREE_CODE (@1) == INTEGER_CST && INTEGRAL_TYPE_P (TREE_TYPE (@0)) - && int_fits_type_p (@1, TREE_TYPE (@0))) + && (int_fits_type_p (@1, TREE_TYPE (@0)) + || tree_nop_conversion_p (TREE_TYPE (@0), type))) || types_match (@0, @1)) /* ??? This transform conflicts with fold-const.c doing Convert (T)(x & c) into (T)x & (T)c, if c is an integer diff --git a/gcc/testsuite/gcc.dg/pr25530.c b/gcc/testsuite/gcc.dg/pr25530.c index b846ab3..771b36b9 100644 --- a/gcc/testsuite/gcc.dg/pr25530.c +++ b/gcc/testsuite/gcc.dg/pr25530.c @@ -8,4 +8,4 @@ f (unsigned t) return (t / 2) * 2; } -/* { dg-final { scan-tree-dump "\& -2" "optimized" } } */ +/* { dg-final { scan-tree-dump "\& -2|4294967294" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr103220-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr103220-1.c new file mode 100644 index 0000000..f2ef3f1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr103220-1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +unsigned char f(unsigned char a) +{ + signed char d = (signed char) a; + signed char e = d & ~1; + unsigned char t = e; + t &= ~2; + return t; +} +/* The above should reduce down to just & 252 rather than keping + the two &s there. */ +/* { dg-final { scan-tree-dump-times "& 252" 1 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "& -2" 0 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "& 253" 0 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr103220-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr103220-2.c new file mode 100644 index 0000000..25d7412 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr103220-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +signed char f(unsigned char a) +{ + unsigned char b = a & 127; + signed char c = (signed char) b; + signed char d = (signed char) a; + signed char e = d & -128; + signed char h = c | e; + return h; +} +/* The above should reduce down to just return with a cast. + removing the two &s there and |'s. */ +/* { dg-final { scan-tree-dump-times "& 127" 0 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "& -128" 0 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "\\\| " 0 "optimized"} } */ -- cgit v1.1 From 7950c96ca667ddaab9d6e894da3958ebc2e2dccb Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Sat, 20 Nov 2021 11:20:07 -0500 Subject: Clobber the condition code in the bfin doloop patterns Per Aldy's excellent, but tough to follow analysis in PR 103226, this patch fixes the bfin-elf regression. In simplest terms the doloop patterns on this port may clobber the condition code register, but they do not expose that until after register allocation. That would be fine, except that other patterns have exposed CC earlier. As a result the dataflow, particularly for CC, is incorrect. This leads the register allocators to assume that a value in CC outside the loop is still valid inside the loop when in fact, the value has been clobbered. This is what caused pr80974 to start failing. With this fix, not only do we fix the pr80974 regression, but we fix ~20 other execution failures in the port. It also reduces test time for the port from ~90 minutes to ~60 minutes. PR tree-optimization/103226 gcc/ * config/bfin/bfin.md (doloop pattern, splitter and expander): Clobber CC. --- gcc/config/bfin/bfin.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/config/bfin/bfin.md b/gcc/config/bfin/bfin.md index fd65f4d..10a19aa 100644 --- a/gcc/config/bfin/bfin.md +++ b/gcc/config/bfin/bfin.md @@ -1959,7 +1959,8 @@ (plus:SI (match_dup 0) (const_int -1))) (unspec [(const_int 0)] UNSPEC_LSETUP_END) - (clobber (match_dup 2))])] ; match_scratch + (clobber (match_dup 2)) + (clobber (reg:BI REG_CC))])] ; match_scratch "" { /* The loop optimizer doesn't check the predicates... */ @@ -1979,7 +1980,8 @@ (plus (match_dup 2) (const_int -1))) (unspec [(const_int 0)] UNSPEC_LSETUP_END) - (clobber (match_scratch:SI 3 "=X,&r,&r"))] + (clobber (match_scratch:SI 3 "=X,&r,&r")) + (clobber (reg:BI REG_CC))] "" "@ /* loop end %0 %l1 */ @@ -1997,7 +1999,8 @@ (plus (match_dup 0) (const_int -1))) (unspec [(const_int 0)] UNSPEC_LSETUP_END) - (clobber (match_scratch:SI 2))] + (clobber (match_scratch:SI 2)) + (clobber (reg:BI REG_CC))] "memory_operand (operands[0], SImode) || splitting_loops" [(set (match_dup 2) (match_dup 0)) (set (match_dup 2) (plus:SI (match_dup 2) (const_int -1))) -- cgit v1.1 From a0e99d5bb741d3db74a67d492f47b28217fbf88a Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sun, 21 Nov 2021 00:35:22 +0100 Subject: Fix looping flag discovery in ipa-pure-const The testcase shows situation where there is non-trivial cycle in the callgraph involving a noreturn call. This cycle is important for const function discovery but not important for pure. IPA pure const uses same strongly connected components for both propagations which makes it to get suboptimal result (does not detect the pure flag). However local pure const gets the situation right becaue it processes functions in right order. This hits rarely executed code in propagate_pure_const that merge results with previously known state that has long standing bug in it that makes it to throw away the looping flag. Bootstrapped/regtested x86_64-linux. gcc/ChangeLog: 2021-11-21 Jan Hubicka PR ipa/103052 * ipa-pure-const.c (propagate_pure_const): Fix merging of loping flag. gcc/testsuite/ChangeLog: 2021-11-21 Jan Hubicka PR ipa/103052 * gcc.c-torture/execute/pr103052.c: New test. --- gcc/ipa-pure-const.c | 4 +-- gcc/testsuite/gcc.c-torture/execute/pr103052.c | 35 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr103052.c (limited to 'gcc') diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index a332940..fea8b08 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -1782,9 +1782,9 @@ propagate_pure_const (void) if (w_l->state_previously_known != IPA_NEITHER && this_state > w_l->state_previously_known) { - this_state = w_l->state_previously_known; if (this_state == IPA_NEITHER) - this_looping = w_l->looping_previously_known; + this_looping = w_l->looping_previously_known; + this_state = w_l->state_previously_known; } if (!this_looping && self_recursive_p (w)) this_looping = true; diff --git a/gcc/testsuite/gcc.c-torture/execute/pr103052.c b/gcc/testsuite/gcc.c-torture/execute/pr103052.c new file mode 100644 index 0000000..bef8674 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr103052.c @@ -0,0 +1,35 @@ +static void js_error(void); +static int top; +static void js_throw(void) +{ + __builtin_exit(0); +} + +// LOCATION A -- if js_pop is here, the bug is present +static void js_pop(void) +{ + if (++top > 100) + js_error(); +} + +static void jsC_error(const char *v) +{ + if (v[0] == 0) + js_error(); + js_throw(); +} +static void checkfutureword(const char *exp) +{ + if (!__builtin_strcmp(exp, "const")) + jsC_error("boom"); +} +static void js_error(void) { + checkfutureword("foo"); + checkfutureword("bar"); + js_pop(); +} +int main(void) +{ + checkfutureword("const"); + __builtin_abort (); +} -- cgit v1.1 From ce2dbf943ac8ffefe048016ac3abfd3b6a4518d4 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sun, 21 Nov 2021 00:39:42 +0100 Subject: Fix ignore_nondeterminism_p in ipa-modref Improve debug output in ipa-modref and fix ignore_nondeterminism predicate: looping pures and cont are still deterministic. gcc/ChangeLog: 2021-11-21 Jan Hubicka PR ipa/103052 * ipa-modref.c (ignore_nondeterminism_p): Allow looping pure/cont. (merge_call_side_effects): Improve debug output. --- gcc/ipa-modref.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 57e2aa5..20810c7 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -923,8 +923,7 @@ record_access_p (tree expr) static bool ignore_nondeterminism_p (tree caller, int flags) { - if ((flags & (ECF_CONST | ECF_PURE)) - && !(flags & ECF_LOOPING_CONST_OR_PURE)) + if (flags & (ECF_CONST | ECF_PURE)) return true; if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW) || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN))) @@ -1016,6 +1015,10 @@ merge_call_side_effects (modref_summary *cur_summary, && !(flags & ECF_LOOPING_CONST_OR_PURE)) return changed; + if (dump_file) + fprintf (dump_file, " - Merging side effects of %s\n", + callee_node->dump_name ()); + if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE)) || (flags & ECF_LOOPING_CONST_OR_PURE)) { @@ -1061,8 +1064,7 @@ merge_call_side_effects (modref_summary *cur_summary, } if (dump_file) - fprintf (dump_file, " - Merging side effects of %s with parm map:", - callee_node->dump_name ()); + fprintf (dump_file, " Parm map:"); parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true); for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) -- cgit v1.1 From f658f1d7a22c09e1192fb2343f20263890106b82 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 21 Nov 2021 00:16:32 +0000 Subject: Daily bump. --- gcc/ChangeLog | 29 ++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/jit/ChangeLog | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 24 +++++++++++++++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6faa1bd..0100f7a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,32 @@ +2021-11-20 Jan Hubicka + + PR ipa/103052 + * ipa-modref.c (ignore_nondeterminism_p): Allow looping pure/cont. + (merge_call_side_effects): Improve debug output. + +2021-11-20 Jan Hubicka + + PR ipa/103052 + * ipa-pure-const.c (propagate_pure_const): Fix merging of loping flag. + +2021-11-20 Jeff Law + + PR tree-optimization/103226 + * config/bfin/bfin.md (doloop pattern, splitter and expander): Clobber + CC. + +2021-11-20 Andrew Pinski + + PR tree-optimization/103220 + * match.pd ((type) X bitop CST): Don't check if CST + fits into the type if only the sign changes. + +2021-11-20 Alexandre Oliva + + PR tree-optimization/102988 + * gimple-harden-conditionals.cc (detach_value): Copy SSA_NAME + without decl sharing. + 2021-11-19 Iain Sandoe * doc/invoke.texi: Remove whitespace after an @option. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 9e0ed4c..ffe2a46 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20211120 +20211121 diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index d7f7cc5..c2fc2bd 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,54 @@ +2021-11-20 Antoni Boucher + + PR target/96889 + * docs/topics/compatibility.rst (LIBGCCJIT_ABI_16): New ABI tag. + * docs/topics/functions.rst: Add documentation for the + functions gcc_jit_function_get_return_type and + gcc_jit_function_get_param_count + * docs/topics/types.rst: Add documentation for the functions + gcc_jit_function_type_get_return_type, + gcc_jit_function_type_get_param_count, + gcc_jit_function_type_get_param_type, + gcc_jit_type_unqualified, gcc_jit_type_dyncast_array, + gcc_jit_type_is_bool, + gcc_jit_type_dyncast_function_ptr_type, + gcc_jit_type_is_integral, gcc_jit_type_is_pointer, + gcc_jit_type_dyncast_vector, + gcc_jit_vector_type_get_element_type, + gcc_jit_vector_type_get_num_units, + gcc_jit_struct_get_field, gcc_jit_type_is_struct, + and gcc_jit_struct_get_field_count + * libgccjit.c: + (gcc_jit_function_get_return_type, gcc_jit_function_get_param_count, + gcc_jit_function_type_get_return_type, + gcc_jit_function_type_get_param_count, + gcc_jit_function_type_get_param_type, gcc_jit_type_unqualified, + gcc_jit_type_dyncast_array, gcc_jit_type_is_bool, + gcc_jit_type_dyncast_function_ptr_type, gcc_jit_type_is_integral, + gcc_jit_type_is_pointer, gcc_jit_type_dyncast_vector, + gcc_jit_vector_type_get_element_type, + gcc_jit_vector_type_get_num_units, gcc_jit_struct_get_field, + gcc_jit_type_is_struct, gcc_jit_struct_get_field_count): New + functions. + (struct gcc_jit_function_type, struct gcc_jit_vector_type): + New types. + * libgccjit.h: + (gcc_jit_function_get_return_type, gcc_jit_function_get_param_count, + gcc_jit_function_type_get_return_type, + gcc_jit_function_type_get_param_count, + gcc_jit_function_type_get_param_type, gcc_jit_type_unqualified, + gcc_jit_type_dyncast_array, gcc_jit_type_is_bool, + gcc_jit_type_dyncast_function_ptr_type, gcc_jit_type_is_integral, + gcc_jit_type_is_pointer, gcc_jit_type_dyncast_vector, + gcc_jit_vector_type_get_element_type, + gcc_jit_vector_type_get_num_units, gcc_jit_struct_get_field, + gcc_jit_type_is_struct, gcc_jit_struct_get_field_count): New + function declarations. + (struct gcc_jit_function_type, struct gcc_jit_vector_type): + New types. + * jit-recording.h: New functions (is_struct and is_vector) + * libgccjit.map (LIBGCCJIT_ABI_16): New ABI tag. + 2021-11-12 David Malcolm PR jit/103199 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4bc2db5..b342b71 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,27 @@ +2021-11-20 Jan Hubicka + + PR ipa/103052 + * gcc.c-torture/execute/pr103052.c: New test. + +2021-11-20 Andrew Pinski + + PR tree-optimization/103220 + * gcc.dg/tree-ssa/pr103220-1.c: New test. + * gcc.dg/tree-ssa/pr103220-2.c: New test. + * gcc.dg/pr25530.c: Update test to check for + 4294967294 in the case -2 is not matched. + +2021-11-20 Alexandre Oliva + + PR tree-optimization/102988 + * g++.dg/pr102988.C: New. + +2021-11-20 Antoni Boucher + + PR target/96889 + * jit.dg/all-non-failing-tests.h: Add test-reflection.c. + * jit.dg/test-reflection.c: New test. + 2021-11-19 Jakub Jelinek PR c++/101180 -- cgit v1.1 From dc915b361bbc99da83fc53db7f7e0e28d0ce12c8 Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Sun, 21 Nov 2021 11:40:08 +0000 Subject: Tweak tree-ssa-math-opts.c to solve PR target/102117. This patch resolves PR target/102117 on s390. The problem is that some of the functionality of GCC's RTL expanders is no longer triggered following the transition to tree SSA form. On s390, unsigned widening multiplications are converted into WIDEN_MULT_EXPR (aka w* in tree dumps), but signed widening multiplies are left in their original form, which alas doesn't benefit from the clever logic in expand_widening_mult. The fix is to teach convert_mult_to_widen, that RTL expansion can synthesize a signed widening multiplication if the target provides a suitable umul_widen_optab. On s390-linux-gnu with -O2 -m64, the code in the bugzilla PR currently generates: imul128: stmg %r12,%r13,96(%r15) srag %r0,%r4,63 srag %r1,%r3,63 lgr %r13,%r3 mlgr %r12,%r4 msgr %r1,%r4 msgr %r0,%r3 lgr %r4,%r12 agr %r1,%r0 lgr %r5,%r13 agr %r4,%r1 stmg %r4,%r5,0(%r2) lmg %r12,%r13,96(%r15) br %r14 but with this patch should now generate the more efficient: imul128: lgr %r1,%r3 mlgr %r0,%r4 srag %r5,%r3,63 ngr %r5,%r4 srag %r4,%r4,63 sgr %r0,%r5 ngr %r4,%r3 sgr %r0,%r4 stmg %r0,%r1,0(%r2) br %r14 2021-11-21 Roger Sayle Robin Dapp gcc/ChangeLog PR target/102117 * tree-ssa-math-opts.c (convert_mult_to_widen): Recognize signed WIDEN_MULT_EXPR if the target supports umul_widen_optab. gcc/testsuite/ChangeLog PR target/102117 * gcc.target/s390/mul-wide.c: New test case. * gcc.target/s390/umul-wide.c: New test case. --- gcc/testsuite/gcc.target/s390/mul-wide.c | 9 +++++++++ gcc/testsuite/gcc.target/s390/umul-wide.c | 9 +++++++++ gcc/tree-ssa-math-opts.c | 11 ++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/s390/mul-wide.c create mode 100644 gcc/testsuite/gcc.target/s390/umul-wide.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/s390/mul-wide.c b/gcc/testsuite/gcc.target/s390/mul-wide.c new file mode 100644 index 0000000..8a2092e --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/mul-wide.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -m64 -fdump-tree-optimized" } */ + +__int128 foo(long long a, long long b) +{ + return (__int128)a * (__int128)b; +} + +/* { dg-final { scan-tree-dump " w\\* " "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/s390/umul-wide.c b/gcc/testsuite/gcc.target/s390/umul-wide.c new file mode 100644 index 0000000..33a74e5 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/umul-wide.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -m64 -fdump-tree-optimized" } */ + +unsigned __int128 foo(unsigned long long a, unsigned long long b) +{ + return (unsigned __int128)a * (unsigned __int128)b; +} + +/* { dg-final { scan-tree-dump " w\\* " "optimized" } } */ diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c index cc8496c..6131824 100644 --- a/gcc/tree-ssa-math-opts.c +++ b/gcc/tree-ssa-math-opts.c @@ -2723,7 +2723,16 @@ convert_mult_to_widen (gimple *stmt, gimple_stmt_iterator *gsi) from_unsigned1 = from_unsigned2 = false; } else - return false; + { + /* Expand can synthesize smul_widen_optab if the target + supports umul_widen_optab. */ + op = umul_widen_optab; + handler = find_widening_optab_handler_and_mode (op, to_mode, + from_mode, + &actual_mode); + if (handler == CODE_FOR_nothing) + return false; + } } /* Ensure that the inputs to the handler are in the correct precison -- cgit v1.1 From 09a4ffb72aa2f51345f8021aaea3501ce91ae588 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sun, 21 Nov 2021 13:21:32 +0100 Subject: Refactor load/store/kill analysis in ipa-modref Refactor load/store/kill analysis in ipa-modref to a class modref_access_analysis. This is done in order to avoid some code duplication and early exits that has turned out to be hard to maintain and there were multiple bugs we noticed recently. gcc/ChangeLog: 2021-11-21 Jan Hubicka * ipa-modref.c (ignore_nondeterminism_p): Move earlier in source code. (ignore_retval_p): Likewise. (ignore_stores_p): Likewise. (parm_map_for_arg): Likewise. (class modref_access_analysis): New class. (modref_access_analysis::set_side_effects): New member function. (modref_access_analysis::set_nondeterministic): New member function. (get_access): Turn to ... (modref_access_analysis::get_access): ... this one. (record_access): Turn to ... (modref_access_analysis::record_access): ... this one. (record_access_lto): Turn to ... (modref_access_analysis::record_access_lto): ... This one. (record_access_p): Turn to ... (modref_access_analysis::record_access_p): ... This one (modref_access_analysis::record_unknown_load): New member function. (modref_access_analysis::record_unknown_store): New member function. (get_access_for_fnspec): Turn to ... (modref_access_analysis::get_access_for_fnspec): ... this one. (merge_call_side_effects): Turn to ... (moderf_access_analysis::merge_call_side_effects): Turn to ... (collapse_loads): Move later in source code. (collapse_stores): Move later in source code. (process_fnspec): Turn to ... (modref_access_analysis::process_fnspec): ... this one. (analyze_call): Turn to ... (modref_access_analysis::analyze_call): ... this one. (struct summary_ptrs): Remove. (analyze_load): Turn to ... (modref_access_analysis::analyze_load): ... this one. (analyze_store): Turn to ... (modref_access_analysis::analyze_store): ... this one. (analyze_stmt): Turn to ... (modref_access_analysis::analyze_stmt): ... This one. (remove_summary): Remove. (modref_access_analysis::propagate): Break out from ... (modref_access_analysis::analyze): Break out from ... (analyze_function): ... here. --- gcc/ipa-modref.c | 946 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 511 insertions(+), 435 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 20810c7..a04e585 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -775,9 +775,177 @@ get_modref_function_summary (gcall *call, bool *interposed) namespace { +/* Return true if ECF flags says that nondeterminsm can be ignored. */ + +static bool +ignore_nondeterminism_p (tree caller, int flags) +{ + if (flags & (ECF_CONST | ECF_PURE)) + return true; + if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW) + || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN))) + return true; + return false; +} + +/* Return true if ECF flags says that return value can be ignored. */ + +static bool +ignore_retval_p (tree caller, int flags) +{ + if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW) + || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN))) + return true; + return false; +} + +/* Return true if ECF flags says that stores can be ignored. */ + +static bool +ignore_stores_p (tree caller, int flags) +{ + if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS)) + return true; + if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW) + || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN))) + return true; + return false; +} + +/* Determine parm_map for argument OP. */ + +modref_parm_map +parm_map_for_arg (tree op) +{ + bool offset_known; + poly_int64 offset; + struct modref_parm_map parm_map; + + parm_map.parm_offset_known = false; + parm_map.parm_offset = 0; + + offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset); + if (TREE_CODE (op) == SSA_NAME + && SSA_NAME_IS_DEFAULT_DEF (op) + && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL) + { + int index = 0; + for (tree t = DECL_ARGUMENTS (current_function_decl); + t != SSA_NAME_VAR (op); t = DECL_CHAIN (t)) + { + if (!t) + { + index = MODREF_UNKNOWN_PARM; + break; + } + index++; + } + parm_map.parm_index = index; + parm_map.parm_offset_known = offset_known; + parm_map.parm_offset = offset; + } + else if (points_to_local_or_readonly_memory_p (op)) + parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM; + else + parm_map.parm_index = MODREF_UNKNOWN_PARM; + return parm_map; +} + +/* Analyze memory accesses (loads, stores and kills) performed + by the function. Set also side_effects, calls_interposable + and nondeterminism flags. */ + +class modref_access_analysis +{ +public: + modref_access_analysis (bool ipa, modref_summary *summary, + modref_summary_lto *summary_lto) + : m_summary (summary), m_summary_lto (summary_lto), m_ipa (ipa) + { + } + void analyze (); +private: + bool set_side_effects (); + bool set_nondeterministic (); + static modref_access_node get_access (ao_ref *ref); + static void record_access (modref_records *, ao_ref *, modref_access_node &); + static void record_access_lto (modref_records_lto *, ao_ref *, + modref_access_node &a); + bool record_access_p (tree); + bool record_unknown_load (); + bool record_unknown_store (); + bool merge_call_side_effects (gimple *, modref_summary *, + cgraph_node *, bool); + modref_access_node get_access_for_fnspec (gcall *, attr_fnspec &, + unsigned int, modref_parm_map &); + void process_fnspec (gcall *); + void analyze_call (gcall *); + static bool analyze_load (gimple *, tree, tree, void *); + static bool analyze_store (gimple *, tree, tree, void *); + void analyze_stmt (gimple *, bool); + void propagate (); + + /* Summary being computed. + We work eitehr with m_summary or m_summary_lto. Never on both. */ + modref_summary *m_summary; + modref_summary_lto *m_summary_lto; + /* Recursive calls needs simplisitc dataflow after analysis finished. + Collect all calls into this vector during analysis and later process + them in propagate. */ + auto_vec m_recursive_calls; + /* ECF flags of function being analysed. */ + int m_ecf_flags; + /* True if IPA propagation will be done later. */ + bool m_ipa; + /* Set true if statement currently analysed is known to be + executed each time function is called. */ + bool m_always_executed; +}; + +/* Set side_effects flag and return if someting changed. */ + +bool +modref_access_analysis::set_side_effects () +{ + bool changed = false; + + if (m_summary && !m_summary->side_effects) + { + m_summary->side_effects = true; + changed = true; + } + if (m_summary_lto && !m_summary_lto->side_effects) + { + m_summary_lto->side_effects = true; + changed = true; + } + return changed; +} + +/* Set nondeterministic flag and return if someting changed. */ + +bool +modref_access_analysis::set_nondeterministic () +{ + bool changed = false; + + if (m_summary && !m_summary->nondeterministic) + { + m_summary->side_effects = m_summary->nondeterministic = true; + changed = true; + } + if (m_summary_lto && !m_summary_lto->nondeterministic) + { + m_summary_lto->side_effects = m_summary_lto->nondeterministic = true; + changed = true; + } + return changed; +} + /* Construct modref_access_node from REF. */ -static modref_access_node -get_access (ao_ref *ref) + +modref_access_node +modref_access_analysis::get_access (ao_ref *ref) { tree base; @@ -822,8 +990,10 @@ get_access (ao_ref *ref) /* Record access into the modref_records data structure. */ -static void -record_access (modref_records *tt, ao_ref *ref, modref_access_node &a) +void +modref_access_analysis::record_access (modref_records *tt, + ao_ref *ref, + modref_access_node &a) { alias_set_type base_set = !flag_strict_aliasing ? 0 : ao_ref_base_alias_set (ref); @@ -840,8 +1010,9 @@ record_access (modref_records *tt, ao_ref *ref, modref_access_node &a) /* IPA version of record_access_tree. */ -static void -record_access_lto (modref_records_lto *tt, ao_ref *ref, modref_access_node &a) +void +modref_access_analysis::record_access_lto (modref_records_lto *tt, ao_ref *ref, + modref_access_node &a) { /* get_alias_set sometimes use different type to compute the alias set than TREE_TYPE (base). Do same adjustments. */ @@ -906,9 +1077,23 @@ record_access_lto (modref_records_lto *tt, ao_ref *ref, modref_access_node &a) /* Returns true if and only if we should store the access to EXPR. Some accesses, e.g. loads from automatic variables, are not interesting. */ -static bool -record_access_p (tree expr) +bool +modref_access_analysis::record_access_p (tree expr) { + if (TREE_THIS_VOLATILE (expr)) + { + if (dump_file) + fprintf (dump_file, " (volatile; marking nondeterministic) "); + set_nondeterministic (); + } + if (cfun->can_throw_non_call_exceptions + && tree_could_throw_p (expr)) + { + if (dump_file) + fprintf (dump_file, " (can throw; marking side effects) "); + set_side_effects (); + } + if (refs_local_or_readonly_memory_p (expr)) { if (dump_file) @@ -918,154 +1103,120 @@ record_access_p (tree expr) return true; } -/* Return true if ECF flags says that nondeterminsm can be ignored. */ - -static bool -ignore_nondeterminism_p (tree caller, int flags) -{ - if (flags & (ECF_CONST | ECF_PURE)) - return true; - if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW) - || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN))) - return true; - return false; -} - -/* Return true if ECF flags says that return value can be ignored. */ +/* Collapse loads and return true if something changed. */ -static bool -ignore_retval_p (tree caller, int flags) +bool +modref_access_analysis::record_unknown_load () { - if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW) - || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN))) - return true; - return false; -} - -/* Return true if ECF flags says that stores can be ignored. */ + bool changed = false; -static bool -ignore_stores_p (tree caller, int flags) -{ - if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS)) - return true; - if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW) - || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN))) - return true; - return false; + if (m_summary && !m_summary->loads->every_base) + { + m_summary->loads->collapse (); + changed = true; + } + if (m_summary_lto && !m_summary_lto->loads->every_base) + { + m_summary_lto->loads->collapse (); + changed = true; + } + return changed; } -/* Determine parm_map for argument OP. */ +/* Collapse loads and return true if something changed. */ -modref_parm_map -parm_map_for_arg (tree op) +bool +modref_access_analysis::record_unknown_store () { - bool offset_known; - poly_int64 offset; - struct modref_parm_map parm_map; - - parm_map.parm_offset_known = false; - parm_map.parm_offset = 0; + bool changed = false; - offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset); - if (TREE_CODE (op) == SSA_NAME - && SSA_NAME_IS_DEFAULT_DEF (op) - && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL) + if (m_summary && !m_summary->stores->every_base) { - int index = 0; - for (tree t = DECL_ARGUMENTS (current_function_decl); - t != SSA_NAME_VAR (op); t = DECL_CHAIN (t)) - { - if (!t) - { - index = MODREF_UNKNOWN_PARM; - break; - } - index++; - } - parm_map.parm_index = index; - parm_map.parm_offset_known = offset_known; - parm_map.parm_offset = offset; + m_summary->stores->collapse (); + changed = true; } - else if (points_to_local_or_readonly_memory_p (op)) - parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM; - else - parm_map.parm_index = MODREF_UNKNOWN_PARM; - return parm_map; + if (m_summary_lto && !m_summary_lto->stores->every_base) + { + m_summary_lto->stores->collapse (); + changed = true; + } + return changed; } -/* Merge side effects of call STMT to function with CALLEE_SUMMARY - int CUR_SUMMARY. Return true if something changed. +/* Merge side effects of call STMT to function with CALLEE_SUMMARY. + Return true if something changed. If IGNORE_STORES is true, do not merge stores. If RECORD_ADJUSTMENTS is true cap number of adjustments to a given access to make dataflow finite. */ bool -merge_call_side_effects (modref_summary *cur_summary, - gimple *stmt, modref_summary *callee_summary, - bool ignore_stores, cgraph_node *callee_node, - bool record_adjustments, bool always_executed) +modref_access_analysis::merge_call_side_effects + (gimple *stmt, modref_summary *callee_summary, + cgraph_node *callee_node, bool record_adjustments) { - auto_vec parm_map; - modref_parm_map chain_map; - bool changed = false; int flags = gimple_call_flags (stmt); + /* Nothing to do for non-looping cont functions. */ if ((flags & (ECF_CONST | ECF_NOVOPS)) && !(flags & ECF_LOOPING_CONST_OR_PURE)) - return changed; + return false; + + bool changed = false; if (dump_file) fprintf (dump_file, " - Merging side effects of %s\n", callee_node->dump_name ()); + /* Merge side effects and non-determinism. + PURE/CONST flags makes functions deterministic and if there is + no LOOPING_CONST_OR_PURE they also have no side effects. */ if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE)) || (flags & ECF_LOOPING_CONST_OR_PURE)) { - if (!cur_summary->side_effects && callee_summary->side_effects) + if (!m_summary->side_effects && callee_summary->side_effects) { if (dump_file) fprintf (dump_file, " - merging side effects.\n"); - cur_summary->side_effects = true; + m_summary->side_effects = true; changed = true; } - if (!cur_summary->nondeterministic && callee_summary->nondeterministic + if (!m_summary->nondeterministic && callee_summary->nondeterministic && !ignore_nondeterminism_p (current_function_decl, flags)) { if (dump_file) fprintf (dump_file, " - merging nondeterministic.\n"); - cur_summary->nondeterministic = true; + m_summary->nondeterministic = true; changed = true; } } + /* For const functions we are done. */ if (flags & (ECF_CONST | ECF_NOVOPS)) return changed; - if (!cur_summary->calls_interposable && callee_summary->calls_interposable) + /* Merge calls_interposable flags. */ + if (!m_summary->calls_interposable && callee_summary->calls_interposable) { if (dump_file) fprintf (dump_file, " - merging calls interposable.\n"); - cur_summary->calls_interposable = true; + m_summary->calls_interposable = true; changed = true; } - /* We can not safely optimize based on summary of callee if it does - not always bind to current def: it is possible that memory load - was optimized out earlier which may not happen in the interposed - variant. */ - if (!callee_node->binds_to_current_def_p () - && !cur_summary->calls_interposable) + if (!callee_node->binds_to_current_def_p () && !m_summary->calls_interposable) { if (dump_file) fprintf (dump_file, " - May be interposed.\n"); - cur_summary->calls_interposable = true; + m_summary->calls_interposable = true; changed = true; } + /* Now merge the actual load, store and kill vectors. For this we need + to compute map translating new parameters to old. */ if (dump_file) fprintf (dump_file, " Parm map:"); + auto_vec parm_map; parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true); for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) { @@ -1081,6 +1232,8 @@ merge_call_side_effects (modref_summary *cur_summary, } } } + + modref_parm_map chain_map; if (gimple_call_chain (stmt)) { chain_map = parm_map_for_arg (gimple_call_chain (stmt)); @@ -1098,7 +1251,9 @@ merge_call_side_effects (modref_summary *cur_summary, if (dump_file) fprintf (dump_file, "\n"); - if (always_executed + /* Kills can me merged in only if we know the function is going to be + always executed. */ + if (m_always_executed && callee_summary->kills.length () && (!cfun->can_throw_non_call_exceptions || !stmt_could_throw_p (cfun, stmt))) @@ -1124,24 +1279,25 @@ merge_call_side_effects (modref_summary *cur_summary, modref_access_node n = kill; n.parm_index = m.parm_index; n.parm_offset += m.parm_offset; - if (modref_access_node::insert_kill (cur_summary->kills, n, + if (modref_access_node::insert_kill (m_summary->kills, n, record_adjustments)) changed = true; } } - /* Merge with callee's summary. */ - changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map, - &chain_map, record_adjustments); - if (!ignore_stores) + /* Merge in loads. */ + changed |= m_summary->loads->merge (callee_summary->loads, &parm_map, + &chain_map, record_adjustments); + /* Merge in stores. */ + if (!ignore_stores_p (current_function_decl, flags)) { - changed |= cur_summary->stores->merge (callee_summary->stores, - &parm_map, &chain_map, - record_adjustments); - if (!cur_summary->writes_errno + changed |= m_summary->stores->merge (callee_summary->stores, + &parm_map, &chain_map, + record_adjustments); + if (!m_summary->writes_errno && callee_summary->writes_errno) { - cur_summary->writes_errno = true; + m_summary->writes_errno = true; changed = true; } } @@ -1150,9 +1306,10 @@ merge_call_side_effects (modref_summary *cur_summary, /* Return access mode for argument I of call STMT with FNSPEC. */ -static modref_access_node -get_access_for_fnspec (gcall *call, attr_fnspec &fnspec, - unsigned int i, modref_parm_map &map) +modref_access_node +modref_access_analysis::get_access_for_fnspec (gcall *call, attr_fnspec &fnspec, + unsigned int i, + modref_parm_map &map) { tree size = NULL_TREE; unsigned int size_arg; @@ -1185,97 +1342,46 @@ get_access_for_fnspec (gcall *call, attr_fnspec &fnspec, return a; } -/* Collapse loads and return true if something changed. */ - -static bool -collapse_loads (modref_summary *cur_summary, - modref_summary_lto *cur_summary_lto) -{ - bool changed = false; - - if (cur_summary && !cur_summary->loads->every_base) - { - cur_summary->loads->collapse (); - changed = true; - } - if (cur_summary_lto - && !cur_summary_lto->loads->every_base) - { - cur_summary_lto->loads->collapse (); - changed = true; - } - return changed; -} - -/* Collapse loads and return true if something changed. */ - -static bool -collapse_stores (modref_summary *cur_summary, - modref_summary_lto *cur_summary_lto) -{ - bool changed = false; - - if (cur_summary && !cur_summary->stores->every_base) - { - cur_summary->stores->collapse (); - changed = true; - } - if (cur_summary_lto - && !cur_summary_lto->stores->every_base) - { - cur_summary_lto->stores->collapse (); - changed = true; - } - return changed; -} - - /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC. If IGNORE_STORES is true ignore them. Return false if no useful summary can be produced. */ -static bool -process_fnspec (modref_summary *cur_summary, - modref_summary_lto *cur_summary_lto, - gcall *call, bool ignore_stores) +void +modref_access_analysis::process_fnspec (gcall *call) { - attr_fnspec fnspec = gimple_call_fnspec (call); int flags = gimple_call_flags (call); + /* PURE/CONST flags makes functions deterministic and if there is + no LOOPING_CONST_OR_PURE they also have no side effects. */ if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE)) || (flags & ECF_LOOPING_CONST_OR_PURE) || (cfun->can_throw_non_call_exceptions && stmt_could_throw_p (cfun, call))) { - if (cur_summary) - { - cur_summary->side_effects = true; - if (!ignore_nondeterminism_p (current_function_decl, flags)) - cur_summary->nondeterministic = true; - } - if (cur_summary_lto) - { - cur_summary_lto->side_effects = true; - if (!ignore_nondeterminism_p (current_function_decl, flags)) - cur_summary_lto->nondeterministic = true; - } + set_side_effects (); + if (!ignore_nondeterminism_p (current_function_decl, flags)) + set_nondeterministic (); } + + /* For const functions we are done. */ if (flags & (ECF_CONST | ECF_NOVOPS)) - return true; + return; + + attr_fnspec fnspec = gimple_call_fnspec (call); + /* If there is no fnpec we know nothing about loads & stores. */ if (!fnspec.known_p ()) { if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL)) fprintf (dump_file, " Builtin with no fnspec: %s\n", IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call)))); - if (ignore_stores) - { - collapse_loads (cur_summary, cur_summary_lto); - return true; - } - return false; + record_unknown_load (); + if (!ignore_stores_p (current_function_decl, flags)) + record_unknown_store (); + return; } + /* Process fnspec. */ if (fnspec.global_memory_read_p ()) - collapse_loads (cur_summary, cur_summary_lto); + record_unknown_load (); else { for (unsigned int i = 0; i < gimple_call_num_args (call); i++) @@ -1291,27 +1397,20 @@ process_fnspec (modref_summary *cur_summary, continue; if (map.parm_index == MODREF_UNKNOWN_PARM) { - collapse_loads (cur_summary, cur_summary_lto); + record_unknown_load (); break; } - if (cur_summary) - cur_summary->loads->insert (0, 0, - get_access_for_fnspec (call, - fnspec, i, - map), - false); - if (cur_summary_lto) - cur_summary_lto->loads->insert (0, 0, - get_access_for_fnspec (call, - fnspec, i, - map), - false); + modref_access_node a = get_access_for_fnspec (call, fnspec, i, map); + if (m_summary) + m_summary->loads->insert (0, 0, a, false); + if (m_summary_lto) + m_summary_lto->loads->insert (0, 0, a, false); } } - if (ignore_stores) - return true; + if (ignore_stores_p (current_function_decl, flags)) + return; if (fnspec.global_memory_written_p ()) - collapse_stores (cur_summary, cur_summary_lto); + record_unknown_store (); else { for (unsigned int i = 0; i < gimple_call_num_args (call); i++) @@ -1327,44 +1426,35 @@ process_fnspec (modref_summary *cur_summary, continue; if (map.parm_index == MODREF_UNKNOWN_PARM) { - collapse_stores (cur_summary, cur_summary_lto); + record_unknown_store (); break; } - if (cur_summary) - cur_summary->stores->insert (0, 0, - get_access_for_fnspec (call, - fnspec, i, - map), - false); - if (cur_summary_lto) - cur_summary_lto->stores->insert (0, 0, - get_access_for_fnspec (call, - fnspec, i, - map), - false); + modref_access_node a = get_access_for_fnspec (call, fnspec, i, map); + if (m_summary) + m_summary->stores->insert (0, 0, a, false); + if (m_summary_lto) + m_summary_lto->stores->insert (0, 0, a, false); } if (fnspec.errno_maybe_written_p () && flag_errno_math) { - if (cur_summary) - cur_summary->writes_errno = true; - if (cur_summary_lto) - cur_summary_lto->writes_errno = true; + if (m_summary) + m_summary->writes_errno = true; + if (m_summary_lto) + m_summary_lto->writes_errno = true; } } - return true; } /* Analyze function call STMT in function F. Remember recursive calls in RECURSIVE_CALLS. */ -static bool -analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto, - gcall *stmt, vec *recursive_calls, - bool always_executed) +void +modref_access_analysis::analyze_call (gcall *stmt) { /* Check flags on the function call. In certain cases, analysis can be simplified. */ int flags = gimple_call_flags (stmt); + if ((flags & (ECF_CONST | ECF_NOVOPS)) && !(flags & ECF_LOOPING_CONST_OR_PURE)) { @@ -1372,13 +1462,9 @@ analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto, fprintf (dump_file, " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads " "except for args.\n"); - return true; + return; } - /* Pure functions do not affect global memory. Stores by functions which are - noreturn and do not throw can safely be ignored. */ - bool ignore_stores = ignore_stores_p (current_function_decl, flags); - /* Next, we try to get the callee's function declaration. The goal is to merge their summary with ours. */ tree callee = gimple_call_fndecl (stmt); @@ -1389,10 +1475,11 @@ analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto, if (dump_file) fprintf (dump_file, gimple_call_internal_p (stmt) ? " - Internal call" : " - Indirect call.\n"); - return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores); + process_fnspec (stmt); + return; } /* We only need to handle internal calls in IPA mode. */ - gcc_checking_assert (!cur_summary_lto); + gcc_checking_assert (!m_summary_lto && !m_ipa); struct cgraph_node *callee_node = cgraph_node::get_create (callee); @@ -1400,14 +1487,11 @@ analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto, there's nothing to do. */ if (recursive_call_p (current_function_decl, callee)) { - recursive_calls->safe_push (stmt); - if (cur_summary) - cur_summary->side_effects = true; - if (cur_summary_lto) - cur_summary_lto->side_effects = true; + m_recursive_calls.safe_push (stmt); + set_side_effects (); if (dump_file) fprintf (dump_file, " - Skipping recursive call.\n"); - return true; + return; } gcc_assert (callee_node != NULL); @@ -1419,21 +1503,18 @@ analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto, if (builtin_safe_for_const_function_p (&looping, callee)) { if (looping) - { - if (cur_summary) - cur_summary->side_effects = true; - if (cur_summary_lto) - cur_summary_lto->side_effects = true; - } + set_side_effects (); if (dump_file) - fprintf (dump_file, " - Bulitin is safe for const.\n"); - return true; + fprintf (dump_file, " - Builtin is safe for const.\n"); + return; } if (avail <= AVAIL_INTERPOSABLE) { if (dump_file) - fprintf (dump_file, " - Function availability <= AVAIL_INTERPOSABLE.\n"); - return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores); + fprintf (dump_file, + " - Function availability <= AVAIL_INTERPOSABLE.\n"); + process_fnspec (stmt); + return; } /* Get callee's modref summary. As above, if there's no summary, we either @@ -1443,31 +1524,21 @@ analyze_call (modref_summary *cur_summary, modref_summary_lto *cur_summary_lto, { if (dump_file) fprintf (dump_file, " - No modref summary available for callee.\n"); - return process_fnspec (cur_summary, cur_summary_lto, stmt, ignore_stores); + process_fnspec (stmt); + return; } - merge_call_side_effects (cur_summary, stmt, callee_summary, ignore_stores, - callee_node, false, always_executed); + merge_call_side_effects (stmt, callee_summary, callee_node, false); - return true; + return; } -/* Support analysis in non-lto and lto mode in parallel. */ - -struct summary_ptrs -{ - struct modref_summary *nolto; - struct modref_summary_lto *lto; - bool always_executed; -}; - /* Helper for analyze_stmt. */ -static bool -analyze_load (gimple *, tree, tree op, void *data) +bool +modref_access_analysis::analyze_load (gimple *, tree, tree op, void *data) { - modref_summary *summary = ((summary_ptrs *)data)->nolto; - modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto; + modref_access_analysis *t = (modref_access_analysis *)data; if (dump_file) { @@ -1476,39 +1547,26 @@ analyze_load (gimple *, tree, tree op, void *data) fprintf (dump_file, "\n"); } - if (TREE_THIS_VOLATILE (op) - || (cfun->can_throw_non_call_exceptions - && tree_could_throw_p (op))) - { - if (dump_file) - fprintf (dump_file, " (volatile or can throw; marking side effects) "); - if (summary) - summary->side_effects = summary->nondeterministic = true; - if (summary_lto) - summary_lto->side_effects = summary_lto->nondeterministic = true; - } - - if (!record_access_p (op)) + if (!t->record_access_p (op)) return false; ao_ref r; ao_ref_init (&r, op); modref_access_node a = get_access (&r); - if (summary) - record_access (summary->loads, &r, a); - if (summary_lto) - record_access_lto (summary_lto->loads, &r, a); + if (t->m_summary) + t->record_access (t->m_summary->loads, &r, a); + if (t->m_summary_lto) + t->record_access_lto (t->m_summary_lto->loads, &r, a); return false; } /* Helper for analyze_stmt. */ -static bool -analyze_store (gimple *stmt, tree, tree op, void *data) +bool +modref_access_analysis::analyze_store (gimple *stmt, tree, tree op, void *data) { - modref_summary *summary = ((summary_ptrs *)data)->nolto; - modref_summary_lto *summary_lto = ((summary_ptrs *)data)->lto; + modref_access_analysis *t = (modref_access_analysis *)data; if (dump_file) { @@ -1517,40 +1575,28 @@ analyze_store (gimple *stmt, tree, tree op, void *data) fprintf (dump_file, "\n"); } - if (TREE_THIS_VOLATILE (op) - || (cfun->can_throw_non_call_exceptions - && tree_could_throw_p (op))) - { - if (dump_file) - fprintf (dump_file, " (volatile or can throw; marking side effects) "); - if (summary) - summary->side_effects = summary->nondeterministic = true; - if (summary_lto) - summary_lto->side_effects = summary_lto->nondeterministic = true; - } - - if (!record_access_p (op)) + if (!t->record_access_p (op)) return false; ao_ref r; ao_ref_init (&r, op); modref_access_node a = get_access (&r); - if (summary) - record_access (summary->stores, &r, a); - if (summary_lto) - record_access_lto (summary_lto->stores, &r, a); - if (((summary_ptrs *)data)->always_executed + if (t->m_summary) + t->record_access (t->m_summary->stores, &r, a); + if (t->m_summary_lto) + t->record_access_lto (t->m_summary_lto->stores, &r, a); + if (t->m_always_executed && a.useful_for_kill_p () && (!cfun->can_throw_non_call_exceptions || !stmt_could_throw_p (cfun, stmt))) { if (dump_file) fprintf (dump_file, " - Recording kill\n"); - if (summary) - modref_access_node::insert_kill (summary->kills, a, false); - if (summary_lto) - modref_access_node::insert_kill (summary_lto->kills, a, false); + if (t->m_summary) + modref_access_node::insert_kill (t->m_summary->kills, a, false); + if (t->m_summary_lto) + modref_access_node::insert_kill (t->m_summary_lto->kills, a, false); } return false; } @@ -1558,16 +1604,15 @@ analyze_store (gimple *stmt, tree, tree op, void *data) /* Analyze statement STMT of function F. If IPA is true do not merge in side effects of calls. */ -static bool -analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto, - gimple *stmt, bool ipa, vec *recursive_calls, - bool always_executed) +void +modref_access_analysis::analyze_stmt (gimple *stmt, bool always_executed) { + m_always_executed = always_executed; /* In general we can not ignore clobbers because they are barriers for code motion, however after inlining it is safe to do because local optimization passes do not consider clobbers from other functions. Similar logic is in ipa-pure-const.c. */ - if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt)) + if ((m_ipa || cfun->after_inlining) && gimple_clobber_p (stmt)) { if (always_executed && record_access_p (gimple_assign_lhs (stmt))) { @@ -1578,104 +1623,145 @@ analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto, { if (dump_file) fprintf (dump_file, " - Recording kill\n"); - if (summary) - modref_access_node::insert_kill (summary->kills, a, false); - if (summary_lto) - modref_access_node::insert_kill (summary_lto->kills, a, false); + if (m_summary) + modref_access_node::insert_kill (m_summary->kills, a, false); + if (m_summary_lto) + modref_access_node::insert_kill (m_summary_lto->kills, + a, false); } } - return true; + return; } - struct summary_ptrs sums = {summary, summary_lto, always_executed}; - /* Analyze all loads and stores in STMT. */ - walk_stmt_load_store_ops (stmt, &sums, + walk_stmt_load_store_ops (stmt, this, analyze_load, analyze_store); switch (gimple_code (stmt)) { case GIMPLE_ASM: if (gimple_asm_volatile_p (as_a (stmt))) - { - if (summary) - summary->side_effects = summary->nondeterministic = true; - if (summary_lto) - summary_lto->side_effects = summary_lto->nondeterministic = true; - } + set_nondeterministic (); if (cfun->can_throw_non_call_exceptions && stmt_could_throw_p (cfun, stmt)) - { - if (summary) - summary->side_effects = true; - if (summary_lto) - summary_lto->side_effects = true; - } + set_side_effects (); /* If the ASM statement does not read nor write memory, there's nothing to do. Otherwise just give up. */ if (!gimple_asm_clobbers_memory_p (as_a (stmt))) - return true; + return; if (dump_file) fprintf (dump_file, " - Function contains GIMPLE_ASM statement " "which clobbers memory.\n"); - return false; + record_unknown_load (); + record_unknown_store (); + return; case GIMPLE_CALL: - if (!ipa || gimple_call_internal_p (stmt)) - return analyze_call (summary, summary_lto, - as_a (stmt), recursive_calls, - always_executed); + if (!m_ipa || gimple_call_internal_p (stmt)) + analyze_call (as_a (stmt)); else - { - attr_fnspec fnspec = gimple_call_fnspec (as_a (stmt)); - - if (fnspec.known_p () - && (!fnspec.global_memory_read_p () - || !fnspec.global_memory_written_p ())) - { - cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt); - if (e->callee) - { - fnspec_summaries->get_create (e)->fnspec = xstrdup (fnspec.get_str ()); - if (dump_file) - fprintf (dump_file, " Recorded fnspec %s\n", fnspec.get_str ()); - } - } - } - return true; + { + attr_fnspec fnspec = gimple_call_fnspec (as_a (stmt)); + + if (fnspec.known_p () + && (!fnspec.global_memory_read_p () + || !fnspec.global_memory_written_p ())) + { + cgraph_edge *e = cgraph_node::get + (current_function_decl)->get_edge (stmt); + if (e->callee) + { + fnspec_summaries->get_create (e)->fnspec + = xstrdup (fnspec.get_str ()); + if (dump_file) + fprintf (dump_file, " Recorded fnspec %s\n", + fnspec.get_str ()); + } + } + } + return; default: if (cfun->can_throw_non_call_exceptions && stmt_could_throw_p (cfun, stmt)) - { - if (summary) - summary->side_effects = true; - if (summary_lto) - summary_lto->side_effects = true; - } - return true; + set_side_effects (); + return; } } -/* Remove summary of current function because during the function body - scan we determined it is not useful. LTO, NOLTO and IPA determines the - mode of scan. */ +/* Propagate load/stres acress recursive calls. */ -static void -remove_summary (bool lto, bool nolto, bool ipa) +void +modref_access_analysis::propagate () { + if (m_ipa && m_summary) + return; + + bool changed = true; + bool first = true; cgraph_node *fnode = cgraph_node::get (current_function_decl); - if (!ipa) - optimization_summaries->remove (fnode); - else + + m_always_executed = false; + while (changed && m_summary->useful_p (m_ecf_flags, false)) { - if (nolto) - summaries->remove (fnode); - if (lto) - summaries_lto->remove (fnode); - remove_modref_edge_summaries (fnode); + changed = false; + for (unsigned i = 0; i < m_recursive_calls.length (); i++) + { + changed |= merge_call_side_effects (m_recursive_calls[i], m_summary, + fnode, !first); + } + first = false; + } +} + +/* Analyze function. */ + +void +modref_access_analysis::analyze () +{ + m_ecf_flags = flags_from_decl_or_type (current_function_decl); + bool summary_useful = true; + + /* Analyze each statement in each basic block of the function. If the + statement cannot be analyzed (for any reason), the entire function cannot + be analyzed by modref. */ + basic_block bb; + FOR_EACH_BB_FN (bb, cfun) + { + gimple_stmt_iterator si; + bool always_executed + = bb == single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))->dest; + + for (si = gsi_start_nondebug_after_labels_bb (bb); + !gsi_end_p (si); gsi_next_nondebug (&si)) + { + analyze_stmt (gsi_stmt (si), always_executed); + + /* Avoid doing useles work. */ + if ((!m_summary || !m_summary->useful_p (m_ecf_flags, false)) + && (!m_summary_lto + || !m_summary_lto->useful_p (m_ecf_flags, false))) + { + summary_useful = false; + break; + } + if (always_executed + && stmt_can_throw_external (cfun, gsi_stmt (si))) + always_executed = false; + } + if (!summary_useful) + break; + } + /* In non-IPA mode we need to perform iterative datafow on recursive calls. + This needs to be done after all other side effects are computed. */ + if (summary_useful) + { + if (!m_ipa) + propagate (); + if (m_summary && !m_summary->side_effects && !finite_function_p ()) + m_summary->side_effects = true; + if (m_summary_lto && !m_summary_lto->side_effects + && !finite_function_p ()) + m_summary_lto->side_effects = true; } - if (dump_file) - fprintf (dump_file, - " - modref done with result: not tracked.\n"); } /* Return true if OP accesses memory pointed to by SSA_NAME. */ @@ -1730,7 +1816,8 @@ deref_flags (int flags, bool ignore_stores) } -/* Description of an escape point. */ +/* Description of an escape point: a call which affects flags of a given + SSA name. */ struct escape_point { @@ -1745,6 +1832,10 @@ struct escape_point bool direct; }; +/* Lattice used during the eaf flags analsysis dataflow. For a given SSA name + we aim to compute its flags and escape points. We also use the lattice + to dynamically build dataflow graph to propagate on. */ + class modref_lattice { public: @@ -2967,69 +3058,10 @@ analyze_function (function *f, bool ipa) analyze_parms (summary, summary_lto, ipa, past_flags, past_retslot_flags, past_static_chain_flags); - int ecf_flags = flags_from_decl_or_type (current_function_decl); - auto_vec recursive_calls; - - /* Analyze each statement in each basic block of the function. If the - statement cannot be analyzed (for any reason), the entire function cannot - be analyzed by modref. */ - basic_block bb; - FOR_EACH_BB_FN (bb, f) - { - gimple_stmt_iterator si; - bool always_executed - = bb == single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))->dest; - - for (si = gsi_start_nondebug_after_labels_bb (bb); - !gsi_end_p (si); gsi_next_nondebug (&si)) - { - if (!analyze_stmt (summary, summary_lto, - gsi_stmt (si), ipa, &recursive_calls, - always_executed) - || ((!summary || !summary->useful_p (ecf_flags, false)) - && (!summary_lto - || !summary_lto->useful_p (ecf_flags, false)))) - { - collapse_loads (summary, summary_lto); - collapse_stores (summary, summary_lto); - break; - } - if (always_executed - && stmt_can_throw_external (cfun, gsi_stmt (si))) - always_executed = false; - } - } - - /* In non-IPA mode we need to perform iterative datafow on recursive calls. - This needs to be done after all other side effects are computed. */ - if (!ipa) - { - bool changed = true; - bool first = true; - while (changed) - { - changed = false; - for (unsigned i = 0; i < recursive_calls.length (); i++) - { - changed |= merge_call_side_effects - (summary, recursive_calls[i], summary, - ignore_stores_p (current_function_decl, - gimple_call_flags - (recursive_calls[i])), - fnode, !first, false); - if (!summary->useful_p (ecf_flags, false)) - { - remove_summary (lto, nolto, ipa); - return false; - } - } - first = false; - } - } - if (summary && !summary->side_effects && !finite_function_p ()) - summary->side_effects = true; - if (summary_lto && !summary_lto->side_effects && !finite_function_p ()) - summary_lto->side_effects = true; + { + modref_access_analysis analyzer (ipa, summary, summary_lto); + analyzer.analyze (); + } if (!ipa && flag_ipa_pure_const) { @@ -3045,6 +3077,7 @@ analyze_function (function *f, bool ipa) summary->side_effects, true); } } + int ecf_flags = flags_from_decl_or_type (current_function_decl); if (summary && !summary->useful_p (ecf_flags)) { if (!ipa) @@ -4261,6 +4294,49 @@ get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec, return a; } + /* Collapse loads and return true if something changed. */ +static bool +collapse_loads (modref_summary *cur_summary, + modref_summary_lto *cur_summary_lto) +{ + bool changed = false; + + if (cur_summary && !cur_summary->loads->every_base) + { + cur_summary->loads->collapse (); + changed = true; + } + if (cur_summary_lto + && !cur_summary_lto->loads->every_base) + { + cur_summary_lto->loads->collapse (); + changed = true; + } + return changed; +} + +/* Collapse loads and return true if something changed. */ + +static bool +collapse_stores (modref_summary *cur_summary, + modref_summary_lto *cur_summary_lto) +{ + bool changed = false; + + if (cur_summary && !cur_summary->stores->every_base) + { + cur_summary->stores->collapse (); + changed = true; + } + if (cur_summary_lto + && !cur_summary_lto->stores->every_base) + { + cur_summary_lto->stores->collapse (); + changed = true; + } + return changed; +} + /* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and CUR_SUMMARY_LTO accordingly. Return true if something changed. */ -- cgit v1.1 From c8260767aa3b41017b075d8fde3a4065fa637db7 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sun, 21 Nov 2021 16:13:40 +0100 Subject: Fix failure merge_block.c testcase gcc/testsuite/ChangeLog: 2021-11-21 Jan Hubicka PR ipa/103264 * gcc.dg/tree-prof/merge_block.c: Add -fno-ipa-modref --- gcc/testsuite/gcc.dg/tree-prof/merge_block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-prof/merge_block.c b/gcc/testsuite/gcc.dg/tree-prof/merge_block.c index 5da5ddf..e8a8873 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/merge_block.c +++ b/gcc/testsuite/gcc.dg/tree-prof/merge_block.c @@ -1,5 +1,5 @@ -/* { dg-options "-O2 -fno-ipa-pure-const -fdump-tree-optimized-blocks-details -fno-early-inlining" } */ +/* { dg-options "-O2 -fno-ipa-pure-const -fdump-tree-optimized-blocks-details -fno-early-inlining -fno-ipa-modref" } */ int a[8]; int t() { -- cgit v1.1 From 0f5afb626381d19bfced30bc19cf3b03867fa6f5 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sun, 21 Nov 2021 16:15:41 +0100 Subject: Improve base tracking in ipa-modref on exchange2 benchamrk we miss some useful propagation because modref gives up very early on analyzing accesses through pointers. For example in int test (int *a) { int i; for (i=0; a[i];i++); return i+a[i]; } We are not able to determine that a[i] accesses are relative to a. This is because get_access requires the SSA name that is in MEM_REF to be PARM_DECL while on other places we use ipa-prop helper to work out the proper base pointers. This patch commonizes the code in get_access and parm_map_for_arg so both use the check properly and extends it to also figure out that newly allocated memory is not a side effect to caller. gcc/ChangeLog: 2021-11-21 Jan Hubicka PR ipa/103227 * ipa-modref.c (parm_map_for_arg): Rename to ... (parm_map_for_ptr): .. this one; handle static chain and calls to malloc functions. (modref_access_analysis::get_access): Use parm_map_for_ptr. (modref_access_analysis::process_fnspec): Update. (modref_access_analysis::analyze_load): Update. (modref_access_analysis::analyze_store): Update. gcc/testsuite/ChangeLog: 2021-11-21 Jan Hubicka PR ipa/103227 * gcc.dg/tree-ssa/modref-15.c: New test. --- gcc/ipa-modref.c | 71 +++++++++++++++---------------- gcc/testsuite/gcc.dg/tree-ssa/modref-15.c | 9 ++++ 2 files changed, 44 insertions(+), 36 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/modref-15.c (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index a04e585..4f93231 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -812,14 +812,15 @@ ignore_stores_p (tree caller, int flags) return false; } -/* Determine parm_map for argument OP. */ +/* Determine parm_map for PTR which is supposed to be a pointer. */ modref_parm_map -parm_map_for_arg (tree op) +parm_map_for_ptr (tree op) { bool offset_known; poly_int64 offset; struct modref_parm_map parm_map; + gcall *call; parm_map.parm_offset_known = false; parm_map.parm_offset = 0; @@ -830,22 +831,26 @@ parm_map_for_arg (tree op) && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL) { int index = 0; - for (tree t = DECL_ARGUMENTS (current_function_decl); - t != SSA_NAME_VAR (op); t = DECL_CHAIN (t)) - { - if (!t) - { - index = MODREF_UNKNOWN_PARM; - break; - } + + if (cfun->static_chain_decl + && op == ssa_default_def (cfun, cfun->static_chain_decl)) + index = MODREF_STATIC_CHAIN_PARM; + else + for (tree t = DECL_ARGUMENTS (current_function_decl); + t != SSA_NAME_VAR (op); t = DECL_CHAIN (t)) index++; - } parm_map.parm_index = index; parm_map.parm_offset_known = offset_known; parm_map.parm_offset = offset; } else if (points_to_local_or_readonly_memory_p (op)) parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM; + /* Memory allocated in the function is not visible to caller before the + call and thus we do not need to record it as load/stores/kills. */ + else if (TREE_CODE (op) == SSA_NAME + && (call = dyn_cast(SSA_NAME_DEF_STMT (op))) != NULL + && gimple_call_flags (call) & ECF_MALLOC) + parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM; else parm_map.parm_index = MODREF_UNKNOWN_PARM; return parm_map; @@ -955,33 +960,19 @@ modref_access_analysis::get_access (ao_ref *ref) if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF) { tree memref = base; - base = TREE_OPERAND (base, 0); - - if (TREE_CODE (base) == SSA_NAME - && SSA_NAME_IS_DEFAULT_DEF (base) - && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL) - { - a.parm_index = 0; - if (cfun->static_chain_decl - && base == ssa_default_def (cfun, cfun->static_chain_decl)) - a.parm_index = MODREF_STATIC_CHAIN_PARM; - else - for (tree t = DECL_ARGUMENTS (current_function_decl); - t != SSA_NAME_VAR (base); t = DECL_CHAIN (t)) - a.parm_index++; - } - else - a.parm_index = MODREF_UNKNOWN_PARM; + modref_parm_map m = parm_map_for_ptr (TREE_OPERAND (base, 0)); - if (a.parm_index != MODREF_UNKNOWN_PARM - && TREE_CODE (memref) == MEM_REF) + a.parm_index = m.parm_index; + if (a.parm_index != MODREF_UNKNOWN_PARM && TREE_CODE (memref) == MEM_REF) { a.parm_offset_known = wi::to_poly_wide (TREE_OPERAND (memref, 1)).to_shwi (&a.parm_offset); + if (a.parm_offset_known && m.parm_offset_known) + a.parm_offset += m.parm_offset; + else + a.parm_offset_known = false; } - else - a.parm_offset_known = false; } else a.parm_index = MODREF_UNKNOWN_PARM; @@ -1220,7 +1211,7 @@ modref_access_analysis::merge_call_side_effects parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true); for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) { - parm_map[i] = parm_map_for_arg (gimple_call_arg (stmt, i)); + parm_map[i] = parm_map_for_ptr (gimple_call_arg (stmt, i)); if (dump_file) { fprintf (dump_file, " %i", parm_map[i].parm_index); @@ -1236,7 +1227,7 @@ modref_access_analysis::merge_call_side_effects modref_parm_map chain_map; if (gimple_call_chain (stmt)) { - chain_map = parm_map_for_arg (gimple_call_chain (stmt)); + chain_map = parm_map_for_ptr (gimple_call_chain (stmt)); if (dump_file) { fprintf (dump_file, "static chain %i", chain_map.parm_index); @@ -1390,7 +1381,7 @@ modref_access_analysis::process_fnspec (gcall *call) else if (!fnspec.arg_specified_p (i) || fnspec.arg_maybe_read_p (i)) { - modref_parm_map map = parm_map_for_arg + modref_parm_map map = parm_map_for_ptr (gimple_call_arg (call, i)); if (map.parm_index == MODREF_LOCAL_MEMORY_PARM) @@ -1401,6 +1392,8 @@ modref_access_analysis::process_fnspec (gcall *call) break; } modref_access_node a = get_access_for_fnspec (call, fnspec, i, map); + if (a.parm_index == MODREF_LOCAL_MEMORY_PARM) + continue; if (m_summary) m_summary->loads->insert (0, 0, a, false); if (m_summary_lto) @@ -1419,7 +1412,7 @@ modref_access_analysis::process_fnspec (gcall *call) else if (!fnspec.arg_specified_p (i) || fnspec.arg_maybe_written_p (i)) { - modref_parm_map map = parm_map_for_arg + modref_parm_map map = parm_map_for_ptr (gimple_call_arg (call, i)); if (map.parm_index == MODREF_LOCAL_MEMORY_PARM) @@ -1430,6 +1423,8 @@ modref_access_analysis::process_fnspec (gcall *call) break; } modref_access_node a = get_access_for_fnspec (call, fnspec, i, map); + if (a.parm_index == MODREF_LOCAL_MEMORY_PARM) + continue; if (m_summary) m_summary->stores->insert (0, 0, a, false); if (m_summary_lto) @@ -1553,6 +1548,8 @@ modref_access_analysis::analyze_load (gimple *, tree, tree op, void *data) ao_ref r; ao_ref_init (&r, op); modref_access_node a = get_access (&r); + if (a.parm_index == MODREF_LOCAL_MEMORY_PARM) + return false; if (t->m_summary) t->record_access (t->m_summary->loads, &r, a); @@ -1581,6 +1578,8 @@ modref_access_analysis::analyze_store (gimple *stmt, tree, tree op, void *data) ao_ref r; ao_ref_init (&r, op); modref_access_node a = get_access (&r); + if (a.parm_index == MODREF_LOCAL_MEMORY_PARM) + return false; if (t->m_summary) t->record_access (t->m_summary->stores, &r, a); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-15.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-15.c new file mode 100644 index 0000000..06881f2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-15.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-modref1" } */ +int test (int *a) +{ + int i; + for (i=0; a[i];i++); + return i+a[i]; +} +/* { dg-final { scan-tree-dump "access: Parm 0" "modref1"} } */ -- cgit v1.1 From 8fef6f720a5a0a056abfa986ba870bb406ab4716 Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Sun, 21 Nov 2021 19:29:27 +0100 Subject: Fortran: fix lookup for gfortran builtin math intrinsics used by DEC extensions gcc/fortran/ChangeLog: PR fortran/99061 * trans-intrinsic.c (gfc_lookup_intrinsic): Helper function for looking up gfortran builtin intrinsics. (gfc_conv_intrinsic_atrigd): Use it. (gfc_conv_intrinsic_cotan): Likewise. (gfc_conv_intrinsic_cotand): Likewise. (gfc_conv_intrinsic_atan2d): Likewise. gcc/testsuite/ChangeLog: PR fortran/99061 * gfortran.dg/dec_math_5.f90: New test. Co-authored-by: Steven G. Kargl --- gcc/fortran/trans-intrinsic.c | 66 +++++++++++--------- gcc/testsuite/gfortran.dg/dec_math_5.f90 | 104 +++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 31 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/dec_math_5.f90 (limited to 'gcc') diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index c1b51f4..909821d 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -4555,6 +4555,18 @@ rad2deg (int kind) } +static gfc_intrinsic_map_t * +gfc_lookup_intrinsic (gfc_isym_id id) +{ + gfc_intrinsic_map_t *m = gfc_intrinsic_map; + for (; m->id != GFC_ISYM_NONE || m->double_built_in != END_BUILTINS; m++) + if (id == m->id) + break; + gcc_assert (id == m->id); + return m; +} + + /* ACOSD(x) is translated into ACOS(x) * 180 / pi. ASIND(x) is translated into ASIN(x) * 180 / pi. ATAND(x) is translated into ATAN(x) * 180 / pi. */ @@ -4565,20 +4577,27 @@ gfc_conv_intrinsic_atrigd (gfc_se * se, gfc_expr * expr, gfc_isym_id id) tree arg; tree atrigd; tree type; + gfc_intrinsic_map_t *m; type = gfc_typenode_for_spec (&expr->ts); gfc_conv_intrinsic_function_args (se, expr, &arg, 1); - if (id == GFC_ISYM_ACOSD) - atrigd = gfc_builtin_decl_for_float_kind (BUILT_IN_ACOS, expr->ts.kind); - else if (id == GFC_ISYM_ASIND) - atrigd = gfc_builtin_decl_for_float_kind (BUILT_IN_ASIN, expr->ts.kind); - else if (id == GFC_ISYM_ATAND) - atrigd = gfc_builtin_decl_for_float_kind (BUILT_IN_ATAN, expr->ts.kind); - else - gcc_unreachable (); - + switch (id) + { + case GFC_ISYM_ACOSD: + m = gfc_lookup_intrinsic (GFC_ISYM_ACOS); + break; + case GFC_ISYM_ASIND: + m = gfc_lookup_intrinsic (GFC_ISYM_ASIN); + break; + case GFC_ISYM_ATAND: + m = gfc_lookup_intrinsic (GFC_ISYM_ATAN); + break; + default: + gcc_unreachable (); + } + atrigd = gfc_get_intrinsic_lib_fndecl (m, expr); atrigd = build_call_expr_loc (input_location, atrigd, 1, arg); se->expr = fold_build2_loc (input_location, MULT_EXPR, type, atrigd, @@ -4614,13 +4633,9 @@ gfc_conv_intrinsic_cotan (gfc_se *se, gfc_expr *expr) mpfr_clear (pio2); /* Find tan builtin function. */ - m = gfc_intrinsic_map; - for (; m->id != GFC_ISYM_NONE || m->double_built_in != END_BUILTINS; m++) - if (GFC_ISYM_TAN == m->id) - break; - - tmp = fold_build2_loc (input_location, PLUS_EXPR, type, arg, tmp); + m = gfc_lookup_intrinsic (GFC_ISYM_TAN); tan = gfc_get_intrinsic_lib_fndecl (m, expr); + tmp = fold_build2_loc (input_location, PLUS_EXPR, type, arg, tmp); tan = build_call_expr_loc (input_location, tan, 1, tmp); se->expr = fold_build1_loc (input_location, NEGATE_EXPR, type, tan); } @@ -4630,20 +4645,12 @@ gfc_conv_intrinsic_cotan (gfc_se *se, gfc_expr *expr) tree cos; /* Find cos builtin function. */ - m = gfc_intrinsic_map; - for (; m->id != GFC_ISYM_NONE || m->double_built_in != END_BUILTINS; m++) - if (GFC_ISYM_COS == m->id) - break; - + m = gfc_lookup_intrinsic (GFC_ISYM_COS); cos = gfc_get_intrinsic_lib_fndecl (m, expr); cos = build_call_expr_loc (input_location, cos, 1, arg); /* Find sin builtin function. */ - m = gfc_intrinsic_map; - for (; m->id != GFC_ISYM_NONE || m->double_built_in != END_BUILTINS; m++) - if (GFC_ISYM_SIN == m->id) - break; - + m = gfc_lookup_intrinsic (GFC_ISYM_SIN); sin = gfc_get_intrinsic_lib_fndecl (m, expr); sin = build_call_expr_loc (input_location, sin, 1, arg); @@ -4675,11 +4682,7 @@ gfc_conv_intrinsic_cotand (gfc_se *se, gfc_expr *expr) mpfr_clear (ninety); /* Find tand. */ - gfc_intrinsic_map_t *m = gfc_intrinsic_map; - for (; m->id != GFC_ISYM_NONE || m->double_built_in != END_BUILTINS; m++) - if (GFC_ISYM_TAND == m->id) - break; - + gfc_intrinsic_map_t *m = gfc_lookup_intrinsic (GFC_ISYM_TAND); tree tand = gfc_get_intrinsic_lib_fndecl (m, expr); tand = build_call_expr_loc (input_location, tand, 1, arg); @@ -4699,7 +4702,8 @@ gfc_conv_intrinsic_atan2d (gfc_se *se, gfc_expr *expr) gfc_conv_intrinsic_function_args (se, expr, args, 2); type = TREE_TYPE (args[0]); - atan2d = gfc_builtin_decl_for_float_kind (BUILT_IN_ATAN2, expr->ts.kind); + gfc_intrinsic_map_t *m = gfc_lookup_intrinsic (GFC_ISYM_ATAN2); + atan2d = gfc_get_intrinsic_lib_fndecl (m, expr); atan2d = build_call_expr_loc (input_location, atan2d, 2, args[0], args[1]); se->expr = fold_build2_loc (input_location, MULT_EXPR, type, atan2d, diff --git a/gcc/testsuite/gfortran.dg/dec_math_5.f90 b/gcc/testsuite/gfortran.dg/dec_math_5.f90 new file mode 100644 index 0000000..dee2de4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/dec_math_5.f90 @@ -0,0 +1,104 @@ +! { dg-do run } +! { dg-additional-options "-std=gnu" } +! { dg-require-effective-target fortran_real_10 } +! { dg-require-effective-target fortran_real_16 } + +program p + implicit none + integer, parameter :: ep = selected_real_kind (17) ! real(10) + real(4) :: a1, e1 = 1.e-5 + real(8) :: b1, e2 = 1.e-14 + real(ep) :: c1, e3 = 1.e-17 + real(16) :: d1, e4 = 1.e-30 + + a1 = 1; a1 = atand(a1) + b1 = 1; b1 = atand(b1) + c1 = 1; c1 = atand(c1) + d1 = 1; d1 = atand(d1) +! print '(4(F15.11))', a1, b1, c1, d1 + if (abs(a1 - 45) > e1) stop 1 + if (abs(b1 - 45) > e2) stop 2 + if (abs(c1 - 45) > e3) stop 3 + if (abs(d1 - 45) > e4) stop 4 + + a1 = 0.5; a1 = asind(a1) + b1 = 0.5; b1 = asind(b1) + c1 = 0.5; c1 = asind(c1) + d1 = 0.5; d1 = asind(d1) + if (abs(a1 - 30) > e1) stop 5 + if (abs(b1 - 30) > e2) stop 6 + if (abs(c1 - 30) > e3) stop 7 + if (abs(d1 - 30) > e4) stop 8 + + a1 = 0.5; a1 = acosd(a1) + b1 = 0.5; b1 = acosd(b1) + c1 = 0.5; c1 = acosd(c1) + d1 = 0.5; d1 = acosd(d1) + if (abs(a1 - 60) > e1) stop 9 + if (abs(b1 - 60) > e2) stop 10 + if (abs(c1 - 60) > e3) stop 11 + if (abs(d1 - 60) > e4) stop 12 + + a1 = 45; a1 = tand(a1) + b1 = 45; b1 = tand(b1) + c1 = 45; c1 = tand(c1) + d1 = 45; d1 = tand(d1) + if (abs(a1 - 1) > e1) stop 13 + if (abs(b1 - 1) > e2) stop 14 + if (abs(c1 - 1) > e3) stop 15 + if (abs(d1 - 1) > e4) stop 16 + + a1 = 60; a1 = tand(a1) + b1 = 60; b1 = tand(b1) + c1 = 60; c1 = tand(c1) + d1 = 60; d1 = tand(d1) + if (abs(a1 - sqrt (3._4) ) > e1) stop 17 + if (abs(b1 - sqrt (3._8) ) > e2) stop 18 + if (abs(c1 - sqrt (3._ep)) > e3) stop 19 + if (abs(d1 - sqrt (3._16)) > e4) stop 20 + + a1 = 45; a1 = cotand(a1) + b1 = 45; b1 = cotand(b1) + c1 = 45; c1 = cotand(c1) + d1 = 45; d1 = cotand(d1) + if (abs(a1 - 1) > e1) stop 21 + if (abs(b1 - 1) > e2) stop 22 + if (abs(c1 - 1) > e3) stop 23 + if (abs(d1 - 1) > e4) stop 24 + + a1 = 30; a1 = cotand(a1) + b1 = 30; b1 = cotand(b1) + c1 = 30; c1 = cotand(c1) + d1 = 30; d1 = cotand(d1) + if (abs(a1 - sqrt (3._4) ) > e1) stop 25 + if (abs(b1 - sqrt (3._8) ) > e2) stop 26 + if (abs(c1 - sqrt (3._ep)) > e3) stop 27 + if (abs(d1 - sqrt (3._16)) > e4) stop 28 + + a1 = 1; a1 = atan2d(a1, a1) + b1 = 1; b1 = atan2d(b1, b1) + c1 = 1; c1 = atan2d(c1, c1) + d1 = 1; d1 = atan2d(d1, d1) + if (abs(a1 - 45) > e1) stop 29 + if (abs(b1 - 45) > e2) stop 30 + if (abs(c1 - 45) > e3) stop 31 + if (abs(d1 - 45) > e4) stop 32 + + a1 = 30; a1 = sind(a1) + b1 = 30; b1 = sind(b1) + c1 = 30; c1 = sind(c1) + d1 = 30; d1 = sind(d1) + if (abs(a1 - 0.5) > e1) stop 33 + if (abs(b1 - 0.5) > e2) stop 34 + if (abs(c1 - 0.5) > e3) stop 35 + if (abs(d1 - 0.5) > e4) stop 36 + + a1 = 60; a1 = cosd(a1) + b1 = 60; b1 = cosd(b1) + c1 = 60; c1 = cosd(c1) + d1 = 60; d1 = cosd(d1) + if (abs(a1 - 0.5) > e1) stop 37 + if (abs(b1 - 0.5) > e2) stop 38 + if (abs(c1 - 0.5) > e3) stop 39 + if (abs(d1 - 0.5) > e4) stop 40 +end program p -- cgit v1.1 From 364539710f828851b9fac51c39033cd09aa620de Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sun, 21 Nov 2021 21:06:23 +0100 Subject: i386: Fix up handling of target attribute [PR101180] As shown in the testcase below, if a function has multiple target attributes (rather than a single one with one or more arguments) or if a function gets one target attribute on one declaration and another one on another declaration, on x86 their effect is not combined into DECL_FUNCTION_SPECIFIC_TARGET, but instead only the last processed target attribute wins. aarch64 handles this right, the following patch follows what it does, i.e. only start with target_option_default_node if DECL_FUNCTION_SPECIFIC_TARGET is previously NULL (i.e. the first target attribute being processed on a function) and otherwise start from the previous DECL_FUNCTION_SPECIFIC_TARGET. 2021-11-21 Jakub Jelinek PR c++/101180 * config/i386/i386-options.c (ix86_valid_target_attribute_p): If fndecl already has DECL_FUNCTION_SPECIFIC_TARGET, use that as base instead of target_option_default_node. * gcc.target/i386/pr101180.c: New test. --- gcc/config/i386/i386-options.c | 5 ++++- gcc/testsuite/gcc.target/i386/pr101180.c | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr101180.c (limited to 'gcc') diff --git a/gcc/config/i386/i386-options.c b/gcc/config/i386/i386-options.c index feff258..a4da833 100644 --- a/gcc/config/i386/i386-options.c +++ b/gcc/config/i386/i386-options.c @@ -1443,8 +1443,11 @@ ix86_valid_target_attribute_p (tree fndecl, /* Initialize func_options to the default before its target options can be set. */ + tree old_target = DECL_FUNCTION_SPECIFIC_TARGET (fndecl); + if (old_target == NULL_TREE) + old_target = target_option_default_node; cl_target_option_restore (&func_options, &func_options_set, - TREE_TARGET_OPTION (target_option_default_node)); + TREE_TARGET_OPTION (old_target)); /* FLAGS == 1 is used for target_clones attribute. */ new_target diff --git a/gcc/testsuite/gcc.target/i386/pr101180.c b/gcc/testsuite/gcc.target/i386/pr101180.c new file mode 100644 index 0000000..1ac4cb5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101180.c @@ -0,0 +1,12 @@ +/* PR c++/101180 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-avx -mno-crc32" } */ + +#include + +__attribute__((target ("avx"))) __attribute__((target ("crc32"))) void +foo (__m256 *p, unsigned int *q) +{ + __m256 c = _mm256_and_ps (p[0], p[1]); + *q = __crc32b (*q, 0x55); +} -- cgit v1.1 From da17c304e22ba256eba0b03710aa329115163b08 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sun, 21 Nov 2021 21:08:04 +0100 Subject: fortran, debug: Fix up DW_AT_rank [PR103315] For DW_AT_rank we were emitting .uleb128 0x4 # DW_AT_rank .byte 0x97 # DW_OP_push_object_address .byte 0x23 # DW_OP_plus_uconst .uleb128 0x1c .byte 0x6 # DW_OP_deref on 64-bit and .uleb128 0x4 # DW_AT_rank .byte 0x97 # DW_OP_push_object_address .byte 0x23 # DW_OP_plus_uconst .uleb128 0x10 .byte 0x6 # DW_OP_deref on 32-bit. I think this is wrong, as dtype.rank field in the descriptor has unsigned char type, not pointer type nor pointer sized integral. E.g. if we have a REAL :: a(..) dummy argument, which is passed as a reference to the function descriptor, we want to evaluate a->dtype.rank. The above DWARF expressions perform *(uintptr_t *)(a + 0x1c) and *(uintptr_t *)(a + 0x10) respectively. The following patch changes those to: .uleb128 0x5 # DW_AT_rank .byte 0x97 # DW_OP_push_object_address .byte 0x23 # DW_OP_plus_uconst .uleb128 0x1c .byte 0x94 # DW_OP_deref_size .byte 0x1 and .uleb128 0x5 # DW_AT_rank .byte 0x97 # DW_OP_push_object_address .byte 0x23 # DW_OP_plus_uconst .uleb128 0x10 .byte 0x94 # DW_OP_deref_size .byte 0x1 which perform *(unsigned char *)(a + 0x1c) and *(unsigned char *)(a + 0x10) respectively. 2021-11-21 Jakub Jelinek PR debug/103315 * trans-types.c (gfc_get_array_descr_info): Use DW_OP_deref_size 1 instead of DW_OP_deref for DW_AT_rank. --- gcc/fortran/trans-types.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c index e5d36d5..eec4aa6 100644 --- a/gcc/fortran/trans-types.c +++ b/gcc/fortran/trans-types.c @@ -3459,8 +3459,8 @@ gfc_get_array_descr_info (const_tree type, struct array_descr_info *info) if (!integer_zerop (dtype_off)) t = fold_build_pointer_plus (t, rank_off); - t = build1 (NOP_EXPR, build_pointer_type (gfc_array_index_type), t); - t = build1 (INDIRECT_REF, gfc_array_index_type, t); + t = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (field)), t); + t = build1 (INDIRECT_REF, TREE_TYPE (field), t); info->rank = t; t = build0 (PLACEHOLDER_EXPR, TREE_TYPE (dim_off)); t = size_binop (MULT_EXPR, t, dim_size); -- cgit v1.1 From ae957bef065848356215a127d1c3c81c39b68d6b Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Mon, 22 Nov 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/ChangeLog | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/fortran/ChangeLog | 17 +++++++++++++ gcc/testsuite/ChangeLog | 28 +++++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0100f7a..1e94c54 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,70 @@ +2021-11-21 Jakub Jelinek + + PR c++/101180 + * config/i386/i386-options.c (ix86_valid_target_attribute_p): If + fndecl already has DECL_FUNCTION_SPECIFIC_TARGET, use that as base + instead of target_option_default_node. + +2021-11-21 Jan Hubicka + + PR ipa/103227 + * ipa-modref.c (parm_map_for_arg): Rename to ... + (parm_map_for_ptr): .. this one; handle static chain and calls to + malloc functions. + (modref_access_analysis::get_access): Use parm_map_for_ptr. + (modref_access_analysis::process_fnspec): Update. + (modref_access_analysis::analyze_load): Update. + (modref_access_analysis::analyze_store): Update. + +2021-11-21 Jan Hubicka + + * ipa-modref.c (ignore_nondeterminism_p): Move earlier in source + code. + (ignore_retval_p): Likewise. + (ignore_stores_p): Likewise. + (parm_map_for_arg): Likewise. + (class modref_access_analysis): New class. + (modref_access_analysis::set_side_effects): New member function. + (modref_access_analysis::set_nondeterministic): New member function. + (get_access): Turn to ... + (modref_access_analysis::get_access): ... this one. + (record_access): Turn to ... + (modref_access_analysis::record_access): ... this one. + (record_access_lto): Turn to ... + (modref_access_analysis::record_access_lto): ... This one. + (record_access_p): Turn to ... + (modref_access_analysis::record_access_p): ... This one + (modref_access_analysis::record_unknown_load): New member function. + (modref_access_analysis::record_unknown_store): New member function. + (get_access_for_fnspec): Turn to ... + (modref_access_analysis::get_access_for_fnspec): ... this one. + (merge_call_side_effects): Turn to ... + (moderf_access_analysis::merge_call_side_effects): Turn to ... + (collapse_loads): Move later in source code. + (collapse_stores): Move later in source code. + (process_fnspec): Turn to ... + (modref_access_analysis::process_fnspec): ... this one. + (analyze_call): Turn to ... + (modref_access_analysis::analyze_call): ... this one. + (struct summary_ptrs): Remove. + (analyze_load): Turn to ... + (modref_access_analysis::analyze_load): ... this one. + (analyze_store): Turn to ... + (modref_access_analysis::analyze_store): ... this one. + (analyze_stmt): Turn to ... + (modref_access_analysis::analyze_stmt): ... This one. + (remove_summary): Remove. + (modref_access_analysis::propagate): Break out from ... + (modref_access_analysis::analyze): Break out from ... + (analyze_function): ... here. + +2021-11-21 Roger Sayle + Robin Dapp + + PR target/102117 + * tree-ssa-math-opts.c (convert_mult_to_widen): Recognize + signed WIDEN_MULT_EXPR if the target supports umul_widen_optab. + 2021-11-20 Jan Hubicka PR ipa/103052 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index ffe2a46..7e15177 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20211121 +20211122 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index de5d4de..f3c885c 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,20 @@ +2021-11-21 Jakub Jelinek + + PR debug/103315 + * trans-types.c (gfc_get_array_descr_info): Use DW_OP_deref_size 1 + instead of DW_OP_deref for DW_AT_rank. + +2021-11-21 Harald Anlauf + Steven G. Kargl + + PR fortran/99061 + * trans-intrinsic.c (gfc_lookup_intrinsic): Helper function for + looking up gfortran builtin intrinsics. + (gfc_conv_intrinsic_atrigd): Use it. + (gfc_conv_intrinsic_cotan): Likewise. + (gfc_conv_intrinsic_cotand): Likewise. + (gfc_conv_intrinsic_atan2d): Likewise. + 2021-11-18 Harald Anlauf Steven G. Kargl diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b342b71..9872619 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,31 @@ +2021-11-21 Jakub Jelinek + + PR c++/101180 + * gcc.target/i386/pr101180.c: New test. + +2021-11-21 Harald Anlauf + Steven G. Kargl + + PR fortran/99061 + * gfortran.dg/dec_math_5.f90: New test. + +2021-11-21 Jan Hubicka + + PR ipa/103227 + * gcc.dg/tree-ssa/modref-15.c: New test. + +2021-11-21 Jan Hubicka + + PR ipa/103264 + * gcc.dg/tree-prof/merge_block.c: Add -fno-ipa-modref + +2021-11-21 Roger Sayle + Robin Dapp + + PR target/102117 + * gcc.target/s390/mul-wide.c: New test case. + * gcc.target/s390/umul-wide.c: New test case. + 2021-11-20 Jan Hubicka PR ipa/103052 -- cgit v1.1 From 2b5b8610e985e23a0c2e0272339ab074a750e240 Mon Sep 17 00:00:00 2001 From: Kewen Lin Date: Sun, 21 Nov 2021 20:18:31 -0600 Subject: xtensa: Fix non-robust split condition in define_insn_and_split This patch is to fix some non-robust split conditions in some define_insn_and_splits, to make each of them applied on top of the corresponding condition for define_insn part, otherwise the splitting could perform unexpectedly. gcc/ChangeLog: * config/xtensa/xtensa.md (movdi_internal, movdf_internal): Fix split condition. --- gcc/config/xtensa/xtensa.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index cdf22f1..e0bf720 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -779,7 +779,7 @@ "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)" "#" - "reload_completed" + "&& reload_completed" [(set (match_dup 0) (match_dup 2)) (set (match_dup 1) (match_dup 3))] { @@ -1053,7 +1053,7 @@ "register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)" "#" - "reload_completed" + "&& reload_completed" [(set (match_dup 0) (match_dup 2)) (set (match_dup 1) (match_dup 3))] { -- cgit v1.1 From b5844cb0bc8c7d9be2ff1ecded249cad82b9b71c Mon Sep 17 00:00:00 2001 From: liuhongt Date: Wed, 17 Nov 2021 15:48:37 +0800 Subject: Don't allow mask/sse/mmx mov in TLS code sequences. As change in assembler, refer to [1], this patch disallow mask/sse/mmx mov in TLS code sequences which require integer MOV instructions. [1] https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=d7e3e627027fcf37d63e284144fe27ff4eba36b5 gcc/ChangeLog: PR target/103275 * config/i386/constraints.md (Bk): New define_memory_constraint. * config/i386/i386-protos.h (ix86_gpr_tls_address_pattern_p): Declare. * config/i386/i386.c (ix86_gpr_tls_address_pattern_p): New function. * config/i386/i386.md (*movsi_internal): Don't allow mask/sse/mmx move in TLS code sequences. (*movdi_internal): Ditto. gcc/testsuite/ChangeLog: * gcc.target/i386/pr103275.c: New test. --- gcc/config/i386/constraints.md | 5 ++ gcc/config/i386/i386-protos.h | 1 + gcc/config/i386/i386.c | 30 ++++++++++++ gcc/config/i386/i386.md | 8 +-- gcc/testsuite/gcc.target/i386/pr103275.c | 83 ++++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr103275.c (limited to 'gcc') diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md index 87cceac..6b291a0 100644 --- a/gcc/config/i386/constraints.md +++ b/gcc/config/i386/constraints.md @@ -186,6 +186,11 @@ (and (match_operand 0 "memory_operand") (match_test "constant_address_p (XEXP (op, 0))"))) +(define_memory_constraint "Bk" + "@internal TLS address that allows insn using non-integer registers." + (and (match_operand 0 "memory_operand") + (not (match_test "ix86_gpr_tls_address_pattern_p (op)")))) + (define_special_memory_constraint "Bn" "@internal Memory operand without REX prefix." (match_operand 0 "norex_memory_operand")) diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 7e05510..1cd2197 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -243,6 +243,7 @@ extern unsigned int ix86_get_callcvt (const_tree); #endif extern rtx ix86_tls_module_base (void); +extern bool ix86_gpr_tls_address_pattern_p (rtx); extern bool ix86_tls_address_pattern_p (rtx); extern rtx ix86_rewrite_tls_address (rtx); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 7fe271b..10bfa0e 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -11628,6 +11628,36 @@ legitimize_tls_address (rtx x, enum tls_model model, bool for_mov) return dest; } +/* Return true if the TLS address requires insn using integer registers. + It's used to prevent KMOV/VMOV in TLS code sequences which require integer + MOV instructions, refer to PR103275. */ +bool +ix86_gpr_tls_address_pattern_p (rtx mem) +{ + gcc_assert (MEM_P (mem)); + + rtx addr = XEXP (mem, 0); + subrtx_var_iterator::array_type array; + FOR_EACH_SUBRTX_VAR (iter, array, addr, ALL) + { + rtx op = *iter; + if (GET_CODE (op) == UNSPEC) + switch (XINT (op, 1)) + { + case UNSPEC_GOTNTPOFF: + return true; + case UNSPEC_TPOFF: + if (!TARGET_64BIT) + return true; + break; + default: + break; + } + } + + return false; +} + /* Return true if OP refers to a TLS address. */ bool ix86_tls_address_pattern_p (rtx op) diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 7b2de60..03d401e 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -2164,9 +2164,9 @@ (define_insn "*movdi_internal" [(set (match_operand:DI 0 "nonimmediate_operand" - "=r ,o ,r,r ,r,m ,*y,*y,?*y,?m,?r,?*y,*v,*v,*v,m ,m,?r ,?*Yd,?r,?*v,?*y,?*x,*k,*k ,*r,*m,*k") + "=r ,o ,r,r ,r,m ,*y,*y,?*y,?m,?r,?*y,*v,*v,*v,m ,m,?r ,?*Yd,?r,?*v,?*y,?*x,*k,*k ,*r,*m,*k") (match_operand:DI 1 "general_operand" - "riFo,riF,Z,rem,i,re,C ,*y,m ,*y,*y,r ,C ,*v,m ,*v,v,*Yd,r ,*v,r ,*x ,*y ,*r,*km,*k,*k,CBC"))] + "riFo,riF,Z,rem,i,re,C ,*y,Bk ,*y,*y,r ,C ,*v,Bk,*v,v,*Yd,r ,*v,r ,*x ,*y ,*r,*kBk,*k,*k,CBC"))] "!(MEM_P (operands[0]) && MEM_P (operands[1])) && ix86_hardreg_mov_ok (operands[0], operands[1])" { @@ -2385,9 +2385,9 @@ (define_insn "*movsi_internal" [(set (match_operand:SI 0 "nonimmediate_operand" - "=r,m ,*y,*y,?*y,?m,?r,?*y,*v,*v,*v,m ,?r,?*v,*k,*k ,*rm,*k") + "=r,m ,*y,*y,?*y,?m,?r,?*y,*v,*v,*v,m ,?r,?*v,*k,*k ,*rm,*k") (match_operand:SI 1 "general_operand" - "g ,re,C ,*y,m ,*y,*y,r ,C ,*v,m ,*v,*v,r ,*r,*km,*k ,CBC"))] + "g ,re,C ,*y,Bk ,*y,*y,r ,C ,*v,Bk,*v,*v,r ,*r,*kBk,*k ,CBC"))] "!(MEM_P (operands[0]) && MEM_P (operands[1])) && ix86_hardreg_mov_ok (operands[0], operands[1])" { diff --git a/gcc/testsuite/gcc.target/i386/pr103275.c b/gcc/testsuite/gcc.target/i386/pr103275.c new file mode 100644 index 0000000..c93413f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr103275.c @@ -0,0 +1,83 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -march=tigerlake -fPIC" } */ +/* { dg-final { scan-assembler-not {(?n)kmovd.*@gotntpoff} } } */ + +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; + +typedef uint32_t in_addr_t; +struct in_addr { in_addr_t s_addr; }; + +extern __thread const uint16_t * __libc_tsd_CTYPE_B __attribute__ ((tls_model ("initial-exec"))); +extern __thread int __libc_errno __attribute__ ((tls_model ("initial-exec"))); + +extern unsigned long strtoul (const char*, char**, int); +extern uint32_t __bswap_32 (in_addr_t); +int +inet_aton_end (const char *cp, struct in_addr *addr, const char **endp) +{ + static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; + in_addr_t val; + char c; + union iaddr + { + uint8_t bytes[4]; + uint32_t word; + } res; + uint8_t *pp = res.bytes; + int digit; + + int saved_errno = __libc_errno; + __libc_errno = 0; + res.word = 0; + c = *cp; + + for (;;) + { + if (c < '0' || c > '9') + goto ret_0; + { + char *endp; + unsigned long ul = strtoul (cp, &endp, 0); + if (ul == 0x7fffffffL && __libc_errno == 34) + goto ret_0; + if (ul > 0xfffffffful) + goto ret_0; + val = ul; + digit = cp != endp; + cp = endp; + } + c = *cp; + if (c == '.') + { + if (pp > res.bytes + 2 || val > 0xff) + goto ret_0; + *pp++ = val; + c = *++cp; + } + else + break; + } + + if (!(__libc_tsd_CTYPE_B[(int)c] & 8192)) + goto ret_0; + + if (!digit) + goto ret_0; + + if (val > max[pp - res.bytes]) + goto ret_0; + + if (addr != 0) + addr->s_addr = res.word | __bswap_32 (val); + *endp = cp; + + __libc_errno = saved_errno; + return 1; + + ret_0: + __libc_errno = saved_errno; + return 0; +} -- cgit v1.1 From 4b1e14346a08554dc33f71fca980578a7a3e38a2 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 22 Nov 2021 10:13:24 +0100 Subject: openmp: Handle OMP_MASKED in potential_constant_expression_1 [PR103349] WHen adding OMP_MASKED, I apparently forgot to handle it in potential_constant_expression_1, which means we can ICE on it. 2021-11-22 Jakub Jelinek PR c++/103349 * constexpr.c (potential_constant_expression_1): Punt on OMP_MASKED. * g++.dg/gomp/masked-1.C: New test. --- gcc/cp/constexpr.c | 1 + gcc/testsuite/g++.dg/gomp/masked-1.C | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 gcc/testsuite/g++.dg/gomp/masked-1.C (limited to 'gcc') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index c8f9d5f..d66a565 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -8686,6 +8686,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case OMP_SINGLE: case OMP_SECTION: case OMP_MASTER: + case OMP_MASKED: case OMP_TASKGROUP: case OMP_TARGET_UPDATE: case OMP_TARGET_ENTER_DATA: diff --git a/gcc/testsuite/g++.dg/gomp/masked-1.C b/gcc/testsuite/g++.dg/gomp/masked-1.C new file mode 100644 index 0000000..1ea4a13 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/masked-1.C @@ -0,0 +1,14 @@ +// PR c++/103349 +// { dg-do compile { target c++11 } } + +int v; + +void +foo (int x, int y) +{ + [=] () + { +#pragma omp masked + v = x + y; + } (); +} -- cgit v1.1 From f456eaf2e0fb3ceb51c641fd348429bf59d215a9 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 22 Nov 2021 11:23:55 +0100 Subject: tree-optimization/103351 - avoid compare-debug issue wrt CD-DCE change This avoids differences in the split edge of a cluster due to different order of same key PHI args when sorting by sorting after the edge destination index as second key. 2021-11-22 Richard Biener PR tree-optimization/103351 * tree-ssa-dce.c (sort_phi_args): Sort after e->dest_idx as second key. * g++.dg/torture/pr103351.C: New testcase. --- gcc/testsuite/g++.dg/torture/pr103351.C | 88 +++++++++++++++++++++++++++++++++ gcc/tree-ssa-dce.c | 4 ++ 2 files changed, 92 insertions(+) create mode 100644 gcc/testsuite/g++.dg/torture/pr103351.C (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/torture/pr103351.C b/gcc/testsuite/g++.dg/torture/pr103351.C new file mode 100644 index 0000000..d0bf721 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr103351.C @@ -0,0 +1,88 @@ +// { dg-do compile } +// { dg-additional-options "-fcompare-debug" } + +template struct __conditional; +template +using __conditional_t = typename __conditional<_Cond>::type; +template struct __is_void_helper {}; +template _Tp *__addressof(_Tp &__r) { + return __builtin_addressof(__r); +} +template _Tp *addressof(_Tp &__r) { return __addressof(__r); } +template +using __make_not_void = __conditional_t<_Tp ::value, int, _Tp>; +template struct pointer_traits; +template struct pointer_traits<_Tp *> { + typedef _Tp *pointer; + typedef _Tp element_type; + static pointer pointer_to(element_type &__r) { return addressof(__r); } +}; +namespace { +template struct new_allocator; +} +template struct allocator_traits; +template struct allocator; +template struct allocator_traits> { + using pointer = _Tp *; + using const_pointer = _Tp *; +}; +namespace __gnu_cxx { +template +struct __alloc_traits : allocator_traits> {}; +} // namespace __gnu_cxx +template struct char_traits; +template +class Trans_NS___cxx11_basic_string; +template <> struct char_traits { + typedef char char_type; + static void assign(char_type, char_type); +}; +template struct Trans_NS___cxx11_basic_string { + typedef __gnu_cxx::__alloc_traits<> _Alloc_traits; + typedef char_traits traits_type; + typedef _Alloc_traits::pointer pointer; + typedef _Alloc_traits::const_pointer const_pointer; + struct { + pointer _M_p; + } _M_dataplus; + char _M_local_buf[]; + void _M_data(pointer __p) { _M_dataplus._M_p = __p; } + bool _M_is_local() { + const_pointer __trans_tmp_5 = + pointer_traits::pointer_to(*_M_local_buf); + return _M_dataplus._M_p == __trans_tmp_5; + } + void operator=(Trans_NS___cxx11_basic_string __str) { + bool __trans_tmp_2; + if (__str._M_is_local()) { + Trans_NS___cxx11_basic_string *__trans_tmp_1; + if (__builtin_expect(__trans_tmp_1 != this, true)) + size(); + } else if (__trans_tmp_2) + __str._M_data(__str._M_local_buf); + __str.clear(); + } + void size(); + void clear() { traits_type::assign(_M_dataplus._M_p[0], char()); } +}; +template struct Pool { + template struct PoolIterator { + bool operator!=(PoolIterator); + T *operator*(); + void operator++(); + }; + template struct IterateWrapper { + PoolIterator begin(); + PoolIterator end(); + }; +}; +struct BaseConsist { + Trans_NS___cxx11_basic_string name; +}; +struct Vehicle : BaseConsist {}; +Pool::IterateWrapper __trans_tmp_4; +Trans_NS___cxx11_basic_string __trans_tmp_6; +void FixOldVehicles() { + for (Vehicle *v : __trans_tmp_4) + v->name = __trans_tmp_6; +} diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index dbf02c4..e3e6f09 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -1626,6 +1626,10 @@ sort_phi_args (const void *a_, const void *b_) return -1; else if (ha > hb) return 1; + else if (a->first->dest_idx < b->first->dest_idx) + return -1; + else if (a->first->dest_idx > b->first->dest_idx) + return 1; else return 0; } -- cgit v1.1