From 8792047470073df0da4a5b91997d6058193d7676 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Tue, 4 Oct 2022 17:03:32 +0200 Subject: OpenMP: Update invoke.texi and fix fortran/parse.cc for -fopenmp-simd Split off from the 'Fortran: Add OpenMP's assume(s) directives' patch. gcc/ * doc/invoke.texi (-fopenmp): Mention C++ attribut syntax. (-fopenmp-simd): Likewise; update permitted directives. gcc/fortran/ * parse.cc (decode_omp_directive): Handle '(end) loop' and 'scan' also with -fopenmp-simd. gcc/testsuite/ * gfortran.dg/gomp/openmp-simd-7.f90: New test. --- gcc/doc/invoke.texi | 12 ++++++++---- gcc/fortran/parse.cc | 6 +++--- gcc/testsuite/gfortran.dg/gomp/openmp-simd-7.f90 | 23 +++++++++++++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/gomp/openmp-simd-7.f90 (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index a5dc637..e0c2c57 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -2737,7 +2737,8 @@ can be omitted, to use a target-specific default value. @item -fopenmp @opindex fopenmp @cindex OpenMP parallel -Enable handling of OpenMP directives @code{#pragma omp} in C/C++ and +Enable handling of OpenMP directives @code{#pragma omp} in C/C++, +@code{[[omp::directive(...)]]} and @code{[[omp::sequence(...)]]} in C++ and @code{!$omp} in Fortran. When @option{-fopenmp} is specified, the compiler generates parallel code according to the OpenMP Application Program Interface v4.5 @w{@uref{https://www.openmp.org}}. This option @@ -2749,9 +2750,12 @@ have support for @option{-pthread}. @option{-fopenmp} implies @opindex fopenmp-simd @cindex OpenMP SIMD @cindex SIMD -Enable handling of OpenMP's SIMD directives with @code{#pragma omp} -in C/C++ and @code{!$omp} in Fortran. Other OpenMP directives -are ignored. +Enable handling of OpenMP's @code{simd}, @code{declare simd}, +@code{declare reduction}, @code{assume}, @code{ordered}, @code{scan}, +@code{loop} directives and combined or composite directives with +@code{simd} as constituent with @code{#pragma omp} in C/C++, +@code{[[omp::directive(...)]]} and @code{[[omp::sequence(...)]]} in C++ +and @code{!$omp} in Fortran. Other OpenMP directives are ignored. @item -fpermitted-flt-eval-methods=@var{style} @opindex fpermitted-flt-eval-methods diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc index 5b13441..2e2e977 100644 --- a/gcc/fortran/parse.cc +++ b/gcc/fortran/parse.cc @@ -924,7 +924,7 @@ decode_omp_directive (void) matcho ("end distribute", gfc_match_omp_eos_error, ST_OMP_END_DISTRIBUTE); matchs ("end do simd", gfc_match_omp_end_nowait, ST_OMP_END_DO_SIMD); matcho ("end do", gfc_match_omp_end_nowait, ST_OMP_END_DO); - matcho ("end loop", gfc_match_omp_eos_error, ST_OMP_END_LOOP); + matchs ("end loop", gfc_match_omp_eos_error, ST_OMP_END_LOOP); matchs ("end simd", gfc_match_omp_eos_error, ST_OMP_END_SIMD); matcho ("end masked taskloop simd", gfc_match_omp_eos_error, ST_OMP_END_MASKED_TASKLOOP_SIMD); @@ -1023,7 +1023,7 @@ decode_omp_directive (void) matcho ("nothing", gfc_match_omp_nothing, ST_NONE); break; case 'l': - matcho ("loop", gfc_match_omp_loop, ST_OMP_LOOP); + matchs ("loop", gfc_match_omp_loop, ST_OMP_LOOP); break; case 'o': if (gfc_match ("ordered depend (") == MATCH_YES @@ -1070,7 +1070,7 @@ decode_omp_directive (void) matcho ("requires", gfc_match_omp_requires, ST_OMP_REQUIRES); break; case 's': - matcho ("scan", gfc_match_omp_scan, ST_OMP_SCAN); + matchs ("scan", gfc_match_omp_scan, ST_OMP_SCAN); matcho ("scope", gfc_match_omp_scope, ST_OMP_SCOPE); matcho ("sections", gfc_match_omp_sections, ST_OMP_SECTIONS); matcho ("section", gfc_match_omp_eos_error, ST_OMP_SECTION); diff --git a/gcc/testsuite/gfortran.dg/gomp/openmp-simd-7.f90 b/gcc/testsuite/gfortran.dg/gomp/openmp-simd-7.f90 new file mode 100644 index 0000000..d7010bb --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/openmp-simd-7.f90 @@ -0,0 +1,23 @@ +! { dg-options "-fno-openmp -fopenmp-simd -fdump-tree-original" } + +subroutine foo (a, b) + integer, contiguous :: a(:), b(:) + integer :: i + !$omp simd reduction (inscan, +:r) + do i = 1, 1024 + r = r + a(i) + !$omp scan inclusive(r) + b(i) = r + end do + !$omp end simd + + !$omp loop + do i = 1, 1024 + a(i) = a(i) + i + end do + !$omp end loop +end + +! { dg-final { scan-tree-dump "#pragma omp simd linear\\(i:1\\) reduction\\(inscan,\\+:r\\)" "original" } } +! { dg-final { scan-tree-dump "#pragma omp scan inclusive\\(r\\)" "original" } } +! { dg-final { scan-tree-dump "#pragma omp loop" "original" } } -- cgit v1.1 From c1b0a767f04a8ccbaff2a7b71d5c817cdb469630 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 4 Oct 2022 16:39:18 +0100 Subject: aarch64: Define __ARM_FEATURE_RCPC https://github.com/ARM-software/acle/pull/199 adds a new feature macro for RCPC, for use in things like inline assembly. This patch adds the associated support to GCC. Also, RCPC is required for Armv8.3-A and later, but the armv8.3-a entry didn't include it. This was probably harmless in practice since GCC simply ignored the extension until now. (The GAS definition is OK.) gcc/ * config/aarch64/aarch64.h (AARCH64_ISA_RCPC): New macro. * config/aarch64/aarch64-arches.def (armv8.3-a): Include RCPC. * config/aarch64/aarch64-cores.def (thunderx3t110, zeus, neoverse-v1) (neoverse-512tvb, saphira): Remove RCPC from these Armv8.3-A+ cores. * config/aarch64/aarch64-c.cc (aarch64_update_cpp_builtins): Define __ARM_FEATURE_RCPC when appropriate. gcc/testsuite/ * gcc.target/aarch64/pragma_cpp_predefs_1.c: Add RCPC tests. --- gcc/config/aarch64/aarch64-arches.def | 2 +- gcc/config/aarch64/aarch64-c.cc | 1 + gcc/config/aarch64/aarch64-cores.def | 10 +++++----- gcc/config/aarch64/aarch64.h | 1 + .../gcc.target/aarch64/pragma_cpp_predefs_1.c | 20 ++++++++++++++++++++ 5 files changed, 28 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-arches.def b/gcc/config/aarch64/aarch64-arches.def index 9f82466..5a9eff3 100644 --- a/gcc/config/aarch64/aarch64-arches.def +++ b/gcc/config/aarch64/aarch64-arches.def @@ -33,7 +33,7 @@ AARCH64_ARCH("armv8-a", generic, V8A, 8, (SIMD)) AARCH64_ARCH("armv8.1-a", generic, V8_1A, 8, (V8A, LSE, CRC, RDMA)) AARCH64_ARCH("armv8.2-a", generic, V8_2A, 8, (V8_1A)) -AARCH64_ARCH("armv8.3-a", generic, V8_3A, 8, (V8_2A, PAUTH)) +AARCH64_ARCH("armv8.3-a", generic, V8_3A, 8, (V8_2A, PAUTH, RCPC)) AARCH64_ARCH("armv8.4-a", generic, V8_4A, 8, (V8_3A, F16FML, DOTPROD, FLAGM)) AARCH64_ARCH("armv8.5-a", generic, V8_5A, 8, (V8_4A, SB, SSBS, PREDRES)) AARCH64_ARCH("armv8.6-a", generic, V8_6A, 8, (V8_5A, I8MM, BF16)) diff --git a/gcc/config/aarch64/aarch64-c.cc b/gcc/config/aarch64/aarch64-c.cc index 592af8c..e296c73 100644 --- a/gcc/config/aarch64/aarch64-c.cc +++ b/gcc/config/aarch64/aarch64-c.cc @@ -202,6 +202,7 @@ aarch64_update_cpp_builtins (cpp_reader *pfile) "__ARM_FEATURE_BF16_SCALAR_ARITHMETIC", pfile); aarch64_def_or_undef (TARGET_LS64, "__ARM_FEATURE_LS64", pfile); + aarch64_def_or_undef (AARCH64_ISA_RCPC, "__ARM_FEATURE_RCPC", pfile); /* Not for ACLE, but required to keep "float.h" correct if we switch target between implementations that do or do not support ARMv8.2-A diff --git a/gcc/config/aarch64/aarch64-cores.def b/gcc/config/aarch64/aarch64-cores.def index 6029916..b50628d 100644 --- a/gcc/config/aarch64/aarch64-cores.def +++ b/gcc/config/aarch64/aarch64-cores.def @@ -133,17 +133,17 @@ AARCH64_CORE("tsv110", tsv110, tsv110, V8_2A, (CRYPTO, F16), tsv110, 0x48, 0 /* ARMv8.3-A Architecture Processors. */ /* Marvell cores (TX3). */ -AARCH64_CORE("thunderx3t110", thunderx3t110, thunderx3t110, V8_3A, (CRYPTO, RCPC, SM4, SHA3, F16FML), thunderx3t110, 0x43, 0x0b8, 0x0a) +AARCH64_CORE("thunderx3t110", thunderx3t110, thunderx3t110, V8_3A, (CRYPTO, SM4, SHA3, F16FML), thunderx3t110, 0x43, 0x0b8, 0x0a) /* ARMv8.4-A Architecture Processors. */ /* Arm ('A') cores. */ -AARCH64_CORE("zeus", zeus, cortexa57, V8_4A, (SVE, RCPC, I8MM, BF16, PROFILE, SSBS, RNG), neoversev1, 0x41, 0xd40, -1) -AARCH64_CORE("neoverse-v1", neoversev1, cortexa57, V8_4A, (SVE, RCPC, I8MM, BF16, PROFILE, SSBS, RNG), neoversev1, 0x41, 0xd40, -1) -AARCH64_CORE("neoverse-512tvb", neoverse512tvb, cortexa57, V8_4A, (SVE, RCPC, I8MM, BF16, PROFILE, SSBS, RNG), neoverse512tvb, INVALID_IMP, INVALID_CORE, -1) +AARCH64_CORE("zeus", zeus, cortexa57, V8_4A, (SVE, I8MM, BF16, PROFILE, SSBS, RNG), neoversev1, 0x41, 0xd40, -1) +AARCH64_CORE("neoverse-v1", neoversev1, cortexa57, V8_4A, (SVE, I8MM, BF16, PROFILE, SSBS, RNG), neoversev1, 0x41, 0xd40, -1) +AARCH64_CORE("neoverse-512tvb", neoverse512tvb, cortexa57, V8_4A, (SVE, I8MM, BF16, PROFILE, SSBS, RNG), neoverse512tvb, INVALID_IMP, INVALID_CORE, -1) /* Qualcomm ('Q') cores. */ -AARCH64_CORE("saphira", saphira, saphira, V8_4A, (CRYPTO, RCPC), saphira, 0x51, 0xC01, -1) +AARCH64_CORE("saphira", saphira, saphira, V8_4A, (CRYPTO), saphira, 0x51, 0xC01, -1) /* ARMv8-A big.LITTLE implementations. */ diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 2d62218..05da9af 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -201,6 +201,7 @@ enum class aarch64_feature : unsigned char { #define AARCH64_ISA_SM4 (aarch64_isa_flags & AARCH64_FL_SM4) #define AARCH64_ISA_SHA3 (aarch64_isa_flags & AARCH64_FL_SHA3) #define AARCH64_ISA_F16FML (aarch64_isa_flags & AARCH64_FL_F16FML) +#define AARCH64_ISA_RCPC (aarch64_isa_flags & AARCH64_FL_RCPC) #define AARCH64_ISA_RCPC8_4 (aarch64_isa_flags & AARCH64_FL_V8_4A) #define AARCH64_ISA_RNG (aarch64_isa_flags & AARCH64_FL_RNG) #define AARCH64_ISA_V8_5A (aarch64_isa_flags & AARCH64_FL_V8_5A) diff --git a/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1.c b/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1.c index bfb044f..307fa3d 100644 --- a/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1.c +++ b/gcc/testsuite/gcc.target/aarch64/pragma_cpp_predefs_1.c @@ -248,6 +248,26 @@ #error "__ARM_FEATURE_CRC32 is not defined but should be!" #endif +#pragma GCC target ("arch=armv8.2-a") +#ifdef __ARM_FEATURE_RCPC +#error "__ARM_FEATURE_RCPC is defined but should not be!" +#endif + +#pragma GCC target ("arch=armv8.2-a+rcpc") +#ifndef __ARM_FEATURE_RCPC +#error "__ARM_FEATURE_RCPC is not defined but should be!" +#endif + +#pragma GCC target ("+norcpc") +#ifdef __ARM_FEATURE_RCPC +#error "__ARM_FEATURE_RCPC is defined but should not be!" +#endif + +#pragma GCC target ("arch=armv8.3-a") +#ifndef __ARM_FEATURE_RCPC +#error "__ARM_FEATURE_RCPC is not defined but should be!" +#endif + int foo (int a) { -- cgit v1.1 From e87879a9f5c2869de177c4dde2172f277e81ef1a Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 4 Oct 2022 12:23:46 -0400 Subject: c++: install cp-trait.def as part of plugin headers [PR107136] This is apparently needed since we include cp-trait.def from cp-tree.h (in order to define the cp_trait_kind enum), as with operators.def. PR c++/107136 gcc/cp/ChangeLog: * Make-lang.in (CP_PLUGIN_HEADERS): Add cp-trait.def. --- gcc/cp/Make-lang.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 38d8eee..aa84d68 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -39,7 +39,7 @@ CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)') GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)') CXX_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo c++|sed '$(program_transform_name)') GXX_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo g++|sed '$(program_transform_name)') -CP_PLUGIN_HEADERS := cp-tree.h cxx-pretty-print.h name-lookup.h type-utils.h operators.def +CP_PLUGIN_HEADERS := cp-tree.h cxx-pretty-print.h name-lookup.h type-utils.h operators.def cp-trait.def # # Define the names for selecting c++ in LANGUAGES. -- cgit v1.1 From 87b0fe37a2a5916cd09586e2af83b8203f57612a Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 4 Oct 2022 19:50:28 +0200 Subject: Remove assert from set_nonzero_bits. The assert removed by this patch was there to keep users from passing masks of incompatible types. The self tests are passing host wide ints down (set_nonzero_bits (-1)), which seem to be 32 bits, whereas some embedded targets have integer_type_node's of 16-bits. This is causing problems in m32c-elf, among others. I suppose there's no harm in passing a 32-bit mask, because set_nonzero_bits calls wide_int::from() to convert the mask to the appropriate type. So we can remove the assert. gcc/ChangeLog: * value-range.cc (irange::set_nonzero_bits): Remove assert. --- gcc/value-range.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'gcc') diff --git a/gcc/value-range.cc b/gcc/value-range.cc index afb26a4..a307559 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -2913,7 +2913,6 @@ irange::set_nonzero_bits (const wide_int_ref &bits) { gcc_checking_assert (!undefined_p ()); unsigned prec = TYPE_PRECISION (type ()); - gcc_checking_assert (prec == bits.get_precision ()); // Drop VARYINGs with a nonzero mask to a plain range. if (m_kind == VR_VARYING && bits != -1) -- cgit v1.1 From ade1e0d5896221500d1cbda38cd631cf80325aaa Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 4 Oct 2022 21:05:16 +0200 Subject: attribs: Add missing auto_diagnostic_group 3 times In these spots, the error/error_at has some inform afterwards which are explanation part of the same diagnostics, so should be tied with auto_diagnostic_group with it. 2022-10-04 Jakub Jelinek * attribs.cc (handle_ignored_attributes_option, decl_attributes, common_function_versions): Use auto_diagnostic_group. --- gcc/attribs.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gcc') diff --git a/gcc/attribs.cc b/gcc/attribs.cc index b1f1032..1462c11 100644 --- a/gcc/attribs.cc +++ b/gcc/attribs.cc @@ -251,6 +251,7 @@ handle_ignored_attributes_option (vec *v) /* We don't accept '::attr'. */ if (cln == nullptr || cln == opt) { + auto_diagnostic_group d; error ("wrong argument to ignored attributes"); inform (input_location, "valid format is % or %"); continue; @@ -732,6 +733,7 @@ decl_attributes (tree *node, tree attributes, int flags, || (spec->max_length >= 0 && nargs > spec->max_length)) { + auto_diagnostic_group d; error ("wrong number of arguments specified for %qE attribute", name); if (spec->max_length < 0) @@ -1167,6 +1169,7 @@ common_function_versions (tree fn1, tree fn2) std::swap (fn1, fn2); attr1 = attr2; } + auto_diagnostic_group d; error_at (DECL_SOURCE_LOCATION (fn2), "missing % attribute for multi-versioned %qD", fn2); -- cgit v1.1 From 0764dc8537a4f87089ecd32391cb5f8803b43c96 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 4 Oct 2022 23:13:15 +0200 Subject: attribs: Add overloads with namespace name I've discovered a problem with the way we handle scoped attributes. For declaration or type attributes for attributes we don't know anything about we just don't add them to the declarations or types, so later in the FEs and middle-end it is fine to use lookup_attribute etc. which just check the attribute name and not namespace because non-standard non-GNU attributes just won't show there. But in the case of attributes on statements, nothing has filtered out the unknown attributes, so with my earlier assume attribute patch e.g. c-c++-common/Wno-attributes-6.c test failed because it uses: [[vendor::assume(1 + 1 == 2)]]; with -Wno-attributes=vendor::assume and lookup_attribute ("assume", ) finds such attribute and handled it that way. So, for those cases, this patch introduces lookup_attribute and remove_attribute overloads which specify also the namespace. I think the fallthrough, hot, cold, likely, unlikely attribute handling will need to use the new APIs too, so that we don't handle msft::fallthrough attribute as something we'd know. 2022-10-04 Jakub Jelinek * attribs.h (remove_attribute): Declare overload with additional attr_ns argument. (private_lookup_attribute): Declare overload with additional attr_ns and attr_ns_len arguments. (lookup_attribute): New overload with additional attr_ns argument. * attribs.cc (remove_attribute): New overload with additional attr_ns argument. (private_lookup_attribute): New overload with additional attr_ns and attr_ns_len arguments. --- gcc/attribs.cc | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/attribs.h | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) (limited to 'gcc') diff --git a/gcc/attribs.cc b/gcc/attribs.cc index 1462c11..38f3e926 100644 --- a/gcc/attribs.cc +++ b/gcc/attribs.cc @@ -1645,6 +1645,36 @@ remove_attribute (const char *attr_name, tree list) return list; } +/* Similarly but also match namespace on the removed attributes. */ + +tree +remove_attribute (const char *attr_ns, const char *attr_name, tree list) +{ + tree *p; + gcc_checking_assert (attr_name[0] != '_'); + gcc_checking_assert (attr_ns == NULL || attr_ns[0] != '_'); + + for (p = &list; *p;) + { + tree l = *p; + + tree attr = get_attribute_name (l); + if (is_attribute_p (attr_name, attr)) + { + tree ns = get_attribute_namespace (l); + if ((ns == NULL_TREE && attr_ns == NULL) + || (ns && attr_ns && is_attribute_p (attr_ns, ns))) + { + *p = TREE_CHAIN (l); + continue; + } + } + p = &TREE_CHAIN (l); + } + + return list; +} + /* Return an attribute list that is the union of a1 and a2. */ tree @@ -2042,6 +2072,39 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list) return list; } +/* Similarly but with also attribute namespace. */ + +tree +private_lookup_attribute (const char *attr_ns, const char *attr_name, + size_t attr_ns_len, size_t attr_len, tree list) +{ + while (list) + { + tree attr = get_attribute_name (list); + size_t ident_len = IDENTIFIER_LENGTH (attr); + if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr), + ident_len)) + { + tree ns = get_attribute_namespace (list); + if (ns == NULL_TREE) + { + if (attr_ns == NULL) + break; + } + else if (attr_ns) + { + ident_len = IDENTIFIER_LENGTH (ns); + if (cmp_attribs (attr_ns, attr_ns_len, IDENTIFIER_POINTER (ns), + ident_len)) + break; + } + } + list = TREE_CHAIN (list); + } + + return list; +} + /* Return true if the function decl or type NODE has been declared with attribute ANAME among attributes ATTRS. */ diff --git a/gcc/attribs.h b/gcc/attribs.h index 5b6f63e..b283656 100644 --- a/gcc/attribs.h +++ b/gcc/attribs.h @@ -82,6 +82,10 @@ extern tree merge_type_attributes (tree, tree); extern tree remove_attribute (const char *, tree); +/* Similarly but also with specific attribute namespace. */ + +extern tree remove_attribute (const char *, const char *, tree); + /* Given two attributes lists, return a list of their union. */ extern tree merge_attributes (tree, tree); @@ -113,6 +117,10 @@ extern int attribute_list_contained (const_tree, const_tree); for size. */ extern tree private_lookup_attribute (const char *attr_name, size_t attr_len, tree list); +extern tree private_lookup_attribute (const char *attr_ns, + const char *attr_name, + size_t attr_ns_len, size_t attr_len, + tree list); extern unsigned decls_mismatched_attributes (tree, tree, tree, const char* const[], @@ -209,6 +217,36 @@ lookup_attribute (const char *attr_name, tree list) } } +/* Similar to lookup_attribute, but also match the attribute namespace. */ + +static inline tree +lookup_attribute (const char *attr_ns, const char *attr_name, tree list) +{ + if (CHECKING_P && attr_name[0] != '_') + { + size_t attr_len = strlen (attr_name); + gcc_checking_assert (!canonicalize_attr_name (attr_name, attr_len)); + } + if (CHECKING_P && attr_ns && attr_ns[0] != '_') + { + size_t attr_ns_len = strlen (attr_ns); + gcc_checking_assert (!canonicalize_attr_name (attr_ns, attr_ns_len)); + } + /* In most cases, list is NULL_TREE. */ + if (list == NULL_TREE) + return NULL_TREE; + else + { + size_t attr_ns_len = attr_ns ? strlen (attr_ns) : 0; + size_t attr_len = strlen (attr_name); + /* Do the strlen() before calling the out-of-line implementation. + In most cases attr_name is a string constant, and the compiler + will optimize the strlen() away. */ + return private_lookup_attribute (attr_ns, attr_name, + attr_ns_len, attr_len, list); + } +} + /* Given an attribute name ATTR_NAME and a list of attributes LIST, return a pointer to the attribute's list first element if the attribute starts with ATTR_NAME. ATTR_NAME must be in the form 'text' (not -- cgit v1.1 From ce3a1b5976079b1467473b4628f05797fd2eae08 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 4 Oct 2022 17:06:04 -0400 Subject: c++: fix debug info for array temporary [PR107154] In the testcase the elaboration of the array init that happens at genericize time was getting the location info for the end of the function; fixed by doing the expansion at the location of the original expression. PR c++/107154 gcc/cp/ChangeLog: * cp-gimplify.cc (cp_genericize_init_expr): Use iloc_sentinel. (cp_genericize_target_expr): Likewise. gcc/testsuite/ChangeLog: * g++.dg/debug/dwarf2/lineno-array1.C: New test. --- gcc/cp/cp-gimplify.cc | 2 ++ gcc/testsuite/g++.dg/debug/dwarf2/lineno-array1.C | 25 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/lineno-array1.C (limited to 'gcc') diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index cca3b9f..404a769 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -920,6 +920,7 @@ cp_genericize_init (tree *replace, tree from, tree to) static void cp_genericize_init_expr (tree *stmt_p) { + iloc_sentinel ils = EXPR_LOCATION (*stmt_p); tree to = TREE_OPERAND (*stmt_p, 0); tree from = TREE_OPERAND (*stmt_p, 1); if (SIMPLE_TARGET_EXPR_P (from) @@ -935,6 +936,7 @@ cp_genericize_init_expr (tree *stmt_p) static void cp_genericize_target_expr (tree *stmt_p) { + iloc_sentinel ils = EXPR_LOCATION (*stmt_p); tree slot = TARGET_EXPR_SLOT (*stmt_p); cp_genericize_init (&TARGET_EXPR_INITIAL (*stmt_p), TARGET_EXPR_INITIAL (*stmt_p), slot); diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/lineno-array1.C b/gcc/testsuite/g++.dg/debug/dwarf2/lineno-array1.C new file mode 100644 index 0000000..befac5f --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/lineno-array1.C @@ -0,0 +1,25 @@ +// PR c++/107154 +// { dg-do compile { target c++11 } } +// { dg-additional-options "-gno-as-loc-support -dA" } +// Test that we emit debug info exactly once for the last line. +// { dg-final { scan-assembler-times {:25:1} 1 } } + +bool dummy; + +struct S { + const char *p; + S(const char *p): p(p) {} + ~S() { dummy = true; } +}; + +using Sar = S[]; + +struct X { + X(Sar&&) { } +}; + +int main() +{ + X x(Sar{"", ""}); + return 0; +} -- cgit v1.1 From 85872a69ee1b123557c7c352d45ef608e70b20fb Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 5 Oct 2022 00:17:25 +0000 Subject: Daily bump. --- gcc/ChangeLog | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c-family/ChangeLog | 5 +++ gcc/c/ChangeLog | 27 ++++++++++++++++ gcc/cp/ChangeLog | 40 +++++++++++++++++++++++ gcc/fortran/ChangeLog | 5 +++ gcc/testsuite/ChangeLog | 36 +++++++++++++++++++++ 7 files changed, 198 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 48397ff..06e188e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,87 @@ +2022-10-04 Jakub Jelinek + + * attribs.h (remove_attribute): Declare overload with additional + attr_ns argument. + (private_lookup_attribute): Declare overload with additional + attr_ns and attr_ns_len arguments. + (lookup_attribute): New overload with additional attr_ns argument. + * attribs.cc (remove_attribute): New overload with additional + attr_ns argument. + (private_lookup_attribute): New overload with additional + attr_ns and attr_ns_len arguments. + +2022-10-04 Jakub Jelinek + + * attribs.cc (handle_ignored_attributes_option, decl_attributes, + common_function_versions): Use auto_diagnostic_group. + +2022-10-04 Aldy Hernandez + + * value-range.cc (irange::set_nonzero_bits): Remove assert. + +2022-10-04 Richard Sandiford + + * config/aarch64/aarch64.h (AARCH64_ISA_RCPC): New macro. + * config/aarch64/aarch64-arches.def (armv8.3-a): Include RCPC. + * config/aarch64/aarch64-cores.def (thunderx3t110, zeus, neoverse-v1) + (neoverse-512tvb, saphira): Remove RCPC from these Armv8.3-A+ cores. + * config/aarch64/aarch64-c.cc (aarch64_update_cpp_builtins): Define + __ARM_FEATURE_RCPC when appropriate. + +2022-10-04 Tobias Burnus + + * doc/invoke.texi (-fopenmp): Mention C++ attribut syntax. + (-fopenmp-simd): Likewise; update permitted directives. + +2022-10-04 Tobias Burnus + + * doc/install.texi (Specific): Add missing items to bullet list. + (amdgcn): Update LLVM requirements, use version not date for newlib. + (nvptx): Use version not git hash for newlib. + +2022-10-04 Aldy Hernandez + + * value-range-storage.cc (irange_storage_slot::set_irange): Remove + special case. + * value-range.cc (irange::irange_set): Adjust for nonzero mask + being a wide int. + (irange::irange_set_anti_range): Same. + (irange::set): Same. + (irange::verify_range): Same. + (irange::legacy_equal_p): Same. + (irange::operator==): Same. + (irange::contains_p): Same. + (irange::legacy_intersect): Same. + (irange::legacy_union): Same. + (irange::irange_single_pair_union): Call union_nonzero_bits. + (irange::irange_union): Same. + (irange::irange_intersect): Call intersect_nonzero_bits. + (irange::intersect): Adjust for nonzero mask being a wide int. + (irange::invert): Same. + (irange::set_nonzero_bits): Same. + (irange::get_nonzero_bits_from_range): New. + (irange::set_range_from_nonzero_bits): New. + (irange::get_nonzero_bits): Adjust for nonzero mask being a wide + int. + (irange::intersect_nonzero_bits): Same. + (irange::union_nonzero_bits): Same. + (range_tests_nonzero_bits): Remove test. + * value-range.h (irange::varying_compatible_p): Adjust for nonzero + mask being a wide int. + (gt_ggc_mx): Same. + (gt_pch_nx): Same. + (irange::set_undefined): Same. + (irange::set_varying): Same. + (irange::normalize_kind): Same. + +2022-10-04 Aldy Hernandez + + PR tree-optimization/107130 + * gimple-range-op.cc (class cfn_popcount): Call op_cfn_ffs. + (class cfn_ffs): New. + (gimple_range_op_handler::maybe_builtin_call): Separate out + CASE_CFN_FFS into its own case. + 2022-10-03 Sergei Trofimovich * config/i386/t-i386: Add build-time dependencies against diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 59c7fe2..7759c90 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20221004 +20221005 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index ea4b254..c062fe1 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2022-10-04 Jakub Jelinek + + * c-omp.cc (c_omp_directives): Uncomment begin declare target + entry. + 2022-10-03 Patrick Palka * c-common.cc (c_common_reswords): Use RID_IS_SAME instead of diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index f5c9a59..48eb23e 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,30 @@ +2022-10-04 Jakub Jelinek + + * c-lang.h (struct c_omp_declare_target_attr): New type. + (current_omp_declare_target_attribute): Change type from + int to vec *. + * c-parser.cc (c_parser_translation_unit): Adjust for that change. + If last pushed directive was begin declare target, use different + wording and simplify format strings for easier translations. + (c_parser_omp_clause_device_type): Uncomment + check_no_duplicate_clause call. + (c_parser_omp_declare_target): Adjust for the + current_omp_declare_target_attribute type change, push { -1 }. + Use error_at rather than warning_at for declare target with + only device_type clauses. + (OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK): Define. + (c_parser_omp_begin): Add begin declare target support. + (c_parser_omp_end): Adjust for the + current_omp_declare_target_attribute type change, adjust + diagnostics wording and simplify format strings for easier + translations. + * c-decl.cc (current_omp_declare_target_attribute): Change type from + int to vec *. + (c_decl_attributes): Adjust for the + current_omp_declare_target_attribute type change. If device_type + was present on begin declare target, add "omp declare target host" + and/or "omp declare target nohost" attributes. + 2022-09-29 Joseph Myers * c-decl.cc (handle_std_noreturn_attribute): New function. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index db6fea1..3249d83 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,43 @@ +2022-10-04 Jason Merrill + + PR c++/107154 + * cp-gimplify.cc (cp_genericize_init_expr): Use iloc_sentinel. + (cp_genericize_target_expr): Likewise. + +2022-10-04 Patrick Palka + + PR c++/107136 + * Make-lang.in (CP_PLUGIN_HEADERS): Add cp-trait.def. + +2022-10-04 Jakub Jelinek + + * cp-tree.h (struct omp_declare_target_attr): Rename to ... + (cp_omp_declare_target_attr): ... this. Add device_type member. + (omp_begin_assumes_data): Rename to ... + (cp_omp_begin_assumes_data): ... this. + (struct saved_scope): Change types of omp_declare_target_attribute + and omp_begin_assumes. + * parser.cc (cp_parser_omp_clause_device_type): Uncomment + check_no_duplicate_clause call. + (cp_parser_omp_all_clauses): Fix up pasto, c_name for OMP_CLAUSE_LINK + should be "link" rather than "to". + (cp_parser_omp_declare_target): Adjust for omp_declare_target_attr + to cp_omp_declare_target_attr changes, push -1 as device_type. Use + error_at rather than warning_at for declare target with only + device_type clauses. + (OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK): Define. + (cp_parser_omp_begin): Add begin declare target support. Adjust + for omp_begin_assumes_data to cp_omp_begin_assumes_data change. + (cp_parser_omp_end): Adjust for the + omp_declare_target_attr to cp_omp_declare_target_attr and + omp_begin_assumes_data to cp_omp_begin_assumes_data type changes, + adjust diagnostics wording and simplify format strings for easier + translations. + * semantics.cc (finish_translation_unit): Likewise. + * decl2.cc (cplus_decl_attributes): If device_type was present on + begin declare target, add "omp declare target host" and/or + "omp declare target nohost" attributes. + 2022-10-03 Jakub Jelinek * cp-tree.h (BCS_STMT_EXPR): New enumerator. diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 0559fc3..6923030 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,8 @@ +2022-10-04 Tobias Burnus + + * parse.cc (decode_omp_directive): Handle '(end) loop' and 'scan' + also with -fopenmp-simd. + 2022-10-01 José Rui Faustino de Sousa PR fortran/100040 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0c6e5d4..8a30bb4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,39 @@ +2022-10-04 Jason Merrill + + PR c++/107154 + * g++.dg/debug/dwarf2/lineno-array1.C: New test. + +2022-10-04 Richard Sandiford + + * gcc.target/aarch64/pragma_cpp_predefs_1.c: Add RCPC tests. + +2022-10-04 Tobias Burnus + + * gfortran.dg/gomp/openmp-simd-7.f90: New test. + +2022-10-04 Jakub Jelinek + + * c-c++-common/gomp/declare-target-4.c: Move tests that are now + rejected into declare-target-7.c. + * c-c++-common/gomp/declare-target-6.c: Adjust expected diagnostics. + * c-c++-common/gomp/declare-target-7.c: New test. + * c-c++-common/gomp/begin-declare-target-1.c: New test. + * c-c++-common/gomp/begin-declare-target-2.c: New test. + * c-c++-common/gomp/begin-declare-target-3.c: New test. + * c-c++-common/gomp/begin-declare-target-4.c: New test. + * g++.dg/gomp/attrs-9.C: Add begin declare target tests. + * g++.dg/gomp/attrs-18.C: New test. + +2022-10-04 Aldy Hernandez + + PR tree-optimization/107130 + * gcc.dg/tree-ssa/pr107130.c: New test. + +2022-10-04 Lewis Hyatt + + PR c/91669 + * c-c++-common/pr91669.c: New test. + 2022-10-03 Torbjörn SVENSSON Yvan ROUX -- cgit v1.1 From e6fe02d832209393474ca049ca5e0b56a053fadd Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 4 Oct 2022 20:19:06 -0400 Subject: analyzer: widening_svalues take a function_point rather than a program_point Enabling work towrads better call summarization. gcc/analyzer/ChangeLog: * region-model-manager.cc (region_model_manager::get_or_create_widening_svalue): Use a function_point rather than a program_point. * region-model.cc (selftest::test_widening_constraints): Likewise. * region-model.h (region_model_manager::get_or_create_widening_svalue): Likewise. (model_merger::get_function_point): New. * svalue.cc (svalue::can_merge_p): Use a function_point rather than a program_point. (svalue::can_merge_p): Likewise. * svalue.h (widening_svalue::key_t): Likewise. (widening_svalue::widening_svalue): Likewise. Signed-off-by: David Malcolm --- gcc/analyzer/region-model-manager.cc | 9 +++++---- gcc/analyzer/region-model.cc | 2 +- gcc/analyzer/region-model.h | 6 +++++- gcc/analyzer/svalue.cc | 4 ++-- gcc/analyzer/svalue.h | 8 ++++---- 5 files changed, 17 insertions(+), 12 deletions(-) (limited to 'gcc') diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc index cbda77f..ed5b9c7 100644 --- a/gcc/analyzer/region-model-manager.cc +++ b/gcc/analyzer/region-model-manager.cc @@ -1143,10 +1143,11 @@ region_model_manager::get_or_create_unmergeable (const svalue *arg) and ITER_SVAL at POINT, creating it if necessary. */ const svalue * -region_model_manager::get_or_create_widening_svalue (tree type, - const program_point &point, - const svalue *base_sval, - const svalue *iter_sval) +region_model_manager:: +get_or_create_widening_svalue (tree type, + const function_point &point, + const svalue *base_sval, + const svalue *iter_sval) { gcc_assert (base_sval->get_kind () != SK_WIDENING); gcc_assert (iter_sval->get_kind () != SK_WIDENING); diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 22c5287..e92bba2 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -7956,7 +7956,7 @@ static void test_widening_constraints () { region_model_manager mgr; - program_point point (program_point::origin (mgr)); + function_point point (program_point::origin (mgr).get_function_point ()); tree int_0 = build_int_cst (integer_type_node, 0); tree int_m1 = build_int_cst (integer_type_node, -1); tree int_1 = build_int_cst (integer_type_node, 1); diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index e86720a..baac7ba 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -278,7 +278,7 @@ public: const svalue *inner_svalue); const svalue *get_or_create_unmergeable (const svalue *arg); const svalue *get_or_create_widening_svalue (tree type, - const program_point &point, + const function_point &point, const svalue *base_svalue, const svalue *iter_svalue); const svalue *get_or_create_compound_svalue (tree type, @@ -1282,6 +1282,10 @@ struct model_merger } bool mergeable_svalue_p (const svalue *) const; + const function_point &get_function_point () const + { + return m_point.get_function_point (); + } const region_model *m_model_a; const region_model *m_model_b; diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc index f5a5f1c..a37c152 100644 --- a/gcc/analyzer/svalue.cc +++ b/gcc/analyzer/svalue.cc @@ -207,7 +207,7 @@ svalue::can_merge_p (const svalue *other, if (maybe_get_constant () && other->maybe_get_constant ()) { return mgr->get_or_create_widening_svalue (other->get_type (), - merger->m_point, + merger->get_function_point (), other, this); } @@ -220,7 +220,7 @@ svalue::can_merge_p (const svalue *other, && binop_sval->get_arg1 ()->get_kind () == SK_CONSTANT && other->get_kind () != SK_WIDENING) return mgr->get_or_create_widening_svalue (other->get_type (), - merger->m_point, + merger->get_function_point (), other, this); /* Merge: (Widen(existing_val, V), existing_val) -> Widen (existing_val, V) diff --git a/gcc/analyzer/svalue.h b/gcc/analyzer/svalue.h index f4cab0d..9393d6e 100644 --- a/gcc/analyzer/svalue.h +++ b/gcc/analyzer/svalue.h @@ -1113,9 +1113,9 @@ public: /* A support class for uniquifying instances of widening_svalue. */ struct key_t { - key_t (tree type, const program_point &point, + key_t (tree type, const function_point &point, const svalue *base_sval, const svalue *iter_sval) - : m_type (type), m_point (point.get_function_point ()), + : m_type (type), m_point (point), m_base_sval (base_sval), m_iter_sval (iter_sval) {} @@ -1153,12 +1153,12 @@ public: DIR_UNKNOWN }; - widening_svalue (tree type, const program_point &point, + widening_svalue (tree type, const function_point &point, const svalue *base_sval, const svalue *iter_sval) : svalue (complexity::from_pair (base_sval->get_complexity (), iter_sval->get_complexity ()), type), - m_point (point.get_function_point ()), + m_point (point), m_base_sval (base_sval), m_iter_sval (iter_sval) { gcc_assert (base_sval->can_have_associated_state_p ()); -- cgit v1.1 From 7f42f7adfa69fea029fbb76286048f712bb017ff Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 4 Oct 2022 20:19:06 -0400 Subject: analyzer: fold -(-(VAL)) to VAL gcc/analyzer/ChangeLog: * region-model-manager.cc (region_model_manager::maybe_fold_unaryop): Fold -(-(VAL)) to VAL. Signed-off-by: David Malcolm --- gcc/analyzer/region-model-manager.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'gcc') diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc index ed5b9c7..1956cfc 100644 --- a/gcc/analyzer/region-model-manager.cc +++ b/gcc/analyzer/region-model-manager.cc @@ -432,6 +432,17 @@ region_model_manager::maybe_fold_unaryop (tree type, enum tree_code op, } } break; + case NEGATE_EXPR: + { + /* -(-(VAL)) is VAL, for integer types. */ + if (const unaryop_svalue *unaryop = arg->dyn_cast_unaryop_svalue ()) + if (unaryop->get_op () == NEGATE_EXPR + && type == unaryop->get_type () + && type + && INTEGRAL_TYPE_P (type)) + return unaryop->get_arg (); + } + break; } /* Constants. */ -- cgit v1.1 From 0167154cdd02c9508239982ea7568a7a8cee080e Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 4 Oct 2022 20:19:06 -0400 Subject: analyzer: move region_model_manager decl to its own header gcc/analyzer/ChangeLog: * region-model.h: Include "analyzer/region-model-manager.h" (class region_model_manager): Move decl to... * region-model-manager.h: ...this new file. Signed-off-by: David Malcolm --- gcc/analyzer/region-model-manager.h | 312 ++++++++++++++++++++++++++++++++++++ gcc/analyzer/region-model.h | 289 +-------------------------------- 2 files changed, 313 insertions(+), 288 deletions(-) create mode 100644 gcc/analyzer/region-model-manager.h (limited to 'gcc') diff --git a/gcc/analyzer/region-model-manager.h b/gcc/analyzer/region-model-manager.h new file mode 100644 index 0000000..0057326 --- /dev/null +++ b/gcc/analyzer/region-model-manager.h @@ -0,0 +1,312 @@ +/* Consolidation of svalues and regions. + Copyright (C) 2020-2022 Free Software Foundation, Inc. + Contributed by David Malcolm . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_ANALYZER_REGION_MODEL_MANAGER_H +#define GCC_ANALYZER_REGION_MODEL_MANAGER_H + +namespace ana { + +/* A class responsible for owning and consolidating region and svalue + instances. + region and svalue instances are immutable as far as clients are + concerned, so they are provided as "const" ptrs. */ + +class region_model_manager +{ +public: + region_model_manager (logger *logger = NULL); + ~region_model_manager (); + + /* call_string consolidation. */ + const call_string &get_empty_call_string () const + { + return m_empty_call_string; + } + + /* svalue consolidation. */ + const svalue *get_or_create_constant_svalue (tree cst_expr); + const svalue *get_or_create_int_cst (tree type, poly_int64); + const svalue *get_or_create_unknown_svalue (tree type); + const svalue *get_or_create_setjmp_svalue (const setjmp_record &r, + tree type); + const svalue *get_or_create_poisoned_svalue (enum poison_kind kind, + tree type); + const svalue *get_or_create_initial_value (const region *reg); + const svalue *get_ptr_svalue (tree ptr_type, const region *pointee); + const svalue *get_or_create_unaryop (tree type, enum tree_code op, + const svalue *arg); + const svalue *get_or_create_cast (tree type, const svalue *arg); + const svalue *get_or_create_binop (tree type, + enum tree_code op, + const svalue *arg0, const svalue *arg1); + const svalue *get_or_create_sub_svalue (tree type, + const svalue *parent_svalue, + const region *subregion); + const svalue *get_or_create_repeated_svalue (tree type, + const svalue *outer_size, + const svalue *inner_svalue); + const svalue *get_or_create_bits_within (tree type, + const bit_range &bits, + const svalue *inner_svalue); + const svalue *get_or_create_unmergeable (const svalue *arg); + const svalue *get_or_create_widening_svalue (tree type, + const function_point &point, + const svalue *base_svalue, + const svalue *iter_svalue); + const svalue *get_or_create_compound_svalue (tree type, + const binding_map &map); + const svalue *get_or_create_conjured_svalue (tree type, const gimple *stmt, + const region *id_reg, + const conjured_purge &p); + const svalue * + get_or_create_asm_output_svalue (tree type, + const gasm *asm_stmt, + unsigned output_idx, + const vec &inputs); + const svalue * + get_or_create_const_fn_result_svalue (tree type, + tree fndecl, + const vec &inputs); + + const svalue *maybe_get_char_from_string_cst (tree string_cst, + tree byte_offset_cst); + + /* Dynamically-allocated svalue instances. + The number of these within the analysis can grow arbitrarily. + They are still owned by the manager. */ + const svalue *create_unique_svalue (tree type); + + /* region consolidation. */ + const stack_region * get_stack_region () const { return &m_stack_region; } + const heap_region *get_heap_region () const { return &m_heap_region; } + const code_region *get_code_region () const { return &m_code_region; } + const globals_region *get_globals_region () const + { + return &m_globals_region; + } + const function_region *get_region_for_fndecl (tree fndecl); + const label_region *get_region_for_label (tree label); + const decl_region *get_region_for_global (tree expr); + const region *get_field_region (const region *parent, tree field); + const region *get_element_region (const region *parent, + tree element_type, + const svalue *index); + const region *get_offset_region (const region *parent, + tree type, + const svalue *byte_offset); + const region *get_sized_region (const region *parent, + tree type, + const svalue *byte_size_sval); + const region *get_cast_region (const region *original_region, + tree type); + const frame_region *get_frame_region (const frame_region *calling_frame, + function *fun); + const region *get_symbolic_region (const svalue *sval); + const string_region *get_region_for_string (tree string_cst); + const region *get_bit_range (const region *parent, tree type, + const bit_range &bits); + const var_arg_region *get_var_arg_region (const frame_region *parent, + unsigned idx); + + const region *get_unknown_symbolic_region (tree region_type); + + const region * + get_region_for_unexpected_tree_code (region_model_context *ctxt, + tree t, + const dump_location_t &loc); + + unsigned alloc_region_id () { return m_next_region_id++; } + + store_manager *get_store_manager () { return &m_store_mgr; } + bounded_ranges_manager *get_range_manager () const { return m_range_mgr; } + + known_function_manager *get_known_function_manager () + { + return &m_known_fn_mgr; + } + + /* Dynamically-allocated region instances. + The number of these within the analysis can grow arbitrarily. + They are still owned by the manager. */ + const region *create_region_for_heap_alloc (); + const region *create_region_for_alloca (const frame_region *frame); + + void log_stats (logger *logger, bool show_objs) const; + + void begin_checking_feasibility (void) { m_checking_feasibility = true; } + void end_checking_feasibility (void) { m_checking_feasibility = false; } + + logger *get_logger () const { return m_logger; } + + void dump_untracked_regions () const; + +private: + bool too_complex_p (const complexity &c) const; + bool reject_if_too_complex (svalue *sval); + + const svalue *maybe_fold_unaryop (tree type, enum tree_code op, + const svalue *arg); + const svalue *maybe_fold_binop (tree type, enum tree_code op, + const svalue *arg0, const svalue *arg1); + const svalue *maybe_fold_sub_svalue (tree type, + const svalue *parent_svalue, + const region *subregion); + const svalue *maybe_fold_repeated_svalue (tree type, + const svalue *outer_size, + const svalue *inner_svalue); + const svalue *maybe_fold_bits_within_svalue (tree type, + const bit_range &bits, + const svalue *inner_svalue); + const svalue *maybe_undo_optimize_bit_field_compare (tree type, + const compound_svalue *compound_sval, + tree cst, const svalue *arg1); + const svalue *maybe_fold_asm_output_svalue (tree type, + const vec &inputs); + + logger *m_logger; + + const call_string m_empty_call_string; + + unsigned m_next_region_id; + root_region m_root_region; + stack_region m_stack_region; + heap_region m_heap_region; + + /* svalue consolidation. */ + typedef hash_map constants_map_t; + constants_map_t m_constants_map; + + typedef hash_map unknowns_map_t; + unknowns_map_t m_unknowns_map; + const unknown_svalue *m_unknown_NULL; + + typedef hash_map poisoned_values_map_t; + poisoned_values_map_t m_poisoned_values_map; + + typedef hash_map setjmp_values_map_t; + setjmp_values_map_t m_setjmp_values_map; + + typedef hash_map initial_values_map_t; + initial_values_map_t m_initial_values_map; + + typedef hash_map pointer_values_map_t; + pointer_values_map_t m_pointer_values_map; + + typedef hash_map unaryop_values_map_t; + unaryop_values_map_t m_unaryop_values_map; + + typedef hash_map binop_values_map_t; + binop_values_map_t m_binop_values_map; + + typedef hash_map sub_values_map_t; + sub_values_map_t m_sub_values_map; + + typedef hash_map repeated_values_map_t; + repeated_values_map_t m_repeated_values_map; + + typedef hash_map bits_within_values_map_t; + bits_within_values_map_t m_bits_within_values_map; + + typedef hash_map unmergeable_values_map_t; + unmergeable_values_map_t m_unmergeable_values_map; + + typedef hash_map + widening_values_map_t; + widening_values_map_t m_widening_values_map; + + typedef hash_map compound_values_map_t; + compound_values_map_t m_compound_values_map; + + typedef hash_map conjured_values_map_t; + conjured_values_map_t m_conjured_values_map; + + typedef hash_map asm_output_values_map_t; + asm_output_values_map_t m_asm_output_values_map; + + typedef hash_map const_fn_result_values_map_t; + const_fn_result_values_map_t m_const_fn_result_values_map; + + bool m_checking_feasibility; + + /* "Dynamically-allocated" svalue instances. + The number of these within the analysis can grow arbitrarily. + They are still owned by the manager. */ + auto_delete_vec m_managed_dynamic_svalues; + + /* Maximum complexity of svalues that weren't rejected. */ + complexity m_max_complexity; + + /* region consolidation. */ + + code_region m_code_region; + typedef hash_map fndecls_map_t; + typedef fndecls_map_t::iterator fndecls_iterator_t; + fndecls_map_t m_fndecls_map; + + typedef hash_map labels_map_t; + typedef labels_map_t::iterator labels_iterator_t; + labels_map_t m_labels_map; + + globals_region m_globals_region; + typedef hash_map globals_map_t; + typedef globals_map_t::iterator globals_iterator_t; + globals_map_t m_globals_map; + + consolidation_map m_field_regions; + consolidation_map m_element_regions; + consolidation_map m_offset_regions; + consolidation_map m_sized_regions; + consolidation_map m_cast_regions; + consolidation_map m_frame_regions; + consolidation_map m_symbolic_regions; + + typedef hash_map string_map_t; + string_map_t m_string_map; + + consolidation_map m_bit_range_regions; + consolidation_map m_var_arg_regions; + + store_manager m_store_mgr; + + bounded_ranges_manager *m_range_mgr; + + known_function_manager m_known_fn_mgr; + + /* "Dynamically-allocated" region instances. + The number of these within the analysis can grow arbitrarily. + They are still owned by the manager. */ + auto_delete_vec m_managed_dynamic_regions; +}; + +} // namespace ana + +#endif /* GCC_ANALYZER_REGION_MODEL_MANAGER_H */ diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index baac7ba..be0a97a 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/svalue.h" #include "analyzer/region.h" #include "analyzer/known-function-manager.h" +#include "analyzer/region-model-manager.h" using namespace ana; @@ -230,294 +231,6 @@ public: virtual void visit_region (const region *) {} }; -} // namespace ana - -namespace ana { - -/* A class responsible for owning and consolidating region and svalue - instances. - region and svalue instances are immutable as far as clients are - concerned, so they are provided as "const" ptrs. */ - -class region_model_manager -{ -public: - region_model_manager (logger *logger = NULL); - ~region_model_manager (); - - /* call_string consolidation. */ - const call_string &get_empty_call_string () const - { - return m_empty_call_string; - } - - /* svalue consolidation. */ - const svalue *get_or_create_constant_svalue (tree cst_expr); - const svalue *get_or_create_int_cst (tree type, poly_int64); - const svalue *get_or_create_unknown_svalue (tree type); - const svalue *get_or_create_setjmp_svalue (const setjmp_record &r, - tree type); - const svalue *get_or_create_poisoned_svalue (enum poison_kind kind, - tree type); - const svalue *get_or_create_initial_value (const region *reg); - const svalue *get_ptr_svalue (tree ptr_type, const region *pointee); - const svalue *get_or_create_unaryop (tree type, enum tree_code op, - const svalue *arg); - const svalue *get_or_create_cast (tree type, const svalue *arg); - const svalue *get_or_create_binop (tree type, - enum tree_code op, - const svalue *arg0, const svalue *arg1); - const svalue *get_or_create_sub_svalue (tree type, - const svalue *parent_svalue, - const region *subregion); - const svalue *get_or_create_repeated_svalue (tree type, - const svalue *outer_size, - const svalue *inner_svalue); - const svalue *get_or_create_bits_within (tree type, - const bit_range &bits, - const svalue *inner_svalue); - const svalue *get_or_create_unmergeable (const svalue *arg); - const svalue *get_or_create_widening_svalue (tree type, - const function_point &point, - const svalue *base_svalue, - const svalue *iter_svalue); - const svalue *get_or_create_compound_svalue (tree type, - const binding_map &map); - const svalue *get_or_create_conjured_svalue (tree type, const gimple *stmt, - const region *id_reg, - const conjured_purge &p); - const svalue * - get_or_create_asm_output_svalue (tree type, - const gasm *asm_stmt, - unsigned output_idx, - const vec &inputs); - const svalue * - get_or_create_const_fn_result_svalue (tree type, - tree fndecl, - const vec &inputs); - - const svalue *maybe_get_char_from_string_cst (tree string_cst, - tree byte_offset_cst); - - /* Dynamically-allocated svalue instances. - The number of these within the analysis can grow arbitrarily. - They are still owned by the manager. */ - const svalue *create_unique_svalue (tree type); - - /* region consolidation. */ - const stack_region * get_stack_region () const { return &m_stack_region; } - const heap_region *get_heap_region () const { return &m_heap_region; } - const code_region *get_code_region () const { return &m_code_region; } - const globals_region *get_globals_region () const - { - return &m_globals_region; - } - const function_region *get_region_for_fndecl (tree fndecl); - const label_region *get_region_for_label (tree label); - const decl_region *get_region_for_global (tree expr); - const region *get_field_region (const region *parent, tree field); - const region *get_element_region (const region *parent, - tree element_type, - const svalue *index); - const region *get_offset_region (const region *parent, - tree type, - const svalue *byte_offset); - const region *get_sized_region (const region *parent, - tree type, - const svalue *byte_size_sval); - const region *get_cast_region (const region *original_region, - tree type); - const frame_region *get_frame_region (const frame_region *calling_frame, - function *fun); - const region *get_symbolic_region (const svalue *sval); - const string_region *get_region_for_string (tree string_cst); - const region *get_bit_range (const region *parent, tree type, - const bit_range &bits); - const var_arg_region *get_var_arg_region (const frame_region *parent, - unsigned idx); - - const region *get_unknown_symbolic_region (tree region_type); - - const region * - get_region_for_unexpected_tree_code (region_model_context *ctxt, - tree t, - const dump_location_t &loc); - - unsigned alloc_region_id () { return m_next_region_id++; } - - store_manager *get_store_manager () { return &m_store_mgr; } - bounded_ranges_manager *get_range_manager () const { return m_range_mgr; } - - known_function_manager *get_known_function_manager () - { - return &m_known_fn_mgr; - } - - /* Dynamically-allocated region instances. - The number of these within the analysis can grow arbitrarily. - They are still owned by the manager. */ - const region *create_region_for_heap_alloc (); - const region *create_region_for_alloca (const frame_region *frame); - - void log_stats (logger *logger, bool show_objs) const; - - void begin_checking_feasibility (void) { m_checking_feasibility = true; } - void end_checking_feasibility (void) { m_checking_feasibility = false; } - - logger *get_logger () const { return m_logger; } - - void dump_untracked_regions () const; - -private: - bool too_complex_p (const complexity &c) const; - bool reject_if_too_complex (svalue *sval); - - const svalue *maybe_fold_unaryop (tree type, enum tree_code op, - const svalue *arg); - const svalue *maybe_fold_binop (tree type, enum tree_code op, - const svalue *arg0, const svalue *arg1); - const svalue *maybe_fold_sub_svalue (tree type, - const svalue *parent_svalue, - const region *subregion); - const svalue *maybe_fold_repeated_svalue (tree type, - const svalue *outer_size, - const svalue *inner_svalue); - const svalue *maybe_fold_bits_within_svalue (tree type, - const bit_range &bits, - const svalue *inner_svalue); - const svalue *maybe_undo_optimize_bit_field_compare (tree type, - const compound_svalue *compound_sval, - tree cst, const svalue *arg1); - const svalue *maybe_fold_asm_output_svalue (tree type, - const vec &inputs); - - logger *m_logger; - - const call_string m_empty_call_string; - - unsigned m_next_region_id; - root_region m_root_region; - stack_region m_stack_region; - heap_region m_heap_region; - - /* svalue consolidation. */ - typedef hash_map constants_map_t; - constants_map_t m_constants_map; - - typedef hash_map unknowns_map_t; - unknowns_map_t m_unknowns_map; - const unknown_svalue *m_unknown_NULL; - - typedef hash_map poisoned_values_map_t; - poisoned_values_map_t m_poisoned_values_map; - - typedef hash_map setjmp_values_map_t; - setjmp_values_map_t m_setjmp_values_map; - - typedef hash_map initial_values_map_t; - initial_values_map_t m_initial_values_map; - - typedef hash_map pointer_values_map_t; - pointer_values_map_t m_pointer_values_map; - - typedef hash_map unaryop_values_map_t; - unaryop_values_map_t m_unaryop_values_map; - - typedef hash_map binop_values_map_t; - binop_values_map_t m_binop_values_map; - - typedef hash_map sub_values_map_t; - sub_values_map_t m_sub_values_map; - - typedef hash_map repeated_values_map_t; - repeated_values_map_t m_repeated_values_map; - - typedef hash_map bits_within_values_map_t; - bits_within_values_map_t m_bits_within_values_map; - - typedef hash_map unmergeable_values_map_t; - unmergeable_values_map_t m_unmergeable_values_map; - - typedef hash_map - widening_values_map_t; - widening_values_map_t m_widening_values_map; - - typedef hash_map compound_values_map_t; - compound_values_map_t m_compound_values_map; - - typedef hash_map conjured_values_map_t; - conjured_values_map_t m_conjured_values_map; - - typedef hash_map asm_output_values_map_t; - asm_output_values_map_t m_asm_output_values_map; - - typedef hash_map const_fn_result_values_map_t; - const_fn_result_values_map_t m_const_fn_result_values_map; - - bool m_checking_feasibility; - - /* "Dynamically-allocated" svalue instances. - The number of these within the analysis can grow arbitrarily. - They are still owned by the manager. */ - auto_delete_vec m_managed_dynamic_svalues; - - /* Maximum complexity of svalues that weren't rejected. */ - complexity m_max_complexity; - - /* region consolidation. */ - - code_region m_code_region; - typedef hash_map fndecls_map_t; - typedef fndecls_map_t::iterator fndecls_iterator_t; - fndecls_map_t m_fndecls_map; - - typedef hash_map labels_map_t; - typedef labels_map_t::iterator labels_iterator_t; - labels_map_t m_labels_map; - - globals_region m_globals_region; - typedef hash_map globals_map_t; - typedef globals_map_t::iterator globals_iterator_t; - globals_map_t m_globals_map; - - consolidation_map m_field_regions; - consolidation_map m_element_regions; - consolidation_map m_offset_regions; - consolidation_map m_sized_regions; - consolidation_map m_cast_regions; - consolidation_map m_frame_regions; - consolidation_map m_symbolic_regions; - - typedef hash_map string_map_t; - string_map_t m_string_map; - - consolidation_map m_bit_range_regions; - consolidation_map m_var_arg_regions; - - store_manager m_store_mgr; - - bounded_ranges_manager *m_range_mgr; - - known_function_manager m_known_fn_mgr; - - /* "Dynamically-allocated" region instances. - The number of these within the analysis can grow arbitrarily. - They are still owned by the manager. */ - auto_delete_vec m_managed_dynamic_regions; -}; - struct append_regions_cb_data; /* Helper class for handling calls to functions with known behavior. -- cgit v1.1 From bfca9505f6fce631c2488f89aa156d56c7fae9ed Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 4 Oct 2022 20:19:07 -0400 Subject: analyzer: revamp side-effects of call summaries [PR107072] With -fanalyzer-call-summaries the analyzer canl attempt to summarize the effects of some function calls at their call site, rather than simulate the call directly, which can avoid big slowdowns during analysis. Previously, this summarization was extremely simplistic: no attempt was made to update sm-state, and region_model::update_for_call_summary would simply set the return value of the function to UNKNOWN, and assume the function had no side effects. This patch implements less simplistic summarizations: it tracks each possible return enode from the called function, and attempts to generate a successor enode from the callsite for each that have compatible conditions, mapping state changes in the summary to state changes at the callsite. It also implements the beginnings of heuristics for generating user-facing descriptions of a summary e.g. "when 'foo' returns NULL" versus: "when 'foo' returns a heap-allocated buffer" This still has some bugs, but much more accurately tracks the effects of a call, and so is an improvement; it should only have an effect when -fanalyzer-call-summaries is enabled. As before, -fanalyzer-call-summaries is disabled by default in analyzer.opt (but enabled by default in the test suite). gcc/ChangeLog: PR analyzer/107072 * Makefile.in (ANALYZER_OBJS): Add analyzer/call-summary.o. gcc/analyzer/ChangeLog: PR analyzer/107072 * analyzer-logging.h: Include "diagnostic-core.h". * analyzer.h: Include "function.h". (class call_summary): New forward decl. (class call_summary_replay): New forward decl. (struct per_function_data): New forward decl. (struct interesting_t): New forward decl. (custom_edge_info::update_state): New vfunc. * call-info.cc (custom_edge_info::update_state): New. * call-summary.cc: New file. * call-summary.h: New file. * constraint-manager.cc: Include "analyzer/call-summary.h". (class replay_fact_visitor): New. (constraint_manager::replay_call_summary): New. * constraint-manager.h (constraint_manager::replay_call_summary): New. * engine.cc: Include "analyzer/call-summary.h". (exploded_node::on_stmt): Handle call summaries. (class call_summary_edge_info): New. (exploded_node::replay_call_summaries): New. (exploded_node::replay_call_summary): New. (per_function_data::~per_function_data): New. (per_function_data::add_call_summary): Move here from header and reimplement. (exploded_graph::process_node): Call update_state rather than update_model when handling bifurcation (viz_callgraph_node::dump_dot): Use a regular label rather than an HTML table; add summaries to dump. * exploded-graph.h: Include "alloc-pool.h", "fibonacci_heap.h", "supergraph.h", "sbitmap.h", "shortest-paths.h", "analyzer/sm.h", "analyzer/program-state.h", and "analyzer/diagnostic-manager.h". (exploded_node::replay_call_summaries): New decl. (exploded_node::replay_call_summary): New decl. (per_function_data::~per_function_data): New decl. (per_function_data::add_call_summary): Move implemention from header. (per_function_data::m_summaries): Update type of element. * known-function-manager.h: Include "analyzer/analyzer-logging.h". * program-point.h: Include "pretty-print.h" and "analyzer/call-string.h". * program-state.cc: Include "analyzer/call-summary.h". (sm_state_map::replay_call_summary): New. (program_state::replay_call_summary): New. * program-state.h (sm_state_map::replay_call_summary): New decl. (program_state::replay_call_summary): New decl. * region-model-manager.cc (region_model_manager::get_or_create_asm_output_svalue): New overload. * region-model-manager.h (region_model_manager::get_or_create_asm_output_svalue): New overload decl. * region-model.cc: Include "analyzer/call-summary.h". (region_model::maybe_update_for_edge): Remove call to region_model::update_for_call_summary on SUPEREDGE_INTRAPROCEDURAL_CALL. (region_model::update_for_call_summary): Delete. (region_model::replay_call_summary): New. * region-model.h (region_model::replay_call_summary): New decl. (region_model::update_for_call_summary): Delete decl. * store.cc: Include "analyzer/call-summary.h". (store::replay_call_summary): New. (store::replay_call_summary_cluster): New. * store.h: Include "tristate.h". (is_a_helper ::test): New. (store::replay_call_summary): New decl. (store::replay_call_summary_cluster): New decl. * supergraph.cc (get_ultimate_function_for_cgraph_edge): Remove "static" from decl. (supergraph_call_edge): Make stmt param const. * supergraph.h: Include "ordered-hash-map.h", "cfg.h", "basic-block.h", "gimple.h", "gimple-iterator.h", and "digraph.h". (supergraph_call_edge): Make stmt param const. (get_ultimate_function_for_cgraph_edge): New decl. * svalue.cc (compound_svalue::compound_svalue): Assert that we're not nesting compound_svalues. * svalue.h: Include "json.h", "analyzer/store.h", and "analyzer/program-point.h". (asm_output_svalue::get_num_outputs): New accessor. gcc/testsuite/ChangeLog: PR analyzer/107072 * gcc.dg/analyzer/call-summaries-2.c: New test. * gcc.dg/analyzer/call-summaries-3.c: New test. * gcc.dg/analyzer/call-summaries-asm-x86.c: New test. * gcc.dg/analyzer/call-summaries-malloc.c: New test. * gcc.dg/analyzer/call-summaries-pr107072.c: New test. Signed-off-by: David Malcolm --- gcc/Makefile.in | 1 + gcc/analyzer/analyzer-logging.h | 2 + gcc/analyzer/analyzer.h | 11 + gcc/analyzer/call-info.cc | 12 +- gcc/analyzer/call-summary.cc | 875 +++++++++++++++++++++ gcc/analyzer/call-summary.h | 118 +++ gcc/analyzer/constraint-manager.cc | 55 ++ gcc/analyzer/constraint-manager.h | 3 + gcc/analyzer/engine.cc | 201 ++++- gcc/analyzer/exploded-graph.h | 36 +- gcc/analyzer/known-function-manager.h | 2 + gcc/analyzer/program-point.h | 3 + gcc/analyzer/program-state.cc | 48 ++ gcc/analyzer/program-state.h | 6 + gcc/analyzer/region-model-manager.cc | 27 + gcc/analyzer/region-model-manager.h | 6 + gcc/analyzer/region-model.cc | 49 +- gcc/analyzer/region-model.h | 5 +- gcc/analyzer/store.cc | 161 ++++ gcc/analyzer/store.h | 16 + gcc/analyzer/supergraph.cc | 9 +- gcc/analyzer/supergraph.h | 10 +- gcc/analyzer/svalue.cc | 8 +- gcc/analyzer/svalue.h | 4 + gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c | 646 +++++++++++++++ gcc/testsuite/gcc.dg/analyzer/call-summaries-3.c | 29 + .../gcc.dg/analyzer/call-summaries-asm-x86.c | 20 + .../gcc.dg/analyzer/call-summaries-malloc.c | 80 ++ .../gcc.dg/analyzer/call-summaries-pr107072.c | 90 +++ 29 files changed, 2479 insertions(+), 54 deletions(-) create mode 100644 gcc/analyzer/call-summary.cc create mode 100644 gcc/analyzer/call-summary.h create mode 100644 gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/call-summaries-3.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/call-summaries-asm-x86.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/call-summaries-malloc.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c (limited to 'gcc') diff --git a/gcc/Makefile.in b/gcc/Makefile.in index c1d0438..f672e6e 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1255,6 +1255,7 @@ ANALYZER_OBJS = \ analyzer/bar-chart.o \ analyzer/call-info.o \ analyzer/call-string.o \ + analyzer/call-summary.o \ analyzer/checker-path.o \ analyzer/complexity.o \ analyzer/constraint-manager.o \ diff --git a/gcc/analyzer/analyzer-logging.h b/gcc/analyzer/analyzer-logging.h index ef14b29..71b540c 100644 --- a/gcc/analyzer/analyzer-logging.h +++ b/gcc/analyzer/analyzer-logging.h @@ -23,6 +23,8 @@ along with GCC; see the file COPYING3. If not see #ifndef ANALYZER_LOGGING_H #define ANALYZER_LOGGING_H +#include "diagnostic-core.h" + namespace ana { /* A logger encapsulates a logging stream: a way to send diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h index b325aee..49c19af 100644 --- a/gcc/analyzer/analyzer.h +++ b/gcc/analyzer/analyzer.h @@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_ANALYZER_H #define GCC_ANALYZER_ANALYZER_H +#include "function.h" + class graphviz_out; namespace ana { @@ -114,6 +116,10 @@ class state_machine; class logger; class visitor; class known_function_manager; +class call_summary; +class call_summary_replay; +struct per_function_data; +struct interesting_t; /* Forward decls of functions. */ @@ -263,6 +269,11 @@ public: /* Hook for making .dot label more readable. */ virtual void print (pretty_printer *pp) const = 0; + /* Hook for updating STATE when handling bifurcation. */ + virtual bool update_state (program_state *state, + const exploded_edge *eedge, + region_model_context *ctxt) const; + /* Hook for updating MODEL within exploded_path::feasible_p and when handling bifurcation. */ virtual bool update_model (region_model *model, diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc index efc070b..d9a261f 100644 --- a/gcc/analyzer/call-info.cc +++ b/gcc/analyzer/call-info.cc @@ -66,7 +66,17 @@ along with GCC; see the file COPYING3. If not see namespace ana { -/* class call_info : public custom_eedge_info_t. */ +/* class custom_edge_info. */ + +bool +custom_edge_info::update_state (program_state *state, + const exploded_edge *eedge, + region_model_context *ctxt) const +{ + return update_model (state->m_region_model, eedge, ctxt); +} + +/* class call_info : public custom_edge_info. */ /* Implementation of custom_edge_info::print vfunc for call_info: use get_desc to get a label_text, and print it to PP. */ diff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc new file mode 100644 index 0000000..9d8716d --- /dev/null +++ b/gcc/analyzer/call-summary.cc @@ -0,0 +1,875 @@ +/* Classes for working with summaries of function calls. + Copyright (C) 2022 David Malcolm . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tree-dfa.h" +#include "diagnostic.h" +#include "tree-diagnostic.h" +#include "selftest.h" +#include "analyzer/analyzer.h" +#include "analyzer/region-model.h" +#include "analyzer/call-summary.h" +#include "analyzer/exploded-graph.h" + +#if ENABLE_ANALYZER + +namespace ana { + +/* class call_summary. */ + +const program_state & +call_summary::get_state () const +{ + return m_enode->get_state (); +} + +tree +call_summary::get_fndecl () const +{ + return m_enode->get_point ().get_fndecl (); +} + +label_text +call_summary::get_desc () const +{ + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + + get_user_facing_desc (&pp); + if (flag_analyzer_verbose_edges) + pp_printf (&pp, " (call summary; EN: %i)", m_enode->m_index); + + return label_text::take (xstrdup (pp_formatted_text (&pp))); +} + +/* Generate a user-facing description of this call summary.c + This has various heuristics for distinguishing between different + summaries. + This will help with debugging, too. */ + +void +call_summary::get_user_facing_desc (pretty_printer *pp) const +{ + tree fndecl = get_fndecl (); + + /* If there are multiple summaries, try to use the return value to + distinguish between them. */ + if (m_per_fn_data->m_summaries.length () > 1) + { + if (tree result = DECL_RESULT (fndecl)) + { + const region *result_reg + = get_state ().m_region_model->get_lvalue (result, NULL); + const svalue *result_sval + = get_state ().m_region_model->get_store_value (result_reg, NULL); + switch (result_sval->get_kind ()) + { + default: + break; + case SK_REGION: + { + const region_svalue *region_sval + = as_a (result_sval); + const region *pointee_reg = region_sval->get_pointee (); + switch (pointee_reg->get_kind ()) + { + default: + break; + case RK_HEAP_ALLOCATED: + pp_printf (pp, + "when %qE returns pointer" + " to heap-allocated buffer", + fndecl); + return; + } + } + break; + case SK_CONSTANT: + { + const constant_svalue *constant_sval + = as_a (result_sval); + tree cst = constant_sval->get_constant (); + if (POINTER_TYPE_P (TREE_TYPE (result)) + && zerop (cst)) + pp_printf (pp, "when %qE returns NULL", fndecl); + else + pp_printf (pp, "when %qE returns %qE", fndecl, cst); + return; + } + } + } + } + + /* Fallback. */ + pp_printf (pp, "when %qE returns", fndecl); +} + +/* Dump a multiline representation of this object to PP. */ + +void +call_summary::dump_to_pp (const extrinsic_state &ext_state, + pretty_printer *pp, + bool simple) const +{ + label_text desc = get_desc (); + pp_printf (pp, "desc: %qs", desc.get ()); + pp_newline (pp); + + get_state ().dump_to_pp (ext_state, simple, true, pp); +} + +/* Dump a multiline representation of this object to FILE. */ + +void +call_summary::dump (const extrinsic_state &ext_state, + FILE *fp, + bool simple) const +{ + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + pp_show_color (&pp) = pp_show_color (global_dc->printer); + pp.buffer->stream = fp; + dump_to_pp (ext_state, &pp, simple); + pp_flush (&pp); +} + +/* Dump a multiline representation of this object to stderr. */ + +DEBUG_FUNCTION void +call_summary::dump (const extrinsic_state &ext_state, bool simple) const +{ + dump (ext_state, stderr, simple); +} + +/* class call_summary_replay. */ + +/* call_summary_replay's ctor. + Populate the cache with params for the summary based on + arguments at the caller. */ + +call_summary_replay::call_summary_replay (const call_details &cd, + function *called_fn, + call_summary *summary, + const extrinsic_state &ext_state) +: m_cd (cd), + m_called_fn (called_fn), + m_summary (summary), + m_ext_state (ext_state) +{ + region_model_manager *mgr = cd.get_manager (); + + // populate params based on args + tree fndecl = called_fn->decl; + + /* Get a frame_region for use with respect to the summary. + This will be a top-level frame, since that's what's in + the summary. */ + const frame_region *summary_frame + = mgr->get_frame_region (NULL, called_fn); + + unsigned idx = 0; + for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm; + iter_parm = DECL_CHAIN (iter_parm), ++idx) + { + /* If there's a mismatching declaration, the call stmt might + not have enough args. Handle this case by leaving the + rest of the params as uninitialized. */ + if (idx >= cd.num_args ()) + break; + const svalue *caller_arg_sval = cd.get_arg_svalue (idx); + tree parm_lval = iter_parm; + if (tree parm_default_ssa = ssa_default_def (called_fn, iter_parm)) + parm_lval = parm_default_ssa; + const region *summary_parm_reg + = summary_frame->get_region_for_local (mgr, parm_lval, cd.get_ctxt ()); + const svalue *summary_initial_parm_reg + = mgr->get_or_create_initial_value (summary_parm_reg); + add_svalue_mapping (summary_initial_parm_reg, caller_arg_sval); + } + + /* Handle any variadic args. */ + unsigned va_arg_idx = 0; + for (; idx < cd.num_args (); idx++, va_arg_idx++) + { + const svalue *caller_arg_sval = cd.get_arg_svalue (idx); + const region *summary_var_arg_reg + = mgr->get_var_arg_region (summary_frame, va_arg_idx); + const svalue *summary_initial_var_arg_reg + = mgr->get_or_create_initial_value (summary_var_arg_reg); + add_svalue_mapping (summary_initial_var_arg_reg, caller_arg_sval); + } +} + +/* Try to convert SUMMARY_SVAL in the summary to a corresponding svalue + in the caller, caching the result. + + Return NULL if the conversion is not possible. */ + +const svalue * +call_summary_replay::convert_svalue_from_summary (const svalue *summary_sval) +{ + gcc_assert (summary_sval); + + if (const svalue **slot + = m_map_svalue_from_summary_to_caller.get (summary_sval)) + return *slot; + + const svalue *caller_sval = convert_svalue_from_summary_1 (summary_sval); + + /* Add to cache. */ + add_svalue_mapping (summary_sval, caller_sval); + + return caller_sval; +} + +/* Implementation of call_summary_replay::convert_svalue_from_summary. */ + +const svalue * +call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval) +{ + gcc_assert (summary_sval); + + switch (summary_sval->get_kind ()) + { + default: + gcc_unreachable (); + case SK_REGION: + { + const region_svalue *region_summary_sval + = as_a (summary_sval); + const region *summary_reg = region_summary_sval->get_pointee (); + const region *caller_reg = convert_region_from_summary (summary_reg); + if (!caller_reg) + return NULL; + region_model_manager *mgr = get_manager (); + const svalue *caller_ptr + = mgr->get_ptr_svalue (summary_sval->get_type (), + caller_reg); + return caller_ptr; + } + break; + + case SK_CONSTANT: + case SK_PLACEHOLDER: + case SK_POISONED: + case SK_UNKNOWN: + return summary_sval; + + case SK_SETJMP: + return NULL; // TODO + + case SK_INITIAL: + { + const initial_svalue *initial_summary_sval + = as_a (summary_sval); + /* Params should already be in the cache, courtesy of the ctor. */ + gcc_assert (!initial_summary_sval->initial_value_of_param_p ()); + + /* Initial value of region within the summary is the value of the + region at the point of the call. */ + const region *summary_reg = initial_summary_sval->get_region (); + const region *caller_reg = convert_region_from_summary (summary_reg); + if (!caller_reg) + return NULL; + const svalue *caller_sval + = m_cd.get_model ()->get_store_value (caller_reg, m_cd.get_ctxt ()); + return caller_sval; + } + break; + case SK_UNARYOP: + { + const unaryop_svalue *unaryop_summary_sval + = as_a (summary_sval); + region_model_manager *mgr = get_manager (); + return mgr->get_or_create_unaryop + (summary_sval->get_type (), + unaryop_summary_sval->get_op (), + convert_svalue_from_summary (unaryop_summary_sval->get_arg ())); + } + break; + case SK_BINOP: + { + const binop_svalue *binop_summary_sval + = as_a (summary_sval); + region_model_manager *mgr = get_manager (); + return mgr->get_or_create_binop + (summary_sval->get_type (), + binop_summary_sval->get_op (), + convert_svalue_from_summary (binop_summary_sval->get_arg0 ()), + convert_svalue_from_summary (binop_summary_sval->get_arg1 ())); + } + break; + case SK_SUB: + { + const sub_svalue *sub_summary_sval + = as_a (summary_sval); + region_model_manager *mgr = get_manager (); + const svalue *summary_parent_sval = sub_summary_sval->get_parent (); + if (!summary_parent_sval) + return NULL; + const region *summary_subregion = sub_summary_sval->get_subregion (); + if (!summary_subregion) + return NULL; + return mgr->get_or_create_sub_svalue (summary_sval->get_type (), + summary_parent_sval, + summary_subregion); + } + break; + case SK_REPEATED: + { + const repeated_svalue *repeated_summary_sval + = as_a (summary_sval); + const svalue *summary_outer_size + = repeated_summary_sval->get_outer_size (); + const svalue *caller_outer_size + = convert_svalue_from_summary (summary_outer_size); + if (!caller_outer_size) + return NULL; + const svalue *summary_inner_sval + = repeated_summary_sval->get_inner_svalue (); + const svalue *caller_inner_sval + = convert_svalue_from_summary (summary_inner_sval); + if (!caller_inner_sval) + return NULL; + region_model_manager *mgr = get_manager (); + return mgr->get_or_create_repeated_svalue (summary_sval->get_type (), + caller_outer_size, + caller_inner_sval); + } + break; + case SK_BITS_WITHIN: + { + const bits_within_svalue *bits_within_summary_sval + = as_a (summary_sval); + const bit_range &bits = bits_within_summary_sval->get_bits (); + const svalue *summary_inner_sval + = bits_within_summary_sval->get_inner_svalue (); + const svalue *caller_inner_sval + = convert_svalue_from_summary (summary_inner_sval); + if (!caller_inner_sval) + return NULL; + region_model_manager *mgr = get_manager (); + return mgr->get_or_create_bits_within (summary_sval->get_type (), + bits, + caller_inner_sval); + } + break; + case SK_UNMERGEABLE: + { + const unmergeable_svalue *unmergeable_summary_sval + = as_a (summary_sval); + const svalue *summary_arg_sval = unmergeable_summary_sval->get_arg (); + const svalue *caller_arg_sval + = convert_svalue_from_summary (summary_arg_sval); + if (!caller_arg_sval) + return NULL; + region_model_manager *mgr = get_manager (); + return mgr->get_or_create_unmergeable (caller_arg_sval); + } + break; + case SK_WIDENING: + { + const widening_svalue *widening_summary_sval + = as_a (summary_sval); + const function_point &point = widening_summary_sval->get_point (); + const svalue *summary_base_sval + = widening_summary_sval->get_base_svalue (); + const svalue *caller_base_sval + = convert_svalue_from_summary (summary_base_sval); + if (!(caller_base_sval + && caller_base_sval->can_have_associated_state_p ())) + return NULL; + const svalue *summary_iter_sval + = widening_summary_sval->get_iter_svalue (); + const svalue *caller_iter_sval + = convert_svalue_from_summary (summary_iter_sval); + if (!(caller_iter_sval + && caller_iter_sval->can_have_associated_state_p ())) + return NULL; + region_model_manager *mgr = get_manager (); + return mgr->get_or_create_widening_svalue + (summary_iter_sval->get_type (), + point, + caller_base_sval, + caller_iter_sval); + } + break; + case SK_COMPOUND: + { + const compound_svalue *compound_summary_sval + = as_a (summary_sval); + region_model_manager *mgr = get_manager (); + store_manager *store_mgr = mgr->get_store_manager (); + binding_map caller_map; + auto_vec summary_keys; + for (auto kv : *compound_summary_sval) + summary_keys.safe_push (kv.first); + summary_keys.qsort (binding_key::cmp_ptrs); + for (auto key : summary_keys) + { + gcc_assert (key->concrete_p ()); + /* No remapping is needed for concrete binding keys. */ + + const svalue *bound_summary_sval + = compound_summary_sval->get_map ().get (key); + const svalue *caller_sval + = convert_svalue_from_summary (bound_summary_sval); + if (!caller_sval) + caller_sval = mgr->get_or_create_unknown_svalue (NULL_TREE); + + if (const compound_svalue *inner_compound_sval + = caller_sval->dyn_cast_compound_svalue ()) + { + const concrete_binding *outer_key + = as_a (key); + for (auto inner_kv : *inner_compound_sval) + { + // These should already be mapped to the caller. + const binding_key *inner_key = inner_kv.first; + const svalue *inner_sval = inner_kv.second; + gcc_assert (inner_key->concrete_p ()); + const concrete_binding *concrete_key + = as_a (inner_key); + bit_offset_t effective_start + = (concrete_key->get_start_bit_offset () + + outer_key->get_start_bit_offset ()); + const concrete_binding *effective_concrete_key + = store_mgr->get_concrete_binding + (effective_start, + concrete_key->get_size_in_bits ()); + caller_map.put (effective_concrete_key, inner_sval); + } + } + else + caller_map.put (key, caller_sval); + } + return mgr->get_or_create_compound_svalue (summary_sval->get_type (), + caller_map); + } + break; + case SK_CONJURED: + { + region_model_manager *mgr = get_manager (); + return mgr->get_or_create_unknown_svalue (summary_sval->get_type ()); + } + break; + case SK_ASM_OUTPUT: + { + const asm_output_svalue *asm_output_summary_sval + = as_a (summary_sval); + const char *asm_string = asm_output_summary_sval->get_asm_string (); + unsigned output_idx = asm_output_summary_sval->get_output_idx (); + unsigned num_inputs = asm_output_summary_sval->get_num_inputs (); + unsigned num_outputs = asm_output_summary_sval->get_num_outputs (); + auto_vec inputs (num_inputs); + for (unsigned idx = 0; idx < num_inputs; idx++) + { + const svalue *summary_input + = asm_output_summary_sval->get_input (idx); + const svalue *caller_input + = convert_svalue_from_summary (summary_input); + if (!caller_input) + return NULL; + inputs.safe_push (caller_input); + } + region_model_manager *mgr = get_manager (); + return mgr->get_or_create_asm_output_svalue (summary_sval->get_type (), + asm_string, + output_idx, + num_outputs, + inputs); + } + break; + case SK_CONST_FN_RESULT: + { + const const_fn_result_svalue *const_fn_result_summary_sval + = as_a (summary_sval); + tree fndecl = const_fn_result_summary_sval->get_fndecl (); + unsigned num_inputs = const_fn_result_summary_sval->get_num_inputs (); + auto_vec inputs (num_inputs); + for (unsigned idx = 0; idx < num_inputs; idx++) + { + const svalue *summary_input + = const_fn_result_summary_sval->get_input (idx); + const svalue *caller_input + = convert_svalue_from_summary (summary_input); + if (!caller_input) + return NULL; + inputs.safe_push (caller_input); + } + region_model_manager *mgr = get_manager (); + return mgr->get_or_create_const_fn_result_svalue + (summary_sval->get_type (), + fndecl, + inputs); + } + break; + } +} + +/* Try to convert SUMMARY_REG in the summary to a corresponding region + in the caller, caching the result. + + Return NULL if the conversion is not possible. */ + +const region * +call_summary_replay::convert_region_from_summary (const region *summary_reg) +{ + gcc_assert (summary_reg); + + if (const region **slot + = m_map_region_from_summary_to_caller.get (summary_reg)) + return *slot; + + const region *caller_reg = convert_region_from_summary_1 (summary_reg); + + /* Add to cache. */ + add_region_mapping (summary_reg, caller_reg); + + return caller_reg; +} + +/* Implementation of call_summary_replay::convert_region_from_summary. */ + +const region * +call_summary_replay::convert_region_from_summary_1 (const region *summary_reg) +{ + gcc_assert (summary_reg); + + region_model_manager *mgr = get_manager (); + switch (summary_reg->get_kind ()) + { + default: + gcc_unreachable (); + /* Top-level regions. */ + case RK_FRAME: + case RK_GLOBALS: + case RK_CODE: + case RK_STACK: + case RK_HEAP: + case RK_ROOT: + /* These should never be pointed to by a region_svalue. */ + gcc_unreachable (); + + case RK_FUNCTION: + case RK_LABEL: + case RK_STRING: + case RK_UNKNOWN: + /* We can reuse these regions directly. */ + return summary_reg; + + case RK_SYMBOLIC: + { + const symbolic_region *summary_symbolic_reg + = as_a (summary_reg); + const svalue *summary_ptr_sval = summary_symbolic_reg->get_pointer (); + const svalue *caller_ptr_sval + = convert_svalue_from_summary (summary_ptr_sval); + if (!caller_ptr_sval) + return NULL; + const region *caller_reg + = get_caller_model ()->deref_rvalue (caller_ptr_sval, + NULL_TREE, + get_ctxt ()); + return caller_reg; + } + break; + + case RK_DECL: + { + const decl_region *summary_decl_reg + = as_a (summary_reg); + tree decl = summary_decl_reg->get_decl (); + switch (TREE_CODE (decl)) + { + default: + gcc_unreachable (); + case SSA_NAME: + /* We don't care about writes to locals within + the summary. */ + return NULL; + case VAR_DECL: + /* We don't care about writes to locals within + the summary. */ + if (is_global_var (decl)) + /* If it's a global, we can reuse the region directly. */ + return summary_reg; + else + /* Otherwise, we don't care about locals. */ + return NULL; + case RESULT_DECL: + return m_cd.get_lhs_region (); + case PARM_DECL: + /* Writes (by value) to parms should be visible to the caller. */ + return NULL; + } + } + break; + case RK_FIELD: + { + const field_region *summary_field_reg + = as_a (summary_reg); + const region *summary_parent_reg = summary_reg->get_parent_region (); + const region *caller_parent_reg + = convert_region_from_summary (summary_parent_reg); + if (!caller_parent_reg) + return NULL; + tree field = summary_field_reg->get_field (); + return mgr->get_field_region (caller_parent_reg, field); + } + break; + case RK_ELEMENT: + { + const element_region *summary_element_reg + = as_a (summary_reg); + const region *summary_parent_reg = summary_reg->get_parent_region (); + const region *caller_parent_reg + = convert_region_from_summary (summary_parent_reg); + if (!caller_parent_reg) + return NULL; + const svalue *summary_index = summary_element_reg->get_index (); + const svalue *caller_index + = convert_svalue_from_summary (summary_index); + if (!caller_index) + return NULL; + return mgr->get_element_region (caller_parent_reg, + summary_reg->get_type (), + caller_index); + } + break; + case RK_OFFSET: + { + const offset_region *summary_offset_reg + = as_a (summary_reg); + const region *summary_parent_reg = summary_reg->get_parent_region (); + const region *caller_parent_reg + = convert_region_from_summary (summary_parent_reg); + if (!caller_parent_reg) + return NULL; + const svalue *summary_byte_offset + = summary_offset_reg->get_byte_offset (); + const svalue *caller_byte_offset + = convert_svalue_from_summary (summary_byte_offset); + if (!caller_byte_offset) + return NULL; + return mgr->get_offset_region (caller_parent_reg, + summary_reg->get_type (), + caller_byte_offset); + } + break; + case RK_SIZED: + { + const sized_region *summary_sized_reg + = as_a (summary_reg); + const region *summary_parent_reg = summary_reg->get_parent_region (); + const region *caller_parent_reg + = convert_region_from_summary (summary_parent_reg); + if (!caller_parent_reg) + return NULL; + const svalue *summary_byte_size + = summary_sized_reg->get_byte_size_sval (mgr); + const svalue *caller_byte_size + = convert_svalue_from_summary (summary_byte_size); + if (!caller_byte_size) + return NULL; + return mgr->get_sized_region (caller_parent_reg, + summary_reg->get_type (), + caller_byte_size); + } + break; + case RK_CAST: + { + const cast_region *summary_cast_reg + = as_a (summary_reg); + const region *summary_original_reg + = summary_cast_reg->get_original_region (); + const region *caller_original_reg + = convert_region_from_summary (summary_original_reg); + if (!caller_original_reg) + return NULL; + return mgr->get_cast_region (caller_original_reg, + summary_reg->get_type ()); + } + break; + case RK_HEAP_ALLOCATED: + { + /* If we have a heap-allocated region in the summary, then + it was allocated within the callee. + Create a new heap-allocated region to summarize this. */ + return mgr->create_region_for_heap_alloc (); + } + break; + case RK_ALLOCA: + return NULL; + case RK_BIT_RANGE: + { + const bit_range_region *summary_bit_range_reg + = as_a (summary_reg); + const region *summary_parent_reg = summary_reg->get_parent_region (); + const region *caller_parent_reg + = convert_region_from_summary (summary_parent_reg); + if (!caller_parent_reg) + return NULL; + const bit_range &bits = summary_bit_range_reg->get_bits (); + return mgr->get_bit_range (caller_parent_reg, + summary_reg->get_type (), + bits); + } + break; + case RK_VAR_ARG: + return NULL; + } +} + +/* Try to convert SUMMARY_KEY in the summary to a corresponding binding key + in the caller. + + Return NULL if the conversion is not possible. */ + +const binding_key * +call_summary_replay::convert_key_from_summary (const binding_key *summary_key) +{ + if (summary_key->concrete_p ()) + return summary_key; + + const symbolic_binding *symbolic_key = (const symbolic_binding *)summary_key; + const region *summary_reg = symbolic_key->get_region (); + const region *caller_reg = convert_region_from_summary (summary_reg); + if (!caller_reg) + return NULL; + region_model_manager *mgr = get_manager (); + store_manager *store_mgr = mgr->get_store_manager (); + return store_mgr->get_symbolic_binding (caller_reg); +} + +/* Record that SUMMARY_SVAL maps to CALLER_SVAL for this replay. */ + +void +call_summary_replay::add_svalue_mapping (const svalue *summary_sval, + const svalue *caller_sval) +{ + gcc_assert (summary_sval); + // CALLER_SVAL can be NULL + m_map_svalue_from_summary_to_caller.put (summary_sval, caller_sval); +} + +/* Record that SUMMARY_REG maps to CALLER_REG for this replay. */ + +void +call_summary_replay::add_region_mapping (const region *summary_reg, + const region *caller_reg) +{ + gcc_assert (summary_reg); + // CALLER_REG can be NULL + m_map_region_from_summary_to_caller.put (summary_reg, caller_reg); +} + +/* Dump a multiline representation of this object to PP. */ + +void +call_summary_replay::dump_to_pp (pretty_printer *pp, bool simple) const +{ + pp_newline (pp); + pp_string (pp, "CALL DETAILS:"); + pp_newline (pp); + m_cd.dump_to_pp (pp, simple); + + pp_newline (pp); + pp_string (pp, "CALLEE SUMMARY:"); + pp_newline (pp); + m_summary->dump_to_pp (m_ext_state, pp, simple); + + /* Current state of caller (could be in mid-update). */ + pp_newline (pp); + pp_string (pp, "CALLER:"); + pp_newline (pp); + m_cd.get_model ()->dump_to_pp (pp, simple, true); + + pp_newline (pp); + pp_string (pp, "REPLAY STATE:"); + pp_newline (pp); + pp_string (pp, "svalue mappings from summary to caller:"); + pp_newline (pp); + auto_vec summary_svals; + for (auto kv : m_map_svalue_from_summary_to_caller) + summary_svals.safe_push (kv.first); + summary_svals.qsort (svalue::cmp_ptr_ptr); + for (auto summary_sval : summary_svals) + { + pp_string (pp, "sval in summary: "); + summary_sval->dump_to_pp (pp, simple); + pp_newline (pp); + + const svalue *caller_sval + = *((const_cast + (m_map_svalue_from_summary_to_caller)).get (summary_sval)); + pp_string (pp, " sval in caller: "); + caller_sval->dump_to_pp (pp, simple); + pp_newline (pp); + } + + pp_newline (pp); + pp_string (pp, "region mappings from summary to caller:"); + pp_newline (pp); + auto_vec summary_regs; + for (auto kv : m_map_region_from_summary_to_caller) + summary_regs.safe_push (kv.first); + summary_regs.qsort (region::cmp_ptr_ptr); + for (auto summary_reg : summary_regs) + { + pp_string (pp, "reg in summary: "); + summary_reg->dump_to_pp (pp, simple); + pp_newline (pp); + + const region *caller_reg + = *((const_cast + (m_map_region_from_summary_to_caller)).get (summary_reg)); + pp_string (pp, " reg in caller: "); + caller_reg->dump_to_pp (pp, simple); + pp_newline (pp); + } +} + +/* Dump a multiline representation of this object to FILE. */ + +void +call_summary_replay::dump (FILE *fp, bool simple) const +{ + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + pp_show_color (&pp) = pp_show_color (global_dc->printer); + pp.buffer->stream = fp; + dump_to_pp (&pp, simple); + pp_flush (&pp); +} + +/* Dump a multiline representation of this object to stderr. */ + +DEBUG_FUNCTION void +call_summary_replay::dump (bool simple) const +{ + dump (stderr, simple); +} + +} // namespace ana + +#endif /* #if ENABLE_ANALYZER */ diff --git a/gcc/analyzer/call-summary.h b/gcc/analyzer/call-summary.h new file mode 100644 index 0000000..f4c5ff0 --- /dev/null +++ b/gcc/analyzer/call-summary.h @@ -0,0 +1,118 @@ +/* Classes for working with summaries of function calls. + Copyright (C) 2022 David Malcolm . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_ANALYZER_CALL_SUMMARY_H +#define GCC_ANALYZER_CALL_SUMMARY_H + +namespace ana { + +/* A class summarizing one particular outcome of a function that + we've already analyzed. + This lets us efficiently replay the analysis when we see calls + to the function, providing an approximation of the behavior of + the function without having to execute within the function itself. */ + +class call_summary +{ +public: + call_summary (per_function_data *per_fn_data, + const exploded_node *enode) + : m_per_fn_data (per_fn_data), + m_enode (enode) + {} + const program_state &get_state () const; + tree get_fndecl () const; + + label_text get_desc () const; + + void dump_to_pp (const extrinsic_state &ext_state, + pretty_printer *pp, + bool simple) const; + void dump (const extrinsic_state &ext_state, FILE *fp, bool simple) const; + void dump (const extrinsic_state &ext_state, bool simple) const; + +private: + void get_user_facing_desc (pretty_printer *pp) const; + + per_function_data *const m_per_fn_data; + const exploded_node *const m_enode; +}; + +/* A class for handling replaying a specific call summary at + a specific call site. + + Supports remapping svalues and regions, e.g. remapping + INIT_VAL(param of callee) + to: + whatever that argument is at the call site. */ + +class call_summary_replay +{ +public: + call_summary_replay (const call_details &cd, + function *called_fn, + call_summary *m_summary, + const extrinsic_state &ext_state); + + const call_details &get_call_details () const { return m_cd; } + const gcall *get_call_stmt () const { return m_cd.get_call_stmt (); } + region_model_manager *get_manager () const { return m_cd.get_manager (); } + store_manager *get_store_manager () const + { + return get_manager ()->get_store_manager (); + } + region_model_context *get_ctxt () const { return m_cd.get_ctxt (); } + region_model *get_caller_model () const { return m_cd.get_model (); } + + const svalue *convert_svalue_from_summary (const svalue *); + const region *convert_region_from_summary (const region *); + const binding_key *convert_key_from_summary (const binding_key *); + + void add_svalue_mapping (const svalue *summary_sval, + const svalue *caller_sval); + void add_region_mapping (const region *summary_sval, + const region *caller_sval); + + void dump_to_pp (pretty_printer *pp, bool simple) const; + void dump (FILE *fp, bool simple) const; + void dump (bool simple) const; + +private: + DISABLE_COPY_AND_ASSIGN (call_summary_replay); + + const svalue *convert_svalue_from_summary_1 (const svalue *); + const region *convert_region_from_summary_1 (const region *); + + const call_details &m_cd; + function *m_called_fn; + call_summary *m_summary; + const extrinsic_state &m_ext_state; + + // Mapping from svalues in summary to svalues for callsite: + typedef hash_map svalue_map_t; + svalue_map_t m_map_svalue_from_summary_to_caller; + + // Mapping from regions in summary to regions for callsite: + typedef hash_map region_map_t; + region_map_t m_map_region_from_summary_to_caller; +}; + +} // namespace ana + +#endif /* GCC_ANALYZER_CALL_SUMMARY_H */ diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc index 4133a13..6685e2e 100644 --- a/gcc/analyzer/constraint-manager.cc +++ b/gcc/analyzer/constraint-manager.cc @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/constraint-manager.h" +#include "analyzer/call-summary.h" #include "analyzer/analyzer-selftests.h" #include "tree-pretty-print.h" @@ -3043,6 +3044,60 @@ constraint_manager::for_each_fact (fact_visitor *visitor) const } } +/* Subclass of fact_visitor for use by + constraint_manager::replay_call_summary. */ + +class replay_fact_visitor : public fact_visitor +{ +public: + replay_fact_visitor (call_summary_replay &r, + constraint_manager *out) + : m_r (r), m_out (out), m_feasible (true) + {} + + bool feasible_p () const { return m_feasible; } + + void on_fact (const svalue *lhs, enum tree_code code, const svalue *rhs) + final override + { + const svalue *caller_lhs = m_r.convert_svalue_from_summary (lhs); + if (!caller_lhs) + return; + const svalue *caller_rhs = m_r.convert_svalue_from_summary (rhs); + if (!caller_rhs) + return; + if (!m_out->add_constraint (caller_lhs, code, caller_rhs)) + m_feasible = false; + } + + void on_ranges (const svalue *lhs_sval, + const bounded_ranges *ranges) final override + { + const svalue *caller_lhs = m_r.convert_svalue_from_summary (lhs_sval); + if (!caller_lhs) + return; + if (!m_out->add_bounded_ranges (caller_lhs, ranges)) + m_feasible = false; + } + +private: + call_summary_replay &m_r; + constraint_manager *m_out; + bool m_feasible; +}; + +/* Attempt to use R to replay the constraints from SUMMARY into this object. + Return true if it is feasible. */ + +bool +constraint_manager::replay_call_summary (call_summary_replay &r, + const constraint_manager &summary) +{ + replay_fact_visitor v (r, this); + summary.for_each_fact (&v); + return v.feasible_p (); +} + /* Assert that this object is valid. */ void diff --git a/gcc/analyzer/constraint-manager.h b/gcc/analyzer/constraint-manager.h index 1271f18..daacaa3 100644 --- a/gcc/analyzer/constraint-manager.h +++ b/gcc/analyzer/constraint-manager.h @@ -487,6 +487,9 @@ public: bounded_ranges_manager *get_range_manager () const; + bool replay_call_summary (call_summary_replay &r, + const constraint_manager &summary); + auto_delete_vec m_equiv_classes; auto_vec m_constraints; auto_vec m_bounded_ranges_constraints; diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 742ac02..b4deee5 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -72,6 +72,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "tree-dfa.h" #include "analyzer/known-function-manager.h" +#include "analyzer/call-summary.h" /* For an overview, see gcc/doc/analyzer.texi. */ @@ -1425,6 +1426,26 @@ exploded_node::on_stmt (exploded_graph &eg, &old_state, state, uncertainty, path_ctxt, stmt); + /* Handle call summaries here. */ + if (cgraph_edge *cgedge + = supergraph_call_edge (snode->get_function (), stmt)) + if (eg.get_analysis_plan ().use_summary_p (cgedge)) + { + function *called_fn = get_ultimate_function_for_cgraph_edge (cgedge); + per_function_data *called_fn_data + = eg.get_per_function_data (called_fn); + if (called_fn_data) + return replay_call_summaries (eg, + snode, + as_a (stmt), + state, + uncertainty, + path_ctxt, + called_fn, + called_fn_data, + &ctxt); + } + bool unknown_side_effects = false; bool terminate_path = false; @@ -1520,6 +1541,142 @@ exploded_node::on_stmt_post (const gimple *stmt, state->m_region_model->on_call_post (call, unknown_side_effects, ctxt); } +/* A concrete call_info subclass representing a replay of a call summary. */ + +class call_summary_edge_info : public call_info +{ +public: + call_summary_edge_info (const call_details &cd, + function *called_fn, + call_summary *summary, + const extrinsic_state &ext_state) + : call_info (cd), + m_called_fn (called_fn), + m_summary (summary), + m_ext_state (ext_state) + {} + + bool update_state (program_state *state, + const exploded_edge *, + region_model_context *ctxt) const final override + { + /* Update STATE based on summary_end_state. */ + call_details cd (get_call_details (state->m_region_model, ctxt)); + call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state); + const program_state &summary_end_state = m_summary->get_state (); + return state->replay_call_summary (r, summary_end_state); + } + + bool update_model (region_model *model, + const exploded_edge *, + region_model_context *ctxt) const final override + { + /* Update STATE based on summary_end_state. */ + call_details cd (get_call_details (model, ctxt)); + call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state); + const program_state &summary_end_state = m_summary->get_state (); + model->replay_call_summary (r, *summary_end_state.m_region_model); + return true; + } + + label_text get_desc (bool /*can_colorize*/) const final override + { + return m_summary->get_desc (); + } + +private: + function *m_called_fn; + call_summary *m_summary; + const extrinsic_state &m_ext_state; +}; + +/* Use PATH_CTXT to bifurcate, which when handled will add custom edges + for a replay of the various feasible summaries in CALLED_FN_DATA. */ + +exploded_node::on_stmt_flags +exploded_node::replay_call_summaries (exploded_graph &eg, + const supernode *snode, + const gcall *call_stmt, + program_state *state, + uncertainty_t *uncertainty, + path_context *path_ctxt, + function *called_fn, + per_function_data *called_fn_data, + region_model_context *ctxt) +{ + logger *logger = eg.get_logger (); + LOG_SCOPE (logger); + + gcc_assert (called_fn); + gcc_assert (called_fn_data); + + /* Each summary will call bifurcate on the PATH_CTXT. */ + for (auto summary : called_fn_data->m_summaries) + replay_call_summary (eg, snode, call_stmt, state, uncertainty, + path_ctxt, called_fn, summary, ctxt); + path_ctxt->terminate_path (); + + return on_stmt_flags (); +} + +/* Use PATH_CTXT to bifurcate, which when handled will add a + custom edge for a replay of SUMMARY, if the summary's + conditions are feasible based on the current state. */ + +void +exploded_node::replay_call_summary (exploded_graph &eg, + const supernode *snode, + const gcall *call_stmt, + program_state *old_state, + uncertainty_t *uncertainty, + path_context *path_ctxt, + function *called_fn, + call_summary *summary, + region_model_context *ctxt) +{ + logger *logger = eg.get_logger (); + LOG_SCOPE (logger); + gcc_assert (snode); + gcc_assert (call_stmt); + gcc_assert (old_state); + gcc_assert (called_fn); + gcc_assert (summary); + + if (logger) + logger->log ("using %s as summary for call to %qE from %qE", + summary->get_desc ().get (), + called_fn->decl, + snode->get_function ()->decl); + const extrinsic_state &ext_state = eg.get_ext_state (); + const program_state &summary_end_state = summary->get_state (); + if (logger) + { + pretty_printer *pp = logger->get_printer (); + + logger->start_log_line (); + pp_string (pp, "callsite state: "); + old_state->dump_to_pp (ext_state, true, false, pp); + logger->end_log_line (); + + logger->start_log_line (); + pp_string (pp, "summary end state: "); + summary_end_state.dump_to_pp (ext_state, true, false, pp); + logger->end_log_line (); + } + + program_state new_state (*old_state); + + call_details cd (call_stmt, new_state.m_region_model, ctxt); + call_summary_replay r (cd, called_fn, summary, ext_state); + + if (path_ctxt) + path_ctxt->bifurcate (new call_summary_edge_info (cd, + called_fn, + summary, + ext_state)); +} + + /* Consider the effect of following superedge SUCC from this node. Return true if it's feasible to follow the edge, or false @@ -2115,6 +2272,20 @@ stats::get_total_enodes () const return result; } +/* struct per_function_data. */ + +per_function_data::~per_function_data () +{ + for (auto iter : m_summaries) + delete iter; +} + +void +per_function_data::add_call_summary (exploded_node *node) +{ + m_summaries.safe_push (new call_summary (this, node)); +} + /* strongly_connected_components's ctor. Tarjan's SCC algorithm. */ strongly_connected_components:: @@ -3980,7 +4151,7 @@ exploded_graph::process_node (exploded_node *node) NULL, // uncertainty_t *uncertainty NULL, // path_context *path_ctxt stmt); - if (edge_info->update_model (bifurcated_new_state.m_region_model, + if (edge_info->update_state (&bifurcated_new_state, NULL, /* no exploded_edge yet. */ &bifurcation_ctxt)) { @@ -5350,24 +5521,17 @@ public: pretty_printer *pp = gv->get_pp (); dump_dot_id (pp); - pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=<", + pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"", "lightgrey"); - pp_string (pp, ""); pp_write_text_to_stream (pp); - gv->begin_trtd (); pp_printf (pp, "VCG: %i: %s", m_index, function_name (m_fun)); - gv->end_tdtr (); pp_newline (pp); - gv->begin_trtd (); pp_printf (pp, "supernodes: %i\n", m_num_supernodes); - gv->end_tdtr (); pp_newline (pp); - gv->begin_trtd (); pp_printf (pp, "superedges: %i\n", m_num_superedges); - gv->end_tdtr (); pp_newline (pp); if (args.m_eg) @@ -5380,9 +5544,7 @@ public: if (enode->get_point ().get_function () == m_fun) num_enodes++; } - gv->begin_trtd (); pp_printf (pp, "enodes: %i\n", num_enodes); - gv->end_tdtr (); pp_newline (pp); // TODO: also show the per-callstring breakdown @@ -5404,11 +5566,8 @@ public: } if (num_enodes > 0) { - gv->begin_trtd (); cs->print (pp); pp_printf (pp, ": %i\n", num_enodes); - pp_write_text_as_html_like_dot_to_stream (pp); - gv->end_tdtr (); } } @@ -5417,14 +5576,20 @@ public: if (data) { pp_newline (pp); - gv->begin_trtd (); pp_printf (pp, "summaries: %i\n", data->m_summaries.length ()); - pp_write_text_as_html_like_dot_to_stream (pp); - gv->end_tdtr (); + for (auto summary : data->m_summaries) + { + pp_printf (pp, "\nsummary: %s:\n", summary->get_desc ().get ()); + const extrinsic_state &ext_state = args.m_eg->get_ext_state (); + const program_state &state = summary->get_state (); + state.dump_to_pp (ext_state, false, true, pp); + pp_newline (pp); + } } } - pp_string (pp, "
>];\n\n"); + pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true); + pp_string (pp, "\"];\n\n"); pp_flush (pp); } diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h index f957568..ea4a890 100644 --- a/gcc/analyzer/exploded-graph.h +++ b/gcc/analyzer/exploded-graph.h @@ -21,6 +21,15 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_EXPLODED_GRAPH_H #define GCC_ANALYZER_EXPLODED_GRAPH_H +#include "alloc-pool.h" +#include "fibonacci_heap.h" +#include "supergraph.h" +#include "sbitmap.h" +#include "shortest-paths.h" +#include "analyzer/sm.h" +#include "analyzer/program-state.h" +#include "analyzer/diagnostic-manager.h" + namespace ana { /* Concrete implementation of region_model_context, wiring it up to the @@ -258,6 +267,25 @@ class exploded_node : public dnode bool unknown_side_effects, region_model_context *ctxt); + on_stmt_flags replay_call_summaries (exploded_graph &eg, + const supernode *snode, + const gcall *call_stmt, + program_state *state, + uncertainty_t *uncertainty, + path_context *path_ctxt, + function *called_fn, + per_function_data *called_fn_data, + region_model_context *ctxt); + void replay_call_summary (exploded_graph &eg, + const supernode *snode, + const gcall *call_stmt, + program_state *state, + uncertainty_t *uncertainty, + path_context *path_ctxt, + function *called_fn, + call_summary *summary, + region_model_context *ctxt); + bool on_edge (exploded_graph &eg, const superedge *succ, program_point *next_point, @@ -611,13 +639,11 @@ struct per_call_string_data struct per_function_data { per_function_data () {} + ~per_function_data (); - void add_call_summary (exploded_node *node) - { - m_summaries.safe_push (node); - } + void add_call_summary (exploded_node *node); - auto_vec m_summaries; + auto_vec m_summaries; }; diff --git a/gcc/analyzer/known-function-manager.h b/gcc/analyzer/known-function-manager.h index fbde853..2b95b7e 100644 --- a/gcc/analyzer/known-function-manager.h +++ b/gcc/analyzer/known-function-manager.h @@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_KNOWN_FUNCTION_MANAGER_H #define GCC_ANALYZER_KNOWN_FUNCTION_MANAGER_H +#include "analyzer/analyzer-logging.h" + namespace ana { class known_function_manager : public log_user diff --git a/gcc/analyzer/program-point.h b/gcc/analyzer/program-point.h index 63f7224..f72b86d 100644 --- a/gcc/analyzer/program-point.h +++ b/gcc/analyzer/program-point.h @@ -21,6 +21,9 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_PROGRAM_POINT_H #define GCC_ANALYZER_PROGRAM_POINT_H +#include "pretty-print.h" +#include "analyzer/call-string.h" + namespace ana { class exploded_graph; diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index f0f4046..b54bdce 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" #include "analyzer/state-purge.h" +#include "analyzer/call-summary.h" #include "analyzer/analyzer-selftests.h" #if ENABLE_ANALYZER @@ -743,6 +744,31 @@ program_state::program_state (const extrinsic_state &ext_state) } } +/* Attempt to to use R to replay SUMMARY into this object. + Return true if it is possible. */ + +bool +sm_state_map::replay_call_summary (call_summary_replay &r, + const sm_state_map &summary) +{ + for (auto kv : summary.m_map) + { + const svalue *summary_sval = kv.first; + const svalue *caller_sval = r.convert_svalue_from_summary (summary_sval); + if (!caller_sval) + continue; + const svalue *summary_origin = kv.second.m_origin; + const svalue *caller_origin + = (summary_origin + ? r.convert_svalue_from_summary (summary_origin) + : NULL); + // caller_origin can be NULL. + m_map.put (caller_sval, entry_t (kv.second.m_state, caller_origin)); + } + m_global_state = summary.m_global_state; + return true; +} + /* program_state's copy ctor. */ program_state::program_state (const program_state &other) @@ -1437,6 +1463,28 @@ program_state::detect_leaks (const program_state &src_state, dest_state.m_region_model->unset_dynamic_extents (reg); } +/* Attempt to to use R to replay SUMMARY into this object. + Return true if it is possible. */ + +bool +program_state::replay_call_summary (call_summary_replay &r, + const program_state &summary) +{ + if (!m_region_model->replay_call_summary (r, *summary.m_region_model)) + return false; + + for (unsigned sm_idx = 0; sm_idx < m_checker_states.length (); sm_idx++) + { + const sm_state_map *summary_sm_map = summary.m_checker_states[sm_idx]; + m_checker_states[sm_idx]->replay_call_summary (r, *summary_sm_map); + } + + if (!summary.m_valid) + m_valid = false; + + return true; +} + /* Handle calls to "__analyzer_dump_state". */ void diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h index baab787..ad40578 100644 --- a/gcc/analyzer/program-state.h +++ b/gcc/analyzer/program-state.h @@ -171,6 +171,9 @@ public: static const svalue * canonicalize_svalue (const svalue *sval, const extrinsic_state &ext_state); + bool replay_call_summary (call_summary_replay &r, + const sm_state_map &summary); + private: const state_machine &m_sm; map_t m_map; @@ -273,6 +276,9 @@ public: const extrinsic_state &ext_state, region_model_context *ctxt); + bool replay_call_summary (call_summary_replay &r, + const program_state &summary); + void impl_call_analyzer_dump_state (const gcall *call, const extrinsic_state &ext_state, region_model_context *ctxt); diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc index 1956cfc..9a2ee08 100644 --- a/gcc/analyzer/region-model-manager.cc +++ b/gcc/analyzer/region-model-manager.cc @@ -1275,6 +1275,33 @@ get_or_create_asm_output_svalue (tree type, return asm_output_sval; } +/* Return the svalue * of type TYPE for OUTPUT_IDX of a deterministic + asm stmt with string ASM_STRING with NUM_OUTPUTS outputs, given + INPUTS as inputs. */ + +const svalue * +region_model_manager:: +get_or_create_asm_output_svalue (tree type, + const char *asm_string, + unsigned output_idx, + unsigned num_outputs, + const vec &inputs) +{ + gcc_assert (inputs.length () <= asm_output_svalue::MAX_INPUTS); + + if (const svalue *folded + = maybe_fold_asm_output_svalue (type, inputs)) + return folded; + + asm_output_svalue::key_t key (type, asm_string, output_idx, inputs); + if (asm_output_svalue **slot = m_asm_output_values_map.get (key)) + return *slot; + asm_output_svalue *asm_output_sval + = new asm_output_svalue (type, asm_string, output_idx, num_outputs, inputs); + RETURN_UNKNOWN_IF_TOO_COMPLEX (asm_output_sval); + m_asm_output_values_map.put (key, asm_output_sval); + return asm_output_sval; +} /* Return the svalue * of type TYPE for the result of a call to FNDECL with __attribute__((const)), given INPUTS as inputs. */ diff --git a/gcc/analyzer/region-model-manager.h b/gcc/analyzer/region-model-manager.h index 0057326..3d8f76e 100644 --- a/gcc/analyzer/region-model-manager.h +++ b/gcc/analyzer/region-model-manager.h @@ -81,6 +81,12 @@ public: unsigned output_idx, const vec &inputs); const svalue * + get_or_create_asm_output_svalue (tree type, + const char *asm_string, + unsigned output_idx, + unsigned num_outputs, + const vec &inputs); + const svalue * get_or_create_const_fn_result_svalue (tree type, tree fndecl, const vec &inputs); diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index e92bba2..d14f3a1 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -66,6 +66,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/region-model-reachability.h" #include "analyzer/analyzer-selftests.h" #include "analyzer/program-state.h" +#include "analyzer/call-summary.h" #include "stor-layout.h" #include "attribs.h" #include "tree-object-size.h" @@ -5038,11 +5039,8 @@ region_model::maybe_update_for_edge (const superedge &edge, break; case SUPEREDGE_INTRAPROCEDURAL_CALL: - { - const callgraph_superedge *cg_sedge - = as_a (&edge); - update_for_call_summary (*cg_sedge, ctxt); - } + /* This is a no-op for call summaries; we should already + have handled the effect of the call summary at the call stmt. */ break; } @@ -5140,25 +5138,34 @@ region_model::update_for_return_superedge (const return_superedge &return_edge, update_for_return_gcall (call_stmt, ctxt); } -/* Update this region_model with a summary of the effect of calling - and returning from CG_SEDGE. +/* Attempt to to use R to replay SUMMARY into this object. + Return true if it is possible. */ - TODO: Currently this is extremely simplistic: we merely set the - return value to "unknown". A proper implementation would e.g. update - sm-state, and presumably be reworked to support multiple outcomes. */ - -void -region_model::update_for_call_summary (const callgraph_superedge &cg_sedge, - region_model_context *ctxt) +bool +region_model::replay_call_summary (call_summary_replay &r, + const region_model &summary) { - /* For now, set any return value to "unknown". */ - const gcall *call_stmt = cg_sedge.get_call_stmt (); - tree lhs = gimple_call_lhs (call_stmt); - if (lhs) - mark_region_as_unknown (get_lvalue (lhs, ctxt), - ctxt ? ctxt->get_uncertainty () : NULL); + gcc_assert (summary.get_stack_depth () == 1); + + m_store.replay_call_summary (r, summary.m_store); - // TODO: actually implement some kind of summary here + if (!m_constraints->replay_call_summary (r, *summary.m_constraints)) + return false; + + for (auto kv : summary.m_dynamic_extents) + { + const region *summary_reg = kv.first; + const region *caller_reg = r.convert_region_from_summary (summary_reg); + if (!caller_reg) + continue; + const svalue *summary_sval = kv.second; + const svalue *caller_sval = r.convert_svalue_from_summary (summary_sval); + if (!caller_sval) + continue; + m_dynamic_extents.put (caller_reg, caller_sval); + } + + return true; } /* Given a true or false edge guarded by conditional statement COND_STMT, diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index be0a97a..6903090 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -529,6 +529,9 @@ class region_model const svalue *get_string_size (const svalue *sval) const; const svalue *get_string_size (const region *reg) const; + bool replay_call_summary (call_summary_replay &r, + const region_model &summary); + void maybe_complain_about_infoleak (const region *dst_reg, const svalue *copied_sval, const region *src_reg, @@ -570,8 +573,6 @@ class region_model region_model_context *ctxt); void update_for_return_superedge (const return_superedge &return_edge, region_model_context *ctxt); - void update_for_call_summary (const callgraph_superedge &cg_sedge, - region_model_context *ctxt); bool apply_constraints_for_gcond (const cfg_superedge &edge, const gcond *cond_stmt, region_model_context *ctxt, diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index 1857d95..74b481d 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" +#include "analyzer/call-summary.h" #include "analyzer/analyzer-selftests.h" #include "stor-layout.h" @@ -3130,6 +3131,166 @@ store::loop_replay_fixup (const store *other_store, } } +/* Use R to replay the bindings from SUMMARY into this object. */ + +void +store::replay_call_summary (call_summary_replay &r, + const store &summary) +{ + if (summary.m_called_unknown_fn) + { + /* A call to an external function occurred in the summary. + Hence we need to invalidate our knownledge of globals, + escaped regions, etc. */ + on_unknown_fncall (r.get_call_stmt (), + r.get_store_manager (), + conjured_purge (r.get_caller_model (), + r.get_ctxt ())); + } + + auto_vec keys (summary.m_cluster_map.elements ()); + for (auto kv : summary.m_cluster_map) + keys.quick_push (kv.first); + keys.qsort (region::cmp_ptr_ptr); + for (auto base_reg : keys) + replay_call_summary_cluster (r, summary, base_reg); +} + +/* Use R and SUMMARY to replay the bindings in SUMMARY_CLUSTER + into this object. */ + +void +store::replay_call_summary_cluster (call_summary_replay &r, + const store &summary, + const region *summary_base_reg) +{ + const call_details &cd = r.get_call_details (); + region_model_manager *reg_mgr = r.get_manager (); + store_manager *mgr = reg_mgr->get_store_manager (); + const binding_cluster *summary_cluster + = summary.get_cluster (summary_base_reg); + + /* Handle "ESCAPED" and "TOUCHED" flags. */ + if (summary_cluster->escaped_p () || summary_cluster->touched_p ()) + if (const region *caller_reg + = r.convert_region_from_summary (summary_base_reg)) + { + const region *caller_base_reg = caller_reg->get_base_region (); + binding_cluster *caller_cluster + = get_or_create_cluster (caller_base_reg); + if (summary_cluster->escaped_p ()) + caller_cluster->mark_as_escaped (); + if (summary_cluster->touched_p ()) + caller_cluster->m_touched = true; + } + + switch (summary_base_reg->get_kind ()) + { + /* Top-level regions. */ + case RK_FRAME: + case RK_GLOBALS: + case RK_CODE: + case RK_STACK: + case RK_HEAP: + case RK_ROOT: + /* Child regions. */ + case RK_FIELD: + case RK_ELEMENT: + case RK_OFFSET: + case RK_SIZED: + case RK_CAST: + case RK_BIT_RANGE: + /* Other regions. */ + case RK_VAR_ARG: + case RK_UNKNOWN: + /* These should never be the base region of a binding cluster. */ + gcc_unreachable (); + break; + + case RK_FUNCTION: + case RK_LABEL: + case RK_STRING: + /* These can be marked as escaping. */ + break; + + case RK_SYMBOLIC: + { + const symbolic_region *summary_symbolic_reg + = as_a (summary_base_reg); + const svalue *summary_ptr_sval = summary_symbolic_reg->get_pointer (); + const svalue *caller_ptr_sval + = r.convert_svalue_from_summary (summary_ptr_sval); + if (!caller_ptr_sval) + return; + const region *caller_dest_reg + = cd.get_model ()->deref_rvalue (caller_ptr_sval, + NULL_TREE, + cd.get_ctxt ()); + const svalue *summary_sval + = summary.get_any_binding (mgr, summary_base_reg); + if (!summary_sval) + return; + const svalue *caller_sval + = r.convert_svalue_from_summary (summary_sval); + if (!caller_sval) + caller_sval = + reg_mgr->get_or_create_unknown_svalue (summary_sval->get_type ()); + set_value (mgr, caller_dest_reg, + caller_sval, NULL /* uncertainty_t * */); + } + break; + case RK_DECL: + { + const region *caller_dest_reg + = r.convert_region_from_summary (summary_base_reg); + if (!caller_dest_reg) + return; + const svalue *summary_sval + = summary.get_any_binding (mgr, summary_base_reg); + const svalue *caller_sval + = r.convert_svalue_from_summary (summary_sval); + if (!caller_sval) + caller_sval = + reg_mgr->get_or_create_unknown_svalue (summary_sval->get_type ()); + set_value (mgr, caller_dest_reg, + caller_sval, NULL /* uncertainty_t * */); + } + break; + case RK_HEAP_ALLOCATED: + { + const region *caller_dest_reg + = r.convert_region_from_summary (summary_base_reg); + gcc_assert (caller_dest_reg); + binding_cluster *caller_cluster + = get_or_create_cluster (caller_dest_reg); + auto_vec summary_keys; + for (auto kv : *summary_cluster) + summary_keys.safe_push (kv.first); + summary_keys.qsort (binding_key::cmp_ptrs); + for (auto summary_key : summary_keys) + { + const binding_key *caller_key + = r.convert_key_from_summary (summary_key); + if (!caller_key) + continue; + const svalue *summary_sval + = summary_cluster->get_map ().get (summary_key); + const svalue *caller_sval + = r.convert_svalue_from_summary (summary_sval); + if (!caller_sval) + caller_sval = reg_mgr->get_or_create_unknown_svalue + (summary_sval->get_type ()); + caller_cluster->bind_key (caller_key, caller_sval); + } + } + break; + + case RK_ALLOCA: + /* Ignore bindings of alloca regions in the summary. */ + break; + } +} + #if CHECKING_P namespace selftest { diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h index d172ee75..0b5cbd6 100644 --- a/gcc/analyzer/store.h +++ b/gcc/analyzer/store.h @@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_STORE_H #define GCC_ANALYZER_STORE_H +#include "tristate.h" + /* Implementation of the region-based ternary model described in: "A Memory Model for Static Analysis of C Programs" (Zhongxing Xu, Ted Kremenek, and Jian Zhang) @@ -418,6 +420,14 @@ private: } // namespace ana +template <> +template <> +inline bool +is_a_helper ::test (const ana::binding_key *key) +{ + return key->concrete_p (); +} + template <> struct default_hash_traits : public member_function_hash_traits { @@ -786,6 +796,12 @@ public: void loop_replay_fixup (const store *other_store, region_model_manager *mgr); + void replay_call_summary (call_summary_replay &r, + const store &summary); + void replay_call_summary_cluster (call_summary_replay &r, + const store &summary, + const region *base_reg); + private: void remove_overlapping_bindings (store_manager *mgr, const region *reg, uncertainty_t *uncertainty); diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index 01e30f7..a4a495a 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -62,7 +62,7 @@ namespace ana { /* Get the function of the ultimate alias target being called at EDGE, if any. */ -static function * +function * get_ultimate_function_for_cgraph_edge (cgraph_edge *edge) { cgraph_node *ultimate_node = edge->callee->ultimate_alias_target (); @@ -74,12 +74,13 @@ get_ultimate_function_for_cgraph_edge (cgraph_edge *edge) /* Get the cgraph_edge, but only if there's an underlying function body. */ cgraph_edge * -supergraph_call_edge (function *fun, gimple *stmt) +supergraph_call_edge (function *fun, const gimple *stmt) { - gcall *call = dyn_cast (stmt); + const gcall *call = dyn_cast (stmt); if (!call) return NULL; - cgraph_edge *edge = cgraph_node::get (fun->decl)->get_edge (stmt); + cgraph_edge *edge + = cgraph_node::get (fun->decl)->get_edge (const_cast (stmt)); if (!edge) return NULL; if (!edge->callee) diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h index e9a5be2..f66058c 100644 --- a/gcc/analyzer/supergraph.h +++ b/gcc/analyzer/supergraph.h @@ -21,6 +21,13 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_SUPERGRAPH_H #define GCC_ANALYZER_SUPERGRAPH_H +#include "ordered-hash-map.h" +#include "cfg.h" +#include "basic-block.h" +#include "gimple.h" +#include "gimple-iterator.h" +#include "digraph.h" + using namespace ana; namespace ana { @@ -605,7 +612,8 @@ class dot_annotator } }; -extern cgraph_edge *supergraph_call_edge (function *fun, gimple *stmt); +extern cgraph_edge *supergraph_call_edge (function *fun, const gimple *stmt); +extern function *get_ultimate_function_for_cgraph_edge (cgraph_edge *edge); } // namespace ana diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc index a37c152..d8d419a 100644 --- a/gcc/analyzer/svalue.cc +++ b/gcc/analyzer/svalue.cc @@ -1728,13 +1728,17 @@ unmergeable_svalue::implicitly_live_p (const svalue_set *live_svalues, compound_svalue::compound_svalue (tree type, const binding_map &map) : svalue (calc_complexity (map), type), m_map (map) { - /* All keys within the underlying binding_map are required to be concrete, - not symbolic. */ #if CHECKING_P for (iterator_t iter = begin (); iter != end (); ++iter) { + /* All keys within the underlying binding_map are required to be concrete, + not symbolic. */ const binding_key *key = (*iter).first; gcc_assert (key->concrete_p ()); + + /* We don't nest compound svalues. */ + const svalue *sval = (*iter).second; + gcc_assert (sval->get_kind () != SK_COMPOUND); } #endif } diff --git a/gcc/analyzer/svalue.h b/gcc/analyzer/svalue.h index 9393d6e..9d0f04d 100644 --- a/gcc/analyzer/svalue.h +++ b/gcc/analyzer/svalue.h @@ -21,7 +21,10 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_SVALUE_H #define GCC_ANALYZER_SVALUE_H +#include "json.h" #include "analyzer/complexity.h" +#include "analyzer/store.h" +#include "analyzer/program-point.h" using namespace ana; @@ -1527,6 +1530,7 @@ public: const char *get_asm_string () const { return m_asm_string; } unsigned get_output_idx () const { return m_output_idx; } + unsigned get_num_outputs () const { return m_num_outputs; } unsigned get_num_inputs () const { return m_num_inputs; } const svalue *get_input (unsigned idx) const { return m_input_arr[idx]; } diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c new file mode 100644 index 0000000..0aaf67b --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c @@ -0,0 +1,646 @@ +/* { dg-additional-options "-fanalyzer-call-summaries --param analyzer-min-snodes-for-call-summary=0" } */ + +/* There need to be at least two calls to a function for the + call-summarization code to be used. + TODO: add some kind of test that summarization *was* used. */ + +#include +#include "analyzer-decls.h" + +extern int external_fn (void *); + +int returns_const (void) +{ + return 42; +} + +void test_summarized_returns_const (void) +{ + __analyzer_eval (returns_const () == 42); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_const () == 42); /* { dg-warning "TRUE" } */ +} + +void test_summarized_returns_const_2 (void) +{ + returns_const (); /* { dg-message "when 'returns_const' returns" } */ + __analyzer_dump_path (); /* { dg-message "path" } */ +} + +int returns_param (int i) +{ + return i; +} + +void test_summarized_returns_param (int j) +{ + __analyzer_eval (returns_param (j) == j); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_param (j) == j); /* { dg-warning "TRUE" } */ +} + +void writes_const_to_ptr (int *p) +{ + *p = 42; +} + +void test_summarized_writes_const_to_ptr (void) +{ + int i, j; + writes_const_to_ptr (&i); + writes_const_to_ptr (&j); + __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */ + __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */ +} + +// TODO: we should complain about this: + +void test_summarized_write_through_null (void) +{ + writes_const_to_ptr (NULL); +} + +void writes_param_to_ptr (int i, int *p) +{ + *p = i; +} + +void test_summarized_writes_param_to_ptr (int j) +{ + int x, y; + writes_param_to_ptr (j, &x); + writes_param_to_ptr (j, &y); + __analyzer_eval (x == j); /* { dg-warning "TRUE" } */ + __analyzer_eval (y == j); /* { dg-warning "TRUE" } */ +} + +int g; + +void writes_to_global (int i) +{ + g = i; +} + +void test_writes_to_global (int x, int y) +{ + writes_to_global (x); + __analyzer_eval (g == x); /* { dg-warning "TRUE" } */ + + writes_to_global (y); + __analyzer_eval (g == y); /* { dg-warning "TRUE" } */ +} + +int reads_from_global (void) +{ + return g; +} + +void test_reads_from_global (int x, int y) +{ + g = x; + __analyzer_eval (reads_from_global () == x); /* { dg-warning "TRUE" } */ + + g = y; + __analyzer_eval (reads_from_global () == y); /* { dg-warning "TRUE" } */ +} + +/* Example of a unary op. */ + +int returns_negation (int i) +{ + return -i; +} + +void test_returns_negation (int x) +{ + __analyzer_eval (returns_negation (5) == -5); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_negation (x) == -x); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_negation (-x) == x); /* { dg-warning "TRUE" } */ +} + +/* Example of a binary op. */ + +int returns_sum (int i, int j) +{ + return i + j; +} + +void test_returns_sum (int x, int y) +{ + __analyzer_eval (returns_sum (5, 3) == 8); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_sum (7, 2) == 9); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_sum (x, y) == x + y); /* { dg-warning "TRUE" } */ +} + +struct coord +{ + int x; + int y; +}; + +struct coord make_coord (int x, int y) +{ + struct coord result = {x, y}; + return result; +} + +void test_make_coord (int i, int j) +{ + struct coord c1 = make_coord (3, 4); + __analyzer_eval (c1.x == 3); /* { dg-warning "TRUE" } */ + __analyzer_eval (c1.y == 4); /* { dg-warning "TRUE" } */ + + struct coord c2 = make_coord (i, j); + __analyzer_eval (c2.x == i); /* { dg-warning "TRUE" } */ + __analyzer_eval (c2.y == j); /* { dg-warning "TRUE" } */ +} + +/* Example of nested usage of summaries. */ + +struct rect +{ + struct coord nw; + struct coord se; +}; + +struct rect make_rect (int top, int bottom, int left, int right) +{ + struct rect result = {make_coord (left, top), + make_coord (right, bottom)}; + return result; +} + +void test_make_rect (int top, int bottom, int left, int right) +{ + struct rect r1 = make_rect (3, 4, 5, 6); + __analyzer_eval (r1.nw.y == 3); /* { dg-warning "TRUE" } */ + __analyzer_eval (r1.se.y == 4); /* { dg-warning "TRUE" } */ + __analyzer_eval (r1.nw.x == 5); /* { dg-warning "TRUE" } */ + __analyzer_eval (r1.se.x == 6); /* { dg-warning "TRUE" } */ + + struct rect r2 = make_rect (top, bottom, left, right); + __analyzer_eval (r2.nw.y == top); /* { dg-warning "TRUE" } */ + __analyzer_eval (r2.se.y == bottom); /* { dg-warning "TRUE" } */ + __analyzer_eval (r2.nw.x == left); /* { dg-warning "TRUE" } */ + __analyzer_eval (r2.se.x == right); /* { dg-warning "TRUE" } */ +} + +const char *returns_str (void) +{ + return "abc"; +} + +void test_returns_str (void) +{ + __analyzer_eval (returns_str () != NULL); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_str ()[0] == 'a'); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_str ()[1] == 'b'); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_str ()[2] == 'c'); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_str ()[3] == '\0'); /* { dg-warning "TRUE" } */ +} + +int returns_field (struct coord *p) +{ + return p->y; +} + +void test_returns_field (struct coord *q) +{ + __analyzer_eval (returns_field (q) == q->y); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_field (q) == q->y); /* { dg-warning "TRUE" } */ +} + +void writes_to_fields (struct coord *p, int x, int y) +{ + p->x = x; + p->y = y; +} + +void test_writes_to_field (struct coord *q, int qx, int qy) +{ + struct coord a, b; + writes_to_fields (&a, 1, 2); + __analyzer_eval (a.x == 1); /* { dg-warning "TRUE" } */ + __analyzer_eval (a.y == 2); /* { dg-warning "TRUE" } */ + writes_to_fields (&b, 3, 4); + __analyzer_eval (b.x == 3); /* { dg-warning "TRUE" } */ + __analyzer_eval (b.y == 4); /* { dg-warning "TRUE" } */ + writes_to_fields (q, qx, qy); + __analyzer_eval (q->x == qx); /* { dg-warning "TRUE" } */ + __analyzer_eval (q->y == qy); /* { dg-warning "TRUE" } */ +} + +/* Example of nested function summarization. */ + +int get_min_x (struct rect *p) +{ + return p->nw.x; +} + +int get_min_y (struct rect *p) +{ + return p->nw.y; +} + +int get_max_x (struct rect *p) +{ + return p->se.x; +} + +int get_max_y (struct rect *p) +{ + return p->se.y; +} + +int get_area (struct rect *p) +{ + return ((get_max_x (p) - get_min_x (p)) + * (get_max_y (p) - get_min_y (p))); +} + +void test_get_area (int top, int bottom, int left, int right, struct rect *p) +{ + { + /* 1x1 at origin. */ + struct rect a = make_rect (0, 1, 0, 1); + __analyzer_eval (get_min_y (&a) == 0); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_max_y (&a) == 1); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_min_x (&a) == 0); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_max_x (&a) == 1); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_area (&a) == 1); /* { dg-warning "TRUE" } */ + } + + { + /* 4x5. */ + struct rect b = make_rect (3, 7, 4, 9); + __analyzer_eval (get_min_y (&b) == 3); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_max_y (&b) == 7); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_min_x (&b) == 4); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_max_x (&b) == 9); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_area (&b) == 20); /* { dg-warning "TRUE" } */ + } + + { + /* Symbolic. */ + struct rect c = make_rect (top, bottom, left, right); + __analyzer_eval (get_min_y (&c) == top); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_max_y (&c) == bottom); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_min_x (&c) == left); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_max_x (&c) == right); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_area (&c) == ((right - left) * (bottom - top))); /* { dg-warning "TRUE" } */ + } + + /* Symbolic via ptr. */ + __analyzer_eval (get_min_y (p) == p->nw.y); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_max_y (p) == p->se.y); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_min_x (p) == p->nw.x); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_max_x (p) == p->se.x); /* { dg-warning "TRUE" } */ + __analyzer_eval (get_area (p) == ((p->se.x - p->nw.x) * (p->se.y - p->nw.y))); /* { dg-warning "TRUE" } */ +} + +int returns_element (int i) +{ + static const int arr[3] = {7, 8, 9}; + return arr[i]; +} + +void test_returns_element (int j) +{ + __analyzer_eval (returns_element (0) == 7); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (returns_element (1) == 8); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (returns_element (2) == 9); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (returns_element (3) == 10); /* { dg-warning "UNKNOWN" } */ + // TODO: out of bounds +} + +const int *returns_element_ptr (int i) +{ + static const int arr[3] = {7, 8, 9}; + return &arr[i]; +} + +int test_returns_element_ptr (int j) +{ + __analyzer_eval (*returns_element_ptr (0) == 7); /* { dg-warning "TRUE" } */ + __analyzer_eval (*returns_element_ptr (1) == 8); /* { dg-warning "TRUE" } */ + __analyzer_eval (*returns_element_ptr (2) == 9); /* { dg-warning "TRUE" } */ + return *returns_element_ptr (3); /* { dg-warning "buffer overread" } */ +} + +int returns_offset (int arr[3], int i) +{ + return arr[i]; +} + +void test_returns_offset (int outer_arr[3], int idx) +{ + int a[3] = {4, 5, 6}; + __analyzer_eval (returns_offset (a, 0) == 4); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_offset (a, 1) == 5); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_offset (a, 2) == 6); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_offset (a, idx) == a[idx]); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (returns_offset (outer_arr, 0) == outer_arr[0]); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_offset (outer_arr, idx) == outer_arr[idx]); /* { dg-warning "TRUE" } */ +} + +int returns_offset_2 (int arr[], int i) +{ + return arr[i]; +} + +void test_returns_offset_2 (int outer_arr[], int idx) +{ + int a[3] = {4, 5, 6}; + __analyzer_eval (returns_offset_2 (a, 0) == 4); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_offset_2 (a, 1) == 5); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_offset_2 (a, 2) == 6); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_offset_2 (a, idx) == a[idx]); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (returns_offset_2 (outer_arr, 0) == outer_arr[0]); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_offset_2 (outer_arr, idx) == outer_arr[idx]); /* { dg-warning "TRUE" } */ +} + +int returns_offset_3 (int *p, int i) +{ + return p[i]; +} + +void test_returns_offset_3 (int *q, int j) +{ + __analyzer_eval (returns_offset_3 (q, j) == q[j]); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_offset_3 (q, j) == q[j]); /* { dg-warning "TRUE" } */ +} + +/* With state merging, this is summarized as returning "UNKNOWN". */ + +int two_outcomes (int flag, int x, int y) +{ + if (flag) + return x; + else + return y; +} + +void test_two_outcomes (int outer_flag, int a, int b) +{ + int r; + __analyzer_eval (two_outcomes (1, a, b) == a); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (two_outcomes (0, a, b) == b); /* { dg-warning "UNKNOWN" } */ + r = two_outcomes (outer_flag, a, b); + if (outer_flag) + __analyzer_eval (r == a); /* { dg-warning "UNKNOWN" } */ + else + __analyzer_eval (r == b); /* { dg-warning "UNKNOWN" } */ +} + +/* Verify that summary replays capture postconditions. */ + +void check_int_nonnegative (int i) +{ + if (i < 0) + __builtin_unreachable (); +} + +void test_check_int_nonnegative (int i, int j) +{ + __analyzer_eval (i >= 0); /* { dg-warning "UNKNOWN" } */ + check_int_nonnegative (i); + __analyzer_eval (i >= 0); /* { dg-warning "TRUE" } */ + + __analyzer_eval (j >= 0); /* { dg-warning "UNKNOWN" } */ + check_int_nonnegative (j); + __analyzer_eval (j >= 0); /* { dg-warning "TRUE" } */ +} + +void calls_external_fn (void) +{ + external_fn (NULL); +} + +void test_calls_external_fn (void) +{ + g = 1; + __analyzer_eval (g == 1); /* { dg-warning "TRUE" } */ + calls_external_fn (); + calls_external_fn (); + __analyzer_eval (g == 1); /* { dg-warning "UNKNOWN" "expected" { xfail *-*-* } } */ + /* { dg-bogus "TRUE" "bogus" { xfail *-*-* } .-1 } */ + // TODO(xfails) +} + +int returns_iterator (int n) +{ + int i; + for (i = 0; i < n; i++) + { + } + return i; +} + +void test_returns_iterator (int j, int k) +{ + __analyzer_eval (returns_iterator (j) == j); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (returns_iterator (k) == k); /* { dg-warning "UNKNOWN" } */ + /* TODO: ideally we'd capture these equalities, but this is an issue + with how we handle loops. */ +} + +int returns_external_result (void) +{ + return external_fn (NULL); +} + +int test_returns_external_result (void) +{ + int i, j; + i = returns_external_result (); + j = returns_external_result (); + __analyzer_eval (i == j); /* { dg-warning "UNKNOWN" } */ + return i * j; +} + +int uses_alloca (int i) +{ + int *p = alloca (sizeof (int)); + *p = i; + return *p; +} + +void test_uses_alloca (int x) +{ + __analyzer_eval (uses_alloca (42) == 42); /* { dg-warning "TRUE" } */ + __analyzer_eval (uses_alloca (x) == x); /* { dg-warning "TRUE" } */ +} + +struct bits +{ + unsigned b0 : 1; + unsigned b1 : 1; + unsigned b2 : 1; + unsigned b3 : 1; + unsigned b4 : 1; + unsigned b5 : 1; + unsigned b6 : 1; + unsigned b7 : 1; +}; + +int returns_bitfield (struct bits b) +{ + return b.b3; +} + +void test_returns_bitfield (struct bits s) +{ + __analyzer_eval (returns_bitfield (s) == s.b3); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (returns_bitfield (s) == s.b3); /* { dg-warning "UNKNOWN" } */ + // TODO: ideally it would figure out that these are equal +} + +int consume_two_ints_from_va_list (__builtin_va_list ap) +{ + int i, j; + i = __builtin_va_arg (ap, int); + j = __builtin_va_arg (ap, int); + return i * j; +} + +int test_consume_two_ints_from_va_list (__builtin_va_list ap1) +{ + int p1, p2; + __builtin_va_list ap2; + __builtin_va_copy (ap2, ap1); + p1 = consume_two_ints_from_va_list (ap1); + p2 = consume_two_ints_from_va_list (ap2); + __analyzer_eval (p1 == p2); /* { dg-warning "UNKNOWN" } */ + // TODO: ideally it would figure out these are equal + __builtin_va_end (ap2); +} + +int consume_two_ints_from_varargs (int placeholder, ...) +{ + int i, j; + __builtin_va_list ap; + __builtin_va_start (ap, placeholder); + i = __builtin_va_arg (ap, int); + j = __builtin_va_arg (ap, int); + __builtin_va_end (ap); + return i * j; +} + +void test_consume_two_ints_from_varargs (int x, int y) +{ + __analyzer_eval (consume_two_ints_from_varargs (0, 4, 5) == 20); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (consume_two_ints_from_varargs (0, 3, 6) == 18); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (consume_two_ints_from_varargs (0, x, 6) == x * y); /* { dg-warning "UNKNOWN" } */ + // TODO: ideally it would figure these out +} + +extern int const_fn_1 (int) __attribute__ ((const)); +int calls_const_fn (int i) +{ + return const_fn_1 (i); +} + +void test_calls_const_fn (int x) +{ + int r1, r2; + r1 = calls_const_fn (x); + r2 = calls_const_fn (x); + __analyzer_eval (r1 == r2); /* { dg-warning "TRUE" } */ +} + +typedef struct iv2 { int arr[2]; } iv2_t; +typedef struct iv4 { int arr[4]; } iv4_t; + +iv2_t returns_iv2_t (int x, int y) +{ + iv2_t result = {x, y}; + return result; +} + +void test_returns_iv2_t (int a, int b) +{ + __analyzer_eval (returns_iv2_t (a, b).arr[0] == a); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_iv2_t (a, b).arr[1] == b); /* { dg-warning "TRUE" } */ +} + +iv4_t returns_iv4_t (int a, iv2_t bc, int d) +{ + iv4_t result = {a, bc.arr[0], bc.arr[1], d}; + return result; +} + +void test_returns_iv4_t (int p, iv2_t qr, int s) +{ + __analyzer_eval (returns_iv4_t (p, qr, s).arr[0] == p); /* { dg-warning "TRUE" } */ + __analyzer_eval (returns_iv4_t (p, qr, s).arr[1] == qr.arr[0]); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (returns_iv4_t (p, qr, s).arr[2] == qr.arr[1]); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (returns_iv4_t (p, qr, s).arr[3] == s); /* { dg-warning "TRUE" } */ + // TODO: ideally the UNKNOWNs would be TRUEs. +} + +void copies_iv2_t (int *p, iv2_t xy) +{ + __builtin_memcpy (p, &xy, sizeof (xy)); +} + +void test_copies_iv2_t (iv2_t ab, iv2_t cd) +{ + iv4_t t; + copies_iv2_t (&t.arr[0], ab); + copies_iv2_t (&t.arr[2], cd); + __analyzer_eval (t.arr[0] = ab.arr[0]); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (t.arr[1] = ab.arr[1]); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (t.arr[2] = cd.arr[0]); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (t.arr[3] = cd.arr[1]); /* { dg-warning "UNKNOWN" } */ + // TODO: ideally the UNKNOWNs would be TRUEs. +} + +void partially_inits (int *p, int v) +{ + p[1] = v; +} + +void test_partially_inits (int x) +{ + int arr[2]; + partially_inits (arr, x); + partially_inits (arr, x); + + __analyzer_eval (arr[0]); /* { dg-warning "UNKNOWN" "eval" } */ + /* { dg-warning "use of uninitialized value 'arr\\\[0\\\]'" "uninit" { target *-*-* } .-1 } */ + + __analyzer_eval (arr[1] == x); /* { dg-warning "UNKNOWN" "eval" } */ + /* { dg-bogus "use of uninitialized value 'arr\\\[1\\\]'" "uninit" { xfail *-*-* } .-1 } */ + // TODO(xfail), and eval should be "TRUE" +} + +int uses_switch (int i) +{ + switch (i) + { + case 0: + return 42; + case 1: + return 17; + default: + return i * 2; + } +} + +void test_uses_switch (int x) +{ + __analyzer_eval (uses_switch (0) == 42); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (uses_switch (1) == 17); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (uses_switch (2) == x * 2); /* { dg-warning "UNKNOWN" } */ + // TODO: ideally the UNKNOWNs would be TRUEs. +} + +int *returns_ptr_to_first_field (struct coord *p) +{ + return &p->x; +} + +void test_returns_ptr_to_first_field (struct coord *q) +{ + __analyzer_eval (returns_ptr_to_first_field (q) == (int *)q); /* { dg-warning "UNKNOWN" } */ + __analyzer_eval (returns_ptr_to_first_field (q) == (int *)q); /* { dg-warning "UNKNOWN" } */ + // TODO: ideally the UNKNOWNs would be TRUEs. +} diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-3.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-3.c new file mode 100644 index 0000000..d63eb0c --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-3.c @@ -0,0 +1,29 @@ +/* { dg-additional-options "-fanalyzer-call-summaries --param analyzer-min-snodes-for-call-summary=0 -fno-analyzer-state-merge" } */ + +/* There need to be at least two calls to a function for the + call-summarization code to be used. + TODO: add some kind of test that summarization *was* used. */ + +#include "analyzer-decls.h" + +/* With state merging disabled, we get two summaries here. */ + +int two_outcomes (int flag, int x, int y) +{ + if (flag) + return x; + else + return y; +} + +void test_two_outcomes (int outer_flag, int a, int b) +{ + int r; + __analyzer_eval (two_outcomes (1, a, b) == a); /* { dg-warning "TRUE" } */ + __analyzer_eval (two_outcomes (0, a, b) == b); /* { dg-warning "TRUE" } */ + r = two_outcomes (outer_flag, a, b); + if (outer_flag) + __analyzer_eval (r == a); /* { dg-warning "TRUE" } */ + else + __analyzer_eval (r == b); /* { dg-warning "TRUE" } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-asm-x86.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-asm-x86.c new file mode 100644 index 0000000..cc23283 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-asm-x86.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target x86_64-*-* } } */ +/* { dg-additional-options "-fanalyzer-call-summaries --param analyzer-min-snodes-for-call-summary=0" } */ + +#include "analyzer-decls.h" + +int returns_asm_value (void) +{ + int dst; + asm ("mov 42, %0" + : "=r" (dst)); + return dst; +} + +void test_returns_asm_value (void) +{ + int a, b; + a = returns_asm_value (); + b = returns_asm_value (); + __analyzer_eval (a == b); /* { dg-warning "TRUE" } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-malloc.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-malloc.c new file mode 100644 index 0000000..87173a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-malloc.c @@ -0,0 +1,80 @@ +/* { dg-additional-options "-fanalyzer-call-summaries --param analyzer-min-snodes-for-call-summary=0" } */ + +/* There need to be at least two calls to a function for the + call-summarization code to be used. + TODO: add some kind of test that summarization *was* used. */ + +#include +#include +#include "analyzer-decls.h" + +int *malloc_int (int i) +{ + int *res = malloc (sizeof (int)); + if (!res) + return NULL; + *res = i; + return res; +} + +void test_malloc_int (int x) +{ + int *p, *q; + + p = malloc_int (42); + if (p) + __analyzer_eval (*p == 42); /* { dg-warning "TRUE" } */ + free (p); + + q = malloc_int (x); + if (q) + __analyzer_eval (*q == x); /* { dg-warning "TRUE" } */ + free (q); +} + +void test_leak (int x) +{ + int *p = malloc_int (x); /* { dg-message "when 'malloc_int' returns pointer to heap-allocated buffer" } */ +} /* { dg-message "leak of 'p'" } */ + +void *wrapped_malloc (size_t sz) +{ + return malloc (sz); +} + +void wrapped_free (void *p) +{ + free (p); +} + +void test_wrapped_malloc_and_free (size_t sz) +{ + void *p = wrapped_malloc (100); + void *q = wrapped_malloc (sz); + __analyzer_dump_capacity (p); /* { dg-warning "capacity: '\\(\[^\n\r\]*\\)100'" } */ + __analyzer_dump_capacity (q); /* { dg-warning "capacity: 'INIT_VAL\\(sz_\[^\n\r\]*\\)'" } */ + wrapped_free (p); + wrapped_free (q); +} + +void test_use_after_free (void) +{ + // TODO +} + +void test_use_without_check (size_t sz) +{ + char *buf = wrapped_malloc (sz); /* { dg-message "this call could return NULL" } */ + memset (buf, 'x', sz); /* { dg-warning "use of possibly-NULL 'buf' where non-null expected" } */ + wrapped_free (buf); +} + +void test_out_of_bounds (size_t sz) +{ + char *buf = wrapped_malloc (sz); + if (!buf) + return; + memset (buf, 'x', sz); + buf[sz] = '\0'; /* { dg-warning "heap-based buffer overflow" } */ + wrapped_free (buf); +} diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c new file mode 100644 index 0000000..1e689b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c @@ -0,0 +1,90 @@ +/* { dg-additional-options "-fanalyzer-call-summaries --param analyzer-min-snodes-for-call-summary=0" } */ + +/* There need to be at least two calls to a function for the + call-summarization code to be used. + TODO: add some kind of test that summarization *was* used. */ + +/* Reduced from an example in Emacs in which string_char_and_length + was being incorrectly summarized, failing to see the write to *length. */ + +typedef long int ptrdiff_t; +typedef struct Lisp_X *Lisp_Word; +typedef Lisp_Word Lisp_Object; +extern _Bool STRING_MULTIBYTE(Lisp_Object str); +extern unsigned char *SDATA(Lisp_Object string); +enum { MAX_2_BYTE_CHAR = 0x7FF }; +enum { MAX_3_BYTE_CHAR = 0xFFFF }; +enum { MAX_4_BYTE_CHAR = 0x1FFFFF }; +enum { MAX_5_BYTE_CHAR = 0x3FFF7F }; +extern int make_char_multibyte(int c); +static inline int string_char_and_length(unsigned char const *p, int *length) { + int c = p[0]; + if (!(c & 0x80)) { + *length = 1; + return c; + } + ((0xC0 <= c) ? (void)0 : __builtin_unreachable()); + int d = (c << 6) + p[1] - ((0xC0 << 6) + 0x80); + if (!(c & 0x20)) { + *length = 2; + return d + (c < 0xC2 ? 0x3FFF80 : 0); + } + d = (d << 6) + p[2] - ((0x20 << 12) + 0x80); + if (!(c & 0x10)) { + *length = 3; + ((MAX_2_BYTE_CHAR < d && d <= MAX_3_BYTE_CHAR) + ? (void)0 + : __builtin_unreachable()); + return d; + } + d = (d << 6) + p[3] - ((0x10 << 18) + 0x80); + if (!(c & 0x08)) { + *length = 4; + ((MAX_3_BYTE_CHAR < d && d <= MAX_4_BYTE_CHAR) + ? (void)0 + : __builtin_unreachable()); + return d; + } + d = (d << 6) + p[4] - ((0x08 << 24) + 0x80); + *length = 5; + ((MAX_4_BYTE_CHAR < d && d <= MAX_5_BYTE_CHAR) + ? (void)0 + : __builtin_unreachable()); + return d; +} +int fetch_string_char_advance(Lisp_Object string, + ptrdiff_t *charidx, + ptrdiff_t *byteidx) { + int output; + ptrdiff_t b = *byteidx; + unsigned char *chp = SDATA(string) + b; + if (STRING_MULTIBYTE(string)) { + int chlen; + output = string_char_and_length(chp, &chlen); + b += chlen; + } else { + output = *chp; + b++; + } + (*charidx)++; + *byteidx = b; + return output; +} +int fetch_string_char_as_multibyte_advance(Lisp_Object string, + ptrdiff_t *charidx, + ptrdiff_t *byteidx) { + int output; + ptrdiff_t b = *byteidx; + unsigned char *chp = SDATA(string) + b; + if (STRING_MULTIBYTE(string)) { + int chlen; + output = string_char_and_length(chp, &chlen); + b += chlen; + } else { + output = make_char_multibyte(*chp); + b++; + } + (*charidx)++; + *byteidx = b; + return output; +} -- cgit v1.1 From b77bcdf445685f28dae9e42b69e006801d653001 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Fri, 2 Sep 2022 14:05:33 -0700 Subject: RISC-V: remove deprecate pic code model macro Came across this deprecated symbol when looking around for -mexplicit-relocs handling in code Signed-off-by: Vineet Gupta gcc/ChangeLog: * config/riscv/riscv-c.cc (riscv_cpu_cpp_builtins): Remove __riscv_cmodel_pic, that deprecated in last version. gcc/testsuite/ChangeLog: * gcc.target/riscv/predef-1.c: Remove __riscv_cmodel_pic check. * gcc.target/riscv/predef-2.c: Ditto. * gcc.target/riscv/predef-3.c: Ditto. * gcc.target/riscv/predef-4.c: Ditto. * gcc.target/riscv/predef-5.c: Ditto. * gcc.target/riscv/predef-6.c: Ditto. * gcc.target/riscv/predef-7.c: Ditto. * gcc.target/riscv/predef-8.c: Ditto. --- gcc/config/riscv/riscv-c.cc | 5 ----- gcc/testsuite/gcc.target/riscv/predef-1.c | 3 --- gcc/testsuite/gcc.target/riscv/predef-2.c | 3 --- gcc/testsuite/gcc.target/riscv/predef-3.c | 3 --- gcc/testsuite/gcc.target/riscv/predef-4.c | 3 --- gcc/testsuite/gcc.target/riscv/predef-5.c | 3 --- gcc/testsuite/gcc.target/riscv/predef-6.c | 3 --- gcc/testsuite/gcc.target/riscv/predef-7.c | 3 --- gcc/testsuite/gcc.target/riscv/predef-8.c | 3 --- 9 files changed, 29 deletions(-) (limited to 'gcc') diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc index eb7ef09..8d55ad5 100644 --- a/gcc/config/riscv/riscv-c.cc +++ b/gcc/config/riscv/riscv-c.cc @@ -93,11 +93,6 @@ riscv_cpu_cpp_builtins (cpp_reader *pfile) break; case CM_PIC: - /* __riscv_cmodel_pic is deprecated, and will removed in next GCC release. - see https://github.com/riscv/riscv-c-api-doc/pull/11 */ - builtin_define ("__riscv_cmodel_pic"); - /* FALLTHROUGH. */ - case CM_MEDANY: builtin_define ("__riscv_cmodel_medany"); break; diff --git a/gcc/testsuite/gcc.target/riscv/predef-1.c b/gcc/testsuite/gcc.target/riscv/predef-1.c index 2e57ce6..9dddc18 100644 --- a/gcc/testsuite/gcc.target/riscv/predef-1.c +++ b/gcc/testsuite/gcc.target/riscv/predef-1.c @@ -58,9 +58,6 @@ int main () { #if defined(__riscv_cmodel_medany) #error "__riscv_cmodel_medlow" #endif -#if defined(__riscv_cmodel_pic) -#error "__riscv_cmodel_medlow" -#endif return 0; } diff --git a/gcc/testsuite/gcc.target/riscv/predef-2.c b/gcc/testsuite/gcc.target/riscv/predef-2.c index c85b3c9..755fe4e 100644 --- a/gcc/testsuite/gcc.target/riscv/predef-2.c +++ b/gcc/testsuite/gcc.target/riscv/predef-2.c @@ -58,9 +58,6 @@ int main () { #if !defined(__riscv_cmodel_medany) #error "__riscv_cmodel_medlow" #endif -#if defined(__riscv_cmodel_pic) -#error "__riscv_cmodel_medlow" -#endif return 0; } diff --git a/gcc/testsuite/gcc.target/riscv/predef-3.c b/gcc/testsuite/gcc.target/riscv/predef-3.c index 82a89d4..5136453 100644 --- a/gcc/testsuite/gcc.target/riscv/predef-3.c +++ b/gcc/testsuite/gcc.target/riscv/predef-3.c @@ -58,9 +58,6 @@ int main () { #if !defined(__riscv_cmodel_medany) #error "__riscv_cmodel_medany" #endif -#if !defined(__riscv_cmodel_pic) -#error "__riscv_cmodel_pic" -#endif return 0; } diff --git a/gcc/testsuite/gcc.target/riscv/predef-4.c b/gcc/testsuite/gcc.target/riscv/predef-4.c index 5868d39..76b6fee 100644 --- a/gcc/testsuite/gcc.target/riscv/predef-4.c +++ b/gcc/testsuite/gcc.target/riscv/predef-4.c @@ -58,9 +58,6 @@ int main () { #if defined(__riscv_cmodel_medany) #error "__riscv_cmodel_medlow" #endif -#if defined(__riscv_cmodel_pic) -#error "__riscv_cmodel_medlow" -#endif return 0; } diff --git a/gcc/testsuite/gcc.target/riscv/predef-5.c b/gcc/testsuite/gcc.target/riscv/predef-5.c index 4b2bd38..54a5150 100644 --- a/gcc/testsuite/gcc.target/riscv/predef-5.c +++ b/gcc/testsuite/gcc.target/riscv/predef-5.c @@ -58,9 +58,6 @@ int main () { #if !defined(__riscv_cmodel_medany) #error "__riscv_cmodel_medlow" #endif -#if defined(__riscv_cmodel_pic) -#error "__riscv_cmodel_medlow" -#endif return 0; } diff --git a/gcc/testsuite/gcc.target/riscv/predef-6.c b/gcc/testsuite/gcc.target/riscv/predef-6.c index 8e5ea36..f61709f 100644 --- a/gcc/testsuite/gcc.target/riscv/predef-6.c +++ b/gcc/testsuite/gcc.target/riscv/predef-6.c @@ -58,9 +58,6 @@ int main () { #if !defined(__riscv_cmodel_medany) #error "__riscv_cmodel_medany" #endif -#if !defined(__riscv_cmodel_pic) -#error "__riscv_cmodel_medpic" -#endif return 0; } diff --git a/gcc/testsuite/gcc.target/riscv/predef-7.c b/gcc/testsuite/gcc.target/riscv/predef-7.c index 0bde299..4121755 100644 --- a/gcc/testsuite/gcc.target/riscv/predef-7.c +++ b/gcc/testsuite/gcc.target/riscv/predef-7.c @@ -58,9 +58,6 @@ int main () { #if defined(__riscv_cmodel_medany) #error "__riscv_cmodel_medlow" #endif -#if defined(__riscv_cmodel_pic) -#error "__riscv_cmodel_medlow" -#endif return 0; } diff --git a/gcc/testsuite/gcc.target/riscv/predef-8.c b/gcc/testsuite/gcc.target/riscv/predef-8.c index 18aa591..982056a 100644 --- a/gcc/testsuite/gcc.target/riscv/predef-8.c +++ b/gcc/testsuite/gcc.target/riscv/predef-8.c @@ -58,9 +58,6 @@ int main () { #if !defined(__riscv_cmodel_medany) #error "__riscv_cmodel_medlow" #endif -#if defined(__riscv_cmodel_pic) -#error "__riscv_cmodel_medlow" -#endif return 0; } -- cgit v1.1 From 5fe2e4f87e512407c5c560dfec2fe48ba099c807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20SVENSSON?= Date: Thu, 29 Sep 2022 19:38:10 +0200 Subject: testsuite: /dev/null is not accessible on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running the DejaGNU testsuite on a toolchain built for native Windows, the path /dev/null can't be used to open a stream to void. On native Windows, the resource is instead named "nul". The error would look like this: c:/arm-11.3.rel1/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld.exe: cannot find @/dev/null: No such file or directory Patch has been verified on Windows and Linux. gcc/testsuite: * gcc.misc-tests/outputs.exp: Use "@nul" for Windows, "@/dev/null" for other environments. Co-Authored-By: Yvan ROUX Signed-off-by: Torbjörn SVENSSON Signed-off-by: Jonathan Yong <10walls@gmail.com> --- gcc/testsuite/gcc.misc-tests/outputs.exp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp b/gcc/testsuite/gcc.misc-tests/outputs.exp index ab919db..3fe7270 100644 --- a/gcc/testsuite/gcc.misc-tests/outputs.exp +++ b/gcc/testsuite/gcc.misc-tests/outputs.exp @@ -78,6 +78,13 @@ if {[board_info $dest exists output_format]} { append link_options " additional_flags=-Wl,-oformat,[board_info $dest output_format]" } + +set devnull "/dev/null" +if { [info exists ::env(OS)] && [string match "Windows*" $::env(OS)] } { + # Windows uses special file named "nul" as a substitute for /dev/null + set devnull "nul" +} + # Avoid possible influence from the make jobserver, # otherwise ltrans0.ltrans_args files may be missing. if [info exists env(MAKEFLAGS)] { @@ -353,10 +360,10 @@ outest "$b-21 exe savetmp named2" $mult "-o $b.exe -save-temps" {} {{--1.i --1.s # Additional files are created when an @file is used if !$skip_atsave { -outest "$b-22 exe savetmp namedb-2" $sing "@/dev/null -o $b.exe -save-temps" {} {{--0.i --0.s --0.o .args.0 !!$gld .ld1_args !0 .exe}} -outest "$b-23 exe savetmp named2-2" $mult "@/dev/null -o $b.exe -save-temps" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .args.0 !!$gld .ld1_args !0 .exe}} -outest "$b-24 exe savetmp named2-3" $mult "@/dev/null -I dummy -o $b.exe -save-temps" {} {{--1.i --1.s --1.o --2.i --2.s --2.o -args.0 -args.1 .args.2 !!$gld .ld1_args !0 .exe}} -outest "$b-25 exe savetmp named2-4" $mult "@/dev/null -I dummy -L dummy -o $b.exe -save-temps" {} {{--1.i --1.s --1.o --2.i --2.s --2.o -args.0 -args.1 .args.2 .args.3 !!$gld .ld1_args !0 .exe}} +outest "$b-22 exe savetmp namedb-2" $sing "@$devnull -o $b.exe -save-temps" {} {{--0.i --0.s --0.o .args.0 !!$gld .ld1_args !0 .exe}} +outest "$b-23 exe savetmp named2-2" $mult "@$devnull -o $b.exe -save-temps" {} {{--1.i --1.s --1.o --2.i --2.s --2.o .args.0 !!$gld .ld1_args !0 .exe}} +outest "$b-24 exe savetmp named2-3" $mult "@$devnull -I dummy -o $b.exe -save-temps" {} {{--1.i --1.s --1.o --2.i --2.s --2.o -args.0 -args.1 .args.2 !!$gld .ld1_args !0 .exe}} +outest "$b-25 exe savetmp named2-4" $mult "@$devnull -I dummy -L dummy -o $b.exe -save-temps" {} {{--1.i --1.s --1.o --2.i --2.s --2.o -args.0 -args.1 .args.2 .args.3 !!$gld .ld1_args !0 .exe}} } # Setting the main output to a dir selects it as the default aux&dump @@ -714,7 +721,7 @@ outest "$b-291 lto mult named-2" $mult "-o $b.exe -O2 -flto -fno-use-linker-plug outest "$b-292 lto sing nameddir-2" $sing "-o dir/$b.exe -O2 -flto -fno-use-linker-plugin -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--0.c.???i.icf --0.c.???r.final .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}} outest "$b-293 lto mult nameddir-2" $mult "-o dir/$b.exe -O2 -flto -fno-use-linker-plugin -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage" {dir/} {{--1.c.???i.icf --1.c.???r.final --2.c.???i.icf --2.c.???r.final .wpa.???i.icf .ltrans0.ltrans.???r.final .ltrans0.ltrans.su .exe} {}} if !$skip_atsave { -outest "$b-294 lto sing unnamed-3" $sing "@/dev/null -O2 -flto -fno-use-linker-plugin -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage -save-temps $oaout" {} {{a--0.c.???i.icf a--0.c.???r.final a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a--0.o a--0.s a--0.i a.ltrans0.o a.ltrans.out a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.args.0 a.ltrans0.ltrans.s a.wpa.args.0 a.lto_args a.ld1_args a.ltrans_args a.ltrans0.ltrans.args.0 a.ld_args $aout}} +outest "$b-294 lto sing unnamed-3" $sing "@$devnull -O2 -flto -fno-use-linker-plugin -flto-partition=one -fdump-ipa-icf-optimized -fdump-rtl-final -fstack-usage -save-temps $oaout" {} {{a--0.c.???i.icf a--0.c.???r.final a.wpa.???i.icf a.ltrans0.ltrans.???r.final a.ltrans0.ltrans.su a--0.o a--0.s a--0.i a.ltrans0.o a.ltrans.out a.ltrans0.ltrans.o a.ltrans0.ltrans_args a.args.0 a.ltrans0.ltrans.s a.wpa.args.0 a.lto_args a.ld1_args a.ltrans_args a.ltrans0.ltrans.args.0 a.ld_args $aout}} } } -- cgit v1.1 From fa8e3a055a082e38aeab2561a5016b01ebfd6ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20SVENSSON?= Date: Thu, 29 Sep 2022 20:07:11 +0200 Subject: testsuite: Windows reports errors with CreateProcess MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the mapper can't be executed, Windows report the error like: .../bad-mapper-1.C: error: failed CreateProcess mapper 'this-will-not-work' On Linux, the same error is reported this way: .../bad-mapper-1.C: error: failed execvp mapper 'this-will-not-work' This patch allows both output forms to be accepted. Patch has been verified on Windows and Linux. gcc/testsuite: * g++.dg/modules/bad-mapper-1.C: Also accept CreateProcess. Co-Authored-By: Yvan ROUX Signed-off-by: Torbjörn SVENSSON Signed-off-by: Jonathan Yong <10walls@gmail.com> --- gcc/testsuite/g++.dg/modules/bad-mapper-1.C | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/g++.dg/modules/bad-mapper-1.C b/gcc/testsuite/g++.dg/modules/bad-mapper-1.C index 6d0ed4b..4b23128 100644 --- a/gcc/testsuite/g++.dg/modules/bad-mapper-1.C +++ b/gcc/testsuite/g++.dg/modules/bad-mapper-1.C @@ -1,6 +1,6 @@ // { dg-additional-options "-fmodules-ts -fmodule-mapper=|this-will-not-work" } import unique1.bob; -// { dg-error "-:failed exec.*mapper.* .*this-will-not-work" "" { target { ! { *-*-darwin[89]* *-*-darwin10* } } } 0 } +// { dg-error "-:failed (exec|CreateProcess).*mapper.* .*this-will-not-work" "" { target { ! { *-*-darwin[89]* *-*-darwin10* } } } 0 } // { dg-prune-output "fatal error:" } // { dg-prune-output "failed to read" } // { dg-prune-output "compilation terminated" } -- cgit v1.1 From 1a46a0a8b30405ea353a758971634dabeee89eaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20SVENSSON?= Date: Mon, 19 Sep 2022 18:18:58 +0200 Subject: testsuite: 'b' instruction can't do long enough jumps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After moving the testglue in commit 9d503515cee, the jump to exit and abort is too far for the 'b' instruction on Cortex-M0. As most of the C code would generate a 'bl' instruction instead of a 'b' instruction, lets do the same for the inline assembler. The error seen without this patch: /tmp/cccCRiCl.o: in function `main': stack-protector-1.c:(.text+0x4e): relocation truncated to fit: R_ARM_THM_JUMP11 against symbol `__wrap_exit' defined in .text section in gcc_tg.o stack-protector-1.c:(.text+0x50): relocation truncated to fit: R_ARM_THM_JUMP11 against symbol `__wrap_abort' defined in .text section in gcc_tg.o collect2: error: ld returned 1 exit status gcc/testsuite/ChangeLog: * gcc.target/arm/stack-protector-1.c: Use 'bl' instead of 'b' instruction. * gcc.target/arm/stack-protector-3.c: Likewise. Co-Authored-By: Yvan ROUX Signed-off-by: Torbjörn SVENSSON --- gcc/testsuite/gcc.target/arm/stack-protector-1.c | 4 ++-- gcc/testsuite/gcc.target/arm/stack-protector-3.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/arm/stack-protector-1.c b/gcc/testsuite/gcc.target/arm/stack-protector-1.c index 8d28b0a..3f0ffc9 100644 --- a/gcc/testsuite/gcc.target/arm/stack-protector-1.c +++ b/gcc/testsuite/gcc.target/arm/stack-protector-1.c @@ -56,8 +56,8 @@ asm ( " ldr r1, [sp, #4]\n" CHECK (r1) " mov r0, #0\n" -" b exit\n" +" bl exit\n" "1:\n" -" b abort\n" +" bl abort\n" " .size main, .-main" ); diff --git a/gcc/testsuite/gcc.target/arm/stack-protector-3.c b/gcc/testsuite/gcc.target/arm/stack-protector-3.c index b8f77fa..2f71052 100644 --- a/gcc/testsuite/gcc.target/arm/stack-protector-3.c +++ b/gcc/testsuite/gcc.target/arm/stack-protector-3.c @@ -26,7 +26,7 @@ asm ( " .type __stack_chk_fail, %function\n" "__stack_chk_fail:\n" " movs r0, #0\n" -" b exit\n" +" bl exit\n" " .size __stack_chk_fail, .-__stack_chk_fail" ); -- cgit v1.1 From 233c966dba5012938a1f84e14c26b52d507b2aae Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 5 Oct 2022 12:14:40 +0200 Subject: testsuite: mark a test with xfail PR tree-optimization/106679 gcc/testsuite/ChangeLog: * gcc.dg/tree-prof/cmpsf-1.c: Mark as a known limitation. --- gcc/testsuite/gcc.dg/tree-prof/cmpsf-1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-prof/cmpsf-1.c b/gcc/testsuite/gcc.dg/tree-prof/cmpsf-1.c index 16adb92..696f459 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/cmpsf-1.c +++ b/gcc/testsuite/gcc.dg/tree-prof/cmpsf-1.c @@ -181,4 +181,4 @@ main (void) exit (0); } -/* { dg-final-use-not-autofdo { scan-tree-dump-not "Invalid sum" "dom2"} } */ +/* { dg-final-use-not-autofdo { scan-tree-dump-not "Invalid sum" "dom2" { xfail *-*-* } } } */ -- cgit v1.1 From bcc27369910b818047bca466fbcef6a3034dfc7f Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 5 Oct 2022 13:33:24 +0200 Subject: analyzer: remove unused variables Fixes: gcc/analyzer/call-summary.h:103:13: warning: private field 'm_called_fn' is not used [-Wunused-private-field] gcc/analyzer/engine.cc:1631:24: warning: unused parameter 'uncertainty' [-Wunused-parameter] gcc/analyzer/ChangeLog: * call-summary.cc (call_summary_replay::call_summary_replay): Remove unused variable and arguments. * call-summary.h: Likewise. * engine.cc (exploded_node::on_stmt): Likewise. (exploded_node::replay_call_summaries): Likewise. (exploded_node::replay_call_summary): Likewise. * exploded-graph.h (class exploded_node): Likewise. --- gcc/analyzer/call-summary.cc | 1 - gcc/analyzer/call-summary.h | 1 - gcc/analyzer/engine.cc | 5 +---- gcc/analyzer/exploded-graph.h | 2 -- 4 files changed, 1 insertion(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc index 9d8716d..a8e8814 100644 --- a/gcc/analyzer/call-summary.cc +++ b/gcc/analyzer/call-summary.cc @@ -171,7 +171,6 @@ call_summary_replay::call_summary_replay (const call_details &cd, call_summary *summary, const extrinsic_state &ext_state) : m_cd (cd), - m_called_fn (called_fn), m_summary (summary), m_ext_state (ext_state) { diff --git a/gcc/analyzer/call-summary.h b/gcc/analyzer/call-summary.h index f4c5ff0..07cd3f5 100644 --- a/gcc/analyzer/call-summary.h +++ b/gcc/analyzer/call-summary.h @@ -100,7 +100,6 @@ private: const region *convert_region_from_summary_1 (const region *); const call_details &m_cd; - function *m_called_fn; call_summary *m_summary; const extrinsic_state &m_ext_state; diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index b4deee5..735b5a3 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -1439,7 +1439,6 @@ exploded_node::on_stmt (exploded_graph &eg, snode, as_a (stmt), state, - uncertainty, path_ctxt, called_fn, called_fn_data, @@ -1598,7 +1597,6 @@ exploded_node::replay_call_summaries (exploded_graph &eg, const supernode *snode, const gcall *call_stmt, program_state *state, - uncertainty_t *uncertainty, path_context *path_ctxt, function *called_fn, per_function_data *called_fn_data, @@ -1612,7 +1610,7 @@ exploded_node::replay_call_summaries (exploded_graph &eg, /* Each summary will call bifurcate on the PATH_CTXT. */ for (auto summary : called_fn_data->m_summaries) - replay_call_summary (eg, snode, call_stmt, state, uncertainty, + replay_call_summary (eg, snode, call_stmt, state, path_ctxt, called_fn, summary, ctxt); path_ctxt->terminate_path (); @@ -1628,7 +1626,6 @@ exploded_node::replay_call_summary (exploded_graph &eg, const supernode *snode, const gcall *call_stmt, program_state *old_state, - uncertainty_t *uncertainty, path_context *path_ctxt, function *called_fn, call_summary *summary, diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h index ea4a890..11e46ca 100644 --- a/gcc/analyzer/exploded-graph.h +++ b/gcc/analyzer/exploded-graph.h @@ -271,7 +271,6 @@ class exploded_node : public dnode const supernode *snode, const gcall *call_stmt, program_state *state, - uncertainty_t *uncertainty, path_context *path_ctxt, function *called_fn, per_function_data *called_fn_data, @@ -280,7 +279,6 @@ class exploded_node : public dnode const supernode *snode, const gcall *call_stmt, program_state *state, - uncertainty_t *uncertainty, path_context *path_ctxt, function *called_fn, call_summary *summary, -- cgit v1.1 From 853ce8eea4ff97850a987167e603387b3d0f1401 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Wed, 5 Oct 2022 12:21:03 +0200 Subject: Fix bogus -Wstringop-overflow warning in Ada It comes from a discrepancy between get_offset_range, which uses a signed type, and handle_array_ref, which uses an unsigned one, to do computations. gcc/ PR tree-optimization/106698 * pointer-query.cc (handle_array_ref): Fix handling of low bound. gcc/testsuite/ * gnat.dg/lto26.adb: New test. * gnat.dg/lto26_pkg1.ads, gnat.dg/lto26_pkg1.adb: New helper. * gnat.dg/lto26_pkg2.ads, gnat.dg/lto26_pkg2.adb: Likewise. --- gcc/pointer-query.cc | 19 ++++++++++++------- gcc/testsuite/gnat.dg/lto26.adb | 13 +++++++++++++ gcc/testsuite/gnat.dg/lto26_pkg1.adb | 11 +++++++++++ gcc/testsuite/gnat.dg/lto26_pkg1.ads | 11 +++++++++++ gcc/testsuite/gnat.dg/lto26_pkg2.adb | 15 +++++++++++++++ gcc/testsuite/gnat.dg/lto26_pkg2.ads | 9 +++++++++ 6 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/lto26.adb create mode 100644 gcc/testsuite/gnat.dg/lto26_pkg1.adb create mode 100644 gcc/testsuite/gnat.dg/lto26_pkg1.ads create mode 100644 gcc/testsuite/gnat.dg/lto26_pkg2.adb create mode 100644 gcc/testsuite/gnat.dg/lto26_pkg2.ads (limited to 'gcc') diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index ae56173..0f01002 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -1796,14 +1796,19 @@ handle_array_ref (tree aref, gimple *stmt, bool addr, int ostype, orng[0] = -orng[1] - 1; } - /* Convert the array index range determined above to a byte - offset. */ + /* Convert the array index range determined above to a byte offset. */ tree lowbnd = array_ref_low_bound (aref); - if (!integer_zerop (lowbnd) && tree_fits_uhwi_p (lowbnd)) - { - /* Adjust the index by the low bound of the array domain - (normally zero but 1 in Fortran). */ - unsigned HOST_WIDE_INT lb = tree_to_uhwi (lowbnd); + if (TREE_CODE (lowbnd) == INTEGER_CST && !integer_zerop (lowbnd)) + { + /* Adjust the index by the low bound of the array domain (0 in C/C++, + 1 in Fortran and anything in Ada) by applying the same processing + as in get_offset_range. */ + const wide_int wlb = wi::to_wide (lowbnd); + signop sgn = SIGNED; + if (TYPE_UNSIGNED (TREE_TYPE (lowbnd)) + && wlb.get_precision () < TYPE_PRECISION (sizetype)) + sgn = UNSIGNED; + const offset_int lb = offset_int::from (wlb, sgn); orng[0] -= lb; orng[1] -= lb; } diff --git a/gcc/testsuite/gnat.dg/lto26.adb b/gcc/testsuite/gnat.dg/lto26.adb new file mode 100644 index 0000000..a27348b --- /dev/null +++ b/gcc/testsuite/gnat.dg/lto26.adb @@ -0,0 +1,13 @@ +-- { dg-do run } +-- { dg-options "-O2 -flto" { target lto } } + +with Ada.Streams; use Ada.Streams; +with Lto26_Pkg1; use Lto26_Pkg1; + +procedure Lto26 is + R : Rec; +begin + for I in 1 .. 10 loop + Set (R, (7, 0, 84, Stream_Element (I), 0, 0, 0), 1); + end loop; +end; diff --git a/gcc/testsuite/gnat.dg/lto26_pkg1.adb b/gcc/testsuite/gnat.dg/lto26_pkg1.adb new file mode 100644 index 0000000..c68b134 --- /dev/null +++ b/gcc/testsuite/gnat.dg/lto26_pkg1.adb @@ -0,0 +1,11 @@ +with Lto26_Pkg2; use Lto26_Pkg2; + +package body Lto26_Pkg1 is + + procedure Set (R : Rec; A : Stream_Element_Array; C :Unsigned_8) is + procedure My_Build is new Build; + begin + My_Build (A, C); + end; + +end Lto26_Pkg1; diff --git a/gcc/testsuite/gnat.dg/lto26_pkg1.ads b/gcc/testsuite/gnat.dg/lto26_pkg1.ads new file mode 100644 index 0000000..5279747 --- /dev/null +++ b/gcc/testsuite/gnat.dg/lto26_pkg1.ads @@ -0,0 +1,11 @@ +with Ada.Finalization; +with Ada.Streams; use Ada.Streams; +with Interfaces; use Interfaces; + +package Lto26_Pkg1 is + + type Rec is new Ada.Finalization.Limited_Controlled with null record; + + procedure Set (R : Rec; A : Stream_Element_Array; C :Unsigned_8); + +end Lto26_Pkg1; diff --git a/gcc/testsuite/gnat.dg/lto26_pkg2.adb b/gcc/testsuite/gnat.dg/lto26_pkg2.adb new file mode 100644 index 0000000..9f89733 --- /dev/null +++ b/gcc/testsuite/gnat.dg/lto26_pkg2.adb @@ -0,0 +1,15 @@ +package body Lto26_Pkg2 is + + procedure Build (A : Stream_Element_Array; C : Unsigned_8) is + Start : Stream_Element_Offset := A'First; + Next : Stream_Element_Offset; + Length : Unsigned_8; + begin + for I in 1 .. C loop + Length := Unsigned_8 (A (A'First)); + Next := Start + Stream_Element_Offset (Length); + Start := Next; + end loop; + end; + +end Lto26_Pkg2; diff --git a/gcc/testsuite/gnat.dg/lto26_pkg2.ads b/gcc/testsuite/gnat.dg/lto26_pkg2.ads new file mode 100644 index 0000000..68741bb8 --- /dev/null +++ b/gcc/testsuite/gnat.dg/lto26_pkg2.ads @@ -0,0 +1,9 @@ +with Ada.Streams; use Ada.Streams; +with Interfaces; use Interfaces; + +package Lto26_Pkg2 is + + generic + procedure Build (A : Stream_Element_Array; C : Unsigned_8); + +end Lto26_Pkg2; -- cgit v1.1 From ae56d600d223e996054483d7d7033ec8e258d39d Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 4 Oct 2022 17:03:54 +0200 Subject: [PR tree-optimization/107052] range-ops: Pass nonzero masks through cast. Track nonzero masks through a cast in range-ops. PR tree-optimization/107052 gcc/ChangeLog: * range-op.cc (operator_cast::fold_range): Set nonzero mask. --- gcc/range-op.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc') diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 4f647ab..6fa27a8 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -2515,6 +2515,14 @@ operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, if (r.varying_p ()) return true; } + + // Pass nonzero mask through the cast. + if (!truncating_cast_p (inner, outer)) + { + wide_int nz = inner.get_nonzero_bits (); + nz = wide_int::from (nz, TYPE_PRECISION (type), TYPE_SIGN (inner.type ())); + r.set_nonzero_bits (nz); + } return true; } -- cgit v1.1 From 4c451631f722c9939260a5c2fc209802a47e525f Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 4 Oct 2022 17:05:10 +0200 Subject: [PR tree-optimization/107052] range-ops: Take into account nonzero mask in popcount. PR tree-optimization/107052 gcc/ChangeLog: * gimple-range-op.cc (cfn_popcount::fold_range): Take into account nonzero bit mask. --- gcc/gimple-range-op.cc | 15 ++++++++++++--- gcc/testsuite/gcc.dg/tree-ssa/pr107052.c | 13 +++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr107052.c (limited to 'gcc') diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc index 5b71d1c..42ebc7d 100644 --- a/gcc/gimple-range-op.cc +++ b/gcc/gimple-range-op.cc @@ -422,15 +422,24 @@ public: virtual bool fold_range (irange &r, tree type, const irange &lh, const irange &rh, relation_kind rel) const { + if (lh.undefined_p ()) + return false; + unsigned prec = TYPE_PRECISION (type); + wide_int nz = lh.get_nonzero_bits (); + wide_int pop = wi::shwi (wi::popcount (nz), prec); // Calculating the popcount of a singleton is trivial. if (lh.singleton_p ()) { - wide_int nz = lh.get_nonzero_bits (); - wide_int pop = wi::shwi (wi::popcount (nz), TYPE_PRECISION (type)); r.set (type, pop, pop); return true; } - return cfn_ffs::fold_range (r, type, lh, rh, rel); + if (cfn_ffs::fold_range (r, type, lh, rh, rel)) + { + int_range<2> tmp (type, wi::zero (prec), pop); + r.intersect (tmp); + return true; + } + return false; } } op_cfn_popcount; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr107052.c b/gcc/testsuite/gcc.dg/tree-ssa/pr107052.c new file mode 100644 index 0000000..88b5213 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr107052.c @@ -0,0 +1,13 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-tree-evrp" } + +void link_failure(); +void f(int a) +{ + a &= 0x300; + int b = __builtin_popcount(a); + if (b > 3) + link_failure(); +} + +// { dg-final { scan-tree-dump-not "link_failure" "evrp" } } -- cgit v1.1 From 0afa9dfb8fb3302db7f104add5654436927dcb56 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 5 Oct 2022 12:34:30 +0200 Subject: c: support the attribute starting with '_' PR c/107156 gcc/ChangeLog: * attribs.h (lookup_attribute_by_prefix): Support the attribute starting with underscore (_Noreturn). --- gcc/attribs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/attribs.h b/gcc/attribs.h index b283656..121b9eb 100644 --- a/gcc/attribs.h +++ b/gcc/attribs.h @@ -274,8 +274,8 @@ lookup_attribute_by_prefix (const char *attr_name, tree list) } const char *p = IDENTIFIER_POINTER (name); - gcc_checking_assert (attr_len == 0 || p[0] != '_'); - + gcc_checking_assert (attr_len == 0 || p[0] != '_' + || (ident_len > 1 && p[1] != '_')); if (strncmp (attr_name, p, attr_len) == 0) break; -- cgit v1.1 From df4c584c567263fdcd57d8376f24f29477a892b2 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 5 Oct 2022 13:24:49 +0200 Subject: range-op: Keep nonzero mask up to date with truncating casts. gcc/ChangeLog: * range-op.cc (operator_cast::fold_range): Handle truncating casts for nonzero masks. --- gcc/range-op.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 6fa27a8..df0735c 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -2516,13 +2516,17 @@ operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, return true; } - // Pass nonzero mask through the cast. - if (!truncating_cast_p (inner, outer)) - { - wide_int nz = inner.get_nonzero_bits (); - nz = wide_int::from (nz, TYPE_PRECISION (type), TYPE_SIGN (inner.type ())); - r.set_nonzero_bits (nz); - } + // Update the nonzero mask. Truncating casts are problematic unless + // the conversion fits in the resulting outer type. + wide_int nz = inner.get_nonzero_bits (); + if (truncating_cast_p (inner, outer) + && wi::rshift (nz, wi::uhwi (TYPE_PRECISION (outer.type ()), + TYPE_PRECISION (inner.type ())), + TYPE_SIGN (inner.type ())) != 0) + return true; + nz = wide_int::from (nz, TYPE_PRECISION (type), TYPE_SIGN (inner.type ())); + r.set_nonzero_bits (nz); + return true; } -- cgit v1.1 From 7d935cdd1a6772699ec0ab4f93711928ca4d30a1 Mon Sep 17 00:00:00 2001 From: Ju-Zhe Zhong Date: Fri, 30 Sep 2022 14:58:16 +0800 Subject: RISC-V: Introduce RVV header to enable builtin types gcc/ChangeLog: * config.gcc: Add riscv_vector.h. * config/riscv/riscv-builtins.cc: Add RVV builtin types support. * config/riscv/riscv-c.cc (riscv_pragma_intrinsic): New function. (riscv_register_pragmas): Ditto. * config/riscv/riscv-protos.h (riscv_register_pragmas): Ditto. (init_builtins): Move declaration from riscv-vector-builtins.h to riscv-protos.h. (mangle_builtin_type): Ditto. (verify_type_context): Ditto. (handle_pragma_vector): New function. * config/riscv/riscv-vector-builtins.cc (GTY): New variable. (register_vector_type): New function. (init_builtins): Add RVV builtin types support. (handle_pragma_vector): New function. * config/riscv/riscv-vector-builtins.h (GCC_RISCV_V_BUILTINS_H): Change name according to file name. (GCC_RISCV_VECTOR_BUILTINS_H): Ditto. (init_builtins): Remove declaration in riscv-vector-builtins.h. (mangle_builtin_type): Ditto. (verify_type_context): Ditto. * config/riscv/riscv.cc: Adjust for RVV builtin types support. * config/riscv/riscv.h (REGISTER_TARGET_PRAGMAS): New macro. * config/riscv/t-riscv: Remove redundant file including. * config/riscv/riscv_vector.h: New file. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/base/pragma-1.c: New test. * gcc.target/riscv/rvv/base/pragma-2.c: New test. * gcc.target/riscv/rvv/base/pragma-3.c: New test. * gcc.target/riscv/rvv/base/user-1.c: New test. * gcc.target/riscv/rvv/base/user-2.c: New test. * gcc.target/riscv/rvv/base/user-3.c: New test. * gcc.target/riscv/rvv/base/user-4.c: New test. * gcc.target/riscv/rvv/base/user-5.c: New test. * gcc.target/riscv/rvv/base/user-6.c: New test. * gcc.target/riscv/rvv/base/vread_csr.c: New test. * gcc.target/riscv/rvv/base/vwrite_csr.c: New test. --- gcc/config.gcc | 1 + gcc/config/riscv/riscv-builtins.cc | 2 +- gcc/config/riscv/riscv-c.cc | 41 +++++++++ gcc/config/riscv/riscv-protos.h | 11 +++ gcc/config/riscv/riscv-vector-builtins.cc | 45 ++++++++++ gcc/config/riscv/riscv-vector-builtins.h | 13 ++- gcc/config/riscv/riscv.cc | 7 +- gcc/config/riscv/riscv.h | 2 + gcc/config/riscv/riscv_vector.h | 100 +++++++++++++++++++++ gcc/config/riscv/t-riscv | 2 +- gcc/testsuite/gcc.target/riscv/rvv/base/pragma-1.c | 4 + gcc/testsuite/gcc.target/riscv/rvv/base/pragma-2.c | 4 + gcc/testsuite/gcc.target/riscv/rvv/base/pragma-3.c | 4 + gcc/testsuite/gcc.target/riscv/rvv/base/user-1.c | 65 ++++++++++++++ gcc/testsuite/gcc.target/riscv/rvv/base/user-2.c | 65 ++++++++++++++ gcc/testsuite/gcc.target/riscv/rvv/base/user-3.c | 65 ++++++++++++++ gcc/testsuite/gcc.target/riscv/rvv/base/user-4.c | 65 ++++++++++++++ gcc/testsuite/gcc.target/riscv/rvv/base/user-5.c | 65 ++++++++++++++ gcc/testsuite/gcc.target/riscv/rvv/base/user-6.c | 65 ++++++++++++++ .../gcc.target/riscv/rvv/base/vread_csr.c | 26 ++++++ .../gcc.target/riscv/rvv/base/vwrite_csr.c | 26 ++++++ 21 files changed, 665 insertions(+), 13 deletions(-) create mode 100644 gcc/config/riscv/riscv_vector.h create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/pragma-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/pragma-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/pragma-3.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/user-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/user-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/user-3.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/user-4.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/user-5.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/user-6.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/vread_csr.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/vwrite_csr.c (limited to 'gcc') diff --git a/gcc/config.gcc b/gcc/config.gcc index 35dfc00..e73cb84 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -518,6 +518,7 @@ riscv*) extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o" extra_objs="${extra_objs} riscv-vector-builtins.o" d_target_objs="riscv-d.o" + extra_headers="riscv_vector.h" ;; rs6000*-*-*) extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt" diff --git a/gcc/config/riscv/riscv-builtins.cc b/gcc/config/riscv/riscv-builtins.cc index a51037a..14865d7 100644 --- a/gcc/config/riscv/riscv-builtins.cc +++ b/gcc/config/riscv/riscv-builtins.cc @@ -37,7 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "expr.h" #include "langhooks.h" -#include "riscv-vector-builtins.h" +#include "tm_p.h" /* Macros to create an enumeration identifier for a function prototype. */ #define RISCV_FTYPE_NAME0(A) RISCV_##A##_FTYPE diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc index 8d55ad5..cac0043 100644 --- a/gcc/config/riscv/riscv-c.cc +++ b/gcc/config/riscv/riscv-c.cc @@ -27,6 +27,9 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "c-family/c-common.h" #include "cpplib.h" +#include "c-family/c-pragma.h" +#include "target.h" +#include "tm_p.h" #include "riscv-subset.h" #define builtin_define(TXT) cpp_define (pfile, TXT) @@ -150,3 +153,41 @@ riscv_cpu_cpp_builtins (cpp_reader *pfile) builtin_define_with_int_value (buf, version_value); } } + +/* Implement "#pragma riscv intrinsic". */ + +static void +riscv_pragma_intrinsic (cpp_reader *) +{ + tree x; + + if (pragma_lex (&x) != CPP_STRING) + { + error ("%<#pragma riscv intrinsic%> requires a string parameter"); + return; + } + + const char *name = TREE_STRING_POINTER (x); + + if (strcmp (name, "vector") == 0) + { + if (!TARGET_VECTOR) + { + error ("%<#pragma riscv intrinsic%> option %qs needs 'V' extension " + "enabled", + name); + return; + } + riscv_vector::handle_pragma_vector (); + } + else + error ("unknown %<#pragma riscv intrinsic%> option %qs", name); +} + +/* Implement REGISTER_TARGET_PRAGMAS. */ + +void +riscv_register_pragmas (void) +{ + c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic); +} \ No newline at end of file diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 101361a..a44b34d 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -79,6 +79,7 @@ extern bool riscv_v_ext_enabled_vector_mode_p (machine_mode); /* Routines implemented in riscv-c.cc. */ void riscv_cpu_cpp_builtins (cpp_reader *); +void riscv_register_pragmas (void); /* Routines implemented in riscv-builtins.cc. */ extern void riscv_atomic_assign_expand_fenv (tree *, tree *, tree *); @@ -115,4 +116,14 @@ extern void riscv_run_selftests (void); } // namespace selftest #endif +namespace riscv_vector { +/* Routines implemented in riscv-vector-builtins.cc. */ +extern void init_builtins (void); +extern const char *mangle_builtin_type (const_tree); +#ifdef GCC_TARGET_H +extern bool verify_type_context (location_t, type_context_kind, const_tree, bool); +#endif +extern void handle_pragma_vector (void); +} + #endif /* ! GCC_RISCV_PROTOS_H */ diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc index 019a40d..0096e32 100644 --- a/gcc/config/riscv/riscv-vector-builtins.cc +++ b/gcc/config/riscv/riscv-vector-builtins.cc @@ -46,6 +46,8 @@ #include "regs.h" #include "riscv-vector-builtins.h" +using namespace riscv_vector; + namespace riscv_vector { /* Information about each RVV type. */ @@ -64,6 +66,10 @@ static GTY (()) machine_mode vector_modes[NUM_VECTOR_TYPES]; yields a null tree. */ static GTY(()) tree abi_vector_types[NUM_VECTOR_TYPES + 1]; +/* Same, but with the riscv_vector.h "v..._t" name. */ +extern GTY(()) tree builtin_vector_types[MAX_TUPLE_SIZE][NUM_VECTOR_TYPES + 1]; +tree builtin_vector_types[MAX_TUPLE_SIZE][NUM_VECTOR_TYPES + 1]; + rvv_switcher::rvv_switcher () { /* Set have_regs_of_mode before targetm.init_builtins (). */ @@ -183,6 +189,32 @@ register_builtin_types () } } +/* Register vector type TYPE under its risv_vector.h name. */ +static void +register_vector_type (vector_type_index type) +{ + tree vectype = abi_vector_types[type]; + /* When vectype is NULL, the corresponding builtin type + is disabled according to '-march'. */ + if (!vectype) + return; + tree id = get_identifier (vector_types[type].user_name); + tree decl = build_decl (input_location, TYPE_DECL, id, vectype); + decl = lang_hooks.decls.pushdecl (decl); + + /* Record the new RVV type if pushdecl succeeded without error. Use + the ABI type otherwise, so that the type we record at least has the + right form, even if it doesn't have the right name. This should give + better error recovery behavior than installing error_mark_node or + installing an incorrect type. */ + if (decl && TREE_CODE (decl) == TYPE_DECL + && TREE_TYPE (decl) != error_mark_node + && TYPE_MAIN_VARIANT (TREE_TYPE (decl)) == vectype) + vectype = TREE_TYPE (decl); + + builtin_vector_types[0][type] = vectype; +} + /* Initialize all compiler built-ins related to RVV that should be defined at start-up. */ void @@ -192,6 +224,8 @@ init_builtins () if (!TARGET_VECTOR) return; register_builtin_types (); + if (in_lto_p) + handle_pragma_vector (); } /* Implement TARGET_VERIFY_TYPE_CONTEXT for RVV types. */ @@ -276,4 +310,15 @@ verify_type_context (location_t loc, type_context_kind context, const_tree type, gcc_unreachable (); } +/* Implement #pragma riscv intrinsic vector. */ +void +handle_pragma_vector () +{ + rvv_switcher rvv; + + /* Define the vector and tuple types. */ + for (unsigned int type_i = 0; type_i < NUM_VECTOR_TYPES; ++type_i) + register_vector_type ((enum vector_type_index) type_i); +} + } // end namespace riscv_vector diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h index a4a8c11..6ca0b07 100644 --- a/gcc/config/riscv/riscv-vector-builtins.h +++ b/gcc/config/riscv/riscv-vector-builtins.h @@ -18,11 +18,14 @@ along with GCC; see the file COPYING3. If not see . */ -#ifndef GCC_RISCV_V_BUILTINS_H -#define GCC_RISCV_V_BUILTINS_H +#ifndef GCC_RISCV_VECTOR_BUILTINS_H +#define GCC_RISCV_VECTOR_BUILTINS_H namespace riscv_vector { +/* This is for segment instructions. */ +const unsigned int MAX_TUPLE_SIZE = 8; + /* Static information about each vector type. */ struct vector_type_info { @@ -68,12 +71,6 @@ private: bool m_old_have_regs_of_mode[MAX_MACHINE_MODE]; }; -void init_builtins (); -const char *mangle_builtin_type (const_tree); -#ifdef GCC_TARGET_H -bool verify_type_context (location_t, type_context_kind, const_tree, bool); -#endif - } // end namespace riscv_vector #endif diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 0a4c37e..ad57b99 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" #include "coretypes.h" +#include "target.h" #include "tm.h" #include "rtl.h" #include "regs.h" @@ -45,8 +46,6 @@ along with GCC; see the file COPYING3. If not see #include "emit-rtl.h" #include "reload.h" #include "tm_p.h" -#include "target.h" -#include "target-def.h" #include "basic-block.h" #include "expr.h" #include "optabs.h" @@ -59,7 +58,9 @@ along with GCC; see the file COPYING3. If not see #include "opts.h" #include "tm-constrs.h" #include "rtl-iter.h" -#include "riscv-vector-builtins.h" + +/* This file should be included last. */ +#include "target-def.h" /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */ #define UNSPEC_ADDRESS_P(X) \ diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 363113c..acae68e 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -1078,4 +1078,6 @@ extern void riscv_remove_unneeded_save_restore_calls (void); #define TARGET_SUPPORTS_WIDE_INT 1 +#define REGISTER_TARGET_PRAGMAS() riscv_register_pragmas () + #endif /* ! GCC_RISCV_H */ diff --git a/gcc/config/riscv/riscv_vector.h b/gcc/config/riscv/riscv_vector.h new file mode 100644 index 0000000..1efe3f8 --- /dev/null +++ b/gcc/config/riscv/riscv_vector.h @@ -0,0 +1,100 @@ +/* RISC-V 'V' Extension intrinsics include file. + Copyright (C) 2022-2022 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef __RISCV_VECTOR_H +#define __RISCV_VECTOR_H + +#include +#include + +#ifndef __riscv_vector +#error "Vector intrinsics require the vector extension." +#else +#ifdef __cplusplus +extern "C" { +#endif + +enum RVV_CSR { + RVV_VSTART = 0, + RVV_VXSAT, + RVV_VXRM, + RVV_VCSR, +}; + +__extension__ extern __inline unsigned long +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +vread_csr(enum RVV_CSR csr) +{ + unsigned long rv = 0; + switch (csr) + { + case RVV_VSTART: + __asm__ __volatile__ ("csrr\t%0,vstart" : "=r"(rv) : : "memory"); + break; + case RVV_VXSAT: + __asm__ __volatile__ ("csrr\t%0,vxsat" : "=r"(rv) : : "memory"); + break; + case RVV_VXRM: + __asm__ __volatile__ ("csrr\t%0,vxrm" : "=r"(rv) : : "memory"); + break; + case RVV_VCSR: + __asm__ __volatile__ ("csrr\t%0,vcsr" : "=r"(rv) : : "memory"); + break; + } + return rv; +} + +__extension__ extern __inline void +__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) +vwrite_csr(enum RVV_CSR csr, unsigned long value) +{ + switch (csr) + { + case RVV_VSTART: + __asm__ __volatile__ ("csrw\tvstart,%z0" : : "rJ"(value) : "memory"); + break; + case RVV_VXSAT: + __asm__ __volatile__ ("csrw\tvxsat,%z0" : : "rJ"(value) : "memory"); + break; + case RVV_VXRM: + __asm__ __volatile__ ("csrw\tvxrm,%z0" : : "rJ"(value) : "memory"); + break; + case RVV_VCSR: + __asm__ __volatile__ ("csrw\tvcsr,%z0" : : "rJ"(value) : "memory"); + break; + } +} + +/* NOTE: This implementation of riscv_vector.h is intentionally short. It does + not define the RVV types and intrinsic functions directly in C and C++ + code, but instead uses the following pragma to tell GCC to insert the + necessary type and function definitions itself. The net effect is the + same, and the file is a complete implementation of riscv_vector.h. */ +#pragma riscv intrinsic "vector" + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // __riscv_vector +#endif // __RISCV_VECTOR_H diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv index ad9be09..2f06043 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -9,7 +9,7 @@ riscv-vector-builtins.o: $(srcdir)/config/riscv/riscv-vector-builtins.cc \ $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) $(TM_P_H) \ memmodel.h insn-codes.h $(OPTABS_H) $(RECOG_H) $(DIAGNOSTIC_H) $(EXPR_H) \ $(FUNCTION_H) fold-const.h gimplify.h explow.h stor-layout.h $(REGS_H) \ - alias.h langhooks.h attribs.h stringpool.h $(REGS_H) \ + alias.h langhooks.h attribs.h stringpool.h \ $(srcdir)/config/riscv/riscv-vector-builtins.h \ $(srcdir)/config/riscv/riscv-vector-builtins.def $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pragma-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pragma-1.c new file mode 100644 index 0000000..79b1159 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pragma-1.c @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc -mabi=ilp32d" } */ + +#pragma riscv intrinsic "vector" /* { dg-error {#pragma riscv intrinsic' option 'vector' needs 'V' extension enabled} } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pragma-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pragma-2.c new file mode 100644 index 0000000..fa790b1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pragma-2.c @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +/* { dg-skip-if "test rvv intrinsic" { *-*-* } { "*" } { "-march=rv*v*" } } */ + +#pragma riscv intrinsic "vector" \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pragma-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pragma-3.c new file mode 100644 index 0000000..86da678 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pragma-3.c @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +/* { dg-skip-if "test rvv intrinsic" { *-*-* } { "*" } { "-march=rv*v*" } } */ + +#pragma riscv intrinsic "report-error" /* { dg-error {unknown '#pragma riscv intrinsic' option 'report-error'} } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/user-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/user-1.c new file mode 100644 index 0000000..299e393 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/user-1.c @@ -0,0 +1,65 @@ +/* { dg-do compile } */ +/* { dg-skip-if "test rvv intrinsic" { *-*-* } { "*" } { "-march=rv*v*" } } */ + +#include "riscv_vector.h" + +void foo0 () {vbool64_t t;} +void foo1 () {vbool32_t t;} +void foo2 () {vbool16_t t;} +void foo3 () {vbool8_t t;} +void foo4 () {vbool4_t t;} +void foo5 () {vbool2_t t;} +void foo6 () {vbool1_t t;} +void foo7 () {vint8mf8_t t;} +void foo8 () {vuint8mf8_t t;} +void foo9 () {vint8mf4_t t;} +void foo10 () {vuint8mf4_t t;} +void foo11 () {vint8mf2_t t;} +void foo12 () {vuint8mf2_t t;} +void foo13 () {vint8m1_t t;} +void foo14 () {vuint8m1_t t;} +void foo15 () {vint8m2_t t;} +void foo16 () {vuint8m2_t t;} +void foo17 () {vint8m4_t t;} +void foo18 () {vuint8m4_t t;} +void foo19 () {vint8m8_t t;} +void foo20 () {vuint8m8_t t;} +void foo21 () {vint16mf4_t t;} +void foo22 () {vuint16mf4_t t;} +void foo23 () {vint16mf2_t t;} +void foo24 () {vuint16mf2_t t;} +void foo25 () {vint16m1_t t;} +void foo26 () {vuint16m1_t t;} +void foo27 () {vint16m2_t t;} +void foo28 () {vuint16m2_t t;} +void foo29 () {vint16m4_t t;} +void foo30 () {vuint16m4_t t;} +void foo31 () {vint16m8_t t;} +void foo32 () {vuint16m8_t t;} +void foo33 () {vint32mf2_t t;} +void foo34 () {vuint32mf2_t t;} +void foo35 () {vint32m1_t t;} +void foo36 () {vuint32m1_t t;} +void foo37 () {vint32m2_t t;} +void foo38 () {vuint32m2_t t;} +void foo39 () {vint32m4_t t;} +void foo40 () {vuint32m4_t t;} +void foo41 () {vint32m8_t t;} +void foo42 () {vuint32m8_t t;} +void foo43 () {vint64m1_t t;} +void foo44 () {vuint64m1_t t;} +void foo45 () {vint64m2_t t;} +void foo46 () {vuint64m2_t t;} +void foo47 () {vint64m4_t t;} +void foo48 () {vuint64m4_t t;} +void foo49 () {vint64m8_t t;} +void foo50 () {vuint64m8_t t;} +void foo57 () {vfloat32mf2_t t;} +void foo58 () {vfloat32m1_t t;} +void foo59 () {vfloat32m2_t t;} +void foo60 () {vfloat32m4_t t;} +void foo61 () {vfloat32m8_t t;} +void foo62 () {vfloat64m1_t t;} +void foo63 () {vfloat64m2_t t;} +void foo64 () {vfloat64m4_t t;} +void foo65 () {vfloat64m8_t t;} \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/user-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/user-2.c new file mode 100644 index 0000000..2a88467 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/user-2.c @@ -0,0 +1,65 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc_zve64x -mabi=ilp32d" } */ + +#include "riscv_vector.h" + +void foo0 () {vbool64_t t;} +void foo1 () {vbool32_t t;} +void foo2 () {vbool16_t t;} +void foo3 () {vbool8_t t;} +void foo4 () {vbool4_t t;} +void foo5 () {vbool2_t t;} +void foo6 () {vbool1_t t;} +void foo7 () {vint8mf8_t t;} +void foo8 () {vuint8mf8_t t;} +void foo9 () {vint8mf4_t t;} +void foo10 () {vuint8mf4_t t;} +void foo11 () {vint8mf2_t t;} +void foo12 () {vuint8mf2_t t;} +void foo13 () {vint8m1_t t;} +void foo14 () {vuint8m1_t t;} +void foo15 () {vint8m2_t t;} +void foo16 () {vuint8m2_t t;} +void foo17 () {vint8m4_t t;} +void foo18 () {vuint8m4_t t;} +void foo19 () {vint8m8_t t;} +void foo20 () {vuint8m8_t t;} +void foo21 () {vint16mf4_t t;} +void foo22 () {vuint16mf4_t t;} +void foo23 () {vint16mf2_t t;} +void foo24 () {vuint16mf2_t t;} +void foo25 () {vint16m1_t t;} +void foo26 () {vuint16m1_t t;} +void foo27 () {vint16m2_t t;} +void foo28 () {vuint16m2_t t;} +void foo29 () {vint16m4_t t;} +void foo30 () {vuint16m4_t t;} +void foo31 () {vint16m8_t t;} +void foo32 () {vuint16m8_t t;} +void foo33 () {vint32mf2_t t;} +void foo34 () {vuint32mf2_t t;} +void foo35 () {vint32m1_t t;} +void foo36 () {vuint32m1_t t;} +void foo37 () {vint32m2_t t;} +void foo38 () {vuint32m2_t t;} +void foo39 () {vint32m4_t t;} +void foo40 () {vuint32m4_t t;} +void foo41 () {vint32m8_t t;} +void foo42 () {vuint32m8_t t;} +void foo43 () {vint64m1_t t;} +void foo44 () {vuint64m1_t t;} +void foo45 () {vint64m2_t t;} +void foo46 () {vuint64m2_t t;} +void foo47 () {vint64m4_t t;} +void foo48 () {vuint64m4_t t;} +void foo49 () {vint64m8_t t;} +void foo50 () {vuint64m8_t t;} +void foo57 () {vfloat32mf2_t t;} /* { dg-error {unknown type name 'vfloat32mf2_t'} } */ +void foo58 () {vfloat32m1_t t;} /* { dg-error {unknown type name 'vfloat32m1_t'} } */ +void foo59 () {vfloat32m2_t t;} /* { dg-error {unknown type name 'vfloat32m2_t'} } */ +void foo60 () {vfloat32m4_t t;} /* { dg-error {unknown type name 'vfloat32m4_t'} } */ +void foo61 () {vfloat32m8_t t;} /* { dg-error {unknown type name 'vfloat32m8_t'} } */ +void foo62 () {vfloat64m1_t t;} /* { dg-error {unknown type name 'vfloat64m1_t'} } */ +void foo63 () {vfloat64m2_t t;} /* { dg-error {unknown type name 'vfloat64m2_t'} } */ +void foo64 () {vfloat64m4_t t;} /* { dg-error {unknown type name 'vfloat64m4_t'} } */ +void foo65 () {vfloat64m8_t t;} /* { dg-error {unknown type name 'vfloat64m8_t'} } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/user-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/user-3.c new file mode 100644 index 0000000..85a6d04 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/user-3.c @@ -0,0 +1,65 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc_zve64f -mabi=ilp32d" } */ + +#include "riscv_vector.h" + +void foo0 () {vbool64_t t;} +void foo1 () {vbool32_t t;} +void foo2 () {vbool16_t t;} +void foo3 () {vbool8_t t;} +void foo4 () {vbool4_t t;} +void foo5 () {vbool2_t t;} +void foo6 () {vbool1_t t;} +void foo7 () {vint8mf8_t t;} +void foo8 () {vuint8mf8_t t;} +void foo9 () {vint8mf4_t t;} +void foo10 () {vuint8mf4_t t;} +void foo11 () {vint8mf2_t t;} +void foo12 () {vuint8mf2_t t;} +void foo13 () {vint8m1_t t;} +void foo14 () {vuint8m1_t t;} +void foo15 () {vint8m2_t t;} +void foo16 () {vuint8m2_t t;} +void foo17 () {vint8m4_t t;} +void foo18 () {vuint8m4_t t;} +void foo19 () {vint8m8_t t;} +void foo20 () {vuint8m8_t t;} +void foo21 () {vint16mf4_t t;} +void foo22 () {vuint16mf4_t t;} +void foo23 () {vint16mf2_t t;} +void foo24 () {vuint16mf2_t t;} +void foo25 () {vint16m1_t t;} +void foo26 () {vuint16m1_t t;} +void foo27 () {vint16m2_t t;} +void foo28 () {vuint16m2_t t;} +void foo29 () {vint16m4_t t;} +void foo30 () {vuint16m4_t t;} +void foo31 () {vint16m8_t t;} +void foo32 () {vuint16m8_t t;} +void foo33 () {vint32mf2_t t;} +void foo34 () {vuint32mf2_t t;} +void foo35 () {vint32m1_t t;} +void foo36 () {vuint32m1_t t;} +void foo37 () {vint32m2_t t;} +void foo38 () {vuint32m2_t t;} +void foo39 () {vint32m4_t t;} +void foo40 () {vuint32m4_t t;} +void foo41 () {vint32m8_t t;} +void foo42 () {vuint32m8_t t;} +void foo43 () {vint64m1_t t;} +void foo44 () {vuint64m1_t t;} +void foo45 () {vint64m2_t t;} +void foo46 () {vuint64m2_t t;} +void foo47 () {vint64m4_t t;} +void foo48 () {vuint64m4_t t;} +void foo49 () {vint64m8_t t;} +void foo50 () {vuint64m8_t t;} +void foo57 () {vfloat32mf2_t t;} +void foo58 () {vfloat32m1_t t;} +void foo59 () {vfloat32m2_t t;} +void foo60 () {vfloat32m4_t t;} +void foo61 () {vfloat32m8_t t;} +void foo62 () {vfloat64m1_t t;} /* { dg-error {unknown type name 'vfloat64m1_t'} } */ +void foo63 () {vfloat64m2_t t;} /* { dg-error {unknown type name 'vfloat64m2_t'} } */ +void foo64 () {vfloat64m4_t t;} /* { dg-error {unknown type name 'vfloat64m4_t'} } */ +void foo65 () {vfloat64m8_t t;} /* { dg-error {unknown type name 'vfloat64m8_t'} } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/user-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/user-4.c new file mode 100644 index 0000000..c51c03e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/user-4.c @@ -0,0 +1,65 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc_zve64d -mabi=ilp32d" } */ + +#include "riscv_vector.h" + +void foo0 () {vbool64_t t;} +void foo1 () {vbool32_t t;} +void foo2 () {vbool16_t t;} +void foo3 () {vbool8_t t;} +void foo4 () {vbool4_t t;} +void foo5 () {vbool2_t t;} +void foo6 () {vbool1_t t;} +void foo7 () {vint8mf8_t t;} +void foo8 () {vuint8mf8_t t;} +void foo9 () {vint8mf4_t t;} +void foo10 () {vuint8mf4_t t;} +void foo11 () {vint8mf2_t t;} +void foo12 () {vuint8mf2_t t;} +void foo13 () {vint8m1_t t;} +void foo14 () {vuint8m1_t t;} +void foo15 () {vint8m2_t t;} +void foo16 () {vuint8m2_t t;} +void foo17 () {vint8m4_t t;} +void foo18 () {vuint8m4_t t;} +void foo19 () {vint8m8_t t;} +void foo20 () {vuint8m8_t t;} +void foo21 () {vint16mf4_t t;} +void foo22 () {vuint16mf4_t t;} +void foo23 () {vint16mf2_t t;} +void foo24 () {vuint16mf2_t t;} +void foo25 () {vint16m1_t t;} +void foo26 () {vuint16m1_t t;} +void foo27 () {vint16m2_t t;} +void foo28 () {vuint16m2_t t;} +void foo29 () {vint16m4_t t;} +void foo30 () {vuint16m4_t t;} +void foo31 () {vint16m8_t t;} +void foo32 () {vuint16m8_t t;} +void foo33 () {vint32mf2_t t;} +void foo34 () {vuint32mf2_t t;} +void foo35 () {vint32m1_t t;} +void foo36 () {vuint32m1_t t;} +void foo37 () {vint32m2_t t;} +void foo38 () {vuint32m2_t t;} +void foo39 () {vint32m4_t t;} +void foo40 () {vuint32m4_t t;} +void foo41 () {vint32m8_t t;} +void foo42 () {vuint32m8_t t;} +void foo43 () {vint64m1_t t;} +void foo44 () {vuint64m1_t t;} +void foo45 () {vint64m2_t t;} +void foo46 () {vuint64m2_t t;} +void foo47 () {vint64m4_t t;} +void foo48 () {vuint64m4_t t;} +void foo49 () {vint64m8_t t;} +void foo50 () {vuint64m8_t t;} +void foo57 () {vfloat32mf2_t t;} +void foo58 () {vfloat32m1_t t;} +void foo59 () {vfloat32m2_t t;} +void foo60 () {vfloat32m4_t t;} +void foo61 () {vfloat32m8_t t;} +void foo62 () {vfloat64m1_t t;} +void foo63 () {vfloat64m2_t t;} +void foo64 () {vfloat64m4_t t;} +void foo65 () {vfloat64m8_t t;} \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/user-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/user-5.c new file mode 100644 index 0000000..fb1c684 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/user-5.c @@ -0,0 +1,65 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc_zve32x -mabi=ilp32d" } */ + +#include "riscv_vector.h" + +void foo0 () {vbool64_t t;} /* { dg-error {unknown type name 'vbool64_t'} } */ +void foo1 () {vbool32_t t;} +void foo2 () {vbool16_t t;} +void foo3 () {vbool8_t t;} +void foo4 () {vbool4_t t;} +void foo5 () {vbool2_t t;} +void foo6 () {vbool1_t t;} +void foo7 () {vint8mf8_t t;} /* { dg-error {unknown type name 'vint8mf8_t'} } */ +void foo8 () {vuint8mf8_t t;} /* { dg-error {unknown type name 'vuint8mf8_t'} } */ +void foo9 () {vint8mf4_t t;} +void foo10 () {vuint8mf4_t t;} +void foo11 () {vint8mf2_t t;} +void foo12 () {vuint8mf2_t t;} +void foo13 () {vint8m1_t t;} +void foo14 () {vuint8m1_t t;} +void foo15 () {vint8m2_t t;} +void foo16 () {vuint8m2_t t;} +void foo17 () {vint8m4_t t;} +void foo18 () {vuint8m4_t t;} +void foo19 () {vint8m8_t t;} +void foo20 () {vuint8m8_t t;} +void foo21 () {vint16mf4_t t;} /* { dg-error {unknown type name 'vint16mf4_t'} } */ +void foo22 () {vuint16mf4_t t;} /* { dg-error {unknown type name 'vuint16mf4_t'} } */ +void foo23 () {vint16mf2_t t;} +void foo24 () {vuint16mf2_t t;} +void foo25 () {vint16m1_t t;} +void foo26 () {vuint16m1_t t;} +void foo27 () {vint16m2_t t;} +void foo28 () {vuint16m2_t t;} +void foo29 () {vint16m4_t t;} +void foo30 () {vuint16m4_t t;} +void foo31 () {vint16m8_t t;} +void foo32 () {vuint16m8_t t;} +void foo33 () {vint32mf2_t t;} /* { dg-error {unknown type name 'vint32mf2_t'} } */ +void foo34 () {vuint32mf2_t t;} /* { dg-error {unknown type name 'vuint32mf2_t'} } */ +void foo35 () {vint32m1_t t;} +void foo36 () {vuint32m1_t t;} +void foo37 () {vint32m2_t t;} +void foo38 () {vuint32m2_t t;} +void foo39 () {vint32m4_t t;} +void foo40 () {vuint32m4_t t;} +void foo41 () {vint32m8_t t;} +void foo42 () {vuint32m8_t t;} +void foo43 () {vint64m1_t t;} /* { dg-error {unknown type name 'vint64m1_t'} } */ +void foo44 () {vuint64m1_t t;} /* { dg-error {unknown type name 'vuint64m1_t'} } */ +void foo45 () {vint64m2_t t;} /* { dg-error {unknown type name 'vint64m2_t'} } */ +void foo46 () {vuint64m2_t t;} /* { dg-error {unknown type name 'vuint64m2_t'} } */ +void foo47 () {vint64m4_t t;} /* { dg-error {unknown type name 'vint64m4_t'} } */ +void foo48 () {vuint64m4_t t;} /* { dg-error {unknown type name 'vuint64m4_t'} } */ +void foo49 () {vint64m8_t t;} /* { dg-error {unknown type name 'vint64m8_t'} } */ +void foo50 () {vuint64m8_t t;} /* { dg-error {unknown type name 'vuint64m8_t'} } */ +void foo57 () {vfloat32mf2_t t;} /* { dg-error {unknown type name 'vfloat32mf2_t'} } */ +void foo58 () {vfloat32m1_t t;} /* { dg-error {unknown type name 'vfloat32m1_t'} } */ +void foo59 () {vfloat32m2_t t;} /* { dg-error {unknown type name 'vfloat32m2_t'} } */ +void foo60 () {vfloat32m4_t t;} /* { dg-error {unknown type name 'vfloat32m4_t'} } */ +void foo61 () {vfloat32m8_t t;} /* { dg-error {unknown type name 'vfloat32m8_t'} } */ +void foo62 () {vfloat64m1_t t;} /* { dg-error {unknown type name 'vfloat64m1_t'} } */ +void foo63 () {vfloat64m2_t t;} /* { dg-error {unknown type name 'vfloat64m2_t'} } */ +void foo64 () {vfloat64m4_t t;} /* { dg-error {unknown type name 'vfloat64m4_t'} } */ +void foo65 () {vfloat64m8_t t;} /* { dg-error {unknown type name 'vfloat64m8_t'} } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/user-6.c b/gcc/testsuite/gcc.target/riscv/rvv/base/user-6.c new file mode 100644 index 0000000..5361fbd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/user-6.c @@ -0,0 +1,65 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv32gc_zve32f -mabi=ilp32d" } */ + +#include "riscv_vector.h" + +void foo0 () {vbool64_t t;} /* { dg-error {unknown type name 'vbool64_t'} } */ +void foo1 () {vbool32_t t;} +void foo2 () {vbool16_t t;} +void foo3 () {vbool8_t t;} +void foo4 () {vbool4_t t;} +void foo5 () {vbool2_t t;} +void foo6 () {vbool1_t t;} +void foo7 () {vint8mf8_t t;} /* { dg-error {unknown type name 'vint8mf8_t'} } */ +void foo8 () {vuint8mf8_t t;} /* { dg-error {unknown type name 'vuint8mf8_t'} } */ +void foo9 () {vint8mf4_t t;} +void foo10 () {vuint8mf4_t t;} +void foo11 () {vint8mf2_t t;} +void foo12 () {vuint8mf2_t t;} +void foo13 () {vint8m1_t t;} +void foo14 () {vuint8m1_t t;} +void foo15 () {vint8m2_t t;} +void foo16 () {vuint8m2_t t;} +void foo17 () {vint8m4_t t;} +void foo18 () {vuint8m4_t t;} +void foo19 () {vint8m8_t t;} +void foo20 () {vuint8m8_t t;} +void foo21 () {vint16mf4_t t;} /* { dg-error {unknown type name 'vint16mf4_t'} } */ +void foo22 () {vuint16mf4_t t;} /* { dg-error {unknown type name 'vuint16mf4_t'} } */ +void foo23 () {vint16mf2_t t;} +void foo24 () {vuint16mf2_t t;} +void foo25 () {vint16m1_t t;} +void foo26 () {vuint16m1_t t;} +void foo27 () {vint16m2_t t;} +void foo28 () {vuint16m2_t t;} +void foo29 () {vint16m4_t t;} +void foo30 () {vuint16m4_t t;} +void foo31 () {vint16m8_t t;} +void foo32 () {vuint16m8_t t;} +void foo33 () {vint32mf2_t t;} /* { dg-error {unknown type name 'vint32mf2_t'} } */ +void foo34 () {vuint32mf2_t t;} /* { dg-error {unknown type name 'vuint32mf2_t'} } */ +void foo35 () {vint32m1_t t;} +void foo36 () {vuint32m1_t t;} +void foo37 () {vint32m2_t t;} +void foo38 () {vuint32m2_t t;} +void foo39 () {vint32m4_t t;} +void foo40 () {vuint32m4_t t;} +void foo41 () {vint32m8_t t;} +void foo42 () {vuint32m8_t t;} +void foo43 () {vint64m1_t t;} /* { dg-error {unknown type name 'vint64m1_t'} } */ +void foo44 () {vuint64m1_t t;} /* { dg-error {unknown type name 'vuint64m1_t'} } */ +void foo45 () {vint64m2_t t;} /* { dg-error {unknown type name 'vint64m2_t'} } */ +void foo46 () {vuint64m2_t t;} /* { dg-error {unknown type name 'vuint64m2_t'} } */ +void foo47 () {vint64m4_t t;} /* { dg-error {unknown type name 'vint64m4_t'} } */ +void foo48 () {vuint64m4_t t;} /* { dg-error {unknown type name 'vuint64m4_t'} } */ +void foo49 () {vint64m8_t t;} /* { dg-error {unknown type name 'vint64m8_t'} } */ +void foo50 () {vuint64m8_t t;} /* { dg-error {unknown type name 'vuint64m8_t'} } */ +void foo57 () {vfloat32mf2_t t;} /* { dg-error {unknown type name 'vfloat32mf2_t'} } */ +void foo58 () {vfloat32m1_t t;} +void foo59 () {vfloat32m2_t t;} +void foo60 () {vfloat32m4_t t;} +void foo61 () {vfloat32m8_t t;} +void foo62 () {vfloat64m1_t t;} /* { dg-error {unknown type name 'vfloat64m1_t'} } */ +void foo63 () {vfloat64m2_t t;} /* { dg-error {unknown type name 'vfloat64m2_t'} } */ +void foo64 () {vfloat64m4_t t;} /* { dg-error {unknown type name 'vfloat64m4_t'} } */ +void foo65 () {vfloat64m8_t t;} /* { dg-error {unknown type name 'vfloat64m8_t'} } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/vread_csr.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vread_csr.c new file mode 100644 index 0000000..9151349f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/vread_csr.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O3" } */ +/* { dg-skip-if "test intrinsic using rvv" { *-*-* } { "*" } { "-march=rv*v*zfh*" } } */ + +#include + +unsigned long vread_csr_vstart(void) { + return vread_csr(RVV_VSTART); +} + +unsigned long vread_csr_vxsat(void) { + return vread_csr(RVV_VXSAT); +} + +unsigned long vread_csr_vxrm(void) { + return vread_csr(RVV_VXRM); +} + +unsigned long vread_csr_vcsr(void) { + return vread_csr(RVV_VCSR); +} + +/* { dg-final { scan-assembler-times {csrr\s+(?:ra|[sgtf]p|t[0-6]|s[0-9]|s10|s11|a[0-7]),\s*vstart} 1 } } */ +/* { dg-final { scan-assembler-times {csrr\s+(?:ra|[sgtf]p|t[0-6]|s[0-9]|s10|s11|a[0-7]),\s*vxsat} 1 } } */ +/* { dg-final { scan-assembler-times {csrr\s+(?:ra|[sgtf]p|t[0-6]|s[0-9]|s10|s11|a[0-7]),\s*vxrm} 1 } } */ +/* { dg-final { scan-assembler-times {csrr\s+(?:ra|[sgtf]p|t[0-6]|s[0-9]|s10|s11|a[0-7]),\s*vcsr} 1 } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/vwrite_csr.c b/gcc/testsuite/gcc.target/riscv/rvv/base/vwrite_csr.c new file mode 100644 index 0000000..a50eba7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/vwrite_csr.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O3" } */ +/* { dg-skip-if "test intrinsic using rvv" { *-*-* } { "*" } { "-march=rv*v*zfh*" } } */ + +#include + +void vwrite_csr_vstart(unsigned long value) { + vwrite_csr(RVV_VSTART, value); +} + +void vwrite_csr_vxsat(unsigned long value) { + vwrite_csr(RVV_VXSAT, value); +} + +void vwrite_csr_vxrm(unsigned long value) { + vwrite_csr(RVV_VXRM, value); +} + +void vwrite_csr_vcsr(unsigned long value) { + vwrite_csr(RVV_VCSR, value); +} + +/* { dg-final { scan-assembler-times {csrw\s+vstart,\s*(?:ra|[sgtf]p|t[0-6]|s[0-9]|s10|s11|a[0-7])} 1 } } */ +/* { dg-final { scan-assembler-times {csrw\s+vxsat,\s*(?:ra|[sgtf]p|t[0-6]|s[0-9]|s10|s11|a[0-7])} 1 } } */ +/* { dg-final { scan-assembler-times {csrw\s+vxrm,\s*(?:ra|[sgtf]p|t[0-6]|s[0-9]|s10|s11|a[0-7])} 1 } } */ +/* { dg-final { scan-assembler-times {csrw\s+vcsr,\s*(?:ra|[sgtf]p|t[0-6]|s[0-9]|s10|s11|a[0-7])} 1 } } */ \ No newline at end of file -- cgit v1.1 From 49192c41de94b2746cd33366134b6aeaefa6ca2a Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 3 Oct 2022 17:16:38 -0400 Subject: c++: lvalue_kind tweak I was wondering how lvalue_kind handles VIEW_CONVERT_EXPR; in cases where the type actually changes, it should have the same prvalue->xvalue effect as ARRAY_REF, since we need to materialize a temporary to get an object we can reinterpret as another type. Currently this only fires on builtin-shufflevector-3.c, where we use VIEW_CONVERT_EXPR to reinterpret a vector as an array. REALPART_EXPR and IMAGPART_EXPR should also be treated like COMPONENT_REF. PREINCREMENT_EXPR and PREDECREMENT_EXPR should only be applied to glvalues, but if for some reason they were applied to a prvalue this would be correct. TRY_CATCH_EXPR around a prvalue is also questionable, but this is the right handling. gcc/cp/ChangeLog: * tree.cc (lvalue_kind) [VIEW_CONVERT_EXPR]: Change prvalue to xvalue. --- gcc/cp/tree.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index aa9c1b7..6d968a2 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -104,7 +104,17 @@ lvalue_kind (const_tree ref) case REALPART_EXPR: case IMAGPART_EXPR: case VIEW_CONVERT_EXPR: - return lvalue_kind (TREE_OPERAND (ref, 0)); + op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0)); + /* As for ARRAY_REF and COMPONENT_REF, these codes turn a class prvalue + into an xvalue: we need to materialize the temporary before we mess + with it. Except VIEW_CONVERT_EXPR that doesn't actually change the + type, as in location wrapper and REF_PARENTHESIZED_P. */ + if (op1_lvalue_kind == clk_class + && !(TREE_CODE (ref) == VIEW_CONVERT_EXPR + && (same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (ref), TREE_TYPE (TREE_OPERAND (ref, 0)))))) + return clk_rvalueref; + return op1_lvalue_kind; case ARRAY_REF: { -- cgit v1.1 From e2a228438919d846995bf2c839c9b657442224b2 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Wed, 5 Oct 2022 19:25:27 +0200 Subject: Fortran: Add OpenMP's assume(s) directives libgomp/ChangeLog: * libgomp.texi (OpenMP 5.1 Impl. Status): Mark 'assume' as 'Y'. gcc/fortran/ChangeLog: * dump-parse-tree.cc (show_omp_assumes): New. (show_omp_clauses, show_namespace): Call it. (show_omp_node, show_code_node): Handle OpenMP ASSUME. * gfortran.h (enum gfc_statement): Add ST_OMP_ASSUME, ST_OMP_END_ASSUME, ST_OMP_ASSUMES and ST_NOTHING. (gfc_exec_op): Add EXEC_OMP_ASSUME. (gfc_omp_assumptions): New struct. (gfc_get_omp_assumptions): New XCNEW #define. (gfc_omp_clauses, gfc_namespace): Add assume member. (gfc_resolve_omp_assumptions): New prototype. * match.h (gfc_match_omp_assume, gfc_match_omp_assumes): New. * openmp.cc (omp_code_to_statement): Forward declare. (enum gfc_omp_directive_kind, struct gfc_omp_directive): New. (gfc_free_omp_clauses): Free assume member and its struct data. (enum omp_mask2): Add OMP_CLAUSE_ASSUMPTIONS. (gfc_omp_absent_contains_clause): New. (gfc_match_omp_clauses): Call it; optionally use passed omp_clauses argument. (omp_verify_merge_absent_contains, gfc_match_omp_assume, gfc_match_omp_assumes, gfc_resolve_omp_assumptions): New. (resolve_omp_clauses): Call the latter. (gfc_resolve_omp_directive, omp_code_to_statement): Handle EXEC_OMP_ASSUME. * parse.cc (decode_omp_directive): Parse OpenMP ASSUME(S). (next_statement, parse_executable, parse_omp_structured_block): Handle ST_OMP_ASSUME. (case_omp_decl): Add ST_OMP_ASSUMES. (gfc_ascii_statement): Handle Assumes, optional return string without '!$OMP '/'!$ACC ' prefix. * parse.h (gfc_ascii_statement): Add optional bool arg to prototype. * resolve.cc (gfc_resolve_blocks, gfc_resolve_code): Add EXEC_OMP_ASSUME. (gfc_resolve): Resolve ASSUMES directive. * symbol.cc (gfc_free_namespace): Free omp_assumes member. * st.cc (gfc_free_statement): Handle EXEC_OMP_ASSUME. * trans-openmp.cc (gfc_trans_omp_directive): Likewise. * trans.cc (trans_code): Likewise. gcc/testsuite/ChangeLog: * gfortran.dg/gomp/assume-1.f90: New test. * gfortran.dg/gomp/assume-2.f90: New test. * gfortran.dg/gomp/assumes-1.f90: New test. * gfortran.dg/gomp/assumes-2.f90: New test. --- gcc/fortran/dump-parse-tree.cc | 41 +++ gcc/fortran/gfortran.h | 23 +- gcc/fortran/match.h | 2 + gcc/fortran/openmp.cc | 403 +++++++++++++++++++++++++++ gcc/fortran/parse.cc | 31 ++- gcc/fortran/parse.h | 2 +- gcc/fortran/resolve.cc | 5 + gcc/fortran/st.cc | 1 + gcc/fortran/symbol.cc | 8 +- gcc/fortran/trans-openmp.cc | 2 + gcc/fortran/trans.cc | 1 + gcc/testsuite/gfortran.dg/gomp/assume-1.f90 | 24 ++ gcc/testsuite/gfortran.dg/gomp/assume-2.f90 | 27 ++ gcc/testsuite/gfortran.dg/gomp/assumes-1.f90 | 82 ++++++ gcc/testsuite/gfortran.dg/gomp/assumes-2.f90 | 19 ++ 15 files changed, 664 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/gomp/assume-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/assume-2.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/assumes-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/assumes-2.f90 (limited to 'gcc') diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc index 40c690c..2f042ab 100644 --- a/gcc/fortran/dump-parse-tree.cc +++ b/gcc/fortran/dump-parse-tree.cc @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see #include "gfortran.h" #include "constructor.h" #include "version.h" +#include "parse.h" /* For gfc_ascii_statement. */ /* Keep track of indentation for symbol tree dumps. */ static int show_level = 0; @@ -1458,6 +1459,34 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n) gfc_current_ns = ns_curr; } +static void +show_omp_assumes (gfc_omp_assumptions *assume) +{ + for (int i = 0; i < assume->n_absent; i++) + { + fputs (" ABSENT (", dumpfile); + fputs (gfc_ascii_statement (assume->absent[i], true), dumpfile); + fputc (')', dumpfile); + } + for (int i = 0; i < assume->n_contains; i++) + { + fputs (" CONTAINS (", dumpfile); + fputs (gfc_ascii_statement (assume->contains[i], true), dumpfile); + fputc (')', dumpfile); + } + for (gfc_expr_list *el = assume->holds; el; el = el->next) + { + fputs (" HOLDS (", dumpfile); + show_expr (el->expr); + fputc (')', dumpfile); + } + if (assume->no_openmp) + fputs (" NO_OPENMP", dumpfile); + if (assume->no_openmp_routines) + fputs (" NO_OPENMP_ROUTINES", dumpfile); + if (assume->no_parallelism) + fputs (" NO_PARALLELISM", dumpfile); +} /* Show OpenMP or OpenACC clauses. */ @@ -1998,6 +2027,8 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses) show_expr (omp_clauses->message); fputc (')', dumpfile); } + if (omp_clauses->assume) + show_omp_assumes (omp_clauses->assume); } /* Show a single OpenMP or OpenACC directive node and everything underneath it @@ -2027,6 +2058,7 @@ show_omp_node (int level, gfc_code *c) case EXEC_OACC_CACHE: name = "CACHE"; is_oacc = true; break; case EXEC_OACC_ENTER_DATA: name = "ENTER DATA"; is_oacc = true; break; case EXEC_OACC_EXIT_DATA: name = "EXIT DATA"; is_oacc = true; break; + case EXEC_OMP_ASSUME: name = "ASSUME"; break; case EXEC_OMP_ATOMIC: name = "ATOMIC"; break; case EXEC_OMP_BARRIER: name = "BARRIER"; break; case EXEC_OMP_CANCEL: name = "CANCEL"; break; @@ -2128,6 +2160,7 @@ show_omp_node (int level, gfc_code *c) case EXEC_OACC_CACHE: case EXEC_OACC_ENTER_DATA: case EXEC_OACC_EXIT_DATA: + case EXEC_OMP_ASSUME: case EXEC_OMP_CANCEL: case EXEC_OMP_CANCELLATION_POINT: case EXEC_OMP_DISTRIBUTE: @@ -3353,6 +3386,7 @@ show_code_node (int level, gfc_code *c) case EXEC_OACC_CACHE: case EXEC_OACC_ENTER_DATA: case EXEC_OACC_EXIT_DATA: + case EXEC_OMP_ASSUME: case EXEC_OMP_ATOMIC: case EXEC_OMP_CANCEL: case EXEC_OMP_CANCELLATION_POINT: @@ -3531,6 +3565,13 @@ show_namespace (gfc_namespace *ns) } } + if (ns->omp_assumes) + { + show_indent (); + fprintf (dumpfile, "!$OMP ASSUMES"); + show_omp_assumes (ns->omp_assumes); + } + fputc ('\n', dumpfile); show_indent (); fputs ("code:", dumpfile); diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 4babd77..608dda4 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -316,7 +316,9 @@ enum gfc_statement ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD, ST_OMP_MASKED_TASKLOOP, ST_OMP_END_MASKED_TASKLOOP, ST_OMP_MASKED_TASKLOOP_SIMD, ST_OMP_END_MASKED_TASKLOOP_SIMD, ST_OMP_SCOPE, ST_OMP_END_SCOPE, - ST_OMP_ERROR, ST_NONE + ST_OMP_ERROR, ST_OMP_ASSUME, ST_OMP_END_ASSUME, ST_OMP_ASSUMES, + /* Note: gfc_match_omp_nothing returns ST_NONE. */ + ST_OMP_NOTHING, ST_NONE }; /* Types of interfaces that we can have. Assignment interfaces are @@ -1506,6 +1508,18 @@ enum gfc_omp_bind_type OMP_BIND_THREAD }; +typedef struct gfc_omp_assumptions +{ + int n_absent, n_contains; + enum gfc_statement *absent, *contains; + gfc_expr_list *holds; + bool no_openmp:1, no_openmp_routines:1, no_parallelism:1; +} +gfc_omp_assumptions; + +#define gfc_get_omp_assumptions() XCNEW (gfc_omp_assumptions) + + typedef struct gfc_omp_clauses { gfc_omp_namelist *lists[OMP_LIST_NUM]; @@ -1529,6 +1543,7 @@ typedef struct gfc_omp_clauses struct gfc_expr *if_exprs[OMP_IF_LAST]; struct gfc_expr *dist_chunk_size; struct gfc_expr *message; + struct gfc_omp_assumptions *assume; const char *critical_name; enum gfc_omp_default_sharing default_sharing; enum gfc_omp_atomic_op atomic_op; @@ -2145,6 +2160,9 @@ typedef struct gfc_namespace /* Linked list of !$omp declare variant constructs. */ struct gfc_omp_declare_variant *omp_declare_variant; + /* OpenMP assumptions. */ + struct gfc_omp_assumptions *omp_assumes; + /* A hash set for the gfc expressions that have already been finalized in this namespace. */ @@ -2913,7 +2931,7 @@ enum gfc_exec_op EXEC_OMP_ORDERED, EXEC_OMP_PARALLEL, EXEC_OMP_PARALLEL_DO, EXEC_OMP_PARALLEL_SECTIONS, EXEC_OMP_PARALLEL_WORKSHARE, EXEC_OMP_SECTIONS, EXEC_OMP_SINGLE, EXEC_OMP_WORKSHARE, - EXEC_OMP_ATOMIC, EXEC_OMP_BARRIER, EXEC_OMP_END_NOWAIT, + EXEC_OMP_ASSUME, EXEC_OMP_ATOMIC, EXEC_OMP_BARRIER, EXEC_OMP_END_NOWAIT, EXEC_OMP_END_SINGLE, EXEC_OMP_TASK, EXEC_OMP_TASKWAIT, EXEC_OMP_TASKYIELD, EXEC_OMP_CANCEL, EXEC_OMP_CANCELLATION_POINT, EXEC_OMP_TASKGROUP, EXEC_OMP_SIMD, EXEC_OMP_DO_SIMD, @@ -3576,6 +3594,7 @@ void gfc_free_omp_declare_simd (gfc_omp_declare_simd *); void gfc_free_omp_declare_simd_list (gfc_omp_declare_simd *); void gfc_free_omp_udr (gfc_omp_udr *); gfc_omp_udr *gfc_omp_udr_find (gfc_symtree *, gfc_typespec *); +void gfc_resolve_omp_assumptions (gfc_omp_assumptions *); void gfc_resolve_omp_directive (gfc_code *, gfc_namespace *); void gfc_resolve_do_iterator (gfc_code *, gfc_symbol *, bool); void gfc_resolve_omp_local_vars (gfc_namespace *); diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h index 1f53e0c..2a80581 100644 --- a/gcc/fortran/match.h +++ b/gcc/fortran/match.h @@ -149,6 +149,8 @@ match gfc_match_oacc_routine (void); /* OpenMP directive matchers. */ match gfc_match_omp_eos_error (void); +match gfc_match_omp_assume (void); +match gfc_match_omp_assumes (void); match gfc_match_omp_atomic (void); match gfc_match_omp_barrier (void); match gfc_match_omp_cancel (void); diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc index ce719bd..653c43f 100644 --- a/gcc/fortran/openmp.cc +++ b/gcc/fortran/openmp.cc @@ -29,6 +29,86 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic.h" #include "gomp-constants.h" #include "target-memory.h" /* For gfc_encode_character. */ +#include "bitmap.h" + + +static gfc_statement omp_code_to_statement (gfc_code *); + +enum gfc_omp_directive_kind { + GFC_OMP_DIR_DECLARATIVE, + GFC_OMP_DIR_EXECUTABLE, + GFC_OMP_DIR_INFORMATIONAL, + GFC_OMP_DIR_META, + GFC_OMP_DIR_SUBSIDIARY, + GFC_OMP_DIR_UTILITY +}; + +struct gfc_omp_directive { + const char *name; + enum gfc_omp_directive_kind kind; + gfc_statement st; +}; + +/* Alphabetically sorted OpenMP clauses, except that longer strings are before + substrings; excludes combined/composite directives. See note for "ordered" + and "nothing". */ + +static const struct gfc_omp_directive gfc_omp_directives[] = { + /* {"allocate", GFC_OMP_DIR_DECLARATIVE, ST_OMP_ALLOCATE}, */ + /* {"allocators", GFC_OMP_DIR_EXECUTABLE, ST_OMP_ALLOCATORS}, */ + {"assumes", GFC_OMP_DIR_INFORMATIONAL, ST_OMP_ASSUMES}, + {"assume", GFC_OMP_DIR_INFORMATIONAL, ST_OMP_ASSUME}, + {"atomic", GFC_OMP_DIR_EXECUTABLE, ST_OMP_ATOMIC}, + {"barrier", GFC_OMP_DIR_EXECUTABLE, ST_OMP_BARRIER}, + {"cancellation point", GFC_OMP_DIR_EXECUTABLE, ST_OMP_CANCELLATION_POINT}, + {"cancel", GFC_OMP_DIR_EXECUTABLE, ST_OMP_CANCEL}, + {"critical", GFC_OMP_DIR_EXECUTABLE, ST_OMP_CRITICAL}, + /* {"declare mapper", GFC_OMP_DIR_DECLARATIVE, ST_OMP_DECLARE_MAPPER}, */ + {"declare reduction", GFC_OMP_DIR_DECLARATIVE, ST_OMP_DECLARE_REDUCTION}, + {"declare simd", GFC_OMP_DIR_DECLARATIVE, ST_OMP_DECLARE_SIMD}, + {"declare target", GFC_OMP_DIR_DECLARATIVE, ST_OMP_DECLARE_TARGET}, + {"declare variant", GFC_OMP_DIR_DECLARATIVE, ST_OMP_DECLARE_VARIANT}, + {"depobj", GFC_OMP_DIR_EXECUTABLE, ST_OMP_DEPOBJ}, + /* {"dispatch", GFC_OMP_DIR_EXECUTABLE, ST_OMP_DISPATCH}, */ + {"distribute", GFC_OMP_DIR_EXECUTABLE, ST_OMP_DISTRIBUTE}, + {"do", GFC_OMP_DIR_EXECUTABLE, ST_OMP_DO}, + /* "error" becomes GFC_OMP_DIR_EXECUTABLE with at(execution) */ + {"error", GFC_OMP_DIR_UTILITY, ST_OMP_ERROR}, + {"flush", GFC_OMP_DIR_EXECUTABLE, ST_OMP_FLUSH}, + /* {"interop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_INTEROP}, */ + {"loop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_LOOP}, + {"masked", GFC_OMP_DIR_EXECUTABLE, ST_OMP_MASKED}, + /* {"metadirective", GFC_OMP_DIR_META, ST_OMP_METADIRECTIVE}, */ + /* Note: gfc_match_omp_nothing returns ST_NONE. */ + {"nothing", GFC_OMP_DIR_UTILITY, ST_OMP_NOTHING}, + /* Special case; for now map to the first one. + ordered-blockassoc = ST_OMP_ORDERED + ordered-standalone = ST_OMP_ORDERED_DEPEND + depend/doacross. */ + {"ordered", GFC_OMP_DIR_EXECUTABLE, ST_OMP_ORDERED}, + {"parallel", GFC_OMP_DIR_EXECUTABLE, ST_OMP_PARALLEL}, + {"requires", GFC_OMP_DIR_INFORMATIONAL, ST_OMP_REQUIRES}, + {"scan", GFC_OMP_DIR_SUBSIDIARY, ST_OMP_SCAN}, + {"scope", GFC_OMP_DIR_EXECUTABLE, ST_OMP_SCOPE}, + {"sections", GFC_OMP_DIR_EXECUTABLE, ST_OMP_SECTIONS}, + {"section", GFC_OMP_DIR_SUBSIDIARY, ST_OMP_SECTION}, + {"simd", GFC_OMP_DIR_EXECUTABLE, ST_OMP_SIMD}, + {"single", GFC_OMP_DIR_EXECUTABLE, ST_OMP_SINGLE}, + {"target data", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TARGET_DATA}, + {"target enter data", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TARGET_ENTER_DATA}, + {"target exit data", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TARGET_EXIT_DATA}, + {"target update", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TARGET_UPDATE}, + {"target", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TARGET}, + {"taskloop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TASKLOOP}, + {"taskwait", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TASKWAIT}, + {"taskyield", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TASKYIELD}, + {"task", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TASK}, + {"teams", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TEAMS}, + {"threadprivate", GFC_OMP_DIR_DECLARATIVE, ST_OMP_THREADPRIVATE}, + /* {"tile", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TILE}, */ + /* {"unroll", GFC_OMP_DIR_EXECUTABLE, ST_OMP_UNROLL}, */ + {"workshare", GFC_OMP_DIR_EXECUTABLE, ST_OMP_WORKSHARE}, +}; + /* Match an end of OpenMP directive. End of OpenMP directive is optional whitespace, followed by '\n' or comment '!'. */ @@ -111,6 +191,13 @@ gfc_free_omp_clauses (gfc_omp_clauses *c) gfc_free_expr_list (c->wait_list); gfc_free_expr_list (c->tile_list); free (CONST_CAST (char *, c->critical_name)); + if (c->assume) + { + free (c->assume->absent); + free (c->assume->contains); + gfc_free_expr_list (c->assume->holds); + free (c->assume); + } free (c); } @@ -992,6 +1079,7 @@ enum omp_mask2 OMP_CLAUSE_HAS_DEVICE_ADDR, /* OpenMP 5.1 */ OMP_CLAUSE_ENTER, /* OpenMP 5.2 */ OMP_CLAUSE_DOACROSS, /* OpenMP 5.2 */ + OMP_CLAUSE_ASSUMPTIONS, /* OpenMP 5.1. */ /* This must come last. */ OMP_MASK2_LAST }; @@ -1407,6 +1495,173 @@ gfc_match_omp_clause_reduction (char pc, gfc_omp_clauses *c, bool openacc, return MATCH_YES; } +static match +gfc_omp_absent_contains_clause (gfc_omp_assumptions **assume, bool is_absent) +{ + if (*assume == NULL) + *assume = gfc_get_omp_assumptions (); + do + { + gfc_statement st = ST_NONE; + gfc_gobble_whitespace (); + locus old_loc = gfc_current_locus; + char c = gfc_peek_ascii_char (); + enum gfc_omp_directive_kind kind + = GFC_OMP_DIR_DECLARATIVE; /* Silence warning. */ + for (size_t i = 0; i < ARRAY_SIZE (gfc_omp_directives); i++) + { + if (gfc_omp_directives[i].name[0] > c) + break; + if (gfc_omp_directives[i].name[0] != c) + continue; + if (gfc_match (gfc_omp_directives[i].name) == MATCH_YES) + { + st = gfc_omp_directives[i].st; + kind = gfc_omp_directives[i].kind; + } + } + gfc_gobble_whitespace (); + c = gfc_peek_ascii_char (); + if (st == ST_NONE || (c != ',' && c != ')')) + { + if (st == ST_NONE) + gfc_error ("Unknown directive at %L", &old_loc); + else + gfc_error ("Invalid combined or composit directive at %L", + &old_loc); + return MATCH_ERROR; + } + if (kind == GFC_OMP_DIR_DECLARATIVE + || kind == GFC_OMP_DIR_INFORMATIONAL + || kind == GFC_OMP_DIR_META) + { + gfc_error ("Invalid %qs directive at %L in %s clause: declarative, " + "informational and meta directives not permitted", + gfc_ascii_statement (st, true), &old_loc, + is_absent ? "ABSENT" : "CONTAINS"); + return MATCH_ERROR; + } + if (is_absent) + { + /* Use exponential allocation; equivalent to pow2p(x). */ + int i = (*assume)->n_absent; + int size = ((i == 0) ? 4 + : pow2p_hwi (i) == 1 ? i*2 : 0); + if (size != 0) + (*assume)->absent = XRESIZEVEC (gfc_statement, + (*assume)->absent, size); + (*assume)->absent[(*assume)->n_absent++] = st; + } + else + { + int i = (*assume)->n_contains; + int size = ((i == 0) ? 4 + : pow2p_hwi (i) == 1 ? i*2 : 0); + if (size != 0) + (*assume)->contains = XRESIZEVEC (gfc_statement, + (*assume)->contains, size); + (*assume)->contains[(*assume)->n_contains++] = st; + } + gfc_gobble_whitespace (); + if (gfc_match(",") == MATCH_YES) + continue; + if (gfc_match(")") == MATCH_YES) + break; + gfc_error ("Expected %<,%> or %<)%> at %C"); + return MATCH_ERROR; + } + while (true); + + return MATCH_YES; +} + +/* Check 'check' argument for duplicated statements in absent and/or contains + clauses. If 'merge', merge them from check to 'merge'. */ + +static match +omp_verify_merge_absent_contains (gfc_statement st, gfc_omp_assumptions *check, + gfc_omp_assumptions *merge, locus *loc) +{ + if (check == NULL) + return MATCH_YES; + bitmap_head absent_head, contains_head; + bitmap_obstack_initialize (NULL); + bitmap_initialize (&absent_head, &bitmap_default_obstack); + bitmap_initialize (&contains_head, &bitmap_default_obstack); + + match m = MATCH_YES; + for (int i = 0; i < check->n_absent; i++) + if (!bitmap_set_bit (&absent_head, check->absent[i])) + { + gfc_error ("%qs directive mentioned multiple times in %s clause in %s " + "directive at %L", + gfc_ascii_statement (check->absent[i], true), + "ABSENT", gfc_ascii_statement (st), loc); + m = MATCH_ERROR; + } + for (int i = 0; i < check->n_contains; i++) + { + if (!bitmap_set_bit (&contains_head, check->contains[i])) + { + gfc_error ("%qs directive mentioned multiple times in %s clause in %s " + "directive at %L", + gfc_ascii_statement (check->contains[i], true), + "CONTAINS", gfc_ascii_statement (st), loc); + m = MATCH_ERROR; + } + if (bitmap_bit_p (&absent_head, check->contains[i])) + { + gfc_error ("%qs directive mentioned both times in ABSENT and CONTAINS " + "clauses in %s directive at %L", + gfc_ascii_statement (check->absent[i], true), + gfc_ascii_statement (st), loc); + m = MATCH_ERROR; + } + } + + if (m == MATCH_ERROR) + return MATCH_ERROR; + if (merge == NULL) + return MATCH_YES; + if (merge->absent == NULL && check->absent) + { + merge->n_absent = check->n_absent; + merge->absent = check->absent; + check->absent = NULL; + } + else if (merge->absent && check->absent) + { + check->absent = XRESIZEVEC (gfc_statement, check->absent, + merge->n_absent + check->n_absent); + for (int i = 0; i < merge->n_absent; i++) + if (!bitmap_bit_p (&absent_head, merge->absent[i])) + check->absent[check->n_absent++] = merge->absent[i]; + free (merge->absent); + merge->absent = check->absent; + merge->n_absent = check->n_absent; + check->absent = NULL; + } + if (merge->contains == NULL && check->contains) + { + merge->n_contains = check->n_contains; + merge->contains = check->contains; + check->contains = NULL; + } + else if (merge->contains && check->contains) + { + check->contains = XRESIZEVEC (gfc_statement, check->contains, + merge->n_contains + check->n_contains); + for (int i = 0; i < merge->n_contains; i++) + if (!bitmap_bit_p (&contains_head, merge->contains[i])) + check->contains[check->n_contains++] = merge->contains[i]; + free (merge->contains); + merge->contains = check->contains; + merge->n_contains = check->n_contains; + check->contains = NULL; + } + return MATCH_YES; +} + /* Match with duplicate check. Matches 'name'. If expr != NULL, it then matches '(expr)', otherwise, if open_parens is true, @@ -1511,6 +1766,14 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, case 'a': end_colon = false; head = NULL; + if ((mask & OMP_CLAUSE_ASSUMPTIONS) + && gfc_match ("absent ( ") == MATCH_YES) + { + if (gfc_omp_absent_contains_clause (&c->assume, true) + != MATCH_YES) + goto error; + continue; + } if ((mask & OMP_CLAUSE_ALIGNED) && gfc_match_omp_variable_list ("aligned (", &c->lists[OMP_LIST_ALIGNED], @@ -1743,6 +2006,14 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, needs_space = true; continue; } + if ((mask & OMP_CLAUSE_ASSUMPTIONS) + && gfc_match ("contains ( ") == MATCH_YES) + { + if (gfc_omp_absent_contains_clause (&c->assume, false) + != MATCH_YES) + goto error; + continue; + } if ((mask & OMP_CLAUSE_COPY) && gfc_match ("copy ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], @@ -2277,6 +2548,20 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, goto error; continue; } + if ((mask & OMP_CLAUSE_ASSUMPTIONS) + && gfc_match ("holds ( ") == MATCH_YES) + { + gfc_expr *e; + if (gfc_match ("%e )", &e) != MATCH_YES) + goto error; + if (c->assume == NULL) + c->assume = gfc_get_omp_assumptions (); + gfc_expr_list *el = XCNEW (gfc_expr_list); + el->expr = e; + el->next = c->assume->holds; + c->assume->holds = el; + continue; + } if ((mask & OMP_CLAUSE_HOST_SELF) && gfc_match ("host ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], @@ -2664,6 +2949,41 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, OMP_MAP_IF_PRESENT, true, allow_derived)) continue; + if ((mask & OMP_CLAUSE_ASSUMPTIONS) + && (m = gfc_match_dupl_check (!c->assume + || !c->assume->no_openmp_routines, + "no_openmp_routines")) == MATCH_YES) + { + if (m == MATCH_ERROR) + goto error; + if (c->assume == NULL) + c->assume = gfc_get_omp_assumptions (); + c->assume->no_openmp_routines = needs_space = true; + continue; + } + if ((mask & OMP_CLAUSE_ASSUMPTIONS) + && (m = gfc_match_dupl_check (!c->assume || !c->assume->no_openmp, + "no_openmp")) == MATCH_YES) + { + if (m == MATCH_ERROR) + goto error; + if (c->assume == NULL) + c->assume = gfc_get_omp_assumptions (); + c->assume->no_openmp = needs_space = true; + continue; + } + if ((mask & OMP_CLAUSE_ASSUMPTIONS) + && (m = gfc_match_dupl_check (!c->assume + || !c->assume->no_parallelism, + "no_parallelism")) == MATCH_YES) + { + if (m == MATCH_ERROR) + goto error; + if (c->assume == NULL) + c->assume = gfc_get_omp_assumptions (); + c->assume->no_parallelism = needs_space = true; + continue; + } if ((mask & OMP_CLAUSE_NOGROUP) && (m = gfc_match_dupl_check (!c->nogroup, "nogroup")) != MATCH_NO) @@ -3942,6 +4262,69 @@ match_omp (gfc_exec_op op, const omp_mask mask) match +gfc_match_omp_assume (void) +{ + gfc_omp_clauses *c; + locus loc = gfc_current_locus; + if ((gfc_match_omp_clauses (&c, omp_mask (OMP_CLAUSE_ASSUMPTIONS)) + != MATCH_YES) + || (omp_verify_merge_absent_contains (ST_OMP_ASSUME, c->assume, NULL, + &loc) != MATCH_YES)) + return MATCH_ERROR; + new_st.op = EXEC_OMP_ASSUME; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_omp_assumes (void) +{ + gfc_omp_clauses *c; + locus loc = gfc_current_locus; + if (!gfc_current_ns->proc_name + || (gfc_current_ns->proc_name->attr.flavor != FL_MODULE + && !gfc_current_ns->proc_name->attr.subroutine + && !gfc_current_ns->proc_name->attr.function)) + { + gfc_error ("!$OMP ASSUMES at %C must be in the specification part of a " + "subprogram or module"); + return MATCH_ERROR; + } + if ((gfc_match_omp_clauses (&c, omp_mask (OMP_CLAUSE_ASSUMPTIONS)) + != MATCH_YES) + || (omp_verify_merge_absent_contains (ST_OMP_ASSUMES, c->assume, + gfc_current_ns->omp_assumes, &loc) + != MATCH_YES)) + return MATCH_ERROR; + if (gfc_current_ns->omp_assumes == NULL) + { + gfc_current_ns->omp_assumes = c->assume; + c->assume = NULL; + } + else if (gfc_current_ns->omp_assumes && c->assume) + { + gfc_current_ns->omp_assumes->no_openmp |= c->assume->no_openmp; + gfc_current_ns->omp_assumes->no_openmp_routines + |= c->assume->no_openmp_routines; + gfc_current_ns->omp_assumes->no_parallelism |= c->assume->no_parallelism; + if (gfc_current_ns->omp_assumes->holds && c->assume->holds) + { + gfc_expr_list *el = gfc_current_ns->omp_assumes->holds; + for ( ; el->next ; el = el->next) + ; + el->next = c->assume->holds; + } + else if (c->assume->holds) + gfc_current_ns->omp_assumes->holds = c->assume->holds; + c->assume->holds = NULL; + } + gfc_free_omp_clauses (c); + return MATCH_YES; +} + + +match gfc_match_omp_critical (void) { char n[GFC_MAX_SYMBOL_LEN+1]; @@ -6505,6 +6888,20 @@ resolve_omp_udr_clause (gfc_omp_namelist *n, gfc_namespace *ns, return copy; } + +/* Resolve ASSUME's and ASSUMES' assumption clauses. Note that absent/contains + is handled during parse time in omp_verify_merge_absent_contains. */ + +void +gfc_resolve_omp_assumptions (gfc_omp_assumptions *assume) +{ + for (gfc_expr_list *el = assume->holds; el; el = el->next) + if (!gfc_resolve_expr (el->expr) || el->expr->ts.type != BT_LOGICAL) + gfc_error ("HOLDS expression at %L must be a logical expression", + &el->expr->where); +} + + /* OpenMP directive resolving routines. */ static void @@ -7888,6 +8285,9 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, gfc_error ("% clause at %L must not be used together with " "% clause", &omp_clauses->detach->where); } + + if (omp_clauses->assume) + gfc_resolve_omp_assumptions (omp_clauses->assume); } @@ -9116,6 +9516,8 @@ omp_code_to_statement (gfc_code *code) return ST_OMP_DO; case EXEC_OMP_LOOP: return ST_OMP_LOOP; + case EXEC_OMP_ASSUME: + return ST_OMP_ASSUME; case EXEC_OMP_ATOMIC: return ST_OMP_ATOMIC; case EXEC_OMP_BARRIER: @@ -9635,6 +10037,7 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns) case EXEC_OMP_TEAMS_LOOP: resolve_omp_do (code); break; + case EXEC_OMP_ASSUME: case EXEC_OMP_CANCEL: case EXEC_OMP_ERROR: case EXEC_OMP_MASKED: diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc index 2e2e977..f04fd13 100644 --- a/gcc/fortran/parse.cc +++ b/gcc/fortran/parse.cc @@ -885,6 +885,8 @@ decode_omp_directive (void) switch (c) { case 'a': + matcho ("assumes", gfc_match_omp_assumes, ST_OMP_ASSUMES); + matchs ("assume", gfc_match_omp_assume, ST_OMP_ASSUME); matcho ("atomic", gfc_match_omp_atomic, ST_OMP_ATOMIC); break; case 'b': @@ -913,6 +915,7 @@ decode_omp_directive (void) break; case 'e': matcho ("error", gfc_match_omp_error, ST_OMP_ERROR); + matchs ("end assume", gfc_match_omp_eos_error, ST_OMP_END_ASSUME); matcho ("end atomic", gfc_match_omp_eos_error, ST_OMP_END_ATOMIC); matcho ("end critical", gfc_match_omp_end_critical, ST_OMP_END_CRITICAL); matchs ("end distribute parallel do simd", gfc_match_omp_eos_error, @@ -1716,6 +1719,7 @@ next_statement (void) case ST_OMP_TARGET_SIMD: case ST_OMP_TASKLOOP: case ST_OMP_TASKLOOP_SIMD: \ case ST_OMP_LOOP: case ST_OMP_PARALLEL_LOOP: case ST_OMP_TEAMS_LOOP: \ case ST_OMP_TARGET_PARALLEL_LOOP: case ST_OMP_TARGET_TEAMS_LOOP: \ + case ST_OMP_ASSUME: \ case ST_CRITICAL: \ case ST_OACC_PARALLEL_LOOP: case ST_OACC_PARALLEL: case ST_OACC_KERNELS: \ case ST_OACC_DATA: case ST_OACC_HOST_DATA: case ST_OACC_LOOP: \ @@ -1733,7 +1737,7 @@ next_statement (void) #define case_omp_decl case ST_OMP_THREADPRIVATE: case ST_OMP_DECLARE_SIMD: \ case ST_OMP_DECLARE_TARGET: case ST_OMP_DECLARE_REDUCTION: \ - case ST_OMP_DECLARE_VARIANT: \ + case ST_OMP_DECLARE_VARIANT: case ST_OMP_ASSUMES: \ case ST_OMP_REQUIRES: case ST_OACC_ROUTINE: case ST_OACC_DECLARE /* Block end statements. Errors associated with interchanging these @@ -1925,10 +1929,11 @@ gfc_enclosing_unit (gfc_compile_state * result) } -/* Translate a statement enum to a string. */ +/* Translate a statement enum to a string. If strip_sentinel is true, + the !$OMP/!$ACC sentinel is excluded. */ const char * -gfc_ascii_statement (gfc_statement st) +gfc_ascii_statement (gfc_statement st, bool strip_sentinel) { const char *p; @@ -2353,6 +2358,12 @@ gfc_ascii_statement (gfc_statement st) case ST_OACC_END_ATOMIC: p = "!$ACC END ATOMIC"; break; + case ST_OMP_ASSUME: + p = "!$OMP ASSUME"; + break; + case ST_OMP_ASSUMES: + p = "!$OMP ASSUMES"; + break; case ST_OMP_ATOMIC: p = "!$OMP ATOMIC"; break; @@ -2401,6 +2412,9 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_DO_SIMD: p = "!$OMP DO SIMD"; break; + case ST_OMP_END_ASSUME: + p = "!$OMP END ASSUME"; + break; case ST_OMP_END_ATOMIC: p = "!$OMP END ATOMIC"; break; @@ -2600,6 +2614,10 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_ORDERED_DEPEND: p = "!$OMP ORDERED"; break; + case ST_OMP_NOTHING: + /* Note: gfc_match_omp_nothing returns ST_NONE. */ + p = "!$OMP NOTHING"; + break; case ST_OMP_PARALLEL: p = "!$OMP PARALLEL"; break; @@ -2751,6 +2769,8 @@ gfc_ascii_statement (gfc_statement st) gfc_internal_error ("gfc_ascii_statement(): Bad statement code"); } + if (strip_sentinel && p[0] == '!') + return p + strlen ("!$OMP "); return p; } @@ -5518,6 +5538,9 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only) switch (omp_st) { + case ST_OMP_ASSUME: + omp_end_st = ST_OMP_END_ASSUME; + break; case ST_OMP_PARALLEL: omp_end_st = ST_OMP_END_PARALLEL; break; @@ -5651,6 +5674,7 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only) parse_forall_block (); break; + case ST_OMP_ASSUME: case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_MASKED: case ST_OMP_PARALLEL_MASTER: @@ -5874,6 +5898,7 @@ parse_executable (gfc_statement st) parse_oacc_structured_block (st); break; + case ST_OMP_ASSUME: case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_MASKED: case ST_OMP_PARALLEL_MASTER: diff --git a/gcc/fortran/parse.h b/gcc/fortran/parse.h index 7ddea10..013aeae 100644 --- a/gcc/fortran/parse.h +++ b/gcc/fortran/parse.h @@ -66,7 +66,7 @@ extern gfc_state_data *gfc_state_stack; int gfc_check_do_variable (gfc_symtree *); bool gfc_find_state (gfc_compile_state); gfc_state_data *gfc_enclosing_unit (gfc_compile_state *); -const char *gfc_ascii_statement (gfc_statement); +const char *gfc_ascii_statement (gfc_statement, bool strip_sentinel = false) ; match gfc_match_enum (void); match gfc_match_enumerator_def (void); void gfc_free_enum_history (void); diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc index ae7ebb6..d133bc2 100644 --- a/gcc/fortran/resolve.cc +++ b/gcc/fortran/resolve.cc @@ -10902,6 +10902,7 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns) case EXEC_OACC_ENTER_DATA: case EXEC_OACC_EXIT_DATA: case EXEC_OACC_ROUTINE: + case EXEC_OMP_ASSUME: case EXEC_OMP_CRITICAL: case EXEC_OMP_DISTRIBUTE: case EXEC_OMP_DISTRIBUTE_PARALLEL_DO: @@ -12376,6 +12377,7 @@ start: gfc_resolve_oacc_directive (code, ns); break; + case EXEC_OMP_ASSUME: case EXEC_OMP_ATOMIC: case EXEC_OMP_BARRIER: case EXEC_OMP_CANCEL: @@ -17651,6 +17653,9 @@ gfc_resolve (gfc_namespace *ns) component_assignment_level = 0; resolve_codes (ns); + if (ns->omp_assumes) + gfc_resolve_omp_assumptions (ns->omp_assumes); + gfc_current_ns = old_ns; cs_base = old_cs_base; ns->resolved = 1; diff --git a/gcc/fortran/st.cc b/gcc/fortran/st.cc index 73f30c2..3c8ca66 100644 --- a/gcc/fortran/st.cc +++ b/gcc/fortran/st.cc @@ -214,6 +214,7 @@ gfc_free_statement (gfc_code *p) case EXEC_OACC_ENTER_DATA: case EXEC_OACC_EXIT_DATA: case EXEC_OACC_ROUTINE: + case EXEC_OMP_ASSUME: case EXEC_OMP_ATOMIC: case EXEC_OMP_CANCEL: case EXEC_OMP_CANCELLATION_POINT: diff --git a/gcc/fortran/symbol.cc b/gcc/fortran/symbol.cc index 7a80dfd0..6050359 100644 --- a/gcc/fortran/symbol.cc +++ b/gcc/fortran/symbol.cc @@ -4071,7 +4071,13 @@ gfc_free_namespace (gfc_namespace *&ns) f = f->next; free (current); } - + if (ns->omp_assumes) + { + free (ns->omp_assumes->absent); + free (ns->omp_assumes->contains); + gfc_free_expr_list (ns->omp_assumes->holds); + free (ns->omp_assumes); + } p = ns->contained; free (ns); ns = NULL; diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc index 8e9d534..2105369 100644 --- a/gcc/fortran/trans-openmp.cc +++ b/gcc/fortran/trans-openmp.cc @@ -7487,6 +7487,8 @@ gfc_trans_omp_directive (gfc_code *code) { switch (code->op) { + case EXEC_OMP_ASSUME: + return gfc_trans_omp_code (code->block->next, true); case EXEC_OMP_ATOMIC: return gfc_trans_omp_atomic (code); case EXEC_OMP_BARRIER: diff --git a/gcc/fortran/trans.cc b/gcc/fortran/trans.cc index 912a206..8a64882 100644 --- a/gcc/fortran/trans.cc +++ b/gcc/fortran/trans.cc @@ -2174,6 +2174,7 @@ trans_code (gfc_code * code, tree cond) res = gfc_trans_dt_end (code); break; + case EXEC_OMP_ASSUME: case EXEC_OMP_ATOMIC: case EXEC_OMP_BARRIER: case EXEC_OMP_CANCEL: diff --git a/gcc/testsuite/gfortran.dg/gomp/assume-1.f90 b/gcc/testsuite/gfortran.dg/gomp/assume-1.f90 new file mode 100644 index 0000000..8bd5c72 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/assume-1.f90 @@ -0,0 +1,24 @@ +subroutine foo (i, a) + implicit none + integer, value :: i + integer :: a(:) + integer :: j + + j = 7 + !$omp assume no_openmp, absent (target, teams) holds (i < 32) holds (i < 32_2) + !$omp end assume + + !$omp assume no_openmp_routines, contains (simd) + block + !$omp simd + do j = 1, i + a(i) = j + end do + end block + + !$omp assume no_parallelism, contains (error) + if (i >= 32) then + !$omp error at (execution) message ("Should not happen") + end if + !$omp end assume +end diff --git a/gcc/testsuite/gfortran.dg/gomp/assume-2.f90 b/gcc/testsuite/gfortran.dg/gomp/assume-2.f90 new file mode 100644 index 0000000..ca3e04d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/assume-2.f90 @@ -0,0 +1,27 @@ +subroutine foo (i, a) + implicit none + integer, value :: i + integer :: a(:) + integer :: j + + j = 7 + !$omp assume no_openmp, absent (target, teams,target) holds (i < 32) holds (i < 32_2) ! { dg-error "'TARGET' directive mentioned multiple times in ABSENT clause in !.OMP ASSUME directive" } +! !$omp end assume - silence: 'Unexpected !$OMP END ASSUME statement' + + !$omp assume no_openmp_routines, contains (simd) contains ( simd ) ! { dg-error "'SIMD' directive mentioned multiple times in CONTAINS clause in !.OMP ASSUME directive" } + block + !$omp simd + do j = 1, i + a(i) = j + end do + end block + + !$omp assume no_parallelism, contains (error) absent (error) ! { dg-error "'ERROR' directive mentioned both times in ABSENT and CONTAINS clauses in !.OMP ASSUME directive" } + if (i >= 32) then + !$omp error at (execution) message ("Should not happen") + end if +! !$omp end assume - silence: 'Unexpected !$OMP END ASSUME statement' + + !$omp assume holds (1.0) ! { dg-error "HOLDS expression at .1. must be a logical expression" } + !$omp end assume +end diff --git a/gcc/testsuite/gfortran.dg/gomp/assumes-1.f90 b/gcc/testsuite/gfortran.dg/gomp/assumes-1.f90 new file mode 100644 index 0000000..3d468dc --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/assumes-1.f90 @@ -0,0 +1,82 @@ +! All of the following (up to PROGRAM) are okay: +! +subroutine sub + interface + subroutine sub_iterface() + !$omp assumes no_openmp_routines absent(simd) ! OK inferface of an external subroutine/subprogram + end + end interface + !$omp assumes no_openmp_routines absent(simd) ! OK external subroutine/subprogram +contains + subroutine inner_sub + !$omp assumes no_parallelism absent(teams) ! OK internal subroutine/subprogram + end +end + +integer function func () + !$omp assumes no_openmp_routines absent(simd) ! OK external function/subprogram + interface + integer function func_iterface() + !$omp assumes no_openmp_routines absent(simd) ! OK inferface of an external function/subprogram + end + end interface + func = 0 +contains + integer function inner_func() + !$omp assumes no_parallelism absent(teams) ! OK internal function/subprogram + inner_sub2 = 0 + end +end + +module m + integer ::x + !$omp assumes contains(target) holds(x > 0.0) + + interface + subroutine mod_mod_sub_iterface() + !$omp assumes no_openmp_routines absent(simd) ! OK inferface of an external subroutine/subprogram + end + integer function mod_mod_func_iterface() + !$omp assumes no_openmp_routines absent(error) ! OK inferface of an external subroutine/subprogram + end + end interface + +contains + subroutine mod_sub + interface + subroutine mod_sub_iterface() + !$omp assumes no_openmp_routines absent(simd) ! OK inferface of an external subroutine/subprogram + end + end interface + !$omp assumes no_openmp_routines absent(simd) ! OK module subroutine/subprogram + contains + subroutine mod_inner_sub + !$omp assumes no_parallelism absent(teams) ! OK internal subroutine/subprogram + end + end + + integer function mod_func () + !$omp assumes no_openmp_routines absent(simd) ! OK module function/subprogram + interface + integer function mod_func_iterface() + !$omp assumes no_openmp_routines absent(simd) ! OK inferface of an external function/subprogram + end + end interface + mod_func = 0 + contains + integer function mod_inner_func() + !$omp assumes no_parallelism absent(teams) ! OK internal function/subprogram + mod_inner_sub2 = 0 + end + end +end module m + + +! PROGRAM - invalid as: +! main program is a program unit that is not a subprogram +!$omp assumes no_openmp absent(simd) ! { dg-error "must be in the specification part of a subprogram or module" } + block + ! invalid: block + !$omp assumes no_openmp absent(target) ! { dg-error "must be in the specification part of a subprogram or module" } + end block +end diff --git a/gcc/testsuite/gfortran.dg/gomp/assumes-2.f90 b/gcc/testsuite/gfortran.dg/gomp/assumes-2.f90 new file mode 100644 index 0000000..729c973 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/assumes-2.f90 @@ -0,0 +1,19 @@ +module m + integer ::x +! Nonsense but OpenMP-semantically valid: + !$omp assumes contains(target) holds(x > 0.0) + !$omp assumes absent(target) + !$omp assumes holds(0.0) +! { dg-error "HOLDS expression at .1. must be a logical expression" "" { target *-*-* } .-1 } +end module + +module m2 +interface + subroutine foo + !$omp assumes contains(target) contains(teams,target) ! { dg-error "'TARGET' directive mentioned multiple times in CONTAINS clause in !.OMP ASSUMES directive" } + !$omp assumes absent(declare target) ! { dg-error "Invalid 'DECLARE TARGET' directive at .1. in ABSENT clause: declarative, informational and meta directives not permitted" } + !$omp assumes absent(parallel) absent(do,simd,parallel,distribute) ! { dg-error "'PARALLEL' directive mentioned multiple times in ABSENT clause in !.OMP ASSUMES directive" } + !$omp assumes contains(barrier,atomic) absent(cancel,simd,atomic,distribute) ! { dg-error "'SIMD' directive mentioned both times in ABSENT and CONTAINS clauses in !.OMP ASSUMES directive" } + end subroutine foo +end interface +end module m2 -- cgit v1.1 From 6832c95c0e1a58ba4d342ec002000f9d9d7db5ca Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 5 Oct 2022 13:52:59 -0400 Subject: analyzer: fix ICEs seen with call summaries on PR 107060 This doesn't fix the various false positives seen with -fanalyzer-call-summaries on PR 107060, but stops it crashing at -O2. gcc/analyzer/ChangeLog: PR analyzer/107060 * call-summary.cc (call_summary_replay::convert_svalue_from_summary_1): Handle NULL results from convert_svalue_from_summary in SK_UNARY_OP and SK_BIN_OP. * engine.cc (impl_region_model_context::on_unknown_change): Bail out on svalues that can't have associated state. * region-model-impl-calls.cc (region_model::impl_call_analyzer_get_unknown_ptr): New. * region-model.cc (region_model::on_stmt_pre): Handle "__analyzer_get_unknown_ptr". * region-model.h (region_model::impl_call_analyzer_get_unknown_ptr): New decl. * store.cc (store::replay_call_summary_cluster): Avoid trying to create binding clusters for base regions that shouldn't have them. gcc/ChangeLog: PR analyzer/107060 * doc/analyzer.texi (__analyzer_get_unknown_ptr): Document. gcc/testsuite/ChangeLog: PR analyzer/107060 * gcc.dg/analyzer/analyzer-decls.h (__analyzer_get_unknown_ptr): New decl. * gcc.dg/analyzer/call-summaries-2.c (test_summarized_writes_param_to_ptr_unknown): New test. Signed-off-by: David Malcolm --- gcc/analyzer/call-summary.cc | 28 ++++++++++++++++-------- gcc/analyzer/engine.cc | 2 ++ gcc/analyzer/region-model-impl-calls.cc | 10 +++++++++ gcc/analyzer/region-model.cc | 6 +++++ gcc/analyzer/region-model.h | 1 + gcc/analyzer/store.cc | 16 +++++++++----- gcc/doc/analyzer.texi | 4 ++++ gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h | 3 +++ gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c | 7 ++++++ 9 files changed, 62 insertions(+), 15 deletions(-) (limited to 'gcc') diff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc index a8e8814..3391654 100644 --- a/gcc/analyzer/call-summary.cc +++ b/gcc/analyzer/call-summary.cc @@ -298,23 +298,33 @@ call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval) { const unaryop_svalue *unaryop_summary_sval = as_a (summary_sval); + const svalue *summary_arg = unaryop_summary_sval->get_arg (); + const svalue *caller_arg = convert_svalue_from_summary (summary_arg); + if (!caller_arg) + return NULL; region_model_manager *mgr = get_manager (); - return mgr->get_or_create_unaryop - (summary_sval->get_type (), - unaryop_summary_sval->get_op (), - convert_svalue_from_summary (unaryop_summary_sval->get_arg ())); + return mgr->get_or_create_unaryop (summary_sval->get_type (), + unaryop_summary_sval->get_op (), + caller_arg); } break; case SK_BINOP: { const binop_svalue *binop_summary_sval = as_a (summary_sval); + const svalue *summary_arg0 = binop_summary_sval->get_arg0 (); + const svalue *caller_arg0 = convert_svalue_from_summary (summary_arg0); + if (!caller_arg0) + return NULL; + const svalue *summary_arg1 = binop_summary_sval->get_arg1 (); + const svalue *caller_arg1 = convert_svalue_from_summary (summary_arg1); + if (!caller_arg1) + return NULL; region_model_manager *mgr = get_manager (); - return mgr->get_or_create_binop - (summary_sval->get_type (), - binop_summary_sval->get_op (), - convert_svalue_from_summary (binop_summary_sval->get_arg0 ()), - convert_svalue_from_summary (binop_summary_sval->get_arg1 ())); + return mgr->get_or_create_binop (summary_sval->get_type (), + binop_summary_sval->get_op (), + caller_arg0, + caller_arg1); } break; case SK_SUB: diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 735b5a3..faef0bd 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -172,6 +172,8 @@ void impl_region_model_context::on_unknown_change (const svalue *sval, bool is_mutable) { + if (!sval->can_have_associated_state_p ()) + return; for (sm_state_map *smap : m_new_state->m_checker_states) smap->on_unknown_change (sval, is_mutable, m_ext_state); } diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc index 71fb277..5cc5907 100644 --- a/gcc/analyzer/region-model-impl-calls.cc +++ b/gcc/analyzer/region-model-impl-calls.cc @@ -374,6 +374,16 @@ region_model::impl_call_analyzer_eval (const gcall *call, warning_at (call->location, 0, "%s", t.as_string ()); } +/* Handle the on_call_pre part of "__analyzer_get_unknown_ptr". */ + +void +region_model::impl_call_analyzer_get_unknown_ptr (const call_details &cd) +{ + const svalue *ptr_sval + = m_mgr->get_or_create_unknown_svalue (cd.get_lhs_type ()); + cd.maybe_set_lhs (ptr_sval); +} + /* Handle the on_call_pre part of "__builtin_expect" etc. */ void diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index d14f3a1..aa3d205 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -1256,6 +1256,12 @@ region_model::on_stmt_pre (const gimple *stmt, { /* This is handled elsewhere. */ } + else if (is_special_named_call_p (call, "__analyzer_get_unknown_ptr", + 0)) + { + call_details cd (call, this, ctxt); + impl_call_analyzer_get_unknown_ptr (cd); + } else *out_unknown_side_effects = on_call_pre (call, ctxt, out_terminate_path); diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 6903090..e81595e 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -344,6 +344,7 @@ class region_model void impl_call_analyzer_dump_escaped (const gcall *call); void impl_call_analyzer_eval (const gcall *call, region_model_context *ctxt); + void impl_call_analyzer_get_unknown_ptr (const call_details &cd); void impl_call_builtin_expect (const call_details &cd); void impl_call_calloc (const call_details &cd); bool impl_call_error (const call_details &cd, unsigned min_args, diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index 74b481d..1ca1214 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -3176,12 +3176,16 @@ store::replay_call_summary_cluster (call_summary_replay &r, = r.convert_region_from_summary (summary_base_reg)) { const region *caller_base_reg = caller_reg->get_base_region (); - binding_cluster *caller_cluster - = get_or_create_cluster (caller_base_reg); - if (summary_cluster->escaped_p ()) - caller_cluster->mark_as_escaped (); - if (summary_cluster->touched_p ()) - caller_cluster->m_touched = true; + if (caller_base_reg->tracked_p () + && !caller_base_reg->symbolic_for_unknown_ptr_p ()) + { + binding_cluster *caller_cluster + = get_or_create_cluster (caller_base_reg); + if (summary_cluster->escaped_p ()) + caller_cluster->mark_as_escaped (); + if (summary_cluster->touched_p ()) + caller_cluster->m_touched = true; + } } switch (summary_base_reg->get_kind ()) diff --git a/gcc/doc/analyzer.texi b/gcc/doc/analyzer.texi index 06eb98f..ec49f95 100644 --- a/gcc/doc/analyzer.texi +++ b/gcc/doc/analyzer.texi @@ -544,6 +544,10 @@ __analyzer_eval (expr); will emit a warning with text "TRUE", FALSE" or "UNKNOWN" based on the truthfulness of the argument. This is useful for writing DejaGnu tests. +@smallexample +__analyzer_get_unknown_ptr (); +@end smallexample +will obtain an unknown @code{void *}. @subsection Other Debugging Techniques diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h b/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h index d052579..4478d74 100644 --- a/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h +++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h @@ -47,4 +47,7 @@ extern void __analyzer_dump_state (const char *name, ...); truthfulness of the argument. */ extern void __analyzer_eval (int); +/* Obtain an "unknown" void *. */ +extern void *__analyzer_get_unknown_ptr (void); + #endif /* #ifndef ANALYZER_DECLS_H. */ diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c index 0aaf67b..85cece7 100644 --- a/gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c @@ -72,6 +72,13 @@ void test_summarized_writes_param_to_ptr (int j) __analyzer_eval (y == j); /* { dg-warning "TRUE" } */ } +void test_summarized_writes_param_to_ptr_unknown (int j) +{ + int *p = (int *)__analyzer_get_unknown_ptr (); + writes_param_to_ptr (j, p); + __analyzer_eval (*p == j); /* { dg-warning "UNKNOWN" } */ +} + int g; void writes_to_global (int i) -- cgit v1.1 From 2eff4fe383a59de94267352e25f77b29d8e6bb42 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 5 Oct 2022 13:52:59 -0400 Subject: analyzer: simplify some includes gcc/analyzer/ChangeLog: * analysis-plan.cc: Simplify includes. * analyzer-pass.cc: Likewise. * analyzer-selftests.cc: Likewise. * analyzer.cc: Likewise. * analyzer.h: Add includes of "json.h" and "tristate.h". * call-info.cc: Simplify includes. * call-string.cc: Likewise. * call-summary.cc: Likewise. * checker-path.cc: Likewise. * complexity.cc: Likewise. * constraint-manager.cc: Likewise. * diagnostic-manager.cc: Likewise. * engine.cc: Likewise. * feasible-graph.cc: Likewise. * known-function-manager.cc: Likewise. * pending-diagnostic.cc: Likewise. * program-point.cc: Likewise. * program-state.cc: Likewise. * region-model-asm.cc: Likewise. * region-model-impl-calls.cc: Likewise. * region-model-manager.cc: Likewise. * region-model-reachability.cc: Likewise. * region-model.cc: Likewise. * region-model.h: Include "selftest.h". * region.cc: Simplify includes. * sm-fd.cc: Likewise. * sm-file.cc: Likewise. * sm-malloc.cc: Likewise. * sm-pattern-test.cc: Likewise. * sm-sensitive.cc: Likewise. * sm-signal.cc: Likewise. * sm-taint.cc: Likewise. * sm.cc: Likewise. * state-purge.cc: Likewise. * store.cc: Likewise. * store.h: Likewise. * supergraph.cc: Likewise. * svalue.cc: Likewise. * svalue.h: Likewise. * trimmed-graph.cc: Likewise. * varargs.cc: Likewise. Signed-off-by: David Malcolm --- gcc/analyzer/analysis-plan.cc | 2 -- gcc/analyzer/analyzer-pass.cc | 1 - gcc/analyzer/analyzer-selftests.cc | 1 - gcc/analyzer/analyzer.cc | 1 - gcc/analyzer/analyzer.h | 2 ++ gcc/analyzer/call-info.cc | 7 ------- gcc/analyzer/call-string.cc | 1 - gcc/analyzer/call-summary.cc | 1 - gcc/analyzer/checker-path.cc | 8 -------- gcc/analyzer/complexity.cc | 4 ---- gcc/analyzer/constraint-manager.cc | 3 --- gcc/analyzer/diagnostic-manager.cc | 7 ------- gcc/analyzer/engine.cc | 6 ------ gcc/analyzer/feasible-graph.cc | 7 ------- gcc/analyzer/known-function-manager.cc | 1 - gcc/analyzer/pending-diagnostic.cc | 8 -------- gcc/analyzer/program-point.cc | 4 ---- gcc/analyzer/program-state.cc | 6 ------ gcc/analyzer/region-model-asm.cc | 3 --- gcc/analyzer/region-model-impl-calls.cc | 7 ------- gcc/analyzer/region-model-manager.cc | 7 ------- gcc/analyzer/region-model-reachability.cc | 9 ++------- gcc/analyzer/region-model.cc | 4 ---- gcc/analyzer/region-model.h | 1 + gcc/analyzer/region.cc | 4 ---- gcc/analyzer/sm-fd.cc | 4 ---- gcc/analyzer/sm-file.cc | 3 --- gcc/analyzer/sm-malloc.cc | 4 ---- gcc/analyzer/sm-pattern-test.cc | 4 ---- gcc/analyzer/sm-sensitive.cc | 3 --- gcc/analyzer/sm-signal.cc | 6 ------ gcc/analyzer/sm-taint.cc | 4 ---- gcc/analyzer/sm.cc | 2 -- gcc/analyzer/state-purge.cc | 10 +--------- gcc/analyzer/store.cc | 5 ----- gcc/analyzer/store.h | 2 -- gcc/analyzer/supergraph.cc | 1 - gcc/analyzer/svalue.cc | 10 ++-------- gcc/analyzer/svalue.h | 1 - gcc/analyzer/trimmed-graph.cc | 13 ------------- gcc/analyzer/varargs.cc | 11 ----------- 41 files changed, 8 insertions(+), 180 deletions(-) (limited to 'gcc') diff --git a/gcc/analyzer/analysis-plan.cc b/gcc/analyzer/analysis-plan.cc index c488f37..a4a42c5 100644 --- a/gcc/analyzer/analysis-plan.cc +++ b/gcc/analyzer/analysis-plan.cc @@ -27,7 +27,6 @@ along with GCC; see the file COPYING3. If not see #include "timevar.h" #include "ipa-utils.h" #include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "diagnostic-core.h" #include "analyzer/analyzer-logging.h" @@ -35,7 +34,6 @@ along with GCC; see the file COPYING3. If not see #include "ordered-hash-map.h" #include "options.h" #include "cgraph.h" -#include "function.h" #include "cfg.h" #include "basic-block.h" #include "gimple.h" diff --git a/gcc/analyzer/analyzer-pass.cc b/gcc/analyzer/analyzer-pass.cc index f6cef58..fc7098d 100644 --- a/gcc/analyzer/analyzer-pass.cc +++ b/gcc/analyzer/analyzer-pass.cc @@ -26,7 +26,6 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic.h" #include "options.h" #include "tree.h" -#include "function.h" #include "analyzer/analyzer.h" #include "analyzer/engine.h" diff --git a/gcc/analyzer/analyzer-selftests.cc b/gcc/analyzer/analyzer-selftests.cc index 3765e70..278c245 100644 --- a/gcc/analyzer/analyzer-selftests.cc +++ b/gcc/analyzer/analyzer-selftests.cc @@ -23,7 +23,6 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "tree.h" #include "stringpool.h" -#include "function.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-selftests.h" diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc index c85dbf3..8a2a773 100644 --- a/gcc/analyzer/analyzer.cc +++ b/gcc/analyzer/analyzer.cc @@ -27,7 +27,6 @@ along with GCC; see the file COPYING3. If not see #include "gimple.h" #include "diagnostic.h" #include "intl.h" -#include "function.h" #include "analyzer/analyzer.h" #if ENABLE_ANALYZER diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h index 49c19af..a2d79e4 100644 --- a/gcc/analyzer/analyzer.h +++ b/gcc/analyzer/analyzer.h @@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see #define GCC_ANALYZER_ANALYZER_H #include "function.h" +#include "json.h" +#include "tristate.h" class graphviz_out; diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc index d9a261f..56059ac 100644 --- a/gcc/analyzer/call-info.cc +++ b/gcc/analyzer/call-info.cc @@ -30,11 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "options.h" #include "cgraph.h" #include "tree-pretty-print.h" -#include "tristate.h" #include "bitmap.h" -#include "selftest.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" @@ -56,9 +52,6 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-path.h" #include "analyzer/checker-path.h" #include "analyzer/diagnostic-manager.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" -#include "shortest-paths.h" #include "analyzer/exploded-graph.h" #include "analyzer/call-info.h" diff --git a/gcc/analyzer/call-string.cc b/gcc/analyzer/call-string.cc index a09f569..f0a30d9 100644 --- a/gcc/analyzer/call-string.cc +++ b/gcc/analyzer/call-string.cc @@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see #include "pretty-print.h" #include "tree.h" #include "options.h" -#include "json.h" #include "ordered-hash-map.h" #include "options.h" #include "cgraph.h" diff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc index 3391654..bc50562 100644 --- a/gcc/analyzer/call-summary.cc +++ b/gcc/analyzer/call-summary.cc @@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see #include "tree-dfa.h" #include "diagnostic.h" #include "tree-diagnostic.h" -#include "selftest.h" #include "analyzer/analyzer.h" #include "analyzer/region-model.h" #include "analyzer/call-summary.h" diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc index 22bae2f..371111b 100644 --- a/gcc/analyzer/checker-path.cc +++ b/gcc/analyzer/checker-path.cc @@ -28,26 +28,18 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" #include "gimple-pretty-print.h" #include "fold-const.h" -#include "function.h" #include "diagnostic-path.h" #include "options.h" #include "cgraph.h" -#include "function.h" #include "cfg.h" #include "digraph.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" #include "diagnostic-event-id.h" -#include "shortest-paths.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "sbitmap.h" #include "bitmap.h" -#include "tristate.h" #include "ordered-hash-map.h" -#include "selftest.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" diff --git a/gcc/analyzer/complexity.cc b/gcc/analyzer/complexity.cc index 40ae8f7..39fbbc1 100644 --- a/gcc/analyzer/complexity.cc +++ b/gcc/analyzer/complexity.cc @@ -38,11 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "fold-const.h" #include "tree-pretty-print.h" -#include "tristate.h" #include "bitmap.h" -#include "selftest.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "options.h" diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc index 6685e2e..96ae073 100644 --- a/gcc/analyzer/constraint-manager.cc +++ b/gcc/analyzer/constraint-manager.cc @@ -30,8 +30,6 @@ along with GCC; see the file COPYING3. If not see #include "selftest.h" #include "diagnostic-core.h" #include "graphviz.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "ordered-hash-map.h" #include "options.h" @@ -41,7 +39,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/supergraph.h" #include "sbitmap.h" #include "bitmap.h" -#include "tristate.h" #include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index 2d185a1..695bde5 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -29,15 +29,8 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" #include "diagnostic-event-id.h" #include "diagnostic-path.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" -#include "shortest-paths.h" -#include "sbitmap.h" #include "bitmap.h" -#include "tristate.h" -#include "selftest.h" #include "ordered-hash-map.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index faef0bd..46bcaed 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -25,9 +25,6 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "fold-const.h" #include "gcc-rich-location.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" -#include "shortest-paths.h" #include "diagnostic-core.h" #include "diagnostic-event-id.h" #include "diagnostic-path.h" @@ -35,10 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "pretty-print.h" #include "sbitmap.h" #include "bitmap.h" -#include "tristate.h" #include "ordered-hash-map.h" -#include "selftest.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "analyzer/call-string.h" diff --git a/gcc/analyzer/feasible-graph.cc b/gcc/analyzer/feasible-graph.cc index fe7e79f..a946e4c 100644 --- a/gcc/analyzer/feasible-graph.cc +++ b/gcc/analyzer/feasible-graph.cc @@ -29,15 +29,8 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" #include "diagnostic-event-id.h" #include "diagnostic-path.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" -#include "shortest-paths.h" -#include "sbitmap.h" #include "bitmap.h" -#include "tristate.h" -#include "selftest.h" #include "ordered-hash-map.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" diff --git a/gcc/analyzer/known-function-manager.cc b/gcc/analyzer/known-function-manager.cc index f0fd4fc..48fb005 100644 --- a/gcc/analyzer/known-function-manager.cc +++ b/gcc/analyzer/known-function-manager.cc @@ -22,7 +22,6 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tree.h" -#include "function.h" #include "analyzer/analyzer.h" #include "diagnostic-core.h" #include "analyzer/analyzer-logging.h" diff --git a/gcc/analyzer/pending-diagnostic.cc b/gcc/analyzer/pending-diagnostic.cc index eff050f..50a8afc 100644 --- a/gcc/analyzer/pending-diagnostic.cc +++ b/gcc/analyzer/pending-diagnostic.cc @@ -24,8 +24,6 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "intl.h" #include "diagnostic.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "diagnostic-event-id.h" #include "analyzer/analyzer-logging.h" @@ -34,8 +32,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" -#include "selftest.h" -#include "tristate.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" @@ -50,10 +46,6 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "analyzer/supergraph.h" #include "analyzer/program-state.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" -#include "shortest-paths.h" -#include "sbitmap.h" #include "analyzer/exploded-graph.h" #include "diagnostic-path.h" #include "analyzer/checker-path.h" diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc index 6c296d5..cfa4dda 100644 --- a/gcc/analyzer/program-point.cc +++ b/gcc/analyzer/program-point.cc @@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "gimple-pretty-print.h" #include "gcc-rich-location.h" -#include "json.h" #include "ordered-hash-map.h" #include "options.h" #include "cgraph.h" @@ -41,14 +40,11 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/program-point.h" #include "sbitmap.h" #include "bitmap.h" -#include "tristate.h" #include "selftest.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/sm.h" #include "analyzer/program-state.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" #include "diagnostic-event-id.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index b54bdce..7537dc0 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -24,14 +24,11 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "diagnostic-core.h" #include "diagnostic.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "sbitmap.h" #include "bitmap.h" -#include "tristate.h" #include "ordered-hash-map.h" #include "selftest.h" #include "analyzer/call-string.h" @@ -40,9 +37,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/region-model.h" #include "analyzer/program-state.h" #include "analyzer/constraint-manager.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" -#include "shortest-paths.h" #include "diagnostic-event-id.h" #include "analyzer/pending-diagnostic.h" #include "analyzer/diagnostic-manager.h" diff --git a/gcc/analyzer/region-model-asm.cc b/gcc/analyzer/region-model-asm.cc index bb73e6e..b4c1f91 100644 --- a/gcc/analyzer/region-model-asm.cc +++ b/gcc/analyzer/region-model-asm.cc @@ -28,9 +28,6 @@ along with GCC; see the file COPYING3. If not see #include "gimple-iterator.h" #include "diagnostic-core.h" #include "pretty-print.h" -#include "tristate.h" -#include "selftest.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "options.h" diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc index 5cc5907..8f4940a 100644 --- a/gcc/analyzer/region-model-impl-calls.cc +++ b/gcc/analyzer/region-model-impl-calls.cc @@ -38,18 +38,11 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "diagnostic-color.h" #include "diagnostic-metadata.h" -#include "tristate.h" #include "bitmap.h" -#include "selftest.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" #include "options.h" -#include "cgraph.h" -#include "cfg.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "sbitmap.h" #include "analyzer/call-string.h" diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc index 9a2ee08..f5999e6 100644 --- a/gcc/analyzer/region-model-manager.cc +++ b/gcc/analyzer/region-model-manager.cc @@ -38,18 +38,11 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "fold-const.h" #include "tree-pretty-print.h" -#include "tristate.h" #include "bitmap.h" -#include "selftest.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" #include "options.h" -#include "cgraph.h" -#include "cfg.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "sbitmap.h" #include "analyzer/call-string.h" diff --git a/gcc/analyzer/region-model-reachability.cc b/gcc/analyzer/region-model-reachability.cc index 12d09c3..be1372c 100644 --- a/gcc/analyzer/region-model-reachability.cc +++ b/gcc/analyzer/region-model-reachability.cc @@ -36,23 +36,18 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "fold-const.h" #include "tree-pretty-print.h" -#include "tristate.h" #include "bitmap.h" -#include "selftest.h" -#include "function.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" #include "options.h" -#include "cgraph.h" -#include "cfg.h" -#include "digraph.h" -#include "json.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/region-model-reachability.h" +#include "diagnostic.h" +#include "tree-diagnostic.h" #if ENABLE_ANALYZER diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index aa3d205..c50f5c6 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -39,18 +39,14 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "diagnostic-color.h" #include "diagnostic-metadata.h" -#include "tristate.h" #include "bitmap.h" #include "selftest.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" #include "options.h" #include "cgraph.h" #include "cfg.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "sbitmap.h" #include "analyzer/call-string.h" diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index e81595e..635a0c2 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see (Zhongxing Xu, Ted Kremenek, and Jian Zhang) http://lcs.ios.ac.cn/~xuzb/canalyze/memmodel.pdf */ +#include "selftest.h" #include "analyzer/svalue.h" #include "analyzer/region.h" #include "analyzer/known-function-manager.h" diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc index 09646bf..da5a13e 100644 --- a/gcc/analyzer/region.cc +++ b/gcc/analyzer/region.cc @@ -40,11 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "diagnostic-color.h" #include "diagnostic-metadata.h" -#include "tristate.h" #include "bitmap.h" -#include "selftest.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc index 505d598..c4ad91c 100644 --- a/gcc/analyzer/sm-fd.cc +++ b/gcc/analyzer/sm-fd.cc @@ -28,8 +28,6 @@ along with GCC; see the file COPYING3. If not see #include "options.h" #include "diagnostic-path.h" #include "diagnostic-metadata.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "diagnostic-event-id.h" #include "analyzer/analyzer-logging.h" @@ -37,8 +35,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/pending-diagnostic.h" #include "analyzer/function-set.h" #include "analyzer/analyzer-selftests.h" -#include "tristate.h" -#include "selftest.h" #include "stringpool.h" #include "attribs.h" #include "analyzer/call-string.h" diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc index f6cb29c..13f2507 100644 --- a/gcc/analyzer/sm-file.cc +++ b/gcc/analyzer/sm-file.cc @@ -28,8 +28,6 @@ along with GCC; see the file COPYING3. If not see #include "options.h" #include "diagnostic-path.h" #include "diagnostic-metadata.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "diagnostic-event-id.h" #include "analyzer/analyzer-logging.h" @@ -37,7 +35,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/pending-diagnostic.h" #include "analyzer/function-set.h" #include "analyzer/analyzer-selftests.h" -#include "tristate.h" #include "selftest.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc index 73c549f..fef6e63 100644 --- a/gcc/analyzer/sm-malloc.cc +++ b/gcc/analyzer/sm-malloc.cc @@ -29,15 +29,11 @@ along with GCC; see the file COPYING3. If not see #include "bitmap.h" #include "diagnostic-path.h" #include "diagnostic-metadata.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "diagnostic-event-id.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" -#include "tristate.h" -#include "selftest.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" diff --git a/gcc/analyzer/sm-pattern-test.cc b/gcc/analyzer/sm-pattern-test.cc index 9b2ad68..3208132 100644 --- a/gcc/analyzer/sm-pattern-test.cc +++ b/gcc/analyzer/sm-pattern-test.cc @@ -30,15 +30,11 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "diagnostic-path.h" #include "diagnostic-metadata.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "diagnostic-event-id.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" -#include "tristate.h" -#include "selftest.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" diff --git a/gcc/analyzer/sm-sensitive.cc b/gcc/analyzer/sm-sensitive.cc index 83c1906..cb5f859 100644 --- a/gcc/analyzer/sm-sensitive.cc +++ b/gcc/analyzer/sm-sensitive.cc @@ -24,14 +24,11 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "tree.h" #include "function.h" -#include "function.h" #include "basic-block.h" #include "gimple.h" #include "options.h" #include "diagnostic-path.h" #include "diagnostic-metadata.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "diagnostic-event-id.h" #include "analyzer/analyzer-logging.h" diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc index b601f45..e3b08c3 100644 --- a/gcc/analyzer/sm-signal.cc +++ b/gcc/analyzer/sm-signal.cc @@ -31,15 +31,12 @@ along with GCC; see the file COPYING3. If not see #include "bitmap.h" #include "diagnostic-path.h" #include "diagnostic-metadata.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "diagnostic-event-id.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" #include "sbitmap.h" -#include "tristate.h" #include "ordered-hash-map.h" #include "selftest.h" #include "analyzer/call-string.h" @@ -48,13 +45,10 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/region-model.h" #include "analyzer/program-state.h" #include "analyzer/checker-path.h" -#include "digraph.h" #include "cfg.h" #include "gimple-iterator.h" #include "cgraph.h" #include "analyzer/supergraph.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" #include "analyzer/diagnostic-manager.h" #include "shortest-paths.h" #include "analyzer/exploded-graph.h" diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc index f5c0cc1..bc27533 100644 --- a/gcc/analyzer/sm-taint.cc +++ b/gcc/analyzer/sm-taint.cc @@ -30,13 +30,9 @@ along with GCC; see the file COPYING3. If not see #include "options.h" #include "diagnostic-path.h" #include "diagnostic-metadata.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "gimple-iterator.h" -#include "tristate.h" -#include "selftest.h" #include "ordered-hash-map.h" #include "cgraph.h" #include "cfg.h" diff --git a/gcc/analyzer/sm.cc b/gcc/analyzer/sm.cc index d17d5c7..1ab4c21 100644 --- a/gcc/analyzer/sm.cc +++ b/gcc/analyzer/sm.cc @@ -31,11 +31,9 @@ along with GCC; see the file COPYING3. If not see #include "pretty-print.h" #include "diagnostic.h" #include "tree-diagnostic.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" -#include "tristate.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc index 7a061a1..d3f516a 100644 --- a/gcc/analyzer/state-purge.cc +++ b/gcc/analyzer/state-purge.cc @@ -36,24 +36,16 @@ along with GCC; see the file COPYING3. If not see #include "ssa-iterators.h" #include "diagnostic-core.h" #include "gimple-pretty-print.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/call-string.h" -#include "digraph.h" -#include "ordered-hash-map.h" -#include "cfg.h" -#include "gimple-iterator.h" -#include "cgraph.h" #include "analyzer/supergraph.h" #include "analyzer/program-point.h" #include "analyzer/analyzer-logging.h" #include "analyzer/state-purge.h" -#include "tristate.h" -#include "selftest.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "gimple-walk.h" +#include "cgraph.h" #if ENABLE_ANALYZER diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index 1ca1214..d2279b5 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -38,18 +38,13 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "diagnostic-color.h" #include "diagnostic-metadata.h" -#include "tristate.h" #include "bitmap.h" #include "selftest.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" #include "options.h" -#include "cgraph.h" #include "cfg.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "sbitmap.h" #include "analyzer/call-string.h" diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h index 0b5cbd6..1087782 100644 --- a/gcc/analyzer/store.h +++ b/gcc/analyzer/store.h @@ -21,8 +21,6 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_STORE_H #define GCC_ANALYZER_STORE_H -#include "tristate.h" - /* Implementation of the region-based ternary model described in: "A Memory Model for Static Analysis of C Programs" (Zhongxing Xu, Ted Kremenek, and Jian Zhang) diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index a4a495a..0e9a325 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -44,7 +44,6 @@ along with GCC; see the file COPYING3. If not see #include "bitmap.h" #include "cfganal.h" #include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "ordered-hash-map.h" #include "options.h" diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc index d8d419a..9ec46d6 100644 --- a/gcc/analyzer/svalue.cc +++ b/gcc/analyzer/svalue.cc @@ -38,22 +38,16 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "fold-const.h" #include "tree-pretty-print.h" -#include "tristate.h" #include "bitmap.h" -#include "selftest.h" -#include "function.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" -#include "options.h" -#include "cgraph.h" -#include "cfg.h" -#include "digraph.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/svalue.h" #include "analyzer/region-model.h" +#include "diagnostic.h" +#include "tree-diagnostic.h" #if ENABLE_ANALYZER diff --git a/gcc/analyzer/svalue.h b/gcc/analyzer/svalue.h index 9d0f04d..382b083 100644 --- a/gcc/analyzer/svalue.h +++ b/gcc/analyzer/svalue.h @@ -21,7 +21,6 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_SVALUE_H #define GCC_ANALYZER_SVALUE_H -#include "json.h" #include "analyzer/complexity.h" #include "analyzer/store.h" #include "analyzer/program-point.h" diff --git a/gcc/analyzer/trimmed-graph.cc b/gcc/analyzer/trimmed-graph.cc index 6c85910..9fdb4a9 100644 --- a/gcc/analyzer/trimmed-graph.cc +++ b/gcc/analyzer/trimmed-graph.cc @@ -29,15 +29,8 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" #include "diagnostic-event-id.h" #include "diagnostic-path.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" -#include "shortest-paths.h" -#include "sbitmap.h" #include "bitmap.h" -#include "tristate.h" -#include "selftest.h" #include "ordered-hash-map.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" @@ -48,12 +41,6 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/constraint-manager.h" -#include "cfg.h" -#include "basic-block.h" -#include "gimple.h" -#include "gimple-iterator.h" -#include "cgraph.h" -#include "digraph.h" #include "analyzer/supergraph.h" #include "analyzer/program-state.h" #include "analyzer/exploded-graph.h" diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc index 9400086..b2e6cd5 100644 --- a/gcc/analyzer/varargs.cc +++ b/gcc/analyzer/varargs.cc @@ -26,28 +26,17 @@ along with GCC; see the file COPYING3. If not see #include "basic-block.h" #include "gimple.h" #include "diagnostic-path.h" -#include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" -#include "tristate.h" -#include "selftest.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region-model.h" #include "analyzer/program-state.h" #include "analyzer/checker-path.h" -#include "digraph.h" -#include "ordered-hash-map.h" -#include "cfg.h" -#include "gimple-iterator.h" #include "analyzer/supergraph.h" -#include "alloc-pool.h" -#include "fibonacci_heap.h" -#include "shortest-paths.h" -#include "sbitmap.h" #include "analyzer/diagnostic-manager.h" #include "analyzer/exploded-graph.h" #include "diagnostic-metadata.h" -- cgit v1.1 From ef878564140cbcf23f479da88e07e5a996cec6bb Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 5 Oct 2022 14:07:47 -0400 Subject: analyzer: add regression test for PR 107158 PR analyzer/107158 reports an ICE when using -fanalyzer -fanalyzer-call-summaries on a particular source file. It turns out I just fixed this ICE in r13-3094-g6832c95c0e1a58. This followup patch adds a somewhat reduced reproducer as a regression test. Unfortunately, although the ICE is fixed, there are two false positives from -Wanalyzer-malloc-leak on the test case, so I'm going to use PR analyzer/107158 for tracking those false positives. gcc/testsuite/ChangeLog: PR analyzer/107158 * gcc.dg/analyzer/call-summaries-pr107158.c: New test. Signed-off-by: David Malcolm --- .../gcc.dg/analyzer/call-summaries-pr107158.c | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158.c new file mode 100644 index 0000000..54f442f --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158.c @@ -0,0 +1,83 @@ +/* { dg-additional-options "-fanalyzer-call-summaries" } */ + +typedef __SIZE_TYPE__ size_t; +enum { _ISspace = ((5) < 8 ? ((1 << (5)) << 8) : ((1 << (5)) >> 8)) }; +extern const unsigned short int **__ctype_b_loc(void) + __attribute__((__nothrow__, __leaf__, __const__)); +extern void *malloc(size_t __size) + __attribute__((__nothrow__, __leaf__, __malloc__, __alloc_size__(1))); +extern char *strcpy(char *__restrict __dest, const char *__restrict __src) + __attribute__((__nothrow__, __leaf__, __nonnull__(1, 2))); +extern size_t strlen(const char *__s) + __attribute__((__nothrow__, __leaf__, __pure__, __nonnull__(1))); + +struct mydata { + struct mydata *link; + char *name; + char *type; +}; + +static struct mydata *all_data; +static int line_no; + +__attribute__((__noreturn__)) void failed(const char *message); + +static char *string_dup(const char *string) { + char *buf; + + if ((buf = malloc(strlen(string) + 1)) == ((void *)0)) + failed("malloc() failed"); + + return strcpy(buf, string); +} + +static void store_data(const char *name, const char *type) { + struct mydata *p, *q; + + if ((p = (struct mydata *)malloc(sizeof(struct mydata))) == ((void *)0)) + failed("malloc() failed"); + + p->link = ((void *)0); + p->name = string_dup(name); + p->type = string_dup(type); + + if ((q = all_data) == ((void *)0)) + all_data = p; + else { + while (q->link != ((void *)0)) + q = q->link; + q->link = p; + } +} + +static void parse_tbl(char *buffer) { + char *s = buffer; + char *t = s + strlen(s); + + do { + t--; + if (((*__ctype_b_loc())[(int)(((int)*t))] & (unsigned short int)_ISspace)) + *t = '\0'; + else + break; + } while (t > s); + while (((*__ctype_b_loc())[(int)(((int)*s))] & (unsigned short int)_ISspace)) + s++; + buffer = s; + + line_no++; + if (*buffer != ';' && *buffer != '\0') { + if (*buffer == '#') { + store_data(buffer, ""); /* { dg-bogus "leak" "PR analyzer/107158" { xfail *-*-* } } */ + } else { + + while (*s && !((*__ctype_b_loc())[(int)(((int)*s))] & + (unsigned short int)_ISspace)) + s++; + while ( + ((*__ctype_b_loc())[(int)(((int)*s))] & (unsigned short int)_ISspace)) + *s++ = '\0'; + store_data(buffer, s); /* { dg-bogus "leak" "PR analyzer/107158" { xfail *-*-* } } */ + } + } +} -- cgit v1.1 From c3d131531a23c71e09c032d6222d0b5ff0eb8162 Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Mon, 3 Oct 2022 22:43:48 +0000 Subject: rs6000: Remove "wD" from *vsx_extract__store We can use "n" instead of "wD" if we simply test the value of the integer constant directly. 2022-10-05 Segher Boessenkool * config/rs6000/vsx.md (*vsx_extract__store): Use "n" instead of "wD" constraint. --- gcc/config/rs6000/vsx.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md index e226a93..79a759b 100644 --- a/gcc/config/rs6000/vsx.md +++ b/gcc/config/rs6000/vsx.md @@ -3466,8 +3466,9 @@ [(set (match_operand: 0 "memory_operand" "=m,Z,wY") (vec_select: (match_operand:VSX_D 1 "register_operand" "d,v,v") - (parallel [(match_operand:QI 2 "vsx_scalar_64bit" "wD,wD,wD")])))] - "VECTOR_MEM_VSX_P (mode)" + (parallel [(match_operand:QI 2 "vsx_scalar_64bit" "n,n,n")])))] + "VECTOR_MEM_VSX_P (mode) + && INTVAL (operands[2]) == (BYTES_BIG_ENDIAN ? 0 : 1)" "@ stfd%U0%X0 %1,%0 stxsdx %x1,%y0 -- cgit v1.1 From ba3e5a3826be53ecbb7d6044c50878d44640c296 Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Tue, 4 Oct 2022 02:50:22 +0000 Subject: rs6000: Rework vsx_extract_ Extracting the left and right halfs of a vector are entirely different operations. Things are simpler if they are separate define_insns, and it is easy to get rid of the "wD" constraint use then. This also give the variant that is a no-op copy its own alternative, of length 0 (and this, cost 0, making it more likely RA will choose it. 2022-10-05 Segher Boessenkool * config/rs6000/vsx.md (vsx_extract_): Replace define_insn by a define_expand. Split the contents to... (*vsx_extract__0): ... this. Rewrite. (*vsx_extract__1): ... and this. Rewrite. --- gcc/config/rs6000/vsx.md | 80 ++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 43 deletions(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md index 79a759b..e0e34a7 100644 --- a/gcc/config/rs6000/vsx.md +++ b/gcc/config/rs6000/vsx.md @@ -3388,59 +3388,53 @@ ;; Optimize cases were we can do a simple or direct move. ;; Or see if we can avoid doing the move at all -(define_insn "vsx_extract_" - [(set (match_operand: 0 "gpc_reg_operand" "=wa, wa, wr, wr") +(define_expand "vsx_extract_" + [(set (match_operand: 0 "gpc_reg_operand") (vec_select: - (match_operand:VSX_D 1 "gpc_reg_operand" "wa, wa, wa, wa") + (match_operand:VSX_D 1 "gpc_reg_operand") (parallel - [(match_operand:QI 2 "const_0_to_1_operand" "wD, n, wD, n")])))] + [(match_operand:QI 2 "const_0_to_1_operand")])))] "VECTOR_MEM_VSX_P (mode)" -{ - int element = INTVAL (operands[2]); - int op0_regno = REGNO (operands[0]); - int op1_regno = REGNO (operands[1]); - int fldDM; - - gcc_assert (IN_RANGE (element, 0, 1)); - gcc_assert (VSX_REGNO_P (op1_regno)); - - if (element == VECTOR_ELEMENT_SCALAR_64BIT) - { - if (op0_regno == op1_regno) - return ASM_COMMENT_START " vec_extract to same register"; - - else if (INT_REGNO_P (op0_regno) && TARGET_DIRECT_MOVE - && TARGET_POWERPC64) - return "mfvsrd %0,%x1"; + "") - else if (FP_REGNO_P (op0_regno) && FP_REGNO_P (op1_regno)) - return "fmr %0,%1"; +(define_insn "*vsx_extract__0" + [(set (match_operand: 0 "gpc_reg_operand" "=wa,wa,wr") + (vec_select: + (match_operand:VSX_D 1 "gpc_reg_operand" "0,wa,wa") + (parallel + [(match_operand:QI 2 "const_0_to_1_operand" "n,n,n")])))] + "VECTOR_MEM_VSX_P (mode) + && INTVAL (operands[2]) == (BYTES_BIG_ENDIAN ? 0 : 1)" +{ + if (which_alternative == 0) + return ASM_COMMENT_START " vec_extract to same register"; - else if (VSX_REGNO_P (op0_regno)) - return "xxlor %x0,%x1,%x1"; + if (which_alternative == 2) + return "mfvsrd %0,%x1"; - else - gcc_unreachable (); - } + return "xxlor %x0,%x1,%x1"; +} + [(set_attr "type" "*,veclogical,mfvsr") + (set_attr "isa" "*,*,p8v") + (set_attr "length" "0,*,*")]) - else if (element == VECTOR_ELEMENT_MFVSRLD_64BIT && INT_REGNO_P (op0_regno) - && TARGET_P9_VECTOR && TARGET_POWERPC64 && TARGET_DIRECT_MOVE) +(define_insn "*vsx_extract__1" + [(set (match_operand: 0 "gpc_reg_operand" "=wa,wr") + (vec_select: + (match_operand:VSX_D 1 "gpc_reg_operand" "wa,wa") + (parallel + [(match_operand:QI 2 "const_0_to_1_operand" "n,n")])))] + "VECTOR_MEM_VSX_P (mode) + && INTVAL (operands[2]) == (BYTES_BIG_ENDIAN ? 1 : 0)" +{ + if (which_alternative == 1) return "mfvsrld %0,%x1"; - else if (VSX_REGNO_P (op0_regno)) - { - fldDM = element << 1; - if (!BYTES_BIG_ENDIAN) - fldDM = 3 - fldDM; - operands[3] = GEN_INT (fldDM); - return "xxpermdi %x0,%x1,%x1,%3"; - } - - else - gcc_unreachable (); + operands[3] = GEN_INT (BYTES_BIG_ENDIAN ? 2 : 3); + return "xxpermdi %x0,%x1,%x1,%3"; } - [(set_attr "type" "veclogical,mfvsr,mfvsr,vecperm") - (set_attr "isa" "*,*,p8v,p9v")]) + [(set_attr "type" "mfvsr,vecperm") + (set_attr "isa" "*,p9v")]) ;; Optimize extracting a single scalar element from memory. (define_insn_and_split "*vsx_extract___load" -- cgit v1.1 From e99dcbb54e07b798c3353124f38336f96a826d43 Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Tue, 4 Oct 2022 21:22:15 +0000 Subject: rs6000: Remove the wD constraint 2022-10-05 Segher Boessenkool * config/rs6000/constraints.md (wD): Delete. * doc/md.texi (Machine Constraints): Adjust. --- gcc/config/rs6000/constraints.md | 6 ------ gcc/doc/md.texi | 3 --- 2 files changed, 9 deletions(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/constraints.md b/gcc/config/rs6000/constraints.md index 5a44a92..54fef8d 100644 --- a/gcc/config/rs6000/constraints.md +++ b/gcc/config/rs6000/constraints.md @@ -107,12 +107,6 @@ (match_test "TARGET_P8_VECTOR") (match_operand 0 "s5bit_cint_operand"))) -(define_constraint "wD" - "@internal Int constant that is the element number of the 64-bit scalar - in a vector." - (and (match_code "const_int") - (match_test "TARGET_VSX && (ival == VECTOR_ELEMENT_SCALAR_64BIT)"))) - (define_constraint "wE" "@internal Vector constant that can be loaded with the XXSPLTIB instruction." (match_test "xxspltib_constant_nosplit (op, mode)")) diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index bb42ee1..d0a71ecb 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -3267,9 +3267,6 @@ Like @code{b}, if @option{-mpowerpc64} is used; otherwise, @code{NO_REGS}. @item wB Signed 5-bit constant integer that can be loaded into an Altivec register. -@item wD -Int constant that is the element number of the 64-bit scalar in a vector. - @item wE Vector constant that can be loaded with the XXSPLTIB instruction. -- cgit v1.1 From 966010b2eb4a4c52f139b63548533e7bbd74ec9c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 6 Oct 2022 00:17:24 +0000 Subject: Daily bump. --- gcc/ChangeLog | 85 +++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 179 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/cp/ChangeLog | 5 ++ gcc/fortran/ChangeLog | 40 +++++++++++ gcc/testsuite/ChangeLog | 88 ++++++++++++++++++++++++ 6 files changed, 398 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 06e188e..e40b049 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,88 @@ +2022-10-05 Segher Boessenkool + + * config/rs6000/constraints.md (wD): Delete. + * doc/md.texi (Machine Constraints): Adjust. + +2022-10-05 Segher Boessenkool + + * config/rs6000/vsx.md (vsx_extract_): Replace define_insn by a + define_expand. Split the contents to... + (*vsx_extract__0): ... this. Rewrite. + (*vsx_extract__1): ... and this. Rewrite. + +2022-10-05 Segher Boessenkool + + * config/rs6000/vsx.md (*vsx_extract__store): Use "n" instead of + "wD" constraint. + +2022-10-05 David Malcolm + + PR analyzer/107060 + * doc/analyzer.texi (__analyzer_get_unknown_ptr): Document. + +2022-10-05 Ju-Zhe Zhong + + * config.gcc: Add riscv_vector.h. + * config/riscv/riscv-builtins.cc: Add RVV builtin types support. + * config/riscv/riscv-c.cc (riscv_pragma_intrinsic): New function. + (riscv_register_pragmas): Ditto. + * config/riscv/riscv-protos.h (riscv_register_pragmas): Ditto. + (init_builtins): Move declaration from riscv-vector-builtins.h to riscv-protos.h. + (mangle_builtin_type): Ditto. + (verify_type_context): Ditto. + (handle_pragma_vector): New function. + * config/riscv/riscv-vector-builtins.cc (GTY): New variable. + (register_vector_type): New function. + (init_builtins): Add RVV builtin types support. + (handle_pragma_vector): New function. + * config/riscv/riscv-vector-builtins.h (GCC_RISCV_V_BUILTINS_H): Change + name according to file name. + (GCC_RISCV_VECTOR_BUILTINS_H): Ditto. + (init_builtins): Remove declaration in riscv-vector-builtins.h. + (mangle_builtin_type): Ditto. + (verify_type_context): Ditto. + * config/riscv/riscv.cc: Adjust for RVV builtin types support. + * config/riscv/riscv.h (REGISTER_TARGET_PRAGMAS): New macro. + * config/riscv/t-riscv: Remove redundant file including. + * config/riscv/riscv_vector.h: New file. + +2022-10-05 Aldy Hernandez + + * range-op.cc (operator_cast::fold_range): Handle truncating casts + for nonzero masks. + +2022-10-05 Martin Liska + + PR c/107156 + * attribs.h (lookup_attribute_by_prefix): Support the attribute + starting with underscore (_Noreturn). + +2022-10-05 Aldy Hernandez + + PR tree-optimization/107052 + * gimple-range-op.cc (cfn_popcount::fold_range): Take into account + nonzero bit mask. + +2022-10-05 Aldy Hernandez + + PR tree-optimization/107052 + * range-op.cc (operator_cast::fold_range): Set nonzero mask. + +2022-10-05 Eric Botcazou + + PR tree-optimization/106698 + * pointer-query.cc (handle_array_ref): Fix handling of low bound. + +2022-10-05 Vineet Gupta + + * config/riscv/riscv-c.cc (riscv_cpu_cpp_builtins): + Remove __riscv_cmodel_pic, that deprecated in last version. + +2022-10-05 David Malcolm + + PR analyzer/107072 + * Makefile.in (ANALYZER_OBJS): Add analyzer/call-summary.o. + 2022-10-04 Jakub Jelinek * attribs.h (remove_attribute): Declare overload with additional diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 7759c90..5ba2bc5 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20221005 +20221006 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 3af1a38..627d9d7 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,182 @@ +2022-10-05 David Malcolm + + * analysis-plan.cc: Simplify includes. + * analyzer-pass.cc: Likewise. + * analyzer-selftests.cc: Likewise. + * analyzer.cc: Likewise. + * analyzer.h: Add includes of "json.h" and "tristate.h". + * call-info.cc: Simplify includes. + * call-string.cc: Likewise. + * call-summary.cc: Likewise. + * checker-path.cc: Likewise. + * complexity.cc: Likewise. + * constraint-manager.cc: Likewise. + * diagnostic-manager.cc: Likewise. + * engine.cc: Likewise. + * feasible-graph.cc: Likewise. + * known-function-manager.cc: Likewise. + * pending-diagnostic.cc: Likewise. + * program-point.cc: Likewise. + * program-state.cc: Likewise. + * region-model-asm.cc: Likewise. + * region-model-impl-calls.cc: Likewise. + * region-model-manager.cc: Likewise. + * region-model-reachability.cc: Likewise. + * region-model.cc: Likewise. + * region-model.h: Include "selftest.h". + * region.cc: Simplify includes. + * sm-fd.cc: Likewise. + * sm-file.cc: Likewise. + * sm-malloc.cc: Likewise. + * sm-pattern-test.cc: Likewise. + * sm-sensitive.cc: Likewise. + * sm-signal.cc: Likewise. + * sm-taint.cc: Likewise. + * sm.cc: Likewise. + * state-purge.cc: Likewise. + * store.cc: Likewise. + * store.h: Likewise. + * supergraph.cc: Likewise. + * svalue.cc: Likewise. + * svalue.h: Likewise. + * trimmed-graph.cc: Likewise. + * varargs.cc: Likewise. + +2022-10-05 David Malcolm + + PR analyzer/107060 + * call-summary.cc + (call_summary_replay::convert_svalue_from_summary_1): Handle NULL + results from convert_svalue_from_summary in SK_UNARY_OP and + SK_BIN_OP. + * engine.cc (impl_region_model_context::on_unknown_change): Bail + out on svalues that can't have associated state. + * region-model-impl-calls.cc + (region_model::impl_call_analyzer_get_unknown_ptr): New. + * region-model.cc (region_model::on_stmt_pre): Handle + "__analyzer_get_unknown_ptr". + * region-model.h + (region_model::impl_call_analyzer_get_unknown_ptr): New decl. + * store.cc (store::replay_call_summary_cluster): Avoid trying to + create binding clusters for base regions that shouldn't have them. + +2022-10-05 Martin Liska + + * call-summary.cc (call_summary_replay::call_summary_replay): + Remove unused variable and arguments. + * call-summary.h: Likewise. + * engine.cc (exploded_node::on_stmt): Likewise. + (exploded_node::replay_call_summaries): Likewise. + (exploded_node::replay_call_summary): Likewise. + * exploded-graph.h (class exploded_node): Likewise. + +2022-10-05 David Malcolm + + PR analyzer/107072 + * analyzer-logging.h: Include "diagnostic-core.h". + * analyzer.h: Include "function.h". + (class call_summary): New forward decl. + (class call_summary_replay): New forward decl. + (struct per_function_data): New forward decl. + (struct interesting_t): New forward decl. + (custom_edge_info::update_state): New vfunc. + * call-info.cc (custom_edge_info::update_state): New. + * call-summary.cc: New file. + * call-summary.h: New file. + * constraint-manager.cc: Include "analyzer/call-summary.h". + (class replay_fact_visitor): New. + (constraint_manager::replay_call_summary): New. + * constraint-manager.h (constraint_manager::replay_call_summary): + New. + * engine.cc: Include "analyzer/call-summary.h". + (exploded_node::on_stmt): Handle call summaries. + (class call_summary_edge_info): New. + (exploded_node::replay_call_summaries): New. + (exploded_node::replay_call_summary): New. + (per_function_data::~per_function_data): New. + (per_function_data::add_call_summary): Move here from header and + reimplement. + (exploded_graph::process_node): Call update_state rather than + update_model when handling bifurcation + (viz_callgraph_node::dump_dot): Use a regular label rather + than an HTML table; add summaries to dump. + * exploded-graph.h: Include "alloc-pool.h", "fibonacci_heap.h", + "supergraph.h", "sbitmap.h", "shortest-paths.h", "analyzer/sm.h", + "analyzer/program-state.h", and "analyzer/diagnostic-manager.h". + (exploded_node::replay_call_summaries): New decl. + (exploded_node::replay_call_summary): New decl. + (per_function_data::~per_function_data): New decl. + (per_function_data::add_call_summary): Move implemention from + header. + (per_function_data::m_summaries): Update type of element. + * known-function-manager.h: Include "analyzer/analyzer-logging.h". + * program-point.h: Include "pretty-print.h" and + "analyzer/call-string.h". + * program-state.cc: Include "analyzer/call-summary.h". + (sm_state_map::replay_call_summary): New. + (program_state::replay_call_summary): New. + * program-state.h (sm_state_map::replay_call_summary): New decl. + (program_state::replay_call_summary): New decl. + * region-model-manager.cc + (region_model_manager::get_or_create_asm_output_svalue): New + overload. + * region-model-manager.h + (region_model_manager::get_or_create_asm_output_svalue): New + overload decl. + * region-model.cc: Include "analyzer/call-summary.h". + (region_model::maybe_update_for_edge): Remove call to + region_model::update_for_call_summary on + SUPEREDGE_INTRAPROCEDURAL_CALL. + (region_model::update_for_call_summary): Delete. + (region_model::replay_call_summary): New. + * region-model.h (region_model::replay_call_summary): New decl. + (region_model::update_for_call_summary): Delete decl. + * store.cc: Include "analyzer/call-summary.h". + (store::replay_call_summary): New. + (store::replay_call_summary_cluster): New. + * store.h: Include "tristate.h". + (is_a_helper ::test): New. + (store::replay_call_summary): New decl. + (store::replay_call_summary_cluster): New decl. + * supergraph.cc (get_ultimate_function_for_cgraph_edge): Remove + "static" from decl. + (supergraph_call_edge): Make stmt param const. + * supergraph.h: Include "ordered-hash-map.h", "cfg.h", + "basic-block.h", "gimple.h", "gimple-iterator.h", and "digraph.h". + (supergraph_call_edge): Make stmt param const. + (get_ultimate_function_for_cgraph_edge): New decl. + * svalue.cc (compound_svalue::compound_svalue): Assert that we're + not nesting compound_svalues. + * svalue.h: Include "json.h", "analyzer/store.h", and + "analyzer/program-point.h". + (asm_output_svalue::get_num_outputs): New accessor. + +2022-10-05 David Malcolm + + * region-model.h: Include "analyzer/region-model-manager.h" + (class region_model_manager): Move decl to... + * region-model-manager.h: ...this new file. + +2022-10-05 David Malcolm + + * region-model-manager.cc + (region_model_manager::maybe_fold_unaryop): Fold -(-(VAL)) to VAL. + +2022-10-05 David Malcolm + + * region-model-manager.cc + (region_model_manager::get_or_create_widening_svalue): Use a + function_point rather than a program_point. + * region-model.cc (selftest::test_widening_constraints): Likewise. + * region-model.h + (region_model_manager::get_or_create_widening_svalue): Likewise. + (model_merger::get_function_point): New. + * svalue.cc (svalue::can_merge_p): Use a function_point rather + than a program_point. + (svalue::can_merge_p): Likewise. + * svalue.h (widening_svalue::key_t): Likewise. + (widening_svalue::widening_svalue): Likewise. + 2022-09-12 Martin Liska * region-model.cc (region_model::maybe_complain_about_infoleak): diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3249d83..1fc0799 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2022-10-05 Jason Merrill + + * tree.cc (lvalue_kind) [VIEW_CONVERT_EXPR]: Change prvalue to + xvalue. + 2022-10-04 Jason Merrill PR c++/107154 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 6923030..f359f12 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,43 @@ +2022-10-05 Tobias Burnus + + * dump-parse-tree.cc (show_omp_assumes): New. + (show_omp_clauses, show_namespace): Call it. + (show_omp_node, show_code_node): Handle OpenMP ASSUME. + * gfortran.h (enum gfc_statement): Add ST_OMP_ASSUME, + ST_OMP_END_ASSUME, ST_OMP_ASSUMES and ST_NOTHING. + (gfc_exec_op): Add EXEC_OMP_ASSUME. + (gfc_omp_assumptions): New struct. + (gfc_get_omp_assumptions): New XCNEW #define. + (gfc_omp_clauses, gfc_namespace): Add assume member. + (gfc_resolve_omp_assumptions): New prototype. + * match.h (gfc_match_omp_assume, gfc_match_omp_assumes): New. + * openmp.cc (omp_code_to_statement): Forward declare. + (enum gfc_omp_directive_kind, struct gfc_omp_directive): New. + (gfc_free_omp_clauses): Free assume member and its struct data. + (enum omp_mask2): Add OMP_CLAUSE_ASSUMPTIONS. + (gfc_omp_absent_contains_clause): New. + (gfc_match_omp_clauses): Call it; optionally use passed + omp_clauses argument. + (omp_verify_merge_absent_contains, gfc_match_omp_assume, + gfc_match_omp_assumes, gfc_resolve_omp_assumptions): New. + (resolve_omp_clauses): Call the latter. + (gfc_resolve_omp_directive, omp_code_to_statement): Handle + EXEC_OMP_ASSUME. + * parse.cc (decode_omp_directive): Parse OpenMP ASSUME(S). + (next_statement, parse_executable, parse_omp_structured_block): + Handle ST_OMP_ASSUME. + (case_omp_decl): Add ST_OMP_ASSUMES. + (gfc_ascii_statement): Handle Assumes, optional return + string without '!$OMP '/'!$ACC ' prefix. + * parse.h (gfc_ascii_statement): Add optional bool arg to prototype. + * resolve.cc (gfc_resolve_blocks, gfc_resolve_code): Add + EXEC_OMP_ASSUME. + (gfc_resolve): Resolve ASSUMES directive. + * symbol.cc (gfc_free_namespace): Free omp_assumes member. + * st.cc (gfc_free_statement): Handle EXEC_OMP_ASSUME. + * trans-openmp.cc (gfc_trans_omp_directive): Likewise. + * trans.cc (trans_code): Likewise. + 2022-10-04 Tobias Burnus * parse.cc (decode_omp_directive): Handle '(end) loop' and 'scan' diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8a30bb4..584fba4c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,91 @@ +2022-10-05 David Malcolm + + PR analyzer/107158 + * gcc.dg/analyzer/call-summaries-pr107158.c: New test. + +2022-10-05 David Malcolm + + PR analyzer/107060 + * gcc.dg/analyzer/analyzer-decls.h (__analyzer_get_unknown_ptr): + New decl. + * gcc.dg/analyzer/call-summaries-2.c + (test_summarized_writes_param_to_ptr_unknown): New test. + +2022-10-05 Tobias Burnus + + * gfortran.dg/gomp/assume-1.f90: New test. + * gfortran.dg/gomp/assume-2.f90: New test. + * gfortran.dg/gomp/assumes-1.f90: New test. + * gfortran.dg/gomp/assumes-2.f90: New test. + +2022-10-05 Ju-Zhe Zhong + + * gcc.target/riscv/rvv/base/pragma-1.c: New test. + * gcc.target/riscv/rvv/base/pragma-2.c: New test. + * gcc.target/riscv/rvv/base/pragma-3.c: New test. + * gcc.target/riscv/rvv/base/user-1.c: New test. + * gcc.target/riscv/rvv/base/user-2.c: New test. + * gcc.target/riscv/rvv/base/user-3.c: New test. + * gcc.target/riscv/rvv/base/user-4.c: New test. + * gcc.target/riscv/rvv/base/user-5.c: New test. + * gcc.target/riscv/rvv/base/user-6.c: New test. + * gcc.target/riscv/rvv/base/vread_csr.c: New test. + * gcc.target/riscv/rvv/base/vwrite_csr.c: New test. + +2022-10-05 Aldy Hernandez + + PR tree-optimization/107052 + * gcc.dg/tree-ssa/pr107052.c: New file. + +2022-10-05 Eric Botcazou + + * gnat.dg/lto26.adb: New test. + * gnat.dg/lto26_pkg1.ads, gnat.dg/lto26_pkg1.adb: New helper. + * gnat.dg/lto26_pkg2.ads, gnat.dg/lto26_pkg2.adb: Likewise. + +2022-10-05 Martin Liska + + PR tree-optimization/106679 + * gcc.dg/tree-prof/cmpsf-1.c: Mark as a known limitation. + +2022-10-05 Torbjörn SVENSSON + Yvan ROUX + + * gcc.target/arm/stack-protector-1.c: Use 'bl' instead of 'b' + instruction. + * gcc.target/arm/stack-protector-3.c: Likewise. + +2022-10-05 Torbjörn SVENSSON + Yvan ROUX + + * g++.dg/modules/bad-mapper-1.C: Also accept CreateProcess. + +2022-10-05 Torbjörn SVENSSON + Yvan ROUX + + * gcc.misc-tests/outputs.exp: Use "@nul" for Windows, + "@/dev/null" for other environments. + +2022-10-05 Vineet Gupta + + * gcc.target/riscv/predef-1.c: Remove __riscv_cmodel_pic check. + * gcc.target/riscv/predef-2.c: Ditto. + * gcc.target/riscv/predef-3.c: Ditto. + * gcc.target/riscv/predef-4.c: Ditto. + * gcc.target/riscv/predef-5.c: Ditto. + * gcc.target/riscv/predef-6.c: Ditto. + * gcc.target/riscv/predef-7.c: Ditto. + * gcc.target/riscv/predef-8.c: Ditto. + +2022-10-05 David Malcolm + + PR analyzer/107072 + * gcc.dg/analyzer/call-summaries-2.c: New test. + * gcc.dg/analyzer/call-summaries-3.c: New test. + * gcc.dg/analyzer/call-summaries-asm-x86.c: New test. + * gcc.dg/analyzer/call-summaries-malloc.c: New test. + * gcc.dg/analyzer/call-summaries-pr107072.c: New test. + 2022-10-04 Jason Merrill PR c++/107154 -- cgit v1.1 From ab4909fd8f5f77685e6ec12768c56545347f30c4 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 5 Oct 2022 20:21:07 +0200 Subject: Do not double print INF and NAN in frange pretty printer. gcc/ChangeLog: * value-range-pretty-print.cc (vrange_printer::print_real_value): Avoid printing INF and NAN twice. --- gcc/value-range-pretty-print.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/value-range-pretty-print.cc b/gcc/value-range-pretty-print.cc index 8cbe97b..3a3b4b4 100644 --- a/gcc/value-range-pretty-print.cc +++ b/gcc/value-range-pretty-print.cc @@ -123,7 +123,11 @@ vrange_printer::print_real_value (tree type, const REAL_VALUE_TYPE &r) const char s[100]; real_to_decimal_for_mode (s, &r, sizeof (s), 0, 1, TYPE_MODE (type)); pp_string (pp, s); - if (!DECIMAL_FLOAT_TYPE_P (type)) + if (!DECIMAL_FLOAT_TYPE_P (type) + // real_to_hexadecimal prints infinities and NAN as text. No + // need to print them twice. + && !real_isinf (&r) + && !real_isnan (&r)) { real_to_hexadecimal (s, &r, sizeof (s), 0, 1); pp_printf (pp, " (%s)", s); -- cgit v1.1 From 9eab8e45dd106ee6b9ca9fa9ec46876b0bb7f482 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 5 Oct 2022 20:21:26 +0200 Subject: Do not check finite_operands_p twice in range-ops-float. The uses of finite_operands_p removed are guarded by a call to finite_operands_p already. gcc/ChangeLog: * range-op-float.cc (foperator_lt::fold_range): Remove extra check to finite_operands_p. (foperator_le::fold_range): Same. (foperator_gt::fold_range): Same. (foperator_ge::fold_range): Same. --- gcc/range-op-float.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 6e9d51d..68578aa 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -572,8 +572,7 @@ foperator_lt::fold_range (irange &r, tree type, { if (real_less (&op1.upper_bound (), &op2.lower_bound ())) r = range_true (type); - else if (finite_operands_p (op1, op2) - && !real_less (&op1.lower_bound (), &op2.upper_bound ())) + else if (!real_less (&op1.lower_bound (), &op2.upper_bound ())) r = range_false (type); else r = range_true_and_false (type); @@ -688,8 +687,7 @@ foperator_le::fold_range (irange &r, tree type, { if (real_compare (LE_EXPR, &op1.upper_bound (), &op2.lower_bound ())) r = range_true (type); - else if (finite_operands_p (op1, op2) - && !real_compare (LE_EXPR, &op1.lower_bound (), &op2.upper_bound ())) + else if (!real_compare (LE_EXPR, &op1.lower_bound (), &op2.upper_bound ())) r = range_false (type); else r = range_true_and_false (type); @@ -796,8 +794,7 @@ foperator_gt::fold_range (irange &r, tree type, { if (real_compare (GT_EXPR, &op1.lower_bound (), &op2.upper_bound ())) r = range_true (type); - else if (finite_operands_p (op1, op2) - && !real_compare (GT_EXPR, &op1.upper_bound (), &op2.lower_bound ())) + else if (!real_compare (GT_EXPR, &op1.upper_bound (), &op2.lower_bound ())) r = range_false (type); else r = range_true_and_false (type); @@ -912,8 +909,7 @@ foperator_ge::fold_range (irange &r, tree type, { if (real_compare (GE_EXPR, &op1.lower_bound (), &op2.upper_bound ())) r = range_true (type); - else if (finite_operands_p (op1, op2) - && !real_compare (GE_EXPR, &op1.upper_bound (), &op2.lower_bound ())) + else if (!real_compare (GE_EXPR, &op1.upper_bound (), &op2.lower_bound ())) r = range_false (type); else r = range_true_and_false (type); -- cgit v1.1 From e9d50e7a4e290d7476cc7e6b5a8f2f1fb496c570 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 5 Oct 2022 20:22:38 +0200 Subject: Setting explicit NANs sets UNDEFINED for -ffinite-math-only. We recently agreed that setting a range of NAN should instead set UNDEFINED for -ffinite-math-only. This patch makes that change to frange::set_nan() directly. Also, calling frange::update_nan() will now be a nop for !HONOR_NANS. Doing this in the setters simplifies everywhere we set NANs, as it keeps us from introducing NANs by mistake. gcc/ChangeLog: * value-range.cc (frange::set): Call set_nan unconditionally. (range_tests_nan): Adjust tests. (range_tests_signed_zeros): Same. (range_tests_floats): Same. * value-range.h (frange::update_nan): Guard with HONOR_NANS. (frange::set_nan): Set undefined if !HONOR_NANS. --- gcc/value-range.cc | 59 ++++++++++++++++++++++++++--------------------------- gcc/value-range.h | 60 ++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 67 insertions(+), 52 deletions(-) (limited to 'gcc') diff --git a/gcc/value-range.cc b/gcc/value-range.cc index a307559..87239fa 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -304,13 +304,8 @@ frange::set (tree type, if (real_isnan (&min) || real_isnan (&max)) { gcc_checking_assert (real_identical (&min, &max)); - if (HONOR_NANS (type)) - { - bool sign = real_isneg (&min); - set_nan (type, sign); - } - else - set_undefined (); + bool sign = real_isneg (&min); + set_nan (type, sign); return; } @@ -3624,6 +3619,7 @@ range_tests_nan () { frange r0, r1; REAL_VALUE_TYPE q, r; + bool signbit; // Equal ranges but with differing NAN bits are not equal. if (HONOR_NANS (float_type_node)) @@ -3735,6 +3731,26 @@ range_tests_nan () r0.set_nan (float_type_node); r0.clear_nan (); ASSERT_TRUE (r0.undefined_p ()); + + // [10,20] NAN ^ [21,25] NAN = [NAN] + r0 = frange_float ("10", "20"); + r0.update_nan (); + r1 = frange_float ("21", "25"); + r1.update_nan (); + r0.intersect (r1); + ASSERT_TRUE (r0.known_isnan ()); + + // NAN U [5,6] should be [5,6] +-NAN. + r0.set_nan (float_type_node); + r1 = frange_float ("5", "6"); + r1.clear_nan (); + r0.union_ (r1); + real_from_string (&q, "5"); + real_from_string (&r, "6"); + ASSERT_TRUE (real_identical (&q, &r0.lower_bound ())); + ASSERT_TRUE (real_identical (&r, &r0.upper_bound ())); + ASSERT_TRUE (!r0.signbit_p (signbit)); + ASSERT_TRUE (r0.maybe_isnan ()); } static void @@ -3742,7 +3758,6 @@ range_tests_signed_zeros () { tree zero = build_zero_cst (float_type_node); tree neg_zero = fold_build1 (NEGATE_EXPR, float_type_node, zero); - REAL_VALUE_TYPE q, r; frange r0, r1; bool signbit; @@ -3788,18 +3803,6 @@ range_tests_signed_zeros () r0.intersect (r1); ASSERT_TRUE (r0.zero_p ()); - // NAN U [5,6] should be [5,6] NAN. - r0.set_nan (float_type_node); - r1 = frange_float ("5", "6"); - r1.clear_nan (); - r0.union_ (r1); - real_from_string (&q, "5"); - real_from_string (&r, "6"); - ASSERT_TRUE (real_identical (&q, &r0.lower_bound ())); - ASSERT_TRUE (real_identical (&r, &r0.upper_bound ())); - ASSERT_TRUE (!r0.signbit_p (signbit)); - ASSERT_TRUE (r0.maybe_isnan ()); - r0 = frange_float ("+0", "5"); r0.clear_nan (); ASSERT_TRUE (r0.signbit_p (signbit) && !signbit); @@ -3823,7 +3826,10 @@ range_tests_signed_zeros () r1 = frange_float ("0", "0"); r1.update_nan (); r0.intersect (r1); - ASSERT_TRUE (r0.known_isnan ()); + if (HONOR_NANS (float_type_node)) + ASSERT_TRUE (r0.known_isnan ()); + else + ASSERT_TRUE (r0.undefined_p ()); r0.set_nonnegative (float_type_node); ASSERT_TRUE (r0.signbit_p (signbit) && !signbit); @@ -3863,7 +3869,8 @@ range_tests_floats () { frange r0, r1; - range_tests_nan (); + if (HONOR_NANS (float_type_node)) + range_tests_nan (); range_tests_signbit (); if (HONOR_SIGNED_ZEROS (float_type_node)) @@ -3936,14 +3943,6 @@ range_tests_floats () r0.intersect (r1); ASSERT_EQ (r0, frange_float ("15", "20")); - // [10,20] NAN ^ [21,25] NAN = [NAN] - r0 = frange_float ("10", "20"); - r0.update_nan (); - r1 = frange_float ("21", "25"); - r1.update_nan (); - r0.intersect (r1); - ASSERT_TRUE (r0.known_isnan ()); - // [10,20] ^ [21,25] = [] r0 = frange_float ("10", "20"); r0.clear_nan (); diff --git a/gcc/value-range.h b/gcc/value-range.h index d166362..b06ca74 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -1111,11 +1111,14 @@ inline void frange::update_nan () { gcc_checking_assert (!undefined_p ()); - m_pos_nan = true; - m_neg_nan = true; - normalize_kind (); - if (flag_checking) - verify_range (); + if (HONOR_NANS (m_type)) + { + m_pos_nan = true; + m_neg_nan = true; + normalize_kind (); + if (flag_checking) + verify_range (); + } } // Like above, but set the sign of the NAN. @@ -1124,11 +1127,14 @@ inline void frange::update_nan (bool sign) { gcc_checking_assert (!undefined_p ()); - m_pos_nan = !sign; - m_neg_nan = sign; - normalize_kind (); - if (flag_checking) - verify_range (); + if (HONOR_NANS (m_type)) + { + m_pos_nan = !sign; + m_neg_nan = sign; + normalize_kind (); + if (flag_checking) + verify_range (); + } } // Clear the NAN bit and adjust the range. @@ -1213,12 +1219,17 @@ frange_val_is_max (const REAL_VALUE_TYPE &r, const_tree type) inline void frange::set_nan (tree type) { - m_kind = VR_NAN; - m_type = type; - m_pos_nan = true; - m_neg_nan = true; - if (flag_checking) - verify_range (); + if (HONOR_NANS (type)) + { + m_kind = VR_NAN; + m_type = type; + m_pos_nan = true; + m_neg_nan = true; + if (flag_checking) + verify_range (); + } + else + set_undefined (); } // Build a NAN of type TYPE with SIGN. @@ -1226,12 +1237,17 @@ frange::set_nan (tree type) inline void frange::set_nan (tree type, bool sign) { - m_kind = VR_NAN; - m_type = type; - m_neg_nan = sign; - m_pos_nan = !sign; - if (flag_checking) - verify_range (); + if (HONOR_NANS (type)) + { + m_kind = VR_NAN; + m_type = type; + m_neg_nan = sign; + m_pos_nan = !sign; + if (flag_checking) + verify_range (); + } + else + set_undefined (); } // Return TRUE if range is known to be finite. -- cgit v1.1 From 5fc4d3e1837ea4850aac6460f563913f1d3fc5b8 Mon Sep 17 00:00:00 2001 From: Stefan Schulze Frielinghaus Date: Thu, 6 Oct 2022 08:43:53 +0200 Subject: cselib: Skip BImode while keeping track of subvalue relations [PR107088] For BImode get_narrowest_mode evaluates to QImode but BImode < QImode. Thus FOR_EACH_MODE_UNTIL never reaches BImode and iterates until OImode for which no wider mode exists so we end up with VOIDmode and fail. Fixed by adding a size guard so we effectively skip BImode. gcc/ChangeLog: PR rtl-optimization/107088 * cselib.cc (new_cselib_val): Skip BImode while keeping track of subvalue relations. --- gcc/cselib.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc') diff --git a/gcc/cselib.cc b/gcc/cselib.cc index 9b582e5..2abc763 100644 --- a/gcc/cselib.cc +++ b/gcc/cselib.cc @@ -1571,6 +1571,7 @@ new_cselib_val (unsigned int hash, machine_mode mode, rtx x) scalar_int_mode int_mode; if (REG_P (x) && is_int_mode (mode, &int_mode) + && GET_MODE_SIZE (int_mode) > 1 && REG_VALUES (REGNO (x)) != NULL && (!cselib_current_insn || !DEBUG_INSN_P (cselib_current_insn))) { -- cgit v1.1 From 08b51baddc53d64aa4c5e7a81ef3c4bf320293be Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 6 Oct 2022 08:56:48 +0200 Subject: c++, c: Implement C++23 P1774R8 - Portable assumptions [PR106654] The following patch implements C++23 P1774R8 - Portable assumptions paper, by introducing support for [[assume (cond)]]; attribute for C++. In addition to that the patch adds [[gnu::assume (cond)]]; and __attribute__((assume (cond))); support to both C and C++. As described in C++23, the attribute argument is conditional-expression rather than the usual assignment-expression for attribute arguments, the condition is contextually converted to bool (for C truthvalue conversion is done on it) and is never evaluated at runtime. For C++ constant expression evaluation, I only check the simplest conditions for undefined behavior, because otherwise I'd need to undo changes to *ctx->global which happened during the evaluation (but I believe the spec allows that and we can further improve later). The patch uses a new internal function, .ASSUME, to hold the condition in the FEs. At gimplification time, if the condition is simple/without side-effects, it is gimplified as if (cond) ; else __builtin_unreachable (); and otherwise for now dropped on the floor. The intent is to incrementally outline the conditions into separate artificial functions and use .ASSUME further to tell the ranger and perhaps other optimization passes about the assumptions, as detailed in the PR. When implementing it, I found that assume entry hasn't been added to https://eel.is/c++draft/cpp.cond#6 Jonathan said he'll file a NB comment about it, this patch assumes it has been added into the table as 202207L when the paper has been voted in. With the attributes for both C/C++, I'd say we don't need to add __builtin_assume with similar purpose, especially when __builtin_assume in LLVM is just weird. It is strange for side-effects in function call's argument not to be evaluated, and LLVM in that case (annoyingly) warns and ignores the side-effects (but doesn't do then anything with it), if there are no side-effects, it will work like our if (!cond) __builtin_unreachable (); 2022-10-06 Jakub Jelinek PR c++/106654 gcc/ * internal-fn.def (ASSUME): New internal function. * internal-fn.h (expand_ASSUME): Declare. * internal-fn.cc (expand_ASSUME): Define. * gimplify.cc (gimplify_call_expr): Gimplify IFN_ASSUME. * fold-const.h (simple_condition_p): Declare. * fold-const.cc (simple_operand_p_2): Rename to ... (simple_condition_p): ... this. Remove forward declaration. No longer static. Adjust function comment and fix a typo in it. Adjust recursive call. (simple_operand_p): Adjust function comment. (fold_truth_andor): Adjust simple_operand_p_2 callers to call simple_condition_p. * doc/extend.texi: Document assume attribute. Move fallthrough attribute example to its section. gcc/c-family/ * c-attribs.cc (handle_assume_attribute): New function. (c_common_attribute_table): Add entry for assume attribute. * c-lex.cc (c_common_has_attribute): Handle __have_cpp_attribute (assume). gcc/c/ * c-parser.cc (handle_assume_attribute): New function. (c_parser_declaration_or_fndef): Handle assume attribute. (c_parser_attribute_arguments): Add assume_attr argument, if true, parse first argument as conditional expression. (c_parser_gnu_attribute, c_parser_std_attribute): Adjust c_parser_attribute_arguments callers. (c_parser_statement_after_labels) : Handle assume attribute. gcc/cp/ * cp-tree.h (process_stmt_assume_attribute): Implement C++23 P1774R8 - Portable assumptions. Declare. (diagnose_failing_condition): Declare. (find_failing_clause): Likewise. * parser.cc (assume_attr): New enumerator. (cp_parser_parenthesized_expression_list): Handle assume_attr. Remove identifier variable, for id_attr push the identifier into expression_list right away instead of inserting it before all the others at the end. (cp_parser_conditional_expression): New function. (cp_parser_constant_expression): Use it. (cp_parser_statement): Handle assume attribute. (cp_parser_expression_statement): Likewise. (cp_parser_gnu_attribute_list): Use assume_attr for assume attribute. (cp_parser_std_attribute): Likewise. Handle standard assume attribute like gnu::assume. * cp-gimplify.cc (process_stmt_assume_attribute): New function. * constexpr.cc: Include fold-const.h. (find_failing_clause_r, find_failing_clause): New functions, moved from semantics.cc with ctx argument added and if non-NULL, call cxx_eval_constant_expression rather than fold_non_dependent_expr. (cxx_eval_internal_function): Handle IFN_ASSUME. (potential_constant_expression_1): Likewise. * pt.cc (tsubst_copy_and_build): Likewise. * semantics.cc (diagnose_failing_condition): New function. (find_failing_clause_r, find_failing_clause): Moved to constexpr.cc. (finish_static_assert): Use it. Add auto_diagnostic_group. gcc/testsuite/ * gcc.dg/attr-assume-1.c: New test. * gcc.dg/attr-assume-2.c: New test. * gcc.dg/attr-assume-3.c: New test. * g++.dg/cpp2a/feat-cxx2a.C: Add colon to C++20 features comment, add C++20 attributes comment and move C++20 new features after the attributes before them. * g++.dg/cpp23/feat-cxx2b.C: Likewise. Test __has_cpp_attribute(assume). * g++.dg/cpp23/attr-assume1.C: New test. * g++.dg/cpp23/attr-assume2.C: New test. * g++.dg/cpp23/attr-assume3.C: New test. * g++.dg/cpp23/attr-assume4.C: New test. --- gcc/c-family/c-attribs.cc | 15 +++ gcc/c-family/c-lex.cc | 2 + gcc/c/c-parser.cc | 113 +++++++++++++++-- gcc/cp/constexpr.cc | 90 ++++++++++++++ gcc/cp/cp-gimplify.cc | 44 +++++++ gcc/cp/cp-tree.h | 4 + gcc/cp/parser.cc | 101 ++++++++------- gcc/cp/pt.cc | 27 ++++ gcc/cp/semantics.cc | 75 ++++------- gcc/doc/extend.texi | 49 ++++++-- gcc/fold-const.cc | 28 ++--- gcc/fold-const.h | 1 + gcc/gimplify.cc | 19 +++ gcc/internal-fn.cc | 6 + gcc/internal-fn.def | 4 + gcc/internal-fn.h | 1 + gcc/testsuite/g++.dg/cpp23/attr-assume1.C | 191 ++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp23/attr-assume2.C | 83 +++++++++++++ gcc/testsuite/g++.dg/cpp23/attr-assume3.C | 198 ++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp23/attr-assume4.C | 136 ++++++++++++++++++++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C | 88 +++++++------ gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C | 76 ++++++------ gcc/testsuite/gcc.dg/attr-assume-1.c | 69 +++++++++++ gcc/testsuite/gcc.dg/attr-assume-2.c | 66 ++++++++++ gcc/testsuite/gcc.dg/attr-assume-3.c | 35 ++++++ 25 files changed, 1319 insertions(+), 202 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp23/attr-assume1.C create mode 100644 gcc/testsuite/g++.dg/cpp23/attr-assume2.C create mode 100644 gcc/testsuite/g++.dg/cpp23/attr-assume3.C create mode 100644 gcc/testsuite/g++.dg/cpp23/attr-assume4.C create mode 100644 gcc/testsuite/gcc.dg/attr-assume-1.c create mode 100644 gcc/testsuite/gcc.dg/attr-assume-2.c create mode 100644 gcc/testsuite/gcc.dg/attr-assume-3.c (limited to 'gcc') diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 8bb80e2..671ea38 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -144,6 +144,7 @@ static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *); static tree handle_alloc_align_attribute (tree *, tree, tree, int, bool *); static tree handle_assume_aligned_attribute (tree *, tree, tree, int, bool *); +static tree handle_assume_attribute (tree *, tree, tree, int, bool *); static tree handle_target_attribute (tree *, tree, tree, int, bool *); static tree handle_target_clones_attribute (tree *, tree, tree, int, bool *); static tree handle_optimize_attribute (tree *, tree, tree, int, bool *); @@ -530,6 +531,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_designated_init_attribute, NULL }, { "fallthrough", 0, 0, false, false, false, false, handle_fallthrough_attribute, NULL }, + { "assume", 1, 1, false, false, false, false, + handle_assume_attribute, NULL }, { "patchable_function_entry", 1, 2, true, false, false, false, handle_patchable_function_entry_attribute, NULL }, @@ -5741,6 +5744,18 @@ handle_fallthrough_attribute (tree *, tree name, tree, int, return NULL_TREE; } +/* Handle a "assume" attribute; arguments as in struct + attribute_spec.handler. */ + +tree +handle_assume_attribute (tree *, tree name, tree, int, + bool *no_add_attrs) +{ + pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + return NULL_TREE; +} + /* Handle a "patchable_function_entry" attributes; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc index d4e448a..050fa77 100644 --- a/gcc/c-family/c-lex.cc +++ b/gcc/c-family/c-lex.cc @@ -378,6 +378,8 @@ c_common_has_attribute (cpp_reader *pfile, bool std_syntax) result = 201803; else if (is_attribute_p ("nodiscard", attr_name)) result = 201907; + else if (is_attribute_p ("assume", attr_name)) + result = 202207; } else { diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index f6a94ba..9b76637 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -1823,6 +1823,46 @@ add_debug_begin_stmt (location_t loc) add_stmt (stmt); } +/* Helper function for c_parser_declaration_or_fndef and + Handle assume attribute(s). */ + +static tree +handle_assume_attribute (location_t here, tree attrs, bool nested) +{ + if (nested) + for (tree attr = lookup_attribute ("gnu", "assume", attrs); attr; + attr = lookup_attribute ("gnu", "assume", TREE_CHAIN (attr))) + { + tree args = TREE_VALUE (attr); + int nargs = list_length (args); + if (nargs != 1) + { + error_at (here, "wrong number of arguments specified " + "for %qE attribute", + get_attribute_name (attr)); + inform (here, "expected %i, found %i", 1, nargs); + } + else + { + tree arg = TREE_VALUE (args); + arg = c_objc_common_truthvalue_conversion (here, arg); + arg = c_fully_fold (arg, false, NULL); + if (arg != error_mark_node) + { + tree fn = build_call_expr_internal_loc (here, IFN_ASSUME, + void_type_node, 1, + arg); + add_stmt (fn); + } + } + } + else + pedwarn (here, OPT_Wattributes, + "% attribute at top level"); + + return remove_attribute ("gnu", "assume", attrs); +} + /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 6.7, 6.9.1, C11 6.7, 6.9.1). If FNDEF_OK is true, a function definition is accepted; otherwise (old-style parameter declarations) only other @@ -2037,6 +2077,14 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool auto_type_p = specs->typespec_word == cts_auto_type; if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { + bool handled_assume = false; + if (specs->typespec_kind == ctsk_none + && lookup_attribute ("gnu", "assume", specs->attrs)) + { + handled_assume = true; + specs->attrs + = handle_assume_attribute (here, specs->attrs, nested); + } if (auto_type_p) error_at (here, "%<__auto_type%> in empty declaration"); else if (specs->typespec_kind == ctsk_none @@ -2054,13 +2102,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, pedwarn (here, OPT_Wattributes, "% attribute at top level"); } - else if (empty_ok && !(have_attrs - && specs->non_std_attrs_seen_p)) + else if (empty_ok + && !(have_attrs && specs->non_std_attrs_seen_p) + && !handled_assume) shadow_tag (specs); else { shadow_tag_warned (specs, 1); - pedwarn (here, 0, "empty declaration"); + if (!handled_assume) + pedwarn (here, 0, "empty declaration"); } c_parser_consume_token (parser); if (oacc_routine_data) @@ -2160,6 +2210,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, else if (attribute_fallthrough_p (specs->attrs)) warning_at (here, OPT_Wattributes, "% attribute not followed by %<;%>"); + else if (lookup_attribute ("gnu", "assume", specs->attrs)) + warning_at (here, OPT_Wattributes, + "% attribute not followed by %<;%>"); pending_xref_error (); prefix_attrs = specs->attrs; @@ -4598,7 +4651,8 @@ c_parser_gnu_attribute_any_word (c_parser *parser) static tree c_parser_attribute_arguments (c_parser *parser, bool takes_identifier, - bool require_string, bool allow_empty_args) + bool require_string, bool assume_attr, + bool allow_empty_args) { vec *expr_list; tree attr_args; @@ -4617,6 +4671,7 @@ c_parser_attribute_arguments (c_parser *parser, bool takes_identifier, == CPP_CLOSE_PAREN)) && (takes_identifier || (c_dialect_objc () + && !assume_attr && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))) { @@ -4653,6 +4708,23 @@ c_parser_attribute_arguments (c_parser *parser, bool takes_identifier, tree string = c_parser_string_literal (parser, false, true).value; attr_args = build_tree_list (NULL_TREE, string); } + else if (assume_attr) + { + tree cond + = c_parser_conditional_expression (parser, NULL, NULL_TREE).value; + if (!c_parser_next_token_is (parser, CPP_COMMA)) + attr_args = build_tree_list (NULL_TREE, cond); + else + { + tree tree_list; + c_parser_consume_token (parser); + expr_list = c_parser_expr_list (parser, false, true, + NULL, NULL, NULL, NULL); + tree_list = build_tree_list_vec (expr_list); + attr_args = tree_cons (NULL_TREE, cond, tree_list); + release_tree_vector (expr_list); + } + } else { expr_list = c_parser_expr_list (parser, false, true, @@ -4736,7 +4808,9 @@ c_parser_gnu_attribute (c_parser *parser, tree attrs, tree attr_args = c_parser_attribute_arguments (parser, attribute_takes_identifier_p (attr_name), - false, true); + false, + is_attribute_p ("assume", attr_name), + true); attr = build_tree_list (attr_name, attr_args); if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) @@ -4982,9 +5056,13 @@ c_parser_std_attribute (c_parser *parser, bool for_tm) = (ns == NULL_TREE && (strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0 || strcmp (IDENTIFIER_POINTER (name), "nodiscard") == 0)); + bool assume_attr + = (ns != NULL_TREE + && strcmp (IDENTIFIER_POINTER (ns), "gnu") == 0 + && strcmp (IDENTIFIER_POINTER (name), "assume") == 0); TREE_VALUE (attribute) = c_parser_attribute_arguments (parser, takes_identifier, - require_string, false); + require_string, assume_attr, false); } else c_parser_balanced_token_sequence (parser); @@ -6264,8 +6342,21 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, break; case RID_ATTRIBUTE: { - /* Allow '__attribute__((fallthrough));'. */ + /* Allow '__attribute__((fallthrough));' or + '__attribute__((assume(cond)));'. */ tree attrs = c_parser_gnu_attributes (parser); + bool has_assume = lookup_attribute ("assume", attrs); + if (has_assume) + { + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + attrs = handle_assume_attribute (loc, attrs, true); + else + { + warning_at (loc, OPT_Wattributes, + "% attribute not followed by %<;%>"); + has_assume = false; + } + } if (attribute_fallthrough_p (attrs)) { if (c_parser_next_token_is (parser, CPP_SEMICOLON)) @@ -6282,9 +6373,13 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, "% attribute not followed " "by %<;%>"); } + else if (has_assume) + /* Eat the ';'. */ + c_parser_consume_token (parser); else if (attrs != NULL_TREE) - warning_at (loc, OPT_Wattributes, "only attribute %" - " can be applied to a null statement"); + warning_at (loc, OPT_Wattributes, + "only attribute % or % can " + "be applied to a null statement"); break; } default: diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index db7571d..06dcd71 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "opts.h" #include "stringpool.h" #include "attribs.h" +#include "fold-const.h" static bool verify_constant (tree, bool, bool *, bool *); #define VERIFY_CONSTANT(X) \ @@ -1818,6 +1819,52 @@ cx_error_context (void) return r; } +/* If we have a condition in conjunctive normal form (CNF), find the first + failing clause. In other words, given an expression like + + true && true && false && true && false + + return the first 'false'. EXPR is the expression. */ + +static tree +find_failing_clause_r (constexpr_ctx *ctx, tree expr) +{ + if (TREE_CODE (expr) == TRUTH_ANDIF_EXPR) + { + /* First check the left side... */ + tree e = find_failing_clause_r (ctx, TREE_OPERAND (expr, 0)); + if (e == NULL_TREE) + /* ...if we didn't find a false clause, check the right side. */ + e = find_failing_clause_r (ctx, TREE_OPERAND (expr, 1)); + return e; + } + tree e = contextual_conv_bool (expr, tf_none); + if (ctx) + { + bool new_non_constant_p = false, new_overflow_p = false; + e = cxx_eval_constant_expression (ctx, e, vc_prvalue, + &new_non_constant_p, + &new_overflow_p); + } + else + e = fold_non_dependent_expr (e, tf_none, /*manifestly_const_eval=*/true); + if (integer_zerop (e)) + /* This is the failing clause. */ + return expr; + return NULL_TREE; +} + +/* Wrapper for find_failing_clause_r. */ + +tree +find_failing_clause (constexpr_ctx *ctx, tree expr) +{ + if (TREE_CODE (expr) == TRUTH_ANDIF_EXPR) + if (tree e = find_failing_clause_r (ctx, expr)) + expr = e; + return expr; +} + /* Evaluate a call T to a GCC internal function when possible and return the evaluated result or, under the control of CTX, give an error, set NON_CONSTANT_P, and return the unevaluated call T otherwise. */ @@ -1837,6 +1884,48 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, case IFN_FALLTHROUGH: return void_node; + case IFN_ASSUME: + /* For now, restrict constexpr evaluation of [[assume (cond)]] + only to the cases which don't have side-effects. Evaluating + it even when it does would mean we'd need to somehow undo + all the side-effects e.g. in ctx->global->values. */ + if (!TREE_SIDE_EFFECTS (CALL_EXPR_ARG (t, 0)) + /* And it needs to be a potential constant expression. */ + && potential_rvalue_constant_expression (CALL_EXPR_ARG (t, 0))) + { + constexpr_ctx new_ctx = *ctx; + new_ctx.quiet = true; + tree arg = CALL_EXPR_ARG (t, 0); + bool new_non_constant_p = false, new_overflow_p = false; + arg = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue, + &new_non_constant_p, + &new_overflow_p); + if (!new_non_constant_p && !new_overflow_p && integer_zerop (arg)) + { + if (!*non_constant_p && !ctx->quiet) + { + /* See if we can find which clause was failing + (for logical AND). */ + tree bad = find_failing_clause (&new_ctx, + CALL_EXPR_ARG (t, 0)); + /* If not, or its location is unusable, fall back to the + previous location. */ + location_t cloc = cp_expr_loc_or_loc (bad, EXPR_LOCATION (t)); + + auto_diagnostic_group d; + + /* Report the error. */ + error_at (cloc, + "failed % attribute assumption"); + diagnose_failing_condition (bad, cloc, false); + } + + *non_constant_p = true; + return t; + } + } + return void_node; + case IFN_ADD_OVERFLOW: opcode = PLUS_EXPR; break; @@ -8706,6 +8795,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case IFN_UBSAN_BOUNDS: case IFN_UBSAN_VPTR: case IFN_FALLTHROUGH: + case IFN_ASSUME: return true; case IFN_ADD_OVERFLOW: diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index 404a769..b4599fc3 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -3081,6 +3081,50 @@ process_stmt_hotness_attribute (tree std_attrs, location_t attrs_loc) return std_attrs; } +/* If [[assume (cond)]] appears on this statement, handle it. */ + +tree +process_stmt_assume_attribute (tree std_attrs, tree statement, + location_t attrs_loc) +{ + if (std_attrs == error_mark_node) + return std_attrs; + tree attr = lookup_attribute ("gnu", "assume", std_attrs); + if (!attr) + return std_attrs; + /* The next token after the assume attribute is not ';'. */ + if (statement) + { + warning_at (attrs_loc, OPT_Wattributes, + "% attribute not followed by %<;%>"); + attr = NULL_TREE; + } + for (; attr; attr = lookup_attribute ("gnu", "assume", TREE_CHAIN (attr))) + { + tree args = TREE_VALUE (attr); + int nargs = list_length (args); + if (nargs != 1) + { + auto_diagnostic_group d; + error_at (attrs_loc, "wrong number of arguments specified for " + "%qE attribute", get_attribute_name (attr)); + inform (attrs_loc, "expected %i, found %i", 1, nargs); + } + else + { + tree arg = TREE_VALUE (args); + if (!type_dependent_expression_p (arg)) + arg = contextual_conv_bool (arg, tf_warning_or_error); + if (error_operand_p (arg)) + continue; + statement = build_call_expr_internal_loc (attrs_loc, IFN_ASSUME, + void_type_node, 1, arg); + finish_expr_stmt (statement); + } + } + return remove_attribute ("gnu", "assume", std_attrs); +} + /* Helper of fold_builtin_source_location, return the std::source_location::__impl type after performing verification on it. LOC is used for reporting any errors. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8cf9707..8bc1c2d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7715,6 +7715,7 @@ extern tree build_transaction_expr (location_t, tree, int, tree); extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool, bool); extern tree baselink_for_fns (tree); +extern void diagnose_failing_condition (tree, location_t, bool); extern void finish_static_assert (tree, tree, location_t, bool, bool); extern tree finish_decltype_type (tree, bool, tsubst_flags_t); @@ -8242,6 +8243,7 @@ extern tree predeclare_vla (tree); extern void clear_fold_cache (void); extern tree lookup_hotness_attribute (tree); extern tree process_stmt_hotness_attribute (tree, location_t); +extern tree process_stmt_assume_attribute (tree, tree, location_t); extern bool simple_empty_class_p (tree, tree, tree_code); extern tree fold_builtin_source_location (location_t); @@ -8447,6 +8449,8 @@ extern tree fold_sizeof_expr (tree); extern void clear_cv_and_fold_caches (void); extern tree unshare_constructor (tree CXX_MEM_STAT_INFO); extern bool decl_implicit_constexpr_p (tree); +struct constexpr_ctx; +extern tree find_failing_clause (constexpr_ctx *ctx, tree); extern bool replace_decl (tree *, tree, tree); /* An RAII sentinel used to restrict constexpr evaluation so that it diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 7b41635..baa808a 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -2258,7 +2258,7 @@ static vec *cp_parser_parenthesized_expression_list (cp_parser *, int, bool, bool, bool *, location_t * = NULL, bool = false); /* Values for the second parameter of cp_parser_parenthesized_expression_list. */ -enum { non_attr = 0, normal_attr = 1, id_attr = 2 }; +enum { non_attr = 0, normal_attr = 1, id_attr = 2, assume_attr = 3 }; static void cp_parser_pseudo_destructor_name (cp_parser *, tree, tree *, tree *); static cp_expr cp_parser_unary_expression @@ -2287,6 +2287,7 @@ static cp_expr cp_parser_binary_expression (cp_parser *, bool, bool, enum cp_parser_prec, cp_id_kind *); static tree cp_parser_question_colon_clause (cp_parser *, cp_expr); +static cp_expr cp_parser_conditional_expression (cp_parser *); static cp_expr cp_parser_assignment_expression (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false); static enum tree_code cp_parser_assignment_operator_opt @@ -8480,7 +8481,6 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, bool wrap_locations_p) { vec *expression_list; - tree identifier = NULL_TREE; bool saved_greater_than_is_operator_p; /* Assume all the expressions will be constant. */ @@ -8509,33 +8509,26 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, next token is an identifier. */ if (is_attribute_list == id_attr && cp_lexer_peek_token (parser->lexer)->type == CPP_NAME) - { - cp_token *token; - - /* Consume the identifier. */ - token = cp_lexer_consume_token (parser->lexer); - /* Save the identifier. */ - identifier = token->u.value; - } + expr = cp_lexer_consume_token (parser->lexer)->u.value; + else if (is_attribute_list == assume_attr) + expr = cp_parser_conditional_expression (parser); else - { - expr - = cp_parser_parenthesized_expression_list_elt (parser, cast_p, - allow_expansion_p, - non_constant_p); + expr + = cp_parser_parenthesized_expression_list_elt (parser, cast_p, + allow_expansion_p, + non_constant_p); - if (wrap_locations_p) - expr.maybe_add_location_wrapper (); + if (wrap_locations_p) + expr.maybe_add_location_wrapper (); - /* Add it to the list. We add error_mark_node - expressions to the list, so that we can still tell if - the correct form for a parenthesized expression-list - is found. That gives better errors. */ - vec_safe_push (expression_list, expr.get_value ()); + /* Add it to the list. We add error_mark_node + expressions to the list, so that we can still tell if + the correct form for a parenthesized expression-list + is found. That gives better errors. */ + vec_safe_push (expression_list, expr.get_value ()); - if (expr == error_mark_node) - goto skip_comma; - } + if (expr == error_mark_node) + goto skip_comma; /* After the first item, attribute lists look the same as expression lists. */ @@ -8577,9 +8570,6 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, parser->greater_than_is_operator_p = saved_greater_than_is_operator_p; - if (identifier) - vec_safe_insert (expression_list, 0, identifier); - return expression_list; } @@ -10310,7 +10300,8 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, logical-or-expression that started the conditional-expression. Returns a representation of the entire conditional-expression. - This routine is used by cp_parser_assignment_expression. + This routine is used by cp_parser_assignment_expression + and cp_parser_conditional_expression. ? expression : assignment-expression @@ -10377,6 +10368,28 @@ cp_parser_question_colon_clause (cp_parser* parser, cp_expr logical_or_expr) tf_warning_or_error); } +/* Parse a conditional-expression. + + conditional-expression: + logical-or-expression + logical-or-expression ? expression : assignment-expression + + GNU Extensions: + + logical-or-expression ? : assignment-expression */ + +static cp_expr +cp_parser_conditional_expression (cp_parser *parser) +{ + cp_expr expr = cp_parser_binary_expression (parser, false, false, false, + PREC_NOT_OPERATOR, NULL); + /* If the next token is a `?' then we're actually looking at + a conditional-expression; otherwise we're done. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY)) + return cp_parser_question_colon_clause (parser, expr); + return expr; +} + /* Parse an assignment-expression. assignment-expression: @@ -10702,15 +10715,7 @@ cp_parser_constant_expression (cp_parser* parser, determine whether a particular assignment-expression is in fact constant. */ if (strict_p) - { - /* Parse the binary expressions (logical-or-expression). */ - expression = cp_parser_binary_expression (parser, false, false, false, - PREC_NOT_OPERATOR, NULL); - /* If the next token is a `?' then we're actually looking at - a conditional-expression; otherwise we're done. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY)) - expression = cp_parser_question_colon_clause (parser, expression); - } + expression = cp_parser_conditional_expression (parser); else expression = cp_parser_assignment_expression (parser); /* Restore the old settings. */ @@ -12503,6 +12508,9 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, /* Look for an expression-statement instead. */ statement = cp_parser_expression_statement (parser, in_statement_expr); + std_attrs = process_stmt_assume_attribute (std_attrs, statement, + attrs_loc); + /* Handle [[fallthrough]];. */ if (attribute_fallthrough_p (std_attrs)) { @@ -12526,7 +12534,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, if (statement && STATEMENT_CODE_P (TREE_CODE (statement))) SET_EXPR_LOCATION (statement, statement_location); - /* Allow "[[fallthrough]];", but warn otherwise. */ + /* Allow "[[fallthrough]];" or "[[assume(cond)]];", but warn otherwise. */ if (std_attrs != NULL_TREE) warning_at (attrs_loc, OPT_Wattributes, @@ -12718,6 +12726,8 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr) } } + attr = process_stmt_assume_attribute (attr, statement, loc); + /* Handle [[fallthrough]];. */ if (attribute_fallthrough_p (attr)) { @@ -28876,6 +28886,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */) vec *vec; int attr_flag = (attribute_takes_identifier_p (identifier) ? id_attr : normal_attr); + if (is_attribute_p ("assume", identifier)) + attr_flag = assume_attr; vec = cp_parser_parenthesized_expression_list (parser, attr_flag, /*cast_p=*/false, /*allow_expansion_p=*/false, @@ -29127,6 +29139,9 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) /* C++17 fallthrough attribute is equivalent to GNU's. */ else if (is_attribute_p ("fallthrough", attr_id)) TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier; + /* C++23 assume attribute is equivalent to GNU's. */ + else if (is_attribute_p ("assume", attr_id)) + TREE_PURPOSE (TREE_PURPOSE (attribute)) = gnu_identifier; /* Transactional Memory TS optimize_for_synchronized attribute is equivalent to GNU transaction_callable. */ else if (is_attribute_p ("optimize_for_synchronized", attr_id)) @@ -29171,8 +29186,12 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) return error_mark_node; } - if (attr_ns == gnu_identifier - && attribute_takes_identifier_p (attr_id)) + if (is_attribute_p ("assume", attr_id) + && (attr_ns == NULL_TREE || attr_ns == gnu_identifier)) + /* The assume attribute needs special handling of the argument. */ + attr_flag = assume_attr; + else if (attr_ns == gnu_identifier + && attribute_takes_identifier_p (attr_id)) /* A GNU attribute that takes an identifier in parameter. */ attr_flag = id_attr; diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index bce2a77..bf4ae02 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -21163,6 +21163,33 @@ tsubst_copy_and_build (tree t, break; } + case IFN_ASSUME: + gcc_assert (nargs == 1); + if (vec_safe_length (call_args) != 1) + { + error_at (cp_expr_loc_or_input_loc (t), + "wrong number of arguments to " + "% attribute"); + ret = error_mark_node; + } + else + { + tree &arg = (*call_args)[0]; + if (!type_dependent_expression_p (arg)) + arg = contextual_conv_bool (arg, tf_warning_or_error); + if (error_operand_p (arg)) + { + ret = error_mark_node; + break; + } + ret = build_call_expr_internal_loc (EXPR_LOCATION (t), + IFN_ASSUME, + void_type_node, 1, + arg); + RETURN (ret); + } + break; + default: /* Unsupported internal function with arguments. */ gcc_unreachable (); diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 30cf2f9..39b11ee 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -11172,42 +11172,31 @@ init_cp_semantics (void) } -/* If we have a condition in conjunctive normal form (CNF), find the first - failing clause. In other words, given an expression like +/* Emit additional diagnostics for failing condition BAD. + Used by finish_static_assert and IFN_ASSUME constexpr diagnostics. + If SHOW_EXPR_P is true, print the condition (because it was + instantiation-dependent). */ - true && true && false && true && false - - return the first 'false'. EXPR is the expression. */ - -static tree -find_failing_clause_r (tree expr) +void +diagnose_failing_condition (tree bad, location_t cloc, bool show_expr_p) { - if (TREE_CODE (expr) == TRUTH_ANDIF_EXPR) + /* Nobody wants to see the artificial (bool) cast. */ + bad = tree_strip_nop_conversions (bad); + + /* Actually explain the failure if this is a concept check or a + requires-expression. */ + if (concept_check_p (bad) || TREE_CODE (bad) == REQUIRES_EXPR) + diagnose_constraints (cloc, bad, NULL_TREE); + else if (COMPARISON_CLASS_P (bad) + && ARITHMETIC_TYPE_P (TREE_TYPE (TREE_OPERAND (bad, 0)))) { - /* First check the left side... */ - tree e = find_failing_clause_r (TREE_OPERAND (expr, 0)); - if (e == NULL_TREE) - /* ...if we didn't find a false clause, check the right side. */ - e = find_failing_clause_r (TREE_OPERAND (expr, 1)); - return e; + tree op0 = fold_non_dependent_expr (TREE_OPERAND (bad, 0)); + tree op1 = fold_non_dependent_expr (TREE_OPERAND (bad, 1)); + tree cond = build2 (TREE_CODE (bad), boolean_type_node, op0, op1); + inform (cloc, "the comparison reduces to %qE", cond); } - tree e = contextual_conv_bool (expr, tf_none); - e = fold_non_dependent_expr (e, tf_none, /*manifestly_const_eval=*/true); - if (integer_zerop (e)) - /* This is the failing clause. */ - return expr; - return NULL_TREE; -} - -/* Wrapper for find_failing_clause_r. */ - -static tree -find_failing_clause (tree expr) -{ - if (TREE_CODE (expr) == TRUTH_ANDIF_EXPR) - if (tree e = find_failing_clause_r (expr)) - expr = e; - return expr; + else if (show_expr_p) + inform (cloc, "%qE evaluates to false", bad); } /* Build a STATIC_ASSERT for a static assertion with the condition @@ -11274,12 +11263,12 @@ finish_static_assert (tree condition, tree message, location_t location, int len = TREE_STRING_LENGTH (message) / sz - 1; /* See if we can find which clause was failing (for logical AND). */ - tree bad = find_failing_clause (orig_condition); + tree bad = find_failing_clause (NULL, orig_condition); /* If not, or its location is unusable, fall back to the previous location. */ location_t cloc = cp_expr_loc_or_loc (bad, location); - /* Nobody wants to see the artificial (bool) cast. */ - bad = tree_strip_nop_conversions (bad); + + auto_diagnostic_group d; /* Report the error. */ if (len == 0) @@ -11288,21 +11277,7 @@ finish_static_assert (tree condition, tree message, location_t location, error_at (cloc, "static assertion failed: %s", TREE_STRING_POINTER (message)); - /* Actually explain the failure if this is a concept check or a - requires-expression. */ - if (concept_check_p (bad) - || TREE_CODE (bad) == REQUIRES_EXPR) - diagnose_constraints (location, bad, NULL_TREE); - else if (COMPARISON_CLASS_P (bad) - && ARITHMETIC_TYPE_P (TREE_TYPE (TREE_OPERAND (bad, 0)))) - { - tree op0 = fold_non_dependent_expr (TREE_OPERAND (bad, 0)); - tree op1 = fold_non_dependent_expr (TREE_OPERAND (bad, 1)); - tree cond = build2 (TREE_CODE (bad), boolean_type_node, op0, op1); - inform (cloc, "the comparison reduces to %qE", cond); - } - else if (show_expr_p) - inform (cloc, "%qE evaluates to false", bad); + diagnose_failing_condition (bad, cloc, show_expr_p); } else if (condition && condition != error_mark_node) { diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index a5afb46..9ddfcf7 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -9187,6 +9187,20 @@ available for functions (@pxref{Function Attributes}), variables (@pxref{Variable Attributes}), labels (@pxref{Label Attributes}), enumerators (@pxref{Enumerator Attributes}), and for types (@pxref{Type Attributes}). +@table @code +@item fallthrough +@cindex @code{fallthrough} statement attribute +The @code{fallthrough} attribute with a null statement serves as a +fallthrough statement. It hints to the compiler that a statement +that falls through to another case label, or user-defined label +in a switch statement is intentional and thus the +@option{-Wimplicit-fallthrough} warning must not trigger. The +fallthrough attribute may appear at most once in each attribute +list, and may not be mixed with other attributes. It can only +be used in a switch statement (the compiler will issue an error +otherwise), after a preceding statement and before a logically +succeeding case label, or user-defined label. + This example uses the @code{fallthrough} statement attribute to indicate that the @option{-Wimplicit-fallthrough} warning should not be emitted: @@ -9201,19 +9215,28 @@ switch (cond) @} @end smallexample -@table @code -@item fallthrough -@cindex @code{fallthrough} statement attribute -The @code{fallthrough} attribute with a null statement serves as a -fallthrough statement. It hints to the compiler that a statement -that falls through to another case label, or user-defined label -in a switch statement is intentional and thus the -@option{-Wimplicit-fallthrough} warning must not trigger. The -fallthrough attribute may appear at most once in each attribute -list, and may not be mixed with other attributes. It can only -be used in a switch statement (the compiler will issue an error -otherwise), after a preceding statement and before a logically -succeeding case label, or user-defined label. +@item assume +@cindex @code{assume} statement attribute +The @code{assume} attribute with a null statement serves as portable +assumption. It should have a single argument, a conditional expression, +which is not evaluated. If the argument would evaluate to true +at the point where it appears, it has no effect, otherwise there +is undefined behavior. This is a GNU variant of the ISO C++23 +standard @code{assume} attribute, but it can be used in any version of +both C and C++. + +@smallexample +int +foo (int x, int y) +@{ + __attribute__((assume(x == 42))); + __attribute__((assume(++y == 43))); + return x + y; +@} +@end smallexample + +@code{y} is not actually incremented and the compiler can but does not +have to optimize it to just @code{return 42 + 42;}. @end table diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc index 4f4ec81..9f7beae 100644 --- a/gcc/fold-const.cc +++ b/gcc/fold-const.cc @@ -130,7 +130,6 @@ static tree eval_subst (location_t, tree, tree, tree, tree, tree); static tree optimize_bit_field_compare (location_t, enum tree_code, tree, tree, tree); static bool simple_operand_p (const_tree); -static bool simple_operand_p_2 (tree); static tree range_binop (enum tree_code, tree, tree, int, tree, int); static tree range_predecessor (tree); static tree range_successor (tree); @@ -4868,8 +4867,8 @@ sign_bit_p (tree exp, const_tree val) return NULL_TREE; } -/* Subroutine for fold_truth_andor_1: determine if an operand is simple enough - to be evaluated unconditionally. */ +/* Subroutine for fold_truth_andor_1 and simple_condition_p: determine if an + operand is simple enough to be evaluated unconditionally. */ static bool simple_operand_p (const_tree exp) @@ -4897,13 +4896,12 @@ simple_operand_p (const_tree exp) && (! TREE_STATIC (exp) || DECL_REGISTER (exp)))); } -/* Subroutine for fold_truth_andor: determine if an operand is simple enough - to be evaluated unconditionally. - I addition to simple_operand_p, we assume that comparisons, conversions, +/* Determine if an operand is simple enough to be evaluated unconditionally. + In addition to simple_operand_p, we assume that comparisons, conversions, and logic-not operations are simple, if their operands are simple, too. */ -static bool -simple_operand_p_2 (tree exp) +bool +simple_condition_p (tree exp) { enum tree_code code; @@ -4920,7 +4918,7 @@ simple_operand_p_2 (tree exp) && simple_operand_p (TREE_OPERAND (exp, 1))); if (code == TRUTH_NOT_EXPR) - return simple_operand_p_2 (TREE_OPERAND (exp, 0)); + return simple_condition_p (TREE_OPERAND (exp, 0)); return simple_operand_p (exp); } @@ -9787,10 +9785,10 @@ fold_truth_andor (location_t loc, enum tree_code code, tree type, side-effects, or isn't simple, then we can't add to it, as otherwise we might destroy if-sequence. */ if (TREE_CODE (arg0) == icode - && simple_operand_p_2 (arg1) + && simple_condition_p (arg1) /* Needed for sequence points to handle trappings, and side-effects. */ - && simple_operand_p_2 (TREE_OPERAND (arg0, 1))) + && simple_condition_p (TREE_OPERAND (arg0, 1))) { tem = fold_build2_loc (loc, ncode, type, TREE_OPERAND (arg0, 1), arg1); @@ -9800,10 +9798,10 @@ fold_truth_andor (location_t loc, enum tree_code code, tree type, /* Same as above but for (A AND[-IF] (B AND-IF C)) -> ((A AND B) AND-IF C), or (A OR[-IF] (B OR-IF C) -> ((A OR B) OR-IF C). */ else if (TREE_CODE (arg1) == icode - && simple_operand_p_2 (arg0) + && simple_condition_p (arg0) /* Needed for sequence points to handle trappings, and side-effects. */ - && simple_operand_p_2 (TREE_OPERAND (arg1, 0))) + && simple_condition_p (TREE_OPERAND (arg1, 0))) { tem = fold_build2_loc (loc, ncode, type, arg0, TREE_OPERAND (arg1, 0)); @@ -9814,8 +9812,8 @@ fold_truth_andor (location_t loc, enum tree_code code, tree type, into (A OR B). For sequence point consistancy, we need to check for trapping, and side-effects. */ - else if (code == icode && simple_operand_p_2 (arg0) - && simple_operand_p_2 (arg1)) + else if (code == icode && simple_condition_p (arg0) + && simple_condition_p (arg1)) return fold_build2_loc (loc, ncode, type, arg0, arg1); } diff --git a/gcc/fold-const.h b/gcc/fold-const.h index fe78a4d..fa284c7 100644 --- a/gcc/fold-const.h +++ b/gcc/fold-const.h @@ -215,6 +215,7 @@ extern tree build_range_check (location_t, tree, tree, int, tree, tree); extern bool merge_ranges (int *, tree *, tree *, int, tree, tree, int, tree, tree); extern tree sign_bit_p (tree, const_tree); +extern bool simple_condition_p (tree); extern tree exact_inverse (tree, tree); extern bool expr_not_equal_to (tree t, const wide_int &); extern tree const_unop (enum tree_code, tree, tree); diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 9e0e342..95e16f6 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -3554,6 +3554,25 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) enum internal_fn ifn = CALL_EXPR_IFN (*expr_p); auto_vec vargs (nargs); + if (ifn == IFN_ASSUME) + { + if (simple_condition_p (CALL_EXPR_ARG (*expr_p, 0))) + { + /* If the [[assume (cond)]]; condition is simple + enough and can be evaluated unconditionally + without side-effects, expand it as + if (!cond) __builtin_unreachable (); */ + tree fndecl = builtin_decl_explicit (BUILT_IN_UNREACHABLE); + *expr_p = build3 (COND_EXPR, void_type_node, + CALL_EXPR_ARG (*expr_p, 0), void_node, + build_call_expr_loc (EXPR_LOCATION (*expr_p), + fndecl, 0)); + return GS_OK; + } + /* FIXME: Otherwise expand it specially. */ + return GS_ALL_DONE; + } + for (i = 0; i < nargs; i++) { gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p, diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc index c306240..de608bd4 100644 --- a/gcc/internal-fn.cc +++ b/gcc/internal-fn.cc @@ -4522,3 +4522,9 @@ expand_TRAP (internal_fn, gcall *) { expand_builtin_trap (); } + +void +expand_ASSUME (internal_fn, gcall *) +{ + gcc_unreachable (); +} diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index f49b395..61516da 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -462,6 +462,10 @@ DEF_INTERNAL_FN (TRAP, ECF_CONST | ECF_LEAF | ECF_NORETURN | ECF_NOTHROW | ECF_COLD | ECF_LOOPING_CONST_OR_PURE, NULL) +/* [[assume (cond)]]. */ +DEF_INTERNAL_FN (ASSUME, ECF_CONST | ECF_LEAF | ECF_NOTHROW + | ECF_LOOPING_CONST_OR_PURE, NULL) + #undef DEF_INTERNAL_INT_FN #undef DEF_INTERNAL_FLT_FN #undef DEF_INTERNAL_FLT_FLOATN_FN diff --git a/gcc/internal-fn.h b/gcc/internal-fn.h index c4c94f8..21b1ce4 100644 --- a/gcc/internal-fn.h +++ b/gcc/internal-fn.h @@ -243,6 +243,7 @@ extern void expand_PHI (internal_fn, gcall *); extern void expand_SHUFFLEVECTOR (internal_fn, gcall *); extern void expand_SPACESHIP (internal_fn, gcall *); extern void expand_TRAP (internal_fn, gcall *); +extern void expand_ASSUME (internal_fn, gcall *); extern bool vectorized_internal_fn_supported_p (internal_fn, tree); diff --git a/gcc/testsuite/g++.dg/cpp23/attr-assume1.C b/gcc/testsuite/g++.dg/cpp23/attr-assume1.C new file mode 100644 index 0000000..76b61e9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/attr-assume1.C @@ -0,0 +1,191 @@ +// P1774R8 - Portable assumptions +// { dg-do run { target c++11 } } + +namespace std +{ + constexpr bool + isfinite (float x) + { return __builtin_isfinite (x); } + + constexpr bool + isfinite (double x) + { return __builtin_isfinite (x); } + + constexpr bool + isfinite (long double x) + { return __builtin_isfinite (x); } + + constexpr float + sqrt (float x) + { return __builtin_sqrtf (x); } + + constexpr double + sqrt (double x) + { return __builtin_sqrt (x); } + + constexpr long double + sqrt (long double x) + { return __builtin_sqrtl (x); } + + extern "C" void + abort (); +} + +constexpr int +f1 (int i) +{ +#if __cpp_constexpr >= 201603L + auto f = [=] { [[assume (i == 0)]]; }; + return sizeof (f); +#else + return sizeof (int); +#endif +} + +void +f2 () +{ + static_assert (f1 (0) >= sizeof (int), ""); +} + +int +f3 (int i) +{ + [[assume (i == 42)]]; + return i; +} + +int +f4 (int i) +{ + [[assume (++i == 44)]]; + return i; +} + +int a; +int *volatile c; + +bool +f5 () +{ + ++a; + return true; +} + +constexpr int +f6 () +{ +#if __cpp_constexpr >= 201304L + [[assume (f5 ())]]; +#endif + return 1; +} + +template +bool +f7 () +{ +#if __cpp_fold_expressions >= 201411L + [[assume (((args >= 0) && ...))]]; + return ((args >= 0) && ...); +#else + return true; +#endif +} + +bool +f8 (double x) +{ + [[assume (std::isfinite (x) && x >= 0.0)]]; + return std::isfinite (std::sqrt (x)); +} + +double +f9 (double x) +{ + [[assume (std::isfinite (std::sqrt (x)))]]; + return std::sqrt (x); +} + +template +T +f10 (T x) +{ + [[assume (x == N)]]; + return x; +} + +int +f11 (int x) +{ + [[assume (x == 93 ? true : throw 1)]]; + return x; +} + +constexpr int +f12 (int x) +{ +#if __cpp_constexpr >= 201304L + [[assume (++x == 43)]]; +#endif + return x; +} + +static_assert (f12 (42) == 42, ""); + +struct S +{ + operator bool () { return true; } +}; + +int +f13 () +{ + S s; + [[assume (s)]]; + return 0; +} + +template +int +f14 () +{ + T t; + [[assume (t)]]; + return 0; +} + +int +main () +{ + int b = 42; + double d = 42.0, e = 43.0; + c = &b; + [[assume (f5 ())]]; + if (a) + std::abort (); + [[assume (++b == 43)]]; + if (b != 42 || *c != 42) + std::abort (); + static_assert (f6 () == 1, ""); + if (f6 () != 1) + std::abort (); + if (a) + std::abort (); + if (!f7 <0> () || !f7 <1, 2, 3, 4> ()) + std::abort (); + [[assume (d < e)]]; + if (f10 (45) != 45 + || f10 (128LL) != 128LL +#if __cpp_nontype_template_args >= 201911L + || f10 (-42.0L) != -42.0L +#endif + || false) + std::abort (); + int i = 90, j = 91, k = 92; + [[assume (i == 90), assume (j <= 91)]] [[assume (k >= 92)]]; + if (f11 (93) != 93) + std::abort (); + if (f14 () != 0) + std::abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/attr-assume2.C b/gcc/testsuite/g++.dg/cpp23/attr-assume2.C new file mode 100644 index 0000000..9e54c14 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/attr-assume2.C @@ -0,0 +1,83 @@ +// P1774R8 - Portable assumptions +// { dg-do compile { target c++11 } } + +[[assume (true)]] void f1 (); // { dg-error "'assume' attribute ignored" } +typedef int intx [[assume (true)]]; // { dg-error "'assume' attribute ignored" } +[[assume (true)]]; // { dg-warning "attribute ignored" } + +void +foo () +{ + int i; + [[assume]]; // { dg-error "wrong number of arguments specified for 'assume' attribute" } + // { dg-message "expected 1, found 0" "" { target *-*-* } .-1 } + [[assume ()]]; // { dg-error "parentheses must be omitted if 'assume' attribute argument list is empty" } + // { dg-error "wrong number of arguments specified for 'assume' attribute" "" { target *-*-* } .-1 } + // { dg-message "expected 1, found 0" "" { target *-*-* } .-2 } + [[assume (true, true)]]; // { dg-error "wrong number of arguments specified for 'assume' attribute" } + // { dg-message "expected 1, found 2" "" { target *-*-* } .-1 } + [[assume (true)]] i = 1; // { dg-warning "'assume' attribute not followed by ';'" } + [[assume (throw 1)]]; // { dg-error "expected primary-expression before 'throw'" } + [[assume (i = 1)]]; // { dg-error "expected '\\\)' before '=' token" } +} + +constexpr int +f2 (int x) +{ +#if __cpp_constexpr >= 201304L + [[assume (x == 42)]]; // { dg-error "failed 'assume' attribute assumption" "" { target c++14 } } +#endif // { dg-message "the comparison reduces to '\\\(x == 42\\\)'" "" { target c++14 } .-1 } + return x; +} + +constexpr int a = f2 (44); + +int +f3 (int x) +{ + __asm ("" : "+r" (x)); + return x; +} + +constexpr int +f4 (int x) +{ +#if __cpp_constexpr >= 201304L + [[assume (f3 (42) == 42)]]; +#endif + return x; +} + +static_assert (f4 (42) == 42, ""); + +struct S {}; + +int +f5 () +{ + S s; + [[assume (s)]]; // { dg-error "could not convert 's' from 'S' to 'bool'" } + return 0; +} + +template +int +f6 () +{ + T t; + [[assume (t)]]; // { dg-error "could not convert 't' from 'S' to 'bool'" } + return 0; +} + +int z = f6 (); + +constexpr int +f7 (int x, int y, int z, int w) +{ +#if __cpp_constexpr >= 201304L + [[assume (x == 42 && y == 43 && z == 44 && w == 45)]]; // { dg-error "failed 'assume' attribute assumption" "" { target c++14 } } +#endif // { dg-message "the comparison reduces to '\\\(z == 44\\\)'" "" { target c++14 } .-1 } + return x; +} + +constexpr int w = f7 (42, 43, 45, 44); diff --git a/gcc/testsuite/g++.dg/cpp23/attr-assume3.C b/gcc/testsuite/g++.dg/cpp23/attr-assume3.C new file mode 100644 index 0000000..0be28c7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/attr-assume3.C @@ -0,0 +1,198 @@ +// P1774R8 - Portable assumptions +// { dg-do run { target c++11 } } + +namespace std +{ + constexpr bool + isfinite (float x) + { return __builtin_isfinite (x); } + + constexpr bool + isfinite (double x) + { return __builtin_isfinite (x); } + + constexpr bool + isfinite (long double x) + { return __builtin_isfinite (x); } + + constexpr float + sqrt (float x) + { return __builtin_sqrtf (x); } + + constexpr double + sqrt (double x) + { return __builtin_sqrt (x); } + + constexpr long double + sqrt (long double x) + { return __builtin_sqrtl (x); } + + extern "C" void + abort (); +} + +constexpr int +f1 (int i) +{ +#if __cpp_constexpr >= 201603L + auto f = [=] { [[__assume__ (i == 0)]]; }; + return sizeof (f); +#else + return sizeof (int); +#endif +} + +void +f2 () +{ + static_assert (f1 (0) >= sizeof (int), ""); +} + +int +f3 (int i) +{ + [[gnu::assume (i == 42)]]; + return i; +} + +int +f4 (int i) +{ + __attribute__ ((assume (++i == 44))); + return i; +} + +int a; +int *volatile c; + +bool +f5 () +{ + ++a; + return true; +} + +constexpr int +f6 () +{ +#if __cpp_constexpr >= 201304L + [[__assume__ (f5 ())]]; +#endif + return 1; +} + +template +bool +f7 () +{ +#if __cpp_fold_expressions >= 201411L + [[__gnu__::__assume__ (((args >= 0) && ...))]]; + return ((args >= 0) && ...); +#else + return true; +#endif +} + +bool +f8 (double x) +{ + [[gnu::assume (std::isfinite (x) && x >= 0.0)]]; + return std::isfinite (std::sqrt (x)); +} + +double +f9 (double x) +{ + __attribute__((assume (std::isfinite (std::sqrt (x))))); + return std::sqrt (x); +} + +template +T +f10 (T x) +{ + [[__assume__ (x == N)]]; + return x; +} + +int +f11 (int x) +{ + [[gnu::assume (x == 93 ? true : throw 1)]]; + return x; +} + +constexpr int +f12 (int x) +{ +#if __cpp_constexpr >= 201304L + __attribute__((assume (++x == 43))); +#endif + return x; +} + +static_assert (f12 (42) == 42, ""); + +struct S +{ + operator bool () { return true; } +}; + +int +f13 () +{ + S s; + [[__gnu__::__assume__ (s)]]; + return 0; +} + +template +int +f14 () +{ + T t; + __attribute__((assume (t))); + return 0; +} + +int +main () +{ + int b = 42; + double d = 42.0, e = 43.0; + c = &b; + [[__assume__ (f5 ())]]; + if (a) + std::abort (); + [[gnu::assume (++b == 43)]]; + if (b != 42 || *c != 42) + std::abort (); + static_assert (f6 () == 1, ""); + if (f6 () != 1) + std::abort (); + if (a) + std::abort (); + if (!f7 <0> () || !f7 <1, 2, 3, 4> ()) + std::abort (); + __attribute__((assume (d < e))); + if (f10 (45) != 45 + || f10 (128LL) != 128LL +#if __cpp_nontype_template_args >= 201911L + || f10 (-42.0L) != -42.0L +#endif + || false) + std::abort (); + int i = 90, j = 91, k = 92; + [[__assume__ (i == 90), gnu::assume (j <= 91)]] +#if __cplusplus >= 201703L + [[using gnu:assume (k >= 92)]] +#else + [[gnu::assume (k >= 92)]] +#endif + ; + __attribute__((__assume__ (i == 90), assume (j <= 91))) __attribute__((assume (k >= 92))); + if (f11 (93) != 93) + std::abort (); + if (f14 () != 0) + std::abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/attr-assume4.C b/gcc/testsuite/g++.dg/cpp23/attr-assume4.C new file mode 100644 index 0000000..059d47b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/attr-assume4.C @@ -0,0 +1,136 @@ +// P1774R8 - Portable assumptions +// { dg-do compile { target c++11 } } + +[[__assume__ (true)]] void f1 (); // { dg-error "'assume' attribute ignored" } +typedef int intx [[__assume__ (true)]]; // { dg-error "'assume' attribute ignored" } +[[__assume__ (true)]]; // { dg-warning "attribute ignored" } +[[gnu::assume (true)]] void f1a (); // { dg-error "'assume' attribute ignored" } +typedef int inty [[gnu::__assume__ (true)]]; // { dg-error "'assume' attribute ignored" } +[[__gnu__::assume (true)]]; // { dg-warning "attribute ignored" } +__attribute__((assume (true))) void f1b (); // { dg-error "'assume' attribute ignored" } +typedef int intz __attribute__((assume (true)));// { dg-error "'assume' attribute ignored" } + +void +foo () +{ + int i; + [[__assume__]]; // { dg-error "wrong number of arguments specified for 'assume' attribute" } + // { dg-message "expected 1, found 0" "" { target *-*-* } .-1 } + [[__assume__ ()]]; // { dg-error "parentheses must be omitted if 'assume' attribute argument list is empty" } + // { dg-error "wrong number of arguments specified for 'assume' attribute" "" { target *-*-* } .-1 } + // { dg-message "expected 1, found 0" "" { target *-*-* } .-2 } + [[__assume__ (true, true)]]; // { dg-error "wrong number of arguments specified for 'assume' attribute" } + // { dg-message "expected 1, found 2" "" { target *-*-* } .-1 } + [[__assume__ (true)]] i = 1; // { dg-warning "'assume' attribute not followed by ';'" } + [[__assume__ (throw 1)]]; // { dg-error "expected primary-expression before 'throw'" } + [[__assume__ (i = 1)]]; // { dg-error "expected '\\\)' before '=' token" } + [[gnu::assume]]; // { dg-error "wrong number of arguments specified for 'assume' attribute" } + // { dg-message "expected 1, found 0" "" { target *-*-* } .-1 } + [[gnu::assume ()]]; // { dg-error "parentheses must be omitted if 'assume' attribute argument list is empty" } + // { dg-error "wrong number of arguments specified for 'assume' attribute" "" { target *-*-* } .-1 } + // { dg-message "expected 1, found 0" "" { target *-*-* } .-2 } + [[gnu::assume (true, true)]]; // { dg-error "wrong number of arguments specified for 'assume' attribute" } + // { dg-message "expected 1, found 2" "" { target *-*-* } .-1 } + [[gnu::assume (true)]] i = 1; // { dg-warning "'assume' attribute not followed by ';'" } + [[gnu::assume (throw 1)]]; // { dg-error "expected primary-expression before 'throw'" } + [[gnu::assume (i = 1)]]; // { dg-error "expected '\\\)' before '=' token" } + __attribute__((assume)); // { dg-error "wrong number of arguments specified for 'assume' attribute" } + // { dg-message "expected 1, found 0" "" { target *-*-* } .-1 } + __attribute__((assume ())); // { dg-error "wrong number of arguments specified for 'assume' attribute" } + // { dg-message "expected 1, found 0" "" { target *-*-* } .-1 } + __attribute__((assume (true, true))); // { dg-error "wrong number of arguments specified for 'assume' attribute" } + // { dg-message "expected 1, found 2" "" { target *-*-* } .-1 } + __attribute__((assume (true))) i = 1; // { dg-warning "'assume' attribute not followed by ';'" } + __attribute__((assume (throw 1))); // { dg-error "expected primary-expression before 'throw'" } + __attribute__((assume (i = 1))); // { dg-error "expected '\\\)' before '=' token" } +} + +constexpr int +f2 (int x) +{ +#if __cpp_constexpr >= 201304L + [[__assume__ (x == 42)]]; // { dg-error "failed 'assume' attribute assumption" "" { target c++14 } } +#endif + return x; +} + +constexpr int +f2a (int x) +{ +#if __cpp_constexpr >= 201304L + [[gnu::__assume__ (x == 42)]]; // { dg-error "failed 'assume' attribute assumption" "" { target c++14 } } +#endif + return x; +} + +constexpr int +f2b (int x) +{ +#if __cpp_constexpr >= 201304L + __attribute__((__assume__ (x == 42)));// { dg-error "failed 'assume' attribute assumption" "" { target c++14 } } +#endif + return x; +} + +constexpr int a = f2 (44); +constexpr int aa = f2a (44); +constexpr int ab = f2b (44); + +int +f3 (int x) +{ + __asm ("" : "+r" (x)); + return x; +} + +constexpr int +f4 (int x) +{ +#if __cpp_constexpr >= 201304L + [[__assume__ (f3 (42) == 42)]]; +#endif + return x; +} + +constexpr int +f4a (int x) +{ +#if __cpp_constexpr >= 201304L + [[gnu::assume (f3 (42) == 42)]]; +#endif + return x; +} + +constexpr int +f4b (int x) +{ +#if __cpp_constexpr >= 201304L + __attribute__((assume (f3 (42) == 42))); +#endif + return x; +} + +static_assert (f4 (42) == 42, ""); +static_assert (f4a (42) == 42, ""); +static_assert (f4b (42) == 42, ""); + +struct S {}; + +int +f5 () +{ + S s; + [[gnu::assume (s)]]; // { dg-error "could not convert 's' from 'S' to 'bool'" } + return 0; +} + +template +int +f6 () +{ + T t; + __attribute__((assume (t))); // { dg-error "could not convert 't' from 'S' to 'bool'" } + return 0; +} + +int z = f6 (); diff --git a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C index b52cf37..efe9770 100644 --- a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C +++ b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C @@ -422,7 +422,7 @@ # error "__cpp_nontype_template_parameter_auto != 201606" #endif -// C++20 features +// C++20 features: #ifndef __cpp_conditional_explicit # error "__cpp_conditional_explicit" @@ -460,6 +460,44 @@ # error "__cpp_aggregate_paren_init != 201902" #endif +#ifndef __cpp_char8_t +# error "__cpp_char8_t" +#elif __cpp_char8_t != 202207 +# error "__cpp_char8_t != 202207" +#endif + +#ifndef __cpp_designated_initializers +# error "__cpp_designated_initializers" +#elif __cpp_designated_initializers != 201707 +# error "__cpp_designated_initializers != 201707" +#endif + +#ifndef __cpp_constexpr_in_decltype +# error "__cpp_constexpr_in_decltype" +#elif __cpp_constexpr_in_decltype != 201711 +# error "__cpp_constexpr_in_decltype != 201711" +#endif + +#ifndef __cpp_consteval +# error "__cpp_consteval" +#elif __cpp_consteval != 201811 +# error "__cpp_consteval != 201811" +#endif + +#ifndef __cpp_concepts +# error "__cpp_concepts" +#elif __cpp_concepts != 202002 +# error "__cpp_concepts != 202002" +#endif + +#ifndef __cpp_using_enum +# error "__cpp_using_enum" +#elif __cpp_using_enum != 201907 +# error "__cpp_using_enum != 201907" +#endif + +// C++20 attributes: + #ifdef __has_cpp_attribute # if ! __has_cpp_attribute(maybe_unused) @@ -502,42 +540,6 @@ # error "__has_cpp_attribute" #endif -#ifndef __cpp_char8_t -# error "__cpp_char8_t" -#elif __cpp_char8_t != 202207 -# error "__cpp_char8_t != 202207" -#endif - -#ifndef __cpp_designated_initializers -# error "__cpp_designated_initializers" -#elif __cpp_designated_initializers != 201707 -# error "__cpp_designated_initializers != 201707" -#endif - -#ifndef __cpp_constexpr_in_decltype -# error "__cpp_constexpr_in_decltype" -#elif __cpp_constexpr_in_decltype != 201711 -# error "__cpp_constexpr_in_decltype != 201711" -#endif - -#ifndef __cpp_consteval -# error "__cpp_consteval" -#elif __cpp_consteval != 201811 -# error "__cpp_consteval != 201811" -#endif - -#ifndef __cpp_concepts -# error "__cpp_concepts" -#elif __cpp_concepts != 202002 -# error "__cpp_concepts != 202002" -#endif - -#ifndef __cpp_using_enum -# error "__cpp_using_enum" -#elif __cpp_using_enum != 201907 -# error "__cpp_using_enum != 201907" -#endif - // C++23 features: #ifndef __cpp_size_t_suffix @@ -575,3 +577,15 @@ #elif __cpp_implicit_move != 202207 # error "__cpp_implicit_move != 202207" #endif + +// C++23 attributes: + +#ifdef __has_cpp_attribute +# if ! __has_cpp_attribute(assume) +# error "__has_cpp_attribute(assume)" +# elif __has_cpp_attribute(assume) != 202207 +# error "__has_cpp_attribute(assume) != 202207" +# endif +#else +# error "__has_cpp_attribute" +#endif diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C index 02f3a37..16bc0b8 100644 --- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C +++ b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C @@ -422,7 +422,7 @@ # error "__cpp_nontype_template_parameter_auto != 201606" #endif -// C++20 features +// C++20 features: #ifndef __cpp_conditional_explicit # error "__cpp_conditional_explicit" @@ -460,6 +460,44 @@ # error "__cpp_aggregate_paren_init != 201902" #endif +#ifndef __cpp_char8_t +# error "__cpp_char8_t" +#elif __cpp_char8_t != 202207 +# error "__cpp_char8_t != 202207" +#endif + +#ifndef __cpp_designated_initializers +# error "__cpp_designated_initializers" +#elif __cpp_designated_initializers != 201707 +# error "__cpp_designated_initializers != 201707" +#endif + +#ifndef __cpp_constexpr_in_decltype +# error "__cpp_constexpr_in_decltype" +#elif __cpp_constexpr_in_decltype != 201711 +# error "__cpp_constexpr_in_decltype != 201711" +#endif + +#ifndef __cpp_consteval +# error "__cpp_consteval" +#elif __cpp_consteval != 201811 +# error "__cpp_consteval != 201811" +#endif + +#ifndef __cpp_concepts +# error "__cpp_concepts" +#elif __cpp_concepts != 202002 +# error "__cpp_concepts != 202002" +#endif + +#ifndef __cpp_using_enum +# error "__cpp_using_enum" +#elif __cpp_using_enum != 201907 +# error "__cpp_using_enum != 201907" +#endif + +// C++20 attributes: + #ifdef __has_cpp_attribute # if ! __has_cpp_attribute(maybe_unused) @@ -501,39 +539,3 @@ #else # error "__has_cpp_attribute" #endif - -#ifndef __cpp_char8_t -# error "__cpp_char8_t" -#elif __cpp_char8_t != 202207 -# error "__cpp_char8_t != 202207" -#endif - -#ifndef __cpp_designated_initializers -# error "__cpp_designated_initializers" -#elif __cpp_designated_initializers != 201707 -# error "__cpp_designated_initializers != 201707" -#endif - -#ifndef __cpp_constexpr_in_decltype -# error "__cpp_constexpr_in_decltype" -#elif __cpp_constexpr_in_decltype != 201711 -# error "__cpp_constexpr_in_decltype != 201711" -#endif - -#ifndef __cpp_consteval -# error "__cpp_consteval" -#elif __cpp_consteval != 201811 -# error "__cpp_consteval != 201811" -#endif - -#ifndef __cpp_concepts -# error "__cpp_concepts" -#elif __cpp_concepts != 202002 -# error "__cpp_concepts != 202002" -#endif - -#ifndef __cpp_using_enum -# error "__cpp_using_enum" -#elif __cpp_using_enum != 201907 -# error "__cpp_using_enum != 201907" -#endif diff --git a/gcc/testsuite/gcc.dg/attr-assume-1.c b/gcc/testsuite/gcc.dg/attr-assume-1.c new file mode 100644 index 0000000..16e919e --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-assume-1.c @@ -0,0 +1,69 @@ +/* Portable assumptions */ +/* { dg-do run } */ +/* { dg-options "-std=c2x" } */ + +int +f1 (int i) +{ + [[gnu::assume (i == 42)]]; + return i; +} + +int +f2 (int i) +{ + __attribute__ ((assume (++i == 44))); + return i; +} + +int a; +int *volatile c; + +int +f3 () +{ + ++a; + return 1; +} + +int +f4 (double x) +{ + [[gnu::assume (__builtin_isfinite (x) && x >= 0.0)]]; + return __builtin_isfinite (__builtin_sqrt (x)); +} + +double +f5 (double x) +{ + __attribute__((assume (__builtin_isfinite (__builtin_sqrt (x))))); + return __builtin_sqrt (x); +} + +int +f6 (int x) +{ + [[gnu::assume (x == 93 ? 1 : 0)]]; + return x; +} + +int +main () +{ + int b = 42; + double d = 42.0, e = 43.0; + c = &b; + [[__gnu__::__assume__ (f3 ())]]; + if (a) + __builtin_abort (); + [[gnu::assume (++b == 43)]]; + if (b != 42 || *c != 42) + __builtin_abort (); + __attribute__((assume (d < e))); + int i = 90, j = 91, k = 92; + [[gnu::__assume__ (i == 90), gnu::assume (j <= 91)]] [[gnu::assume (k >= 92)]] + ; + __attribute__((__assume__ (i == 90), assume (j <= 91))) __attribute__((assume (k >= 92))); + if (f6 (93) != 93) + __builtin_abort (); +} diff --git a/gcc/testsuite/gcc.dg/attr-assume-2.c b/gcc/testsuite/gcc.dg/attr-assume-2.c new file mode 100644 index 0000000..aa782e7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-assume-2.c @@ -0,0 +1,66 @@ +/* Portable assumptions */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + +[[gnu::__assume__ (1)]] void f1 (void); /* { dg-warning "'assume' attribute not followed by ';'" } */ + /* { dg-warning "'assume' attribute ignored" "" { target *-*-* } .-1 } */ +typedef int intx [[gnu::assume (1)]]; /* { dg-warning "'assume' attribute ignored" } */ +[[__gnu__::assume (1)]]; /* { dg-warning "'assume' attribute at top level" } */ +__attribute__((assume (1))) void f1b ();/* { dg-warning "'assume' attribute not followed by ';'" } */ + /* { dg-warning "'assume' attribute ignored" "" { target *-*-* } .-1 } */ +typedef int inty __attribute__((assume (1))); /* { dg-warning "'assume' attribute ignored" } */ + +void +foo () +{ + int i; + [[gnu::assume]]; /* { dg-error "wrong number of arguments specified for 'assume' attribute" } */ + /* { dg-message "expected 1, found 0" "" { target *-*-* } .-1 } */ + [[gnu::__assume__ ()]]; /* { dg-error "parentheses must be omitted if attribute argument list is empty" } */ + /* { dg-error "wrong number of arguments specified for 'assume' attribute" "" { target *-*-* } .-1 } */ + /* { dg-message "expected 1, found 0" "" { target *-*-* } .-2 } */ + [[gnu::assume (1, 1)]]; /* { dg-error "wrong number of arguments specified for 'assume' attribute" } */ + /* { dg-message "expected 1, found 2" "" { target *-*-* } .-1 } */ + [[gnu::assume (1)]] i = 1; /* { dg-warning "'assume' attribute ignored" } */ + [[gnu::assume (i = 1)]]; /* { dg-error "expected" } */ + /* { dg-warning "'assume' attribute ignored" "" { target *-*-* } .-1 } */ + __attribute__((assume)); /* { dg-error "wrong number of arguments specified for 'assume' attribute" } */ + /* { dg-message "expected 1, found 0" "" { target *-*-* } .-1 } */ + __attribute__((assume ())); /* { dg-error "wrong number of arguments specified for 'assume' attribute" } */ + /* { dg-message "expected 1, found 0" "" { target *-*-* } .-1 } */ + __attribute__((assume (1, 1))); /* { dg-error "wrong number of arguments specified for 'assume' attribute" } */ + /* { dg-message "expected 1, found 2" "" { target *-*-* } .-1 } */ + __attribute__((assume (i = 1))); /* { dg-error "expected" } */ +} + +int +f2 (int x) +{ + __asm ("" : "+r" (x)); + return x; +} + +int +f3 (int x) +{ + [[gnu::assume (f2 (42) == 42)]]; + return x; +} + +int +f3a (int x) +{ + __attribute__((assume (f2 (42) == 42))); + return x; +} + +struct S {}; + +int +f4 () +{ + struct S s; + [[gnu::assume (s)]]; /* { dg-error "used struct type value where scalar is required" } */ + __attribute__((assume (s))); /* { dg-error "used struct type value where scalar is required" } */ + return 0; +} diff --git a/gcc/testsuite/gcc.dg/attr-assume-3.c b/gcc/testsuite/gcc.dg/attr-assume-3.c new file mode 100644 index 0000000..c611a8f --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-assume-3.c @@ -0,0 +1,35 @@ +/* Portable assumptions */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + +void +foo (int x) +{ + if (x == 1) + goto l1; /* { dg-error "jump into statement expression" } */ + else if (x == 2) + goto l2; /* { dg-error "jump into statement expression" } */ + else if (x == 3) + goto l3; /* { dg-error "jump into statement expression" } */ + [[gnu::assume (({ l0:; if (x == 0) goto l0; 1; }))]]; + [[gnu::assume (({ if (x == 0) __builtin_abort (); 1; }))]]; + [[gnu::assume (({ l1:; 1; }))]]; /* { dg-message "label 'l1' defined here" } */ + [[gnu::assume (({ l2:; 1; }))]]; /* { dg-message "label 'l2' defined here" } */ + __attribute__((assume (({ l3:; 1; })))); /* { dg-message "label 'l3' defined here" } */ + [[gnu::assume (({ l4:; 1; }))]]; /* { dg-message "label 'l4' defined here" } */ + [[gnu::assume (({ l5:; 1; }))]]; /* { dg-message "label 'l5' defined here" } */ + __attribute__((assume (({ l6:; 1; })))); /* { dg-message "label 'l6' defined here" } */ + switch (x) /* { dg-message "switch starts here" } */ + { + case 7: + [[gnu::assume (({ case 8:; 1; }))]]; /* { dg-error "switch jumps into statement expression" } */ + __attribute__((assume (({ default:; 1; })))); /* { dg-error "switch jumps into statement expression" } */ + break; + } + if (x == 4) + goto l4; /* { dg-error "jump into statement expression" } */ + else if (x == 5) + goto l5; /* { dg-error "jump into statement expression" } */ + else if (x == 6) + goto l6; /* { dg-error "jump into statement expression" } */ +} -- cgit v1.1 From 847f5addc4d07a2f3b95f5daa50ab4a64dfd957d Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 6 Oct 2022 10:39:41 +0200 Subject: openmp: Map holds clause to IFN_ASSUME for C/C++ Now that [[assume (cond)]] support is in, this simple patch makes #pragma omp assume holds(cond) use it. 2022-10-06 Jakub Jelinek * c-parser.cc (c_parser_omp_assumption_clauses): Emit IFN_ASSUME call for holds clause on assume construct. * parser.cc (cp_parser_omp_assumption_clauses): Emit IFN_ASSUME call for holds clause on assume construct. * c-c++-common/gomp/assume-4.c: New test. --- gcc/c/c-parser.cc | 8 +++++--- gcc/cp/parser.cc | 8 +++++--- gcc/testsuite/c-c++-common/gomp/assume-4.c | 23 +++++++++++++++++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/assume-4.c (limited to 'gcc') diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 9b76637..67b919c 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -23571,10 +23571,12 @@ c_parser_omp_assumption_clauses (c_parser *parser, bool is_assume) tree t = convert_lvalue_to_rvalue (eloc, expr, true, true).value; t = c_objc_common_truthvalue_conversion (eloc, t); t = c_fully_fold (t, false, NULL); - if (is_assume) + if (is_assume && t != error_mark_node) { - /* FIXME: Emit .ASSUME (t) call here. */ - (void) t; + tree fn = build_call_expr_internal_loc (eloc, IFN_ASSUME, + void_type_node, 1, + t); + add_stmt (fn); } parens.skip_until_found_close (parser); } diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index baa808a..90e06f9 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -46023,13 +46023,15 @@ cp_parser_omp_assumption_clauses (cp_parser *parser, cp_token *pragma_tok, matching_parens parens; if (parens.require_open (parser)) { + location_t eloc = cp_lexer_peek_token (parser->lexer)->location; tree t = cp_parser_assignment_expression (parser); if (!type_dependent_expression_p (t)) t = contextual_conv_bool (t, tf_warning_or_error); - if (is_assume) + if (is_assume && !error_operand_p (t)) { - /* FIXME: Emit .ASSUME (t) call here. */ - (void) t; + t = build_call_expr_internal_loc (eloc, IFN_ASSUME, + void_type_node, 1, t); + finish_expr_stmt (t); } if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, diff --git a/gcc/testsuite/c-c++-common/gomp/assume-4.c b/gcc/testsuite/c-c++-common/gomp/assume-4.c new file mode 100644 index 0000000..9da2296 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/assume-4.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times "return 42;" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-not "return -1;" "optimized" } } */ + +int +foo (int x) +{ + int y; + #pragma omp assume holds (x == 42) + y = x; + return y; +} + +int +bar (int x) +{ + #pragma omp assume holds (x < 42) + ; + if (x == 42) + return -1; + return 42; +} -- cgit v1.1 From 3c01e3a07531b9d4de4777d0cbc04763c5f81aa3 Mon Sep 17 00:00:00 2001 From: Claudiu Zissulescu Date: Thu, 6 Oct 2022 11:36:31 +0300 Subject: arc: Remove max-page-size and common-page-size forced setting Max page size is defined in the ARC's BFD file, and the common page size is also set by the appropriate binutils macros. Remove them from LINK_SPEC. 2022-10-06 Claudiu Zissulescu * config/arc/linux.h (LINK_SPEC): Remove max-page-size and common-pave-size. Signed-off-by: Claudiu Zissulescu --- gcc/config/arc/linux.h | 1 - 1 file changed, 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/arc/linux.h b/gcc/config/arc/linux.h index 0f1ff05..6ebbb14 100644 --- a/gcc/config/arc/linux.h +++ b/gcc/config/arc/linux.h @@ -45,7 +45,6 @@ along with GCC; see the file COPYING3. If not see %{!shared:-dynamic-linker " GNU_USER_DYNAMIC_LINKER "}} \ -X \ %{mbig-endian:-EB} %{EB} %{EL} \ - %{!z:-z max-page-size=0x2000 -z common-page-size=0x2000} \ %{mcpu=nps400:-marclinux_nps; :-marclinux}" #undef STARTFILE_SPEC -- cgit v1.1 From 86b786dc7295f6288296abb38d05572c3f98a758 Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Mon, 26 Sep 2022 12:51:41 +0200 Subject: ada: Fix spurious warning on unreferenced refinement constituents Listing an object as a state refinement constituent shouldn't be considered to be a reference, at least from the point of view of the machinery for detecting objects that are never referenced or written without being referenced. This patch fixes a spurious warning that rarely occurred in practice but was annoyingly emitted for minimal reproducers for issues related to state abstractions. Note: there are other pragmas that should be similarly recognized (e.g. Depends, Global and their refined variants), but recognizing them efficiently probably requires a dedicated utility routine (i.e. to avoid traversal of the parent chain for every kind of pragma). gcc/ada/ * sem_prag.adb (Sig_Pragma): Change flag for pragma Refined_State to mean "not significant"; this is primarily for documentation, because the exact value of the flag is not really taken into account for Refined_State. (Is_Non_Significant_Pragma_Reference): Add special handling for pragma Refined_State. --- gcc/ada/sem_prag.adb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb index 77ff68e..0c3dd81 100644 --- a/gcc/ada/sem_prag.adb +++ b/gcc/ada/sem_prag.adb @@ -31608,7 +31608,7 @@ package body Sem_Prag is Pragma_Refined_Depends => -1, Pragma_Refined_Global => -1, Pragma_Refined_Post => -1, - Pragma_Refined_State => -1, + Pragma_Refined_State => 0, Pragma_Relative_Deadline => 0, Pragma_Remote_Access_Type => -1, Pragma_Remote_Call_Interface => -1, @@ -31713,6 +31713,15 @@ package body Sem_Prag is P := Parent (N); if Nkind (P) /= N_Pragma_Argument_Association then + + -- References within pragma Refined_State are not significant. They + -- can't be recognized using pragma argument number, because they + -- appear inside refinement clauses that rely on aggregate syntax. + + if In_Pragma_Expression (N, Name_Refined_State) then + return True; + end if; + return False; else -- cgit v1.1 From 7d8ba0c67cfb68e3a7806b30c3075d06e8feeb7c Mon Sep 17 00:00:00 2001 From: Bob Duff Date: Tue, 27 Sep 2022 12:10:21 -0400 Subject: ada: Disable slice-of-component optimization in some cases This patch disables the Fast_Copy_Bitfield optimization in certain rare cases that currently do not work (crash in gigi). We could improve Expand_Assign_Array_Bitfield_Fast to handle these cases properly, but that change is delicate, so for now, we simply disable the optimization. gcc/ada/ * exp_ch5.adb (Expand_Assign_Array_Loop_Or_Bitfield): Disable the Fast_Copy_Bitfield optimization in certain cases. --- gcc/ada/exp_ch5.adb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'gcc') diff --git a/gcc/ada/exp_ch5.adb b/gcc/ada/exp_ch5.adb index 209741c..9669737 100644 --- a/gcc/ada/exp_ch5.adb +++ b/gcc/ada/exp_ch5.adb @@ -1660,6 +1660,15 @@ package body Exp_Ch5 is return False; end Volatile_Or_Independent; + function Slice_Of_Packed_Component (L : Node_Id) return Boolean is + (Nkind (L) = N_Slice + and then Nkind (Prefix (L)) = N_Indexed_Component + and then Is_Bit_Packed_Array (Etype (Prefix (Prefix (L))))); + -- L is the left-hand side Name. Returns True if L is a slice of a + -- component of a bit-packed array. The optimization is disabled in + -- that case, because Expand_Assign_Array_Bitfield_Fast cannot + -- currently handle that case correctly. + L : constant Node_Id := Name (N); R : constant Node_Id := Expression (N); -- Left- and right-hand sides of the assignment statement @@ -1681,6 +1690,7 @@ package body Exp_Ch5 is and then not Reverse_Storage_Order (R_Type) and then Ndim = 1 and then Slices + and then not Slice_Of_Packed_Component (L) and then not Volatile_Or_Independent (L, L_Type) and then not Volatile_Or_Independent (R, R_Type) then -- cgit v1.1 From 5a841af88be1ce4ff1c69cbb76a5033f2ceec3d6 Mon Sep 17 00:00:00 2001 From: Yannick Moy Date: Fri, 23 Sep 2022 17:14:52 +0200 Subject: ada: Do not issue compiler warnings in GNATprove mode Use of pragma Warning with a string literal to set warning switches, should not impact GNATprove which is not subject to these switches. gcc/ada/ * sem_prag.adb (Analyze_Pragma): Ignore one variant of pragma Warnings in GNATprove mode. --- gcc/ada/sem_prag.adb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'gcc') diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb index 0c3dd81..f85d091 100644 --- a/gcc/ada/sem_prag.adb +++ b/gcc/ada/sem_prag.adb @@ -25731,6 +25731,13 @@ package body Sem_Prag is ("argument of pragma% must be On/Off or static string " & "expression", Arg1); + -- Use of pragma Warnings to set warning switches is + -- ignored in GNATprove mode, as these switches apply to + -- the compiler only. + + elsif GNATprove_Mode then + null; + -- One argument string expression case else -- cgit v1.1 From 3e7ff131f47f2a07c497af1c5b2df6bf1ba842fb Mon Sep 17 00:00:00 2001 From: Bob Duff Date: Wed, 28 Sep 2022 11:24:49 -0400 Subject: ada: Clean up slice-of-component optimization In the recursive case of Volatile_Or_Independent = False for array types, fall through into later checks, so for example we check the type of the prefix of a slice. The pattern here is "return True in certain cases, otherwise fall through into the final 'return False'". Remove check for "Ndim = 1"; if Slices is True, then the number of dimensions is necessarily 1, because Ada doesn't have multi-dimensional slices. gcc/ada/ * exp_ch5.adb (Expand_Assign_Array_Loop_Or_Bitfield): Minor cleanups. --- gcc/ada/exp_ch5.adb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/exp_ch5.adb b/gcc/ada/exp_ch5.adb index 9669737..d5d66d9 100644 --- a/gcc/ada/exp_ch5.adb +++ b/gcc/ada/exp_ch5.adb @@ -1632,7 +1632,10 @@ package body Exp_Ch5 is end if; if Is_Array_Type (Typ) then - return Volatile_Or_Independent (Empty, Component_Type (Typ)); + if Volatile_Or_Independent (Empty, Component_Type (Typ)) then + return True; + end if; + elsif Is_Record_Type (Typ) then declare Comp : Entity_Id := First_Component (Typ); @@ -1688,7 +1691,6 @@ package body Exp_Ch5 is and then Is_Bit_Packed_Array (R_Type) and then not Reverse_Storage_Order (L_Type) and then not Reverse_Storage_Order (R_Type) - and then Ndim = 1 and then Slices and then not Slice_Of_Packed_Component (L) and then not Volatile_Or_Independent (L, L_Type) -- cgit v1.1 From f775d362aa73353ce07a51c259ca0a3e1f41ba3b Mon Sep 17 00:00:00 2001 From: Gary Dismukes Date: Wed, 28 Sep 2022 13:22:26 -0400 Subject: ada: Accessibility error incorrectly flagged on call within Pre'Class expression The compiler was wrongly reporting an error on a function call within a Pre'Class expression when a formal of the aspect's subprogram was passed to an aliased formal. This occurred due to the call appearing with the return statement of the wrapper function created for the precondition, but the accessibility error check should only be done for return statements that appear in the source program. gcc/ada/ * sem_ch4.adb (Analyze_Call): Add test of Comes_From_Source on the enclosing subprogram's Entity_Id for determining whether to perform the compile-time accessibility check on actuals passed to aliased formals in a function call occurring within a return statement. That test excludes cases where the call occurs within the return statement of a Pre'Class wrapper function. --- gcc/ada/sem_ch4.adb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ada/sem_ch4.adb b/gcc/ada/sem_ch4.adb index ceaf66b..6824941 100644 --- a/gcc/ada/sem_ch4.adb +++ b/gcc/ada/sem_ch4.adb @@ -1467,12 +1467,17 @@ package body Sem_Ch4 is end if; -- Check the accessibility level for actuals for explicitly aliased - -- formals. + -- formals when a function call appears within a return statement. + -- This is only checked if the enclosing subprogram Comes_From_Source, + -- to avoid issuing errors on calls occurring in wrapper subprograms + -- (for example, where the call is part of an expression of an aspect + -- associated with a wrapper, such as Pre'Class). if Nkind (N) = N_Function_Call and then Comes_From_Source (N) and then Present (Nam_Ent) and then In_Return_Value (N) + and then Comes_From_Source (Current_Subprogram) then declare Form : Node_Id; -- cgit v1.1 From b1006d33b330c11952156dd41dae3a3bb2076a76 Mon Sep 17 00:00:00 2001 From: Steve Baird Date: Wed, 28 Sep 2022 10:32:00 -0700 Subject: ada: Incorrect inferences drawn from if/elsif/while conditions with -gnatVo Within the first (respectively, second) statement list of this if statement declare X : constant Integer := ... ; begin if X > 0 then ...; else ...; end if; end; we can safely assume that X is greater (respectively, not greater) than 0. Fix a bug that incorrectly computed the region in which such assumptions can be made to include the condition of the if-statement. This bug usually had no effect because semantic analysis/simplification of the condition was already complete before the code containing the bug was executed. Unfortunately, this is not true in some cases involving -gnatVo validity checking. In these cases, the bug could result in incorrect simplification of the condition at compile time. This, in turn, could lead to incorrect unconditional execution of one arm of the if-statement at run time. Similar errors appear to be possible for the conditions of an elsif or a while loop; the fix addresses these cases as well, although corresponding problems with these constructs have not been demonstrated. gcc/ada/ * exp_util.adb (Get_Current_Value_Condition): Treat references occurring within the condition of an if statement, an elsif, or a while loop in the same way as references that occur before the start of that enclosing construct. --- gcc/ada/exp_util.adb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb index 61395ad..f569d2e 100644 --- a/gcc/ada/exp_util.adb +++ b/gcc/ada/exp_util.adb @@ -6923,6 +6923,11 @@ package body Exp_Util is if Loc < Sloc (CV) then return; + -- In condition of IF statement + + elsif In_Subtree (N => Var, Root => Condition (CV)) then + return; + -- After end of IF statement elsif Loc >= Sloc (CV) + Text_Ptr (UI_To_Int (End_Span (CV))) then @@ -7009,7 +7014,12 @@ package body Exp_Util is if Loc < Sloc (CV) then return; - -- After end of IF statement + -- In condition of ELSIF part + + elsif In_Subtree (N => Var, Root => Condition (CV)) then + return; + + -- After end of IF statement elsif Loc >= Sloc (Stm) + Text_Ptr (UI_To_Int (End_Span (Stm))) @@ -7066,6 +7076,11 @@ package body Exp_Util is if Loc < Sloc (Loop_Stmt) then return; + -- In condition of while loop + + elsif In_Subtree (N => Var, Root => Condition (CV)) then + return; + -- After end of LOOP statement elsif Loc >= Sloc (End_Label (Loop_Stmt)) then -- cgit v1.1 From c3d6d603956ecd20567924888bae55af4cf99c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Poulhi=C3=A8s?= Date: Thu, 28 Jul 2022 15:57:46 +0200 Subject: ada: Add C declarations for Storage Model support Add needed C declarations for Storage Model support in gigi. gcc/ada/ * fe.h (Has_Storage_Model_Type_Aspect) (Has_Designated_Storage_Model_Aspect, Storage_Model_Object) (Storage_Model_Copy_From, Storage_Model_Copy_To): Add declarations. * sem_util.ads: Add WARNING markers for functions for which a new C declaration has been added in fe.h --- gcc/ada/fe.h | 10 ++++++++++ gcc/ada/sem_util.ads | 10 ++++++++++ 2 files changed, 20 insertions(+) (limited to 'gcc') diff --git a/gcc/ada/fe.h b/gcc/ada/fe.h index 02cf105..79a1b58 100644 --- a/gcc/ada/fe.h +++ b/gcc/ada/fe.h @@ -304,17 +304,27 @@ extern Boolean Compile_Time_Known_Value (Node_Id); #define Defining_Entity sem_util__defining_entity #define First_Actual sem_util__first_actual +#define Has_Storage_Model_Type_Aspect sem_util__storage_model_support__has_storage_model_type_aspect +#define Has_Designated_Storage_Model_Aspect sem_util__storage_model_support__has_designated_storage_model_aspect #define Is_Expression_Function sem_util__is_expression_function #define Is_Variable_Size_Record sem_util__is_variable_size_record #define Needs_Secondary_Stack sem_util__needs_secondary_stack #define Next_Actual sem_util__next_actual +#define Storage_Model_Object sem_util__storage_model_support__storage_model_object +#define Storage_Model_Copy_From sem_util__storage_model_support__storage_model_copy_from +#define Storage_Model_Copy_To sem_util__storage_model_support__storage_model_copy_to extern Entity_Id Defining_Entity (Node_Id); extern Node_Id First_Actual (Node_Id); +extern Boolean Has_Storage_Model_Type_Aspect (Entity_Id); +extern Boolean Has_Designated_Storage_Model_Aspect (Entity_Id); extern Boolean Is_Expression_Function (Entity_Id); extern Boolean Is_Variable_Size_Record (Entity_Id); extern Boolean Needs_Secondary_Stack (Entity_Id); extern Node_Id Next_Actual (Node_Id); +extern Entity_Id Storage_Model_Object (Entity_Id); +extern Entity_Id Storage_Model_Copy_From (Entity_Id); +extern Entity_Id Storage_Model_Copy_To (Entity_Id); /* sinfo: */ diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads index 132c2b8..c23d358 100644 --- a/gcc/ada/sem_util.ads +++ b/gcc/ada/sem_util.ads @@ -3655,10 +3655,14 @@ package Sem_Util is function Has_Storage_Model_Type_Aspect (Typ : Entity_Id) return Boolean; -- Returns True iff Typ specifies aspect Storage_Model_Type + -- WARNING: There is a matching C declaration of this subprogram in fe.h + function Has_Designated_Storage_Model_Aspect (Typ : Entity_Id) return Boolean; -- Returns True iff Typ specifies aspect Designated_Storage_Model + -- WARNING: There is a matching C declaration of this subprogram in fe.h + function Storage_Model_Object (Typ : Entity_Id) return Entity_Id; -- Given an access type Typ with aspect Designated_Storage_Model, -- returns the storage-model object associated with that type. @@ -3666,6 +3670,8 @@ package Sem_Util is -- other functions declared in this interface to retrieve operations -- associated with Storage_Model_Type aspect of the object's type. + -- WARNING: There is a matching C declaration of this subprogram in fe.h + function Storage_Model_Type (Obj : Entity_Id) return Entity_Id; -- Given an object Obj of a type specifying aspect Storage_Model_Type, -- returns that type. @@ -3715,12 +3721,16 @@ package Sem_Util is -- type, returns the procedure specified for the Copy_From choice in -- that aspect; returns Empty if the procedure isn't specified. + -- WARNING: There is a matching C declaration of this subprogram in fe.h + function Storage_Model_Copy_To (SM_Obj_Or_Type : Entity_Id) return Entity_Id; -- Given a type with aspect Storage_Model_Type or an object of such a -- type, returns the procedure specified for the Copy_To choice in that -- aspect; returns Empty if the procedure isn't specified. + -- WARNING: There is a matching C declaration of this subprogram in fe.h + function Storage_Model_Storage_Size (SM_Obj_Or_Type : Entity_Id) return Entity_Id; -- Given a type with aspect Storage_Model_Type or an object of such a -- cgit v1.1 From 3da783c5f93d10396d9ad5bf1f3fc68241f50850 Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Fri, 30 Sep 2022 16:56:37 +0200 Subject: ada: Fix inserting of validity checks in lock-free protected subprograms Validity checks for statements in a lock-free implementation of protected subprogram were wrongly inserted in front of the original statements. This happened because the lock-free implementation was created as a shallow copy, where only the protected body statements were copied while its children still had the Parent pointing to the original statements. gcc/ada/ * exp_ch9.adb (Build_Lock_Free_Protected_Subprogram_Body): Replace shallow copy of protected statements with a deep copy. --- gcc/ada/exp_ch9.adb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ada/exp_ch9.adb b/gcc/ada/exp_ch9.adb index 8abff55..decf617 100644 --- a/gcc/ada/exp_ch9.adb +++ b/gcc/ada/exp_ch9.adb @@ -2797,7 +2797,7 @@ package body Exp_Ch9 is Expected_Comp : Entity_Id; Stmt : Node_Id; Stmts : List_Id := - New_Copy_List (Statements (Hand_Stmt_Seq)); + New_Copy_List_Tree (Statements (Hand_Stmt_Seq)); Typ_Size : Int; Unsigned : Entity_Id; -- cgit v1.1 From 09203b787a9a64bd57ee83d1be1495975a384ec6 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Thu, 8 Sep 2022 00:33:15 -0300 Subject: ada: stack scrubbing: exemplify codegen changes gcc/ada/ * doc/gnat_rm/security_hardening_features.rst: Add examples of codegen changes in stack scrubbing. * gnat_rm.texi: Regenerate. --- .../doc/gnat_rm/security_hardening_features.rst | 52 +++++++++++++++++++++ gcc/ada/gnat_rm.texi | 53 +++++++++++++++++++++- 2 files changed, 103 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/doc/gnat_rm/security_hardening_features.rst b/gcc/ada/doc/gnat_rm/security_hardening_features.rst index f5fdc8e..e36d475 100644 --- a/gcc/ada/doc/gnat_rm/security_hardening_features.rst +++ b/gcc/ada/doc/gnat_rm/security_hardening_features.rst @@ -74,6 +74,58 @@ or a variable.) -- scrubbing of the stack space used by that subprogram. +Given these declarations, Foo has its type and body modified as +follows: + +.. code-block:: ada + + function Foo ( : in out System.Address) returns Integer + is + -- ... + begin + <__strub_update> (); -- Updates the stack WaterMark. + -- ... + end; + + +whereas its callers are modified from: + +.. code-block:: ada + + X := Foo; + +to: + +.. code-block:: ada + + declare + : System.Address; + begin + <__strub_enter> (); -- Initialize . + X := Foo (); + <__strub_leave> (); -- Scrubs stack up to . + end; + + +As for Bar, because it is strubbed in internal mode, its callers are +not modified. Its definition is modified roughly as follows: + +.. code-block:: ada + + procedure Bar is + : System.Address; + procedure Strubbed_Bar ( : in out System.Address) is + begin + <__strub_update> (); -- Updates the stack WaterMark. + -- original Bar body. + end Strubbed_Bar; + begin + <__strub_enter> (); -- Initialize . + Strubbed_Bar (); + <__strub_leave> (); -- Scrubs stack up to . + end Bar; + + There are also :switch:`-fstrub={choice}` command-line options to control default settings. For usage and more details on the command-line options, on the ``strub`` attribute, and their use with diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index 64f2e79..ff18456 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -3,7 +3,7 @@ @setfilename gnat_rm.info @documentencoding UTF-8 @ifinfo -@*Generated by Sphinx 5.1.1.@* +@*Generated by Sphinx 5.2.3.@* @end ifinfo @settitle GNAT Reference Manual @defindex ge @@ -19,7 +19,7 @@ @copying @quotation -GNAT Reference Manual , Sep 23, 2022 +GNAT Reference Manual , Oct 04, 2022 AdaCore @@ -28734,6 +28734,55 @@ pragma Machine_Attribute (Var, "strub"); -- scrubbing of the stack space used by that subprogram. @end example +Given these declarations, Foo has its type and body modified as +follows: + +@example +function Foo ( : in out System.Address) returns Integer +is + -- ... +begin + <__strub_update> (); -- Updates the stack WaterMark. + -- ... +end; +@end example + +whereas its callers are modified from: + +@example +X := Foo; +@end example + +to: + +@example +declare + : System.Address; +begin + <__strub_enter> (); -- Initialize . + X := Foo (); + <__strub_leave> (); -- Scrubs stack up to . +end; +@end example + +As for Bar, because it is strubbed in internal mode, its callers are +not modified. Its definition is modified roughly as follows: + +@example +procedure Bar is + : System.Address; + procedure Strubbed_Bar ( : in out System.Address) is + begin + <__strub_update> (); -- Updates the stack WaterMark. + -- original Bar body. + end Strubbed_Bar; +begin + <__strub_enter> (); -- Initialize . + Strubbed_Bar (); + <__strub_leave> (); -- Scrubs stack up to . +end Bar; +@end example + There are also @code{-fstrub=`choice'} command-line options to control default settings. For usage and more details on the command-line options, on the @code{strub} attribute, and their use with -- cgit v1.1 From 21130676a8032b53dad05d224a78244a419e4929 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Thu, 8 Sep 2022 00:15:19 -0300 Subject: ada: hardened booleans: exemplify codegen changes Show the sort of code that is to be expected from using hardened booleans in Ada code. Mention that C traps instead of raising exceptions. gcc/ada/ * doc/gnat_rm/security_hardening_features.rst: Add examples of codegen changes in hardened booleans. Mention that C traps where Ada raises exceptions. * gnat_rm.texi: Regenerate. --- .../doc/gnat_rm/security_hardening_features.rst | 29 +++++++++++++++++++--- gcc/ada/gnat_rm.texi | 26 ++++++++++++++++--- 2 files changed, 48 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/doc/gnat_rm/security_hardening_features.rst b/gcc/ada/doc/gnat_rm/security_hardening_features.rst index e36d475..d8ea849 100644 --- a/gcc/ada/doc/gnat_rm/security_hardening_features.rst +++ b/gcc/ada/doc/gnat_rm/security_hardening_features.rst @@ -265,19 +265,40 @@ further remove checks found to be redundant. For additional hardening, the ``hardbool`` :samp:`Machine_Attribute` pragma can be used to annotate boolean types with representation clauses, so that expressions of such types used as conditions are -checked even when compiling with :switch:`-gnatVT`. +checked even when compiling with :switch:`-gnatVT`: .. code-block:: ada pragma Machine_Attribute (HBool, "hardbool"); + function To_Boolean (X : HBool) returns Boolean is (Boolean (X)); + + +is compiled roughly like: + +.. code-block:: ada + + function To_Boolean (X : HBool) returns Boolean is + begin + if X not in True | False then + raise Constraint_Error; + elsif X in True then + return True; + else + return False; + end if; + end To_Boolean; + Note that :switch:`-gnatVn` will disable even ``hardbool`` testing. Analogous behavior is available as a GCC extension to the C and -Objective C programming languages, through the ``hardbool`` attribute. -For usage and more details on that attribute, see :title:`Using the -GNU Compiler Collection (GCC)`. +Objective C programming languages, through the ``hardbool`` attribute, +with the difference that, instead of raising a Constraint_Error +exception, when a hardened boolean variable is found to hold a value +that stands for neither True nor False, the program traps. For usage +and more details on that attribute, see :title:`Using the GNU Compiler +Collection (GCC)`. .. Control Flow Redundancy: diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index ff18456..dad0092 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -28920,17 +28920,37 @@ further remove checks found to be redundant. For additional hardening, the @code{hardbool} @code{Machine_Attribute} pragma can be used to annotate boolean types with representation clauses, so that expressions of such types used as conditions are -checked even when compiling with @code{-gnatVT}. +checked even when compiling with @code{-gnatVT}: @example pragma Machine_Attribute (HBool, "hardbool"); + +function To_Boolean (X : HBool) returns Boolean is (Boolean (X)); +@end example + +is compiled roughly like: + +@example +function To_Boolean (X : HBool) returns Boolean is +begin + if X not in True | False then + raise Constraint_Error; + elsif X in True then + return True; + else + return False; + end if; +end To_Boolean; @end example Note that @code{-gnatVn} will disable even @code{hardbool} testing. Analogous behavior is available as a GCC extension to the C and -Objective C programming languages, through the @code{hardbool} attribute. -For usage and more details on that attribute, see @cite{Using the GNU Compiler Collection (GCC)}. +Objective C programming languages, through the @code{hardbool} attribute, +with the difference that, instead of raising a Constraint_Error +exception, when a hardened boolean variable is found to hold a value +that stands for neither True nor False, the program traps. For usage +and more details on that attribute, see @cite{Using the GNU Compiler Collection (GCC)}. @c Control Flow Redundancy: -- cgit v1.1 From a93fd547bacd1bab37290f9f3c44ef3ddf334287 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Wed, 7 Sep 2022 23:49:58 -0300 Subject: ada: hardened conditionals: exemplify codegen changes gcc/ada/ * doc/gnat_rm/security_hardening_features.rst: Add examples of codegen changes in hardened conditionals. * gnat_rm.texi: Regenerate. --- .../doc/gnat_rm/security_hardening_features.rst | 51 +++++++++++++++++++++- gcc/ada/gnat_rm.texi | 47 +++++++++++++++++++- 2 files changed, 94 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/doc/gnat_rm/security_hardening_features.rst b/gcc/ada/doc/gnat_rm/security_hardening_features.rst index d8ea849..d7c02b9 100644 --- a/gcc/ada/doc/gnat_rm/security_hardening_features.rst +++ b/gcc/ada/doc/gnat_rm/security_hardening_features.rst @@ -203,11 +203,58 @@ activated by a separate command-line option. The option :switch:`-fharden-compares` enables hardening of compares that compute results stored in variables, adding verification that the -reversed compare yields the opposite result. +reversed compare yields the opposite result, turning: + +.. code-block:: ada + + B := X = Y; + + +into: + +.. code-block:: ada + + B := X = Y; + declare + NotB : Boolean := X /= Y; -- Computed independently of B. + begin + if B = NotB then + <__builtin_trap>; + end if; + end; + The option :switch:`-fharden-conditional-branches` enables hardening of compares that guard conditional branches, adding verification of -the reversed compare to both execution paths. +the reversed compare to both execution paths, turning: + +.. code-block:: ada + + if X = Y then + X := Z + 1; + else + Y := Z - 1; + end if; + + +into: + +.. code-block:: ada + + if X = Y then + if X /= Y then -- Computed independently of X = Y. + <__builtin_trap>; + end if; + X := Z + 1; + else + if X /= Y then -- Computed independently of X = Y. + null; + else + <__builtin_trap>; + end if; + Y := Z - 1; + end if; + These transformations are introduced late in the compilation pipeline, long after boolean expressions are decomposed into separate compares, diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index dad0092..e13dba0 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -28858,11 +28858,54 @@ activated by a separate command-line option. The option @code{-fharden-compares} enables hardening of compares that compute results stored in variables, adding verification that the -reversed compare yields the opposite result. +reversed compare yields the opposite result, turning: + +@example +B := X = Y; +@end example + +into: + +@example +B := X = Y; +declare + NotB : Boolean := X /= Y; -- Computed independently of B. +begin + if B = NotB then + <__builtin_trap>; + end if; +end; +@end example The option @code{-fharden-conditional-branches} enables hardening of compares that guard conditional branches, adding verification of -the reversed compare to both execution paths. +the reversed compare to both execution paths, turning: + +@example +if X = Y then + X := Z + 1; +else + Y := Z - 1; +end if; +@end example + +into: + +@example +if X = Y then + if X /= Y then -- Computed independently of X = Y. + <__builtin_trap>; + end if; + X := Z + 1; +else + if X /= Y then -- Computed independently of X = Y. + null; + else + <__builtin_trap>; + end if; + Y := Z - 1; +end if; +@end example These transformations are introduced late in the compilation pipeline, long after boolean expressions are decomposed into separate compares, -- cgit v1.1 From 56a93169a4f413e0a711e973cf34e2ee89151ef4 Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Mon, 3 Oct 2022 16:45:49 +0200 Subject: ada: Cleanup related to lock-free protected subprograms Cleanup code and documentation; semantics is unaffected. gcc/ada/ * doc/gnat_rm/implementation_defined_pragmas.rst (Lock_Free): Remove inconsistent periods that end item descriptions. * sem_ch9.adb (Allows_Lock_Free_Implementation): Remove unnecessary guard against an empty list of parameters; replace low-level entity kind membership test with a high-level query; refill error message. * gnat_rm.texi: Regenerate. --- gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst | 6 +++--- gcc/ada/gnat_rm.texi | 6 +++--- gcc/ada/sem_ch9.adb | 8 +++----- 3 files changed, 9 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst b/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst index 53836c9..6752d48 100644 --- a/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst +++ b/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst @@ -3744,10 +3744,10 @@ In addition, each protected subprogram body must satisfy: * May reference only one protected component * May not reference nonconstant entities outside the protected subprogram - scope. + scope * May not contain address representation items, allocators, or quantified - expressions. -* May not contain delay, goto, loop, or procedure-call statements. + expressions +* May not contain delay, goto, loop, or procedure-call statements * May not contain exported and imported entities * May not dereferenced access values * Function calls and attribute references must be static diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index e13dba0..e79cdee 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -5243,14 +5243,14 @@ May reference only one protected component @item May not reference nonconstant entities outside the protected subprogram -scope. +scope @item May not contain address representation items, allocators, or quantified -expressions. +expressions @item -May not contain delay, goto, loop, or procedure-call statements. +May not contain delay, goto, loop, or procedure-call statements @item May not contain exported and imported entities diff --git a/gcc/ada/sem_ch9.adb b/gcc/ada/sem_ch9.adb index cae0f23..6506358 100644 --- a/gcc/ada/sem_ch9.adb +++ b/gcc/ada/sem_ch9.adb @@ -178,8 +178,6 @@ package body Sem_Ch9 is elsif Nkind (Decl) = N_Subprogram_Declaration and then Nkind (Specification (Decl)) = N_Procedure_Specification - and then - Present (Parameter_Specifications (Specification (Decl))) then declare Par_Specs : constant List_Id := @@ -477,7 +475,7 @@ package body Sem_Ch9 is -- Prohibit references to non-constant entities -- outside the protected subprogram scope. - if Ekind (Id) in Assignable_Kind + if Is_Assignable (Id) and then not Scope_Within_Or_Same (Scope (Id), Sub_Id) and then not @@ -487,8 +485,8 @@ package body Sem_Ch9 is then if Lock_Free_Given then Error_Msg_NE - ("reference to global variable& not " & - "allowed", N, Id); + ("reference to global variable& not allowed", + N, Id); return Skip; end if; -- cgit v1.1 From 1180b8fb8c74da9991a1e1066961d1b3f2bd6e4b Mon Sep 17 00:00:00 2001 From: Piotr Trojanek Date: Mon, 3 Oct 2022 16:49:19 +0200 Subject: ada: Reject conditional goto in lock-free protected subprograms In lock-free protected subprograms we don't allow goto statements; likewise, we now reject conditional goto statements. This fix only affects semantic checking mode with switch -gnatc. In ordinary compilation we already rejected conditional goto after it was expanded into ordinary goto. gcc/ada/ * sem_ch9.adb (Allows_Lock_Free_Implementation): Reject conditional goto statements. --- gcc/ada/sem_ch9.adb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ada/sem_ch9.adb b/gcc/ada/sem_ch9.adb index 6506358..f2a5901 100644 --- a/gcc/ada/sem_ch9.adb +++ b/gcc/ada/sem_ch9.adb @@ -453,7 +453,7 @@ package body Sem_Ch9 is -- Goto statements restricted - elsif Kind = N_Goto_Statement then + elsif Kind in N_Goto_Statement | N_Goto_When_Statement then if Lock_Free_Given then Error_Msg_N ("goto statement not allowed", N); return Skip; -- cgit v1.1 From 6c62d9b7b44b10ff272d11bcc430538ab07ef8f6 Mon Sep 17 00:00:00 2001 From: Steve Baird Date: Fri, 30 Sep 2022 11:14:20 -0700 Subject: ada: Minor potential bug in sem_ch6.adb In sem_ch6.adb, the procedure Analyze_Procedure_Call is preceded with a comment: -- WARNING: This routine manages Ghost regions. Return statements must be -- replaced by gotos that jump to the end of the routine and restore the -- Ghost mode. Correct a violation of this comment. This is a one-line change. gcc/ada/ * sem_ch6.adb (Analyze_Procedure_Call): Replace "return;" with "goto Leave;", as per comment preceding body of Analyze_Procedure_Call. --- gcc/ada/sem_ch6.adb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb index 7db0cb7..7ad6408 100644 --- a/gcc/ada/sem_ch6.adb +++ b/gcc/ada/sem_ch6.adb @@ -2398,7 +2398,7 @@ package body Sem_Ch6 is Class_Wide_Type (Etype (First_Formal (Subp))) = Typ) and then Try_Object_Operation (P) then - return; + goto Leave; else Analyze_Call_And_Resolve; -- cgit v1.1 From 544d14e1b42eeb337fcefb1efe9d108e71a06d52 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Fri, 23 Sep 2022 12:18:22 +0200 Subject: ada: Implementation of support for storage models in gigi It is based on a new LOAD_EXPR node in GENERIC that is later turned into a bona-fide temporary during gimplification. gcc/ada/ * gcc-interface/ada-tree.def (LOAD_EXPR): New expression code. * gcc-interface/gigi.h (build_storage_model_load): Declare. (build_storage_model_store): Likewise. (instantiate_load_in_expr): Likewise. (INSTANTIATE_LOAD_IN_EXPR): New macro. (instantiate_load_in_array_ref): Declare. * gcc-interface/decl.cc (gnat_to_gnu_entity) : Set a fake discriminant number on the fields of the template type. (gnat_to_gnu_field): Use integer for DECL_DISCRIMINANT_NUMBER. * gcc-interface/misc.cc (gnat_init_ts): Mark LOAD_EXPR as typed. * gcc-interface/trans.cc (fold_constant_decl_in_expr) : Also preserve the 4th operand. (Attribute_to_gnu): Deal with LOAD_EXPR of unconstrained array type. : Call INSTANTIATE_LOAD_IN_EXPR for a storage model. : Likewise. : Likewise. (get_storage_model): New function. (get_storage_model_access): Likewise. (storage_model_access_required_p): Likewise. (Call_to_gnu): Add GNAT_STORAGE_MODEL parameter and deal with it. Also deal with actual parameters that have a storage model. (gnat_to_gnu) : Adjust call to Call_to_gnu. : Deal with a storage model access. : Likewise. : Likewise. : Likewise. : Adjust call to Call_to_gnu. Deal with a storage model access either on the LHS, on the RHS or on both. : Adjust call to Call_to_gnu. : Deal with a pool that is a storage model. Replace test for UNCONSTRAINED_ARRAY_REF with test on the type. (gnat_gimplify_expr) : Tidy up. : New case. : Move down. * gcc-interface/utils.cc (maybe_unconstrained_array): Deal with a LOAD_EXPR by recursing on its first operand. * gcc-interface/utils2.cc (build_allocator): Deal with a pool that is a storage model. (build_storage_model_copy): New function. (build_storage_model_load): Likewise. (build_storage_model_store): Likewise. (instantiate_load_in_expr): Likewise. (instantiate_load_in_array_ref): Likewise. (gnat_rewrite_reference) : Also preserve the 4th operand. (get_inner_constant_reference) : Remove useless test. (gnat_invariant_expr) : Rewrite test. --- gcc/ada/gcc-interface/ada-tree.def | 4 + gcc/ada/gcc-interface/decl.cc | 6 +- gcc/ada/gcc-interface/gigi.h | 28 ++++ gcc/ada/gcc-interface/misc.cc | 1 + gcc/ada/gcc-interface/trans.cc | 326 ++++++++++++++++++++++++++++++++----- gcc/ada/gcc-interface/utils.cc | 7 + gcc/ada/gcc-interface/utils2.cc | 294 +++++++++++++++++++++++++++++++-- 7 files changed, 605 insertions(+), 61 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/gcc-interface/ada-tree.def b/gcc/ada/gcc-interface/ada-tree.def index 8eb4688..7fc95cb 100644 --- a/gcc/ada/gcc-interface/ada-tree.def +++ b/gcc/ada/gcc-interface/ada-tree.def @@ -35,6 +35,10 @@ DEFTREECODE (UNCONSTRAINED_ARRAY_TYPE, "unconstrained_array_type", tcc_type, 0) DEFTREECODE (UNCONSTRAINED_ARRAY_REF, "unconstrained_array_ref", tcc_reference, 1) +/* Same as SAVE_EXPR, but operand 1 contains the statement used to initialize + the temporary instead of using the value of operand 0 directly. */ +DEFTREECODE (LOAD_EXPR, "load_expr", tcc_expression, 2) + /* An expression that returns an RTL suitable for its type. Operand 0 is an expression to be evaluated for side effects only. */ DEFTREECODE (NULL_EXPR, "null_expr", tcc_expression, 1) diff --git a/gcc/ada/gcc-interface/decl.cc b/gcc/ada/gcc-interface/decl.cc index c5a93fb..f8c7698 100644 --- a/gcc/ada/gcc-interface/decl.cc +++ b/gcc/ada/gcc-interface/decl.cc @@ -2279,6 +2279,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) gnu_index_type, gnu_template_type, NULL_TREE, NULL_TREE, 0, 0); + /* Mark the field specifically for INSTANTIATE_LOAD_IN_EXPR. */ + DECL_DISCRIMINANT_NUMBER (gnu_lb_field) = integer_minus_one_node; Sloc_to_locus (Sloc (gnat_entity), &DECL_SOURCE_LOCATION (gnu_lb_field)); @@ -2287,6 +2289,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) gnu_index_type, gnu_template_type, NULL_TREE, NULL_TREE, 0, 0); + /* Mark the field specifically for INSTANTIATE_LOAD_IN_EXPR. */ + DECL_DISCRIMINANT_NUMBER (gnu_hb_field) = integer_minus_one_node; Sloc_to_locus (Sloc (gnat_entity), &DECL_SOURCE_LOCATION (gnu_hb_field)); @@ -7694,7 +7698,7 @@ gnat_to_gnu_field (Entity_Id gnat_field, tree gnu_record_type, int packed, if (Ekind (gnat_field) == E_Discriminant) { DECL_DISCRIMINANT_NUMBER (gnu_field) - = UI_To_gnu (Discriminant_Number (gnat_field), sizetype); + = UI_To_gnu (Discriminant_Number (gnat_field), integer_type_node); DECL_INVARIANT_P (gnu_field) = No (Discriminant_Default_Value (gnat_field)); DECL_NONADDRESSABLE_P (gnu_field) = 0; diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h index 1c1397a..82e2403 100644 --- a/gcc/ada/gcc-interface/gigi.h +++ b/gcc/ada/gcc-interface/gigi.h @@ -912,6 +912,34 @@ extern tree build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc, Entity_Id gnat_pool, Node_Id gnat_node, bool); +/* Build a load of SRC using the storage model of GNAT_SMO. */ +extern tree build_storage_model_load (Entity_Id gnat_smo, tree src); + +/* Build a load of SRC into DEST using the storage model of GNAT_SMO. + If SIZE is specified, use it, otherwise use the size of SRC. */ +extern tree build_storage_model_load (Entity_Id gnat_smo, tree dest, tree src, + tree size = NULL_TREE); + +/* Build a store of SRC into DEST using the storage model of GNAT_SMO. + If SIZE is specified, use it, otherwise use the size of DEST. */ +extern tree build_storage_model_store (Entity_Id gnat_smo, tree dest, tree src, + tree size = NULL_TREE); + +/* Given a tree EXP, instantiate occurrences of LOAD_EXPR in it and associate + them with the storage model of GNAT_SMO. */ +extern tree instantiate_load_in_expr (tree exp, Entity_Id gnat_smo); + +/* This macro calls the above function but short-circuits the common + case of a constant to save time and also checks for NULL. */ + +#define INSTANTIATE_LOAD_IN_EXPR(EXP, GNAT_SMO) \ + ((EXP) == NULL_TREE || TREE_CONSTANT (EXP) ? (EXP) \ + : instantiate_load_in_expr (EXP, GNAT_SMO)) + +/* Given an array or slice reference, instantiate occurrences of LOAD_EXPR in + it and associate them with the storage model of GNAT_SMO. */ +extern void instantiate_load_in_array_ref (tree ref, Entity_Id gnat_smo); + /* Indicate that we need to take the address of T and that it therefore should not be allocated in a register. Returns true if successful. */ extern bool gnat_mark_addressable (tree t); diff --git a/gcc/ada/gcc-interface/misc.cc b/gcc/ada/gcc-interface/misc.cc index f0ca197..e1b5a43 100644 --- a/gcc/ada/gcc-interface/misc.cc +++ b/gcc/ada/gcc-interface/misc.cc @@ -1309,6 +1309,7 @@ gnat_init_ts (void) MARK_TS_COMMON (UNCONSTRAINED_ARRAY_TYPE); MARK_TS_TYPED (UNCONSTRAINED_ARRAY_REF); + MARK_TS_TYPED (LOAD_EXPR); MARK_TS_TYPED (NULL_EXPR); MARK_TS_TYPED (PLUS_NOMOD_EXPR); MARK_TS_TYPED (MINUS_NOMOD_EXPR); diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc index 2d93947..d0ff741 100644 --- a/gcc/ada/gcc-interface/trans.cc +++ b/gcc/ada/gcc-interface/trans.cc @@ -1033,7 +1033,7 @@ fold_constant_decl_in_expr (tree exp) return exp; return fold (build4 (code, TREE_TYPE (exp), op0, TREE_OPERAND (exp, 1), - TREE_OPERAND (exp, 2), NULL_TREE)); + TREE_OPERAND (exp, 2), TREE_OPERAND (exp, 3))); case REALPART_EXPR: case IMAGPART_EXPR: @@ -1671,6 +1671,7 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) tree gnu_type = TREE_TYPE (gnu_prefix); tree gnu_expr, gnu_result_type, gnu_result = error_mark_node; bool prefix_unused = false; + Entity_Id gnat_smo; /* If the input is a NULL_EXPR, make a new one. */ if (TREE_CODE (gnu_prefix) == NULL_EXPR) @@ -1680,6 +1681,14 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) return build1 (NULL_EXPR, gnu_result_type, TREE_OPERAND (gnu_prefix, 0)); } + /* If the input is a LOAD_EXPR of an unconstrained array type, the second + operand contains the storage model object. */ + if (TREE_CODE (gnu_prefix) == LOAD_EXPR + && TREE_CODE (gnu_type) == UNCONSTRAINED_ARRAY_TYPE) + gnat_smo = tree_to_shwi (TREE_OPERAND (gnu_prefix, 1)); + else + gnat_smo = Empty; + switch (attribute) { case Attr_Pred: @@ -1960,7 +1969,11 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) /* Deal with a self-referential size by qualifying the size with the object or returning the maximum size for a type. */ if (TREE_CODE (gnu_prefix) != TYPE_DECL) - gnu_result = SUBSTITUTE_PLACEHOLDER_IN_EXPR (gnu_result, gnu_prefix); + { + gnu_result = SUBSTITUTE_PLACEHOLDER_IN_EXPR (gnu_result, gnu_prefix); + if (Present (gnat_smo)) + gnu_result = INSTANTIATE_LOAD_IN_EXPR (gnu_result, gnat_smo); + } else if (CONTAINS_PLACEHOLDER_P (gnu_result)) gnu_result = max_size (gnu_result, true); @@ -2191,6 +2204,8 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) handling. Note that these attributes could not have been used on an unconstrained array type. */ gnu_result = SUBSTITUTE_PLACEHOLDER_IN_EXPR (gnu_result, gnu_prefix); + if (Present (gnat_smo)) + gnu_result = INSTANTIATE_LOAD_IN_EXPR (gnu_result, gnat_smo); /* Cache the expression we have just computed. Since we want to do it at run time, we force the use of a SAVE_EXPR and let the gimplifier @@ -2351,6 +2366,8 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) /* If this has a PLACEHOLDER_EXPR, qualify it by the object we are handling. */ gnu_result = SUBSTITUTE_PLACEHOLDER_IN_EXPR (gnu_result, gnu_prefix); + if (Present (gnat_smo)) + gnu_result = INSTANTIATE_LOAD_IN_EXPR (gnu_result, gnat_smo); break; } @@ -4356,6 +4373,49 @@ simple_atomic_access_required_p (Node_Id gnat_node, bool *sync) return type == SIMPLE_ATOMIC; } +/* Return the storage model specified by GNAT_NODE, or else Empty. */ + +static Entity_Id +get_storage_model (Node_Id gnat_node) +{ + if (Nkind (gnat_node) == N_Explicit_Dereference + && Has_Designated_Storage_Model_Aspect (Etype (Prefix (gnat_node)))) + return Storage_Model_Object (Etype (Prefix (gnat_node))); + else + return Empty; +} + +/* Compute whether GNAT_NODE requires storage model access and set GNAT_SMO to + the storage model object to be used for it if it does, or else Empty. */ + +static void +get_storage_model_access (Node_Id gnat_node, Entity_Id *gnat_smo) +{ + const Node_Id gnat_parent = Parent (gnat_node); + + /* If we are the prefix of the parent, then the access is above us. */ + if (node_is_component (gnat_parent) && Prefix (gnat_parent) == gnat_node) + { + *gnat_smo = Empty; + return; + } + + while (node_is_component (gnat_node)) + gnat_node = Prefix (gnat_node); + + *gnat_smo = get_storage_model (gnat_node); +} + +/* Return true if GNAT_NODE requires storage model access and, if so, set + GNAT_SMO to the storage model object to be used for it. */ + +static bool +storage_model_access_required_p (Node_Id gnat_node, Entity_Id *gnat_smo) +{ + get_storage_model_access (gnat_node, gnat_smo); + return Present (*gnat_smo); +} + /* Create a temporary variable with PREFIX and TYPE, and return it. */ static tree @@ -4471,11 +4531,14 @@ elaborate_profile (Entity_Id first_formal, Entity_Id result_type) N_Assignment_Statement and the result is to be placed into that object. ATOMIC_ACCESS is the type of atomic access to be used for the assignment to GNU_TARGET. If, in addition, ATOMIC_SYNC is true, then the assignment - to GNU_TARGET requires atomic synchronization. */ + to GNU_TARGET requires atomic synchronization. GNAT_STORAGE_MODEL is the + storage model object to be used for the assignment to GNU_TARGET or Empty + if there is none. */ static tree Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, - atomic_acces_t atomic_access, bool atomic_sync) + atomic_acces_t atomic_access, bool atomic_sync, + Entity_Id gnat_storage_model) { const bool function_call = (Nkind (gnat_node) == N_Function_Call); const bool returning_value = (function_call && !gnu_target); @@ -4507,6 +4570,7 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, Node_Id gnat_actual; atomic_acces_t aa_type; bool aa_sync; + Entity_Id gnat_smo; /* The only way we can make a call via an access type is if GNAT_NAME is an explicit dereference. In that case, get the list of formal args from the @@ -4624,7 +4688,9 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, unconstrained record type with default discriminant, because the return may copy more data than the bit-field can contain. - 5. There is no target and we have misaligned In Out or Out parameters + 5. There is a target which needs to be accessed with a storage model. + + 6. There is no target and we have misaligned In Out or Out parameters passed by reference, because we need to preserve the return value before copying back the parameters. However, in this case, we'll defer creating the temporary, see below. @@ -4654,7 +4720,10 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, && DECL_BIT_FIELD (TREE_OPERAND (gnu_target, 1)) && DECL_SIZE (TREE_OPERAND (gnu_target, 1)) != TYPE_SIZE (TREE_TYPE (gnu_target)) - && type_is_padding_self_referential (gnu_result_type)))) + && type_is_padding_self_referential (gnu_result_type)) + || (gnu_target + && Present (gnat_storage_model) + && Present (Storage_Model_Copy_To (gnat_storage_model))))) { gnu_retval = create_temporary ("R", gnu_result_type); DECL_RETURN_VALUE_P (gnu_retval) = 1; @@ -4725,12 +4794,19 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, = build_compound_expr (TREE_TYPE (gnu_name), init, gnu_name); } - /* If we are passing a non-addressable parameter by reference, pass the - address of a copy. In the In Out or Out case, set up to copy back - out after the call. */ + get_storage_model_access (gnat_actual, &gnat_smo); + + /* If we are passing a non-addressable actual parameter by reference, + pass the address of a copy. Likewise if it needs to be accessed with + a storage model. In the In Out or Out case, set up to copy back out + after the call. */ if (is_by_ref_formal_parm && (gnu_name_type = gnat_to_gnu_type (Etype (gnat_name))) - && !addressable_p (gnu_name, gnu_name_type)) + && (!addressable_p (gnu_name, gnu_name_type) + || (Present (gnat_smo) + && (Present (Storage_Model_Copy_From (gnat_smo)) + || (!in_param + && Present (Storage_Model_Copy_To (gnat_smo))))))) { tree gnu_orig = gnu_name, gnu_temp, gnu_stmt; @@ -4801,20 +4877,40 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, } /* Create an explicit temporary holding the copy. */ + tree gnu_temp_type; + if (Nkind (gnat_actual) == N_Explicit_Dereference + && Present (Actual_Designated_Subtype (gnat_actual))) + gnu_temp_type + = gnat_to_gnu_type (Actual_Designated_Subtype (gnat_actual)); + else + gnu_temp_type = TREE_TYPE (gnu_name); + /* Do not initialize it for the _Init parameter of an initialization procedure since no data is meant to be passed in. */ if (Ekind (gnat_formal) == E_Out_Parameter && Is_Entity_Name (gnat_subprog) && Is_Init_Proc (Entity (gnat_subprog))) - gnu_name = gnu_temp = create_temporary ("A", TREE_TYPE (gnu_name)); + gnu_name = gnu_temp = create_temporary ("A", gnu_temp_type); /* Initialize it on the fly like for an implicit temporary in the other cases, as we don't necessarily have a statement list. */ else { - gnu_temp = create_init_temporary ("A", gnu_name, &gnu_stmt, - gnat_actual); - gnu_name = build_compound_expr (TREE_TYPE (gnu_name), gnu_stmt, + if (Present (gnat_smo) + && Present (Storage_Model_Copy_From (gnat_smo))) + { + gnu_temp = create_temporary ("A", gnu_temp_type); + gnu_stmt + = build_storage_model_load (gnat_smo, gnu_temp, + gnu_name, + TYPE_SIZE_UNIT (gnu_temp_type)); + set_expr_location_from_node (gnu_stmt, gnat_actual); + } + else + gnu_temp = create_init_temporary ("A", gnu_name, &gnu_stmt, + gnat_actual); + + gnu_name = build_compound_expr (gnu_temp_type, gnu_stmt, gnu_temp); } @@ -4830,8 +4926,16 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, (TREE_OPERAND (TREE_OPERAND (gnu_orig, 1), 1))) gnu_orig = TREE_OPERAND (gnu_orig, 2); - gnu_stmt - = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_orig, gnu_temp); + if (Present (gnat_smo) + && Present (Storage_Model_Copy_To (gnat_smo))) + gnu_stmt + = build_storage_model_store (gnat_smo, gnu_orig, + gnu_temp, + TYPE_SIZE_UNIT (gnu_temp_type)); + else + gnu_stmt + = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_orig, + gnu_temp); set_expr_location_from_node (gnu_stmt, gnat_node); append_to_statement_list (gnu_stmt, &gnu_after_list); @@ -4842,12 +4946,19 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, tree gnu_actual = gnu_name; /* If atomic access is required for an In or In Out actual parameter, - build the atomic load. */ + build the atomic load. Or else, if storage model access is required, + build the special load. */ if (is_true_formal_parm && !is_by_ref_formal_parm - && Ekind (gnat_formal) != E_Out_Parameter - && simple_atomic_access_required_p (gnat_actual, &aa_sync)) - gnu_actual = build_atomic_load (gnu_actual, aa_sync); + && Ekind (gnat_formal) != E_Out_Parameter) + { + if (simple_atomic_access_required_p (gnat_actual, &aa_sync)) + gnu_actual = build_atomic_load (gnu_actual, aa_sync); + + else if (Present (gnat_smo) + && Present (Storage_Model_Copy_From (gnat_smo))) + gnu_actual = build_storage_model_load (gnat_smo, gnu_actual); + } /* If this was a procedure call, we may not have removed any padding. So do it here for the part we will use as an input, if any. */ @@ -5211,6 +5322,7 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, } get_atomic_access (gnat_actual, &aa_type, &aa_sync); + get_storage_model_access (gnat_actual, &gnat_smo); /* If an outer atomic access is required for an actual parameter, build the load-modify-store sequence. */ @@ -5224,6 +5336,13 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, gnu_result = build_atomic_store (gnu_actual, gnu_result, aa_sync); + /* Or else, if a storage model access is required, build the special + store. */ + else if (Present (gnat_smo) + && Present (Storage_Model_Copy_To (gnat_smo))) + gnu_result + = build_storage_model_store (gnat_smo, gnu_actual, gnu_result); + /* Otherwise build a regular assignment. */ else gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE, @@ -5298,6 +5417,11 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, = build_load_modify_store (gnu_target, gnu_call, gnat_node); else if (atomic_access == SIMPLE_ATOMIC) gnu_call = build_atomic_store (gnu_target, gnu_call, atomic_sync); + else if (Present (gnat_storage_model) + && Present (Storage_Model_Copy_To (gnat_storage_model))) + gnu_call + = build_storage_model_store (gnat_storage_model, gnu_target, + gnu_call); else gnu_call = build_binary_op (op_code, NULL_TREE, gnu_target, gnu_call); @@ -6104,6 +6228,7 @@ gnat_to_gnu (Node_Id gnat_node) atomic_acces_t aa_type; bool went_into_elab_proc; bool aa_sync; + Entity_Id gnat_smo; /* Save node number for error message and set location information. */ if (Sloc (gnat_node) > No_Location) @@ -6376,7 +6501,7 @@ gnat_to_gnu (Node_Id gnat_node) gnu_result = Call_to_gnu (Prefix (Expression (gnat_node)), &gnu_result_type, gnu_result, - NOT_ATOMIC, false); + NOT_ATOMIC, false, Empty); break; } @@ -6522,15 +6647,25 @@ gnat_to_gnu (Node_Id gnat_node) if (simple_atomic_access_required_p (gnat_node, &aa_sync) && !present_in_lhs_or_actual_p (gnat_node)) gnu_result = build_atomic_load (gnu_result, aa_sync); + + /* If storage model access is required on the RHS, build the load. */ + else if (storage_model_access_required_p (gnat_node, &gnat_smo) + && Present (Storage_Model_Copy_From (gnat_smo)) + && !present_in_lhs_or_actual_p (gnat_node)) + gnu_result = build_storage_model_load (gnat_smo, gnu_result); break; case N_Indexed_Component: { - tree gnu_array_object = gnat_to_gnu ((Prefix (gnat_node))); + const Entity_Id gnat_array_object = Prefix (gnat_node); + tree gnu_array_object = gnat_to_gnu (gnat_array_object); tree gnu_type; int ndim, i; Node_Id *gnat_expr_array; + /* Get the storage model of the array. */ + gnat_smo = get_storage_model (gnat_array_object); + gnu_array_object = maybe_padded_object (gnu_array_object); gnu_array_object = maybe_unconstrained_array (gnu_array_object); @@ -6582,6 +6717,9 @@ gnat_to_gnu (Node_Id gnat_node) gnu_result = build_binary_op (ARRAY_REF, NULL_TREE, gnu_result, gnu_expr); + + if (Present (gnat_smo)) + instantiate_load_in_array_ref (gnu_result, gnat_smo); } gnu_result_type = get_unpadded_type (Etype (gnat_node)); @@ -6590,18 +6728,28 @@ gnat_to_gnu (Node_Id gnat_node) if (simple_atomic_access_required_p (gnat_node, &aa_sync) && !present_in_lhs_or_actual_p (gnat_node)) gnu_result = build_atomic_load (gnu_result, aa_sync); + + /* If storage model access is required on the RHS, build the load. */ + else if (storage_model_access_required_p (gnat_node, &gnat_smo) + && Present (Storage_Model_Copy_From (gnat_smo)) + && !present_in_lhs_or_actual_p (gnat_node)) + gnu_result = build_storage_model_load (gnat_smo, gnu_result); } break; case N_Slice: { - tree gnu_array_object = gnat_to_gnu (Prefix (gnat_node)); + const Entity_Id gnat_array_object = Prefix (gnat_node); + tree gnu_array_object = gnat_to_gnu (gnat_array_object); - gnu_result_type = get_unpadded_type (Etype (gnat_node)); + /* Get the storage model of the array. */ + gnat_smo = get_storage_model (gnat_array_object); gnu_array_object = maybe_padded_object (gnu_array_object); gnu_array_object = maybe_unconstrained_array (gnu_array_object); + gnu_result_type = get_unpadded_type (Etype (gnat_node)); + gnu_expr = TYPE_MIN_VALUE (TYPE_DOMAIN (gnu_result_type)); gnu_expr = maybe_character_value (gnu_expr); @@ -6614,6 +6762,15 @@ gnat_to_gnu (Node_Id gnat_node) gnu_result = build_binary_op (ARRAY_RANGE_REF, gnu_result_type, gnu_array_object, gnu_expr); + + if (Present (gnat_smo)) + instantiate_load_in_array_ref (gnu_result, gnat_smo); + + /* If storage model access is required on the RHS, build the load. */ + if (storage_model_access_required_p (gnat_node, &gnat_smo) + && Present (Storage_Model_Copy_From (gnat_smo)) + && !present_in_lhs_or_actual_p (gnat_node)) + gnu_result = build_storage_model_load (gnat_smo, gnu_result); } break; @@ -6691,6 +6848,12 @@ gnat_to_gnu (Node_Id gnat_node) if (simple_atomic_access_required_p (gnat_node, &aa_sync) && !present_in_lhs_or_actual_p (gnat_node)) gnu_result = build_atomic_load (gnu_result, aa_sync); + + /* If storage model access is required on the RHS, build the load. */ + else if (storage_model_access_required_p (gnat_node, &gnat_smo) + && Present (Storage_Model_Copy_From (gnat_smo)) + && !present_in_lhs_or_actual_p (gnat_node)) + gnu_result = build_storage_model_load (gnat_smo, gnu_result); } break; @@ -7224,9 +7387,10 @@ gnat_to_gnu (Node_Id gnat_node) else if (Nkind (Expression (gnat_node)) == N_Function_Call) { get_atomic_access (Name (gnat_node), &aa_type, &aa_sync); + get_storage_model_access (Name (gnat_node), &gnat_smo); gnu_result = Call_to_gnu (Expression (gnat_node), &gnu_result_type, gnu_lhs, - aa_type, aa_sync); + aa_type, aa_sync, gnat_smo); } /* Otherwise we need to build the assignment statement manually. */ @@ -7264,6 +7428,7 @@ gnat_to_gnu (Node_Id gnat_node) gigi_checking_assert (!Do_Range_Check (gnat_expr)); get_atomic_access (Name (gnat_node), &aa_type, &aa_sync); + get_storage_model_access (Name (gnat_node), &gnat_smo); /* If an outer atomic access is required on the LHS, build the load- modify-store sequence. */ @@ -7275,6 +7440,43 @@ gnat_to_gnu (Node_Id gnat_node) else if (aa_type == SIMPLE_ATOMIC) gnu_result = build_atomic_store (gnu_lhs, gnu_rhs, aa_sync); + /* Or else, if a storage model access is required, build the special + store. */ + else if (Present (gnat_smo) + && Present (Storage_Model_Copy_To (gnat_smo))) + { + tree t = remove_conversions (gnu_rhs, false); + + /* If a storage model load is present on the RHS then instantiate + the temporary associated with it now, lest it be of variable + size and thus could not be instantiated by gimplification. */ + if (TREE_CODE (t) == LOAD_EXPR) + { + t = TREE_OPERAND (t, 1); + gcc_assert (TREE_CODE (t) == CALL_EXPR); + + tree elem + = build_nonstandard_integer_type (BITS_PER_UNIT, 1); + tree size = fold_convert (sizetype, CALL_EXPR_ARG (t, 3)); + tree index = build_index_type (size); + tree temp + = create_temporary ("L", build_array_type (elem, index)); + tree arg = CALL_EXPR_ARG (t, 1); + CALL_EXPR_ARG (t, 1) + = build_unary_op (ADDR_EXPR, TREE_TYPE (arg), temp); + + start_stmt_group (); + add_stmt (t); + t = build_storage_model_store (gnat_smo, gnu_lhs, temp); + add_stmt (t); + gnu_result = end_stmt_group (); + } + + else + gnu_result + = build_storage_model_store (gnat_smo, gnu_lhs, gnu_rhs); + } + /* Or else, use memset when the conditions are met. This has already been validated by Aggr_Assignment_OK_For_Backend in the front-end and the RHS is thus guaranteed to be of the appropriate form. */ @@ -7307,10 +7509,27 @@ gnat_to_gnu (Node_Id gnat_node) gnat_node); } - /* Otherwise build a regular assignment. */ else - gnu_result - = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_lhs, gnu_rhs); + { + tree t = remove_conversions (gnu_rhs, false); + + /* If a storage model load is present on the RHS, then elide the + temporary associated with it. */ + if (TREE_CODE (t) == LOAD_EXPR) + { + gnu_result = TREE_OPERAND (t, 1); + gcc_assert (TREE_CODE (gnu_result) == CALL_EXPR); + + tree arg = CALL_EXPR_ARG (gnu_result, 1); + CALL_EXPR_ARG (gnu_result, 1) + = build_unary_op (ADDR_EXPR, TREE_TYPE (arg), gnu_lhs); + } + + /* Otherwise build a regular assignment. */ + else + gnu_result + = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_lhs, gnu_rhs); + } /* If the assignment type is a regular array and the two sides are not completely disjoint, play safe and use memmove. But don't do @@ -7624,7 +7843,7 @@ gnat_to_gnu (Node_Id gnat_node) case N_Function_Call: case N_Procedure_Call_Statement: gnu_result = Call_to_gnu (gnat_node, &gnu_result_type, NULL_TREE, - NOT_ATOMIC, false); + NOT_ATOMIC, false, Empty); break; /************************/ @@ -8023,10 +8242,14 @@ gnat_to_gnu (Node_Id gnat_node) if (!type_annotate_only) { - tree gnu_ptr, gnu_ptr_type, gnu_obj_type, gnu_actual_obj_type; - const Entity_Id gnat_desig_type = Designated_Type (Underlying_Type (Etype (gnat_temp))); + const Entity_Id gnat_pool = Storage_Pool (gnat_node); + const bool pool_is_storage_model + = Present (gnat_pool) + && Has_Storage_Model_Type_Aspect (Etype (gnat_pool)) + && Present (Storage_Model_Copy_From (gnat_pool)); + tree gnu_ptr, gnu_ptr_type, gnu_obj_type, gnu_actual_obj_type; /* Make sure the designated type is complete before dereferencing, in case it is a Taft Amendment type. */ @@ -8087,12 +8310,13 @@ gnat_to_gnu (Node_Id gnat_node) tree gnu_size = TYPE_SIZE_UNIT (gnu_actual_obj_type); gnu_size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (gnu_size, gnu_ptr); + if (pool_is_storage_model) + gnu_size = INSTANTIATE_LOAD_IN_EXPR (gnu_size, gnat_pool); gnu_result = build_call_alloc_dealloc (gnu_ptr, gnu_size, gnu_obj_type, Procedure_To_Call (gnat_node), - Storage_Pool (gnat_node), - gnat_node); + gnat_pool, gnat_node); } break; @@ -8300,7 +8524,7 @@ gnat_to_gnu (Node_Id gnat_node) && return_type_with_variable_size_p (TREE_TYPE (gnu_result))) ; - else if (TREE_CODE (gnu_result) == UNCONSTRAINED_ARRAY_REF + else if (TREE_CODE (TREE_TYPE (gnu_result)) == UNCONSTRAINED_ARRAY_TYPE && Present (Parent (gnat_node)) && Nkind (Parent (gnat_node)) == N_Attribute_Reference && lvalue_required_for_attribute_p (Parent (gnat_node))) @@ -8739,7 +8963,7 @@ gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p, avoid blocking concatenation in the caller when it is inlined. */ for (int i = 0; i < call_expr_nargs (expr); i++) { - tree arg = *(CALL_EXPR_ARGP (expr) + i); + tree arg = CALL_EXPR_ARG (expr, i); if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg) @@ -8751,7 +8975,7 @@ gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p, if (TREE_CODE (t) == ADDR_EXPR) t = TREE_OPERAND (t, 0); if (TREE_CODE (t) != STRING_CST) - *(CALL_EXPR_ARGP (expr) + i) = tree_output_constant_def (arg); + CALL_EXPR_ARG (expr, i) = tree_output_constant_def (arg); } } break; @@ -8816,11 +9040,21 @@ gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p, TREE_NO_WARNING (expr) = TREE_NO_WARNING (op); break; - case UNCONSTRAINED_ARRAY_REF: - /* We should only do this if we are just elaborating for side effects, - but we can't know that yet. */ - *expr_p = TREE_OPERAND (*expr_p, 0); - return GS_OK; + case LOAD_EXPR: + { + tree new_var = create_tmp_var (type, "L"); + TREE_ADDRESSABLE (new_var) = 1; + + tree init = TREE_OPERAND (expr, 1); + gcc_assert (TREE_CODE (init) == CALL_EXPR); + tree arg = CALL_EXPR_ARG (init, 1); + CALL_EXPR_ARG (init, 1) + = build_unary_op (ADDR_EXPR, TREE_TYPE (arg), new_var); + gimplify_and_add (init, pre_p); + + *expr_p = new_var; + return GS_OK; + } case VIEW_CONVERT_EXPR: op = TREE_OPERAND (expr, 0); @@ -8832,10 +9066,10 @@ gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p, && AGGREGATE_TYPE_P (TREE_TYPE (op)) && !AGGREGATE_TYPE_P (type)) { - tree mod, new_var = create_tmp_var_raw (TREE_TYPE (op), "C"); + tree new_var = create_tmp_var_raw (TREE_TYPE (op), "C"); gimple_add_tmp_var (new_var); - mod = build2 (INIT_EXPR, TREE_TYPE (new_var), new_var, op); + tree mod = build2 (INIT_EXPR, TREE_TYPE (new_var), new_var, op); gimplify_and_add (mod, pre_p); TREE_OPERAND (expr, 0) = new_var; @@ -8843,6 +9077,12 @@ gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p, } break; + case UNCONSTRAINED_ARRAY_REF: + /* We should only do this if we are just elaborating for side effects, + but we can't know that yet. */ + *expr_p = TREE_OPERAND (expr, 0); + return GS_OK; + default: break; } diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc index 3d4c1c1..5942de1 100644 --- a/gcc/ada/gcc-interface/utils.cc +++ b/gcc/ada/gcc-interface/utils.cc @@ -5256,6 +5256,13 @@ maybe_unconstrained_array (tree exp) } } + else if (code == LOAD_EXPR) + { + const Entity_Id gnat_smo = tree_to_shwi (TREE_OPERAND (exp, 1)); + tree t = maybe_unconstrained_array (TREE_OPERAND (exp, 0)); + exp = build_storage_model_load (gnat_smo, t); + } + else if (code == NULL_EXPR) exp = build1 (NULL_EXPR, TREE_TYPE (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (type)))), diff --git a/gcc/ada/gcc-interface/utils2.cc b/gcc/ada/gcc-interface/utils2.cc index 4c66a93..ef81f8d 100644 --- a/gcc/ada/gcc-interface/utils2.cc +++ b/gcc/ada/gcc-interface/utils2.cc @@ -2401,6 +2401,10 @@ tree build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc, Entity_Id gnat_pool, Node_Id gnat_node, bool ignore_init_type) { + const bool pool_is_storage_model + = Present (gnat_pool) + && Has_Storage_Model_Type_Aspect (Etype (gnat_pool)) + && Present (Storage_Model_Copy_To (gnat_pool)); tree size, storage, storage_deref, storage_init; /* If the initializer, if present, is a NULL_EXPR, just return a new one. */ @@ -2433,6 +2437,7 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc, get_identifier ("ALLOC"), false); tree template_type = TREE_TYPE (TYPE_FIELDS (storage_type)); tree storage_ptr_type = build_pointer_type (storage_type); + tree lhs, rhs; size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_SIZE_UNIT (storage_type), init); @@ -2459,17 +2464,21 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc, build_template (template_type, type, init)); CONSTRUCTOR_APPEND_ELT (v, DECL_CHAIN (TYPE_FIELDS (storage_type)), init); - storage_init - = build_binary_op (INIT_EXPR, NULL_TREE, storage_deref, - gnat_build_constructor (storage_type, v)); + + lhs = storage_deref; + rhs = gnat_build_constructor (storage_type, v); } else - storage_init - = build_binary_op (INIT_EXPR, NULL_TREE, - build_component_ref (storage_deref, - TYPE_FIELDS (storage_type), - false), - build_template (template_type, type, NULL_TREE)); + { + lhs = build_component_ref (storage_deref, TYPE_FIELDS (storage_type), + false); + rhs = build_template (template_type, type, NULL_TREE); + } + + if (pool_is_storage_model) + storage_init = build_storage_model_store (gnat_pool, lhs, rhs); + else + storage_init = build_binary_op (INIT_EXPR, NULL_TREE, lhs, rhs); return build2 (COMPOUND_EXPR, result_type, storage_init, convert (result_type, storage)); @@ -2509,14 +2518,263 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc, storage = gnat_protect_expr (storage); storage_deref = build_unary_op (INDIRECT_REF, NULL_TREE, storage); TREE_THIS_NOTRAP (storage_deref) = 1; - storage_init - = build_binary_op (INIT_EXPR, NULL_TREE, storage_deref, init); + if (pool_is_storage_model) + storage_init + = build_storage_model_store (gnat_pool, storage_deref, init); + else + storage_init + = build_binary_op (INIT_EXPR, NULL_TREE, storage_deref, init); return build2 (COMPOUND_EXPR, result_type, storage_init, storage); } return storage; } +/* Build a call to a copy procedure of a storage model given by an object. + DEST, SRC and SIZE are as for a call to memcpy. GNAT_SMO is the entity + for the storage model object and COPY_TO says which procedure to use. */ + +static tree +build_storage_model_copy (Entity_Id gnat_smo, tree dest, tree src, tree size, + bool copy_to) +{ + const Entity_Id gnat_copy_proc + = copy_to + ? Storage_Model_Copy_To (gnat_smo) + : Storage_Model_Copy_From (gnat_smo); + tree gnu_copy_proc = gnat_to_gnu (gnat_copy_proc); + tree gnu_param_type_list = TYPE_ARG_TYPES (TREE_TYPE (gnu_copy_proc)); + tree t1 = TREE_VALUE (gnu_param_type_list); + tree t2 = TREE_VALUE (TREE_CHAIN (gnu_param_type_list)); + tree t3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (gnu_param_type_list))); + tree t4 + = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (gnu_param_type_list)))); + + return + build_call_n_expr (gnu_copy_proc, + 4, + build_unary_op (ADDR_EXPR, t1, gnat_to_gnu (gnat_smo)), + build_unary_op (ADDR_EXPR, t2, dest), + build_unary_op (ADDR_EXPR, t3, src), + convert (t4, size)); +} + +/* Build a load of SRC using the storage model of GNAT_SMO. */ + +tree +build_storage_model_load (Entity_Id gnat_smo, tree src) +{ + tree ret = build2 (LOAD_EXPR, TREE_TYPE (src), src, NULL_TREE); + + /* Unconstrained array references have no size so we need to store the + storage object model for future processing by the machinery. */ + if (TREE_CODE (src) == UNCONSTRAINED_ARRAY_REF) + TREE_OPERAND (ret, 1) = build_int_cst (integer_type_node, gnat_smo); + else + TREE_OPERAND (ret, 1) = build_storage_model_load (gnat_smo, src, src); + + return ret; +} + +/* Build a load of SRC into DEST using the storage model of GNAT_SMO. + If SIZE is specified, use it, otherwise use the size of SRC. */ + +tree +build_storage_model_load (Entity_Id gnat_smo, tree dest, tree src, tree size) +{ + gcc_assert (TREE_CODE (src) != LOAD_EXPR); + + if (!size) + { + size = TYPE_SIZE_UNIT (TREE_TYPE (src)); + size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, src); + size = INSTANTIATE_LOAD_IN_EXPR (size, gnat_smo); + } + + return build_storage_model_copy (gnat_smo, dest, src, size, false); +} + +/* Build a store of SRC into DEST using the storage model of GNAT_SMO. + If SIZE is specified, use it, otherwise use the size of DEST. */ + +tree +build_storage_model_store (Entity_Id gnat_smo, tree dest, tree src, tree size) +{ + gcc_assert (TREE_CODE (src) != LOAD_EXPR); + + if (!size) + { + size = TYPE_SIZE_UNIT (TREE_TYPE (dest)); + size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, dest); + size = INSTANTIATE_LOAD_IN_EXPR (size, gnat_smo); + } + + return build_storage_model_copy (gnat_smo, dest, src, size, true); +} + +/* Given a tree EXP, instantiate occurrences of LOAD_EXPR in it and associate + them with the storage model of GNAT_SMO. */ + +tree +instantiate_load_in_expr (tree exp, Entity_Id gnat_smo) +{ + const enum tree_code code = TREE_CODE (exp); + tree type = TREE_TYPE (exp); + tree op0, op1, op2, op3; + tree new_tree; + + /* We handle TREE_LIST and COMPONENT_REF separately. */ + if (code == TREE_LIST) + { + op0 = INSTANTIATE_LOAD_IN_EXPR (TREE_CHAIN (exp), gnat_smo); + op1 = INSTANTIATE_LOAD_IN_EXPR (TREE_VALUE (exp), gnat_smo); + if (op0 == TREE_CHAIN (exp) && op1 == TREE_VALUE (exp)) + return exp; + + return tree_cons (TREE_PURPOSE (exp), op1, op0); + } + else if (code == COMPONENT_REF) + { + /* The field. */ + op1 = TREE_OPERAND (exp, 1); + + /* If it is a discriminant or equivalent, a LOAD_EXPR is needed. */ + if (DECL_DISCRIMINANT_NUMBER (op1)) + return build_storage_model_load (gnat_smo, exp); + + op0 = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (exp, 0), gnat_smo); + if (op0 == TREE_OPERAND (exp, 0)) + return exp; + + new_tree = fold_build3 (COMPONENT_REF, type, op0, op1, NULL_TREE); + } + else + switch (TREE_CODE_CLASS (code)) + { + case tcc_constant: + case tcc_declaration: + return exp; + + case tcc_expression: + if (code == LOAD_EXPR) + return exp; + + /* Fall through. */ + + case tcc_exceptional: + case tcc_unary: + case tcc_binary: + case tcc_comparison: + case tcc_reference: + switch (TREE_CODE_LENGTH (code)) + { + case 0: + return exp; + + case 1: + op0 = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (exp, 0), gnat_smo); + if (op0 == TREE_OPERAND (exp, 0)) + return exp; + + new_tree = fold_build1 (code, type, op0); + break; + + case 2: + op0 = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (exp, 0), gnat_smo); + op1 = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (exp, 1), gnat_smo); + + if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)) + return exp; + + new_tree = fold_build2 (code, type, op0, op1); + break; + + case 3: + op0 = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (exp, 0), gnat_smo); + op1 = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (exp, 1), gnat_smo); + op2 = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (exp, 2), gnat_smo); + + if (op0 == TREE_OPERAND (exp, 0) + && op1 == TREE_OPERAND (exp, 1) + && op2 == TREE_OPERAND (exp, 2)) + return exp; + + new_tree = fold_build3 (code, type, op0, op1, op2); + break; + + case 4: + op0 = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (exp, 0), gnat_smo); + op1 = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (exp, 1), gnat_smo); + op2 = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (exp, 2), gnat_smo); + op3 = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (exp, 3), gnat_smo); + + if (op0 == TREE_OPERAND (exp, 0) + && op1 == TREE_OPERAND (exp, 1) + && op2 == TREE_OPERAND (exp, 2) + && op3 == TREE_OPERAND (exp, 3)) + return exp; + + new_tree = fold (build4 (code, type, op0, op1, op2, op3)); + break; + + default: + gcc_unreachable (); + } + break; + + case tcc_vl_exp: + { + gcc_assert (code == CALL_EXPR); + + const int n = call_expr_nargs (exp); + gcc_assert (n > 0); + tree *argarray = XALLOCAVEC (tree, n); + for (int i = 0; i < n; i++) + argarray[i] + = INSTANTIATE_LOAD_IN_EXPR (CALL_EXPR_ARG (exp, i), gnat_smo); + + for (int i = 0; i < n; i++) + if (argarray[i] != CALL_EXPR_ARG (exp, i)) + return build_call_array (type, CALL_EXPR_FN (exp), n, argarray); + + return exp; + } + + default: + gcc_unreachable (); + } + + TREE_READONLY (new_tree) |= TREE_READONLY (exp); + + if (code == INDIRECT_REF || code == ARRAY_REF || code == ARRAY_RANGE_REF) + TREE_THIS_NOTRAP (new_tree) |= TREE_THIS_NOTRAP (exp); + + return new_tree; +} + +/* Given an array or slice reference, instantiate occurrences of LOAD_EXPR in + it and associate them with the storage model of GNAT_SMO. */ + +void +instantiate_load_in_array_ref (tree ref, Entity_Id gnat_smo) +{ + tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (ref, 0))); + tree elem_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (ref, 0))); + + TREE_OPERAND (ref, 2) + = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MIN_VALUE (domain_type), ref); + TREE_OPERAND (ref, 2) + = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (ref, 2), gnat_smo); + + TREE_OPERAND (ref, 3) + = size_binop (EXACT_DIV_EXPR, + SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_SIZE_UNIT (elem_type), + ref), + size_int (TYPE_ALIGN_UNIT (elem_type))); + TREE_OPERAND (ref, 3) + = INSTANTIATE_LOAD_IN_EXPR (TREE_OPERAND (ref, 3), gnat_smo); +} + /* Indicate that we need to take the address of T and that it therefore should not be allocated in a register. Return true if successful. */ @@ -2816,7 +3074,7 @@ gnat_rewrite_reference (tree ref, rewrite_fn func, void *data, tree *init) gnat_rewrite_reference (TREE_OPERAND (ref, 0), func, data, init), func (TREE_OPERAND (ref, 1), data), - TREE_OPERAND (ref, 2), NULL_TREE); + TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3)); break; case COMPOUND_EXPR: @@ -2901,9 +3159,6 @@ get_inner_constant_reference (tree exp) case ARRAY_REF: case ARRAY_RANGE_REF: { - if (TREE_OPERAND (exp, 2)) - return NULL_TREE; - tree array_type = TREE_TYPE (TREE_OPERAND (exp, 0)); if (!TREE_CONSTANT (TREE_OPERAND (exp, 1)) || !TREE_CONSTANT (TYPE_MIN_VALUE (TYPE_DOMAIN (array_type))) @@ -3044,8 +3299,13 @@ gnat_invariant_expr (tree expr) case ARRAY_REF: case ARRAY_RANGE_REF: - if (!TREE_CONSTANT (TREE_OPERAND (t, 1)) || TREE_OPERAND (t, 2)) - return NULL_TREE; + { + tree array_type = TREE_TYPE (TREE_OPERAND (t, 0)); + if (!TREE_CONSTANT (TREE_OPERAND (t, 1)) + || !TREE_CONSTANT (TYPE_MIN_VALUE (TYPE_DOMAIN (array_type))) + || !TREE_CONSTANT (TYPE_SIZE_UNIT (TREE_TYPE (array_type)))) + return NULL_TREE; + } break; case BIT_FIELD_REF: -- cgit v1.1 From 85333b9265720fc4e49397301cb16324d2b89aa7 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 6 Oct 2022 11:20:16 +0200 Subject: tree-optimization/107107 - tail-merging VN wrong-code The following fixes an unintended(?) side-effect of the special MODIFY_EXPR expression entries we add for tail-merging during VN. We shouldn't value-number the virtual operand differently here. PR tree-optimization/107107 * tree-ssa-sccvn.cc (visit_reference_op_store): Do not affect value-numbering when doing the tail merging MODIFY_EXPR lookup. * gcc.dg/pr107107.c: New testcase. --- gcc/testsuite/gcc.dg/pr107107.c | 25 +++++++++++++++++++++++++ gcc/tree-ssa-sccvn.cc | 17 +++-------------- 2 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr107107.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/pr107107.c b/gcc/testsuite/gcc.dg/pr107107.c new file mode 100644 index 0000000..5ad6a63 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr107107.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -ftree-tail-merge" } */ + +static inline void set_longish(int is_long_long, void *p, long x) +{ + if (is_long_long) + *(long long*)p = x; + else + *(long*)p = x; +} +static long test(long long *p, int index, int mode) +{ + *p = 1; + set_longish(mode, p+index, 2); + return *p; +} +long (*volatile vtest)(long long*, int, int) = test; +int main(void) +{ + long long x; + long result = vtest(&x, 0, 1); + if (result != 2 || x != 2) + __builtin_abort (); + return 0; +} diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index 2cc2c0e..3748440 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -5718,19 +5718,6 @@ visit_reference_op_store (tree lhs, tree op, gimple *stmt) if (!resultsame) { - /* Only perform the following when being called from PRE - which embeds tail merging. */ - if (default_vn_walk_kind == VN_WALK) - { - assign = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, op); - vn_reference_lookup (assign, vuse, VN_NOWALK, &vnresult, false); - if (vnresult) - { - VN_INFO (vdef)->visited = true; - return set_ssa_val_to (vdef, vnresult->result_vdef); - } - } - if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "No store match\n"); @@ -5755,7 +5742,9 @@ visit_reference_op_store (tree lhs, tree op, gimple *stmt) if (default_vn_walk_kind == VN_WALK) { assign = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, op); - vn_reference_insert (assign, lhs, vuse, vdef); + vn_reference_lookup (assign, vuse, VN_NOWALK, &vnresult, false); + if (!vnresult) + vn_reference_insert (assign, lhs, vuse, vdef); } } else -- cgit v1.1 From b1cfbccc41de6aec950c0f662e7e85ab34bfff8a Mon Sep 17 00:00:00 2001 From: Philipp Tomsich Date: Mon, 3 Oct 2022 21:59:50 +0200 Subject: aarch64: fix off-by-one in reading cpuinfo Fixes: 341573406b39 Don't subtract one from the result of strnlen() when trying to point to the first character after the current string. This issue would cause individual characters (where the 128 byte buffers are stitched together) to be lost. gcc/ChangeLog: * config/aarch64/driver-aarch64.cc (readline): Fix off-by-one. gcc/testsuite/ChangeLog: * gcc.target/aarch64/cpunative/info_18: New test. * gcc.target/aarch64/cpunative/native_cpu_18.c: New test. Signed-off-by: Philipp Tomsich --- gcc/config/aarch64/driver-aarch64.cc | 4 ++-- gcc/testsuite/gcc.target/aarch64/cpunative/info_18 | 8 ++++++++ .../gcc.target/aarch64/cpunative/native_cpu_18.c | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/cpunative/info_18 create mode 100644 gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_18.c (limited to 'gcc') diff --git a/gcc/config/aarch64/driver-aarch64.cc b/gcc/config/aarch64/driver-aarch64.cc index 52ff537..2ae47c0 100644 --- a/gcc/config/aarch64/driver-aarch64.cc +++ b/gcc/config/aarch64/driver-aarch64.cc @@ -203,9 +203,9 @@ readline (FILE *f) return std::string (); /* If we're not at the end of the line then override the \0 added by fgets. */ - last = strnlen (buf, size) - 1; + last = strnlen (buf, size); } - while (!feof (f) && buf[last] != '\n'); + while (!feof (f) && last > 0 && buf[last - 1] != '\n'); std::string result (buf); free (buf); diff --git a/gcc/testsuite/gcc.target/aarch64/cpunative/info_18 b/gcc/testsuite/gcc.target/aarch64/cpunative/info_18 new file mode 100644 index 0000000..25061a4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/cpunative/info_18 @@ -0,0 +1,8 @@ +processor : 0 +BogoMIPS : 2000.00 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm ssbs sb dcpodp flagm2 frint i8mm bf16 rng ecv +CPU implementer : 0xc0 +CPU architecture: 8 +CPU variant : 0x0 +CPU part : 0xac3 +CPU revision : 0 diff --git a/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_18.c b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_18.c new file mode 100644 index 0000000..b5f0a30 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/cpunative/native_cpu_18.c @@ -0,0 +1,15 @@ +/* { dg-do compile { target { { aarch64*-*-linux*} && native } } } */ +/* { dg-set-compiler-env-var GCC_CPUINFO "$srcdir/gcc.target/aarch64/cpunative/info_18" } */ +/* { dg-additional-options "-mcpu=native" } */ + +int main() +{ + return 0; +} + +/* { dg-final { scan-assembler {\.arch armv8.6-a\+crc\+fp16\+aes\+sha3\+rng} } } */ + +/* Test one where the boundary of buffer size would overwrite the last + character read when stitching the fgets-calls together. With the + test data provided, this would truncate the 'sha512' into 'ha512' + (dropping the 'sha3' feature). */ -- cgit v1.1 From db2f5d661239737157cf131de7d4df1c17d8d88d Mon Sep 17 00:00:00 2001 From: Philipp Tomsich Date: Mon, 8 Aug 2022 00:30:52 +0200 Subject: aarch64: update Ampere-1 core definition This brings the extensions detected by -mcpu=native on Ampere-1 systems in sync with the defaults generated for -mcpu=ampere1. Note that some early kernel versions on Ampere1 may misreport the presence of PAUTH and PREDRES (i.e., -mcpu=native will add 'nopauth' and 'nopredres'). gcc/ChangeLog: * config/aarch64/aarch64-cores.def (AARCH64_CORE): Update Ampere-1 core entry. Signed-off-by: Philipp Tomsich --- gcc/config/aarch64/aarch64-cores.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64-cores.def b/gcc/config/aarch64/aarch64-cores.def index b50628d..e9a4b62 100644 --- a/gcc/config/aarch64/aarch64-cores.def +++ b/gcc/config/aarch64/aarch64-cores.def @@ -69,7 +69,7 @@ AARCH64_CORE("thunderxt81", thunderxt81, thunderx, V8A, (CRC, CRYPTO), thu AARCH64_CORE("thunderxt83", thunderxt83, thunderx, V8A, (CRC, CRYPTO), thunderx, 0x43, 0x0a3, -1) /* Ampere Computing ('\xC0') cores. */ -AARCH64_CORE("ampere1", ampere1, cortexa57, V8_6A, (), ampere1, 0xC0, 0xac3, -1) +AARCH64_CORE("ampere1", ampere1, cortexa57, V8_6A, (F16, RNG, AES, SHA3), ampere1, 0xC0, 0xac3, -1) /* Do not swap around "emag" and "xgene1", this order is required to handle variant correctly. */ AARCH64_CORE("emag", emag, xgene1, V8A, (CRC, CRYPTO), emag, 0x50, 0x000, 3) -- cgit v1.1 From badd1ac23d24664b2258b1db4d49f37a3f60ccca Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Thu, 6 Oct 2022 12:08:40 +0100 Subject: aarch64: Add test for LDAR generation from __atomic_load_n I'd like a test to check the generation of LDAR for atomic_load_n. No new functionality added. gcc/testsuite/ChangeLog: * gcc.target/aarch64/ldar_1.c: New test. --- gcc/testsuite/gcc.target/aarch64/ldar_1.c | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 gcc/testsuite/gcc.target/aarch64/ldar_1.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/aarch64/ldar_1.c b/gcc/testsuite/gcc.target/aarch64/ldar_1.c new file mode 100644 index 0000000..d968a72 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/ldar_1.c @@ -0,0 +1,66 @@ +/* Test the LDAR instruction generation from atomic acquire loads. */ +/* { dg-do assemble } */ +/* { dg-additional-options "--save-temps -O1" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +#include + +#pragma GCC target "+norcpc" + +uint8_t v_uint8_t; +uint16_t v_uint16_t; +uint32_t v_uint32_t; +uint64_t v_uint64_t; + +/* +** load_uint8_t: +** ... +** ldarb w0, \[x[0-9]+\] +** ret +*/ + +uint8_t +load_uint8_t (void) +{ + return __atomic_load_n (&v_uint8_t, __ATOMIC_ACQUIRE); +} + +/* +** load_uint16_t: +** ... +** ldarh w0, \[x[0-9]+\] +** ret +*/ + +uint16_t +load_uint16_t (void) +{ + return __atomic_load_n (&v_uint16_t, __ATOMIC_ACQUIRE); +} + +/* +** load_uint32_t: +** ... +** ldar w0, \[x[0-9]+\] +** ret +*/ + +uint32_t +load_uint32_t (void) +{ + return __atomic_load_n (&v_uint32_t, __ATOMIC_ACQUIRE); +} + +/* +** load_uint64_t: +** ... +** ldar x0, \[x[0-9]+\] +** ret +*/ + +uint64_t +load_uint64_t (void) +{ + return __atomic_load_n (&v_uint64_t, __ATOMIC_ACQUIRE); +} + -- cgit v1.1 From 33b93ac3f2fb68a2da0d42fd692fe59533f7a84f Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Thu, 6 Oct 2022 12:09:28 +0100 Subject: aarch64: Remove redundant zero-extends with LDAR Like other loads in AArch64, the LDARB,LDARH,LDAR instructions clear out the top part of their destination register and we can thus avoid having to explicitly zero-extend it. We were missing a combine pattern that this patch adds. For one of the examples in the testcase we generated: load_uint8_t_ext_uint16_t: adrp x0, .LANCHOR0 add x0, x0, :lo12:.LANCHOR0 ldarb w0, [x0] and w0, w0, 255 ret but now generate: load_uint8_t_ext_uint16_t: adrp x0, .LANCHOR0 add x0, x0, :lo12:.LANCHOR0 ldarb w0, [x0] ret Bootstrapped and tested on aarch64-none-linux-gnu. gcc/ChangeLog: * config/aarch64/atomics.md (*atomic_load_zext): New pattern. gcc/testsuite/ChangeLog: * gcc.target/aarch64/ldar_2.c: New test. --- gcc/config/aarch64/atomics.md | 17 +++++++++++++++++ gcc/testsuite/gcc.target/aarch64/ldar_2.c | 27 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 gcc/testsuite/gcc.target/aarch64/ldar_2.c (limited to 'gcc') diff --git a/gcc/config/aarch64/atomics.md b/gcc/config/aarch64/atomics.md index 9048700..bc95f6d 100644 --- a/gcc/config/aarch64/atomics.md +++ b/gcc/config/aarch64/atomics.md @@ -640,6 +640,23 @@ } ) +(define_insn "*atomic_load_zext" + [(set (match_operand:SD_HSDI 0 "register_operand" "=r") + (zero_extend:SD_HSDI + (unspec_volatile:ALLX + [(match_operand:ALLX 1 "aarch64_sync_memory_operand" "Q") + (match_operand:SI 2 "const_int_operand")] ;; model + UNSPECV_LDA)))] + "GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode)" + { + enum memmodel model = memmodel_from_int (INTVAL (operands[2])); + if (is_mm_relaxed (model) || is_mm_consume (model) || is_mm_release (model)) + return "ldr\t%0, %1"; + else + return "ldar\t%0, %1"; + } +) + (define_insn "atomic_load" [(set (match_operand:ALLI 0 "register_operand" "=r") (unspec_volatile:ALLI diff --git a/gcc/testsuite/gcc.target/aarch64/ldar_2.c b/gcc/testsuite/gcc.target/aarch64/ldar_2.c new file mode 100644 index 0000000..60b0717 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/ldar_2.c @@ -0,0 +1,27 @@ +/* Test that the zero-extending patterns for LDAR are used. */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include + +uint8_t v_uint8_t; +uint16_t v_uint16_t; +uint32_t v_uint32_t; +uint64_t v_uint64_t; + +#define FUNC(FROM, TO) \ +TO \ +load_##FROM##_ext_##TO (void) \ +{ \ + return __atomic_load_n (&v_##FROM, __ATOMIC_ACQUIRE); \ +} + +FUNC (uint8_t, uint16_t) +FUNC (uint8_t, uint32_t) +FUNC (uint8_t, uint64_t) +FUNC (uint16_t, uint32_t) +FUNC (uint16_t, uint64_t) +FUNC (uint32_t, uint64_t) + +/* { dg-final { scan-assembler-not {and\tw[0-9+], w[0-9]+, 255} } } */ +/* { dg-final { scan-assembler-not {uxtw\tx[0-9+], w[0-9]+} } } */ -- cgit v1.1 From 0af8d957d5911fc7659b4174cfc2213289bbed23 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Thu, 6 Oct 2022 11:48:03 +0200 Subject: middle-end/107115 - avoid bogus redundant store removal during RTL expansion The following preserves the (premature) redundant store removal done in store_expr by appropriately guarding it with mems_same_for_tbaa_p. The testcase added needs scheduling disabled for now since there's a similar bug there still present. PR middle-end/107115 * expr.cc (store_expr): Check mems_same_for_tbaa_p before eliding a seemingly redundant store. * gcc.dg/torture/pr107115.c: New testcase. --- gcc/expr.cc | 4 +++- gcc/testsuite/gcc.dg/torture/pr107115.c | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/torture/pr107115.c (limited to 'gcc') diff --git a/gcc/expr.cc b/gcc/expr.cc index 80bb1b8..ba627f1 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -6207,7 +6207,9 @@ store_expr (tree exp, rtx target, int call_param_p, if ((! rtx_equal_p (temp, target) || (temp != target && (side_effects_p (temp) - || side_effects_p (target)))) + || side_effects_p (target) + || (MEM_P (temp) + && !mems_same_for_tbaa_p (temp, target))))) && TREE_CODE (exp) != ERROR_MARK /* If store_expr stores a DECL whose DECL_RTL(exp) == TARGET, but TARGET is not valid memory reference, TEMP will differ diff --git a/gcc/testsuite/gcc.dg/torture/pr107115.c b/gcc/testsuite/gcc.dg/torture/pr107115.c new file mode 100644 index 0000000..5f7b6ff --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr107115.c @@ -0,0 +1,37 @@ +/* { dg-do run } */ +/* PR/107115 */ +/* { dg-additional-options "-fno-schedule-insns -fno-schedule-insns2" } */ + +#include + +void test1(long *p1) +{ + p1[0] = 1; +} +long test2(long long *p2, int index1, int index2) +{ + p2[index1] = 2; + return p2[index2]; +} +long test3(long *p3, int index2, long value) +{ + p3[index2] = 3; + p3[index2] = value; + return p3[0]; +} +long test4(void *p4, int index1, int index2) +{ + test1(p4); + long temp = test2(p4, index1, index2); + return test3(p4, index2, temp); +} +long (*volatile vtest)(void *, int, int) = test4; +int main(void) +{ + void *pp = malloc(sizeof (long) + sizeof(long long)); + if (!pp) abort(); + long result = vtest(pp, 0, 0); + if (*(long *)pp != 2 || result != 2) + __builtin_abort (); + return 0; +} -- cgit v1.1 From b9d04e915fe0f4cdcca40e6de65ae384ba82a429 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 6 Oct 2022 15:12:53 +0200 Subject: Minor cleanup in DF code No functional changes. gcc/ * df-scan.cc (df_ref_create_structure): Minor cleanup. --- gcc/df-scan.cc | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'gcc') diff --git a/gcc/df-scan.cc b/gcc/df-scan.cc index 9b2375d..1a41e6d 100644 --- a/gcc/df-scan.cc +++ b/gcc/df-scan.cc @@ -2475,10 +2475,11 @@ df_ref_create_structure (enum df_ref_class cl, enum df_ref_type ref_type, int ref_flags) { - df_ref this_ref = NULL; - unsigned int regno = REGNO (GET_CODE (reg) == SUBREG ? SUBREG_REG (reg) : reg); + const unsigned int regno + = REGNO (GET_CODE (reg) == SUBREG ? SUBREG_REG (reg) : reg); struct df_scan_problem_data *problem_data = (struct df_scan_problem_data *) df_scan->problem_data; + df_ref this_ref; switch (cl) { @@ -2498,12 +2499,15 @@ df_ref_create_structure (enum df_ref_class cl, this_ref->regular_ref.loc = loc; gcc_checking_assert (loc); break; + + default: + gcc_unreachable (); } DF_REF_CLASS (this_ref) = cl; DF_REF_ID (this_ref) = -1; DF_REF_REG (this_ref) = reg; - DF_REF_REGNO (this_ref) = regno; + DF_REF_REGNO (this_ref) = regno; DF_REF_TYPE (this_ref) = ref_type; DF_REF_INSN_INFO (this_ref) = info; DF_REF_CHAIN (this_ref) = NULL; @@ -2512,17 +2516,17 @@ df_ref_create_structure (enum df_ref_class cl, DF_REF_PREV_REG (this_ref) = NULL; DF_REF_ORDER (this_ref) = df->ref_order++; - /* We need to clear this bit because fwprop, and in the future - possibly other optimizations sometimes create new refs using ond - refs as the model. */ + /* We need to clear the DF_HARD_REG_LIVE bit because fwprop, and in the + future possibly other optimizations, sometimes create new refs using + live refs as the model. */ DF_REF_FLAGS_CLEAR (this_ref, DF_HARD_REG_LIVE); - /* See if this ref needs to have DF_HARD_REG_LIVE bit set. */ + /* Now see if this ref really needs to have the bit set. */ if (regno < FIRST_PSEUDO_REGISTER - && !DF_REF_IS_ARTIFICIAL (this_ref) - && !DEBUG_INSN_P (DF_REF_INSN (this_ref))) + && cl != DF_REF_ARTIFICIAL + && !DEBUG_INSN_P (info->insn)) { - if (DF_REF_REG_DEF_P (this_ref)) + if (ref_type == DF_REF_REG_DEF) { if (!DF_REF_FLAGS_IS_SET (this_ref, DF_REF_MAY_CLOBBER)) DF_REF_FLAGS_SET (this_ref, DF_HARD_REG_LIVE); -- cgit v1.1 From 3ec926d36fbf7cb3ff45759471139f3a71d1c4de Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 6 Oct 2022 15:13:50 +0200 Subject: Fix wrong code generated by unroll-and-jam pass There is a loophole in the unroll-and-jam pass that can quickly result in wrong code generation. The code reads: if (!compute_data_dependences_for_loop (outer, true, &loop_nest, &datarefs, &dependences)) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Cannot analyze data dependencies\n"); free_data_refs (datarefs); free_dependence_relations (dependences); continue; } but compute_data_dependences_for_loop may return true even if the analysis is reported as failing by compute_affine_dependence for a dependence pair: (compute_affine_dependence ref_a: data[_14], stmt_a: data[_14] = i_59; ref_b: data[_14], stmt_b: data[_14] = i_59; Data ref a: Data ref b: affine dependence test not usable: access function not affine or constant. ) -> dependence analysis failed Note that this is a self-dependence pair and the code for them reads: /* Nothing interesting for the self dependencies. */ if (dra == drb) continue; This means that the pass may reorder "complex" accesses to the same memory location in successive iterations, which is OK for reads but not for writes. gcc/ * gimple-loop-jam.cc (tree_loop_unroll_and_jam): Bail out for a self dependency that is a write-after-write if the access function is not affine or constant. gcc/testsuite/ * gcc.c-torture/execute/20221006-1.c: New test. --- gcc/gimple-loop-jam.cc | 18 +++++++++++++-- gcc/testsuite/gcc.c-torture/execute/20221006-1.c | 29 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/20221006-1.c (limited to 'gcc') diff --git a/gcc/gimple-loop-jam.cc b/gcc/gimple-loop-jam.cc index a8a57d3..4f7a6e5 100644 --- a/gcc/gimple-loop-jam.cc +++ b/gcc/gimple-loop-jam.cc @@ -545,11 +545,25 @@ tree_loop_unroll_and_jam (void) /* If the refs are independend there's nothing to do. */ if (DDR_ARE_DEPENDENT (ddr) == chrec_known) continue; + dra = DDR_A (ddr); drb = DDR_B (ddr); - /* Nothing interesting for the self dependencies. */ + + /* Nothing interesting for the self dependencies, except for WAW if + the access function is not affine or constant because we may end + up reordering writes to the same location. */ if (dra == drb) - continue; + { + if (DR_IS_WRITE (dra) + && !DR_ACCESS_FNS (dra).is_empty () + && DDR_ARE_DEPENDENT (ddr) == chrec_dont_know) + { + unroll_factor = 0; + break; + } + else + continue; + } /* Now check the distance vector, for determining a sensible outer unroll factor, and for validity of merging the inner diff --git a/gcc/testsuite/gcc.c-torture/execute/20221006-1.c b/gcc/testsuite/gcc.c-torture/execute/20221006-1.c new file mode 100644 index 0000000..80deb3a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20221006-1.c @@ -0,0 +1,29 @@ +#include + +int +main (int argc, char** argv) +{ + const int len = argc == 2 ? atoi(argv[1]) : 4; + + int count; + int data[64]; + int M1[len][len]; + int M2[len][len]; + + for (int i = 0; i < len; i++) + for (int j = 0 ; j < len ; j++) + M1[i][j] = M2[i][j] = i*len + j; + + M2[1][0] = M2[0][1]; + + /* This writes successively 0 and 1 into data[M2[0][1]]. */ + for (int i = 0; i < len - 1; i++) + for (int j = 0 ; j < len ; j++) + if (M1[i+1][j] > M1[i][j]) + data[M2[i][j]] = i; + + if (data [M2[0][1]] != 1) + abort (); + + return 0; +} -- cgit v1.1 From 09df0d8b14dda66c5159a1b2cf85b73f26282152 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 6 Oct 2022 10:04:52 -0400 Subject: c++: remove optimize_specialization_lookup_p Roughly speaking, optimize_specialization_lookup_p returns true for a non-template member function of a class template, e.g. template struct A { int f(); }; The idea behind the optimization guarded by this predicate is that if we want to look up the specialization A::f [with T=int], then we can just do a name lookup for f in A and avoid having to add a spec_entry for f in the decl_specializations table. But the benefit of this optimization seems questionable because in order to do the name lookup we first need to look up A [with T=int] in the type_specializations table, which is as expensive as the decl_specializations lookup we're avoiding. And according to some experiments (using stdc++.h, range-v3 and libstdc++ tests) the compiler is slightly (<1%) _faster_ if we disable this optimization. Additionally, this optimization means we won't record an explicit specialization in decl_specializations for such a template either, which is an unfortunate inconsistency that apparently breaks the below modules testcase. So since this optimization doesn't improve performance, and complicates the explicit specialization story which causes issues with modules, this patch proposes to remove it. gcc/cp/ChangeLog: * pt.cc (optimize_specialization_lookup_p): Remove. (retrieve_specialization): Assume the above returns false and simplify accordingly. (register_specialization): Likewise. gcc/testsuite/ChangeLog: * g++.dg/modules/indirect-3_b.C: Expect that the entity foo::TPL<0>::frob is tagged as a specialization instead of as a declaration. * g++.dg/modules/tpl-spec-8_a.H: New test. * g++.dg/modules/tpl-spec-8_b.C: New test. --- gcc/cp/pt.cc | 157 +++++++--------------------- gcc/testsuite/g++.dg/modules/indirect-3_b.C | 2 +- gcc/testsuite/g++.dg/modules/tpl-spec-8_a.H | 10 ++ gcc/testsuite/g++.dg/modules/tpl-spec-8_b.C | 8 ++ 4 files changed, 59 insertions(+), 118 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/tpl-spec-8_a.H create mode 100644 gcc/testsuite/g++.dg/modules/tpl-spec-8_b.C (limited to 'gcc') diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index bf4ae02..5b9fc58 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -1170,39 +1170,6 @@ maybe_process_partial_specialization (tree type) return type; } -/* Returns nonzero if we can optimize the retrieval of specializations - for TMPL, a TEMPLATE_DECL. In particular, for such a template, we - do not use DECL_TEMPLATE_SPECIALIZATIONS at all. */ - -static inline bool -optimize_specialization_lookup_p (tree tmpl) -{ - return (DECL_FUNCTION_TEMPLATE_P (tmpl) - && DECL_CLASS_SCOPE_P (tmpl) - /* DECL_CLASS_SCOPE_P holds of T::f even if T is a template - parameter. */ - && CLASS_TYPE_P (DECL_CONTEXT (tmpl)) - /* The optimized lookup depends on the fact that the - template arguments for the member function template apply - purely to the containing class, which is not true if the - containing class is an explicit or partial - specialization. */ - && !CLASSTYPE_TEMPLATE_SPECIALIZATION (DECL_CONTEXT (tmpl)) - && !DECL_MEMBER_TEMPLATE_P (tmpl) - && !DECL_CONV_FN_P (tmpl) - /* It is possible to have a template that is not a member - template and is not a member of a template class: - - template - struct S { friend A::f(); }; - - Here, the friend function is a template, but the context does - not have template information. The optimized lookup relies - on having ARGS be the template arguments for both the class - and the function template. */ - && !DECL_UNIQUE_FRIEND_P (DECL_TEMPLATE_RESULT (tmpl))); -} - /* Make sure ARGS doesn't use any inappropriate typedefs; we should have gone through coerce_template_parms by now. */ @@ -1276,54 +1243,21 @@ retrieve_specialization (tree tmpl, tree args, hashval_t hash) if (lambda_fn_in_template_p (tmpl)) return NULL_TREE; - if (optimize_specialization_lookup_p (tmpl)) - { - /* The template arguments actually apply to the containing - class. Find the class specialization with those - arguments. */ - tree class_template = CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (tmpl)); - tree class_specialization - = retrieve_specialization (class_template, args, 0); - if (!class_specialization) - return NULL_TREE; + spec_entry elt; + elt.tmpl = tmpl; + elt.args = args; + elt.spec = NULL_TREE; - /* Find the instance of TMPL. */ - tree fns = get_class_binding (class_specialization, DECL_NAME (tmpl)); - for (ovl_iterator iter (fns); iter; ++iter) - { - tree fn = *iter; - if (tree ti = get_template_info (fn)) - if (TI_TEMPLATE (ti) == tmpl - /* using-declarations can bring in a different - instantiation of tmpl as a member of a different - instantiation of tmpl's class. We don't want those - here. */ - && DECL_CONTEXT (fn) == class_specialization) - return fn; - } - return NULL_TREE; - } + spec_hash_table *specializations; + if (DECL_CLASS_TEMPLATE_P (tmpl)) + specializations = type_specializations; else - { - spec_entry *found; - spec_entry elt; - spec_hash_table *specializations; + specializations = decl_specializations; - elt.tmpl = tmpl; - elt.args = args; - elt.spec = NULL_TREE; - - if (DECL_CLASS_TEMPLATE_P (tmpl)) - specializations = type_specializations; - else - specializations = decl_specializations; - - if (hash == 0) - hash = spec_hasher::hash (&elt); - found = specializations->find_with_hash (&elt, hash); - if (found) - return found->spec; - } + if (hash == 0) + hash = spec_hasher::hash (&elt); + if (spec_entry *found = specializations->find_with_hash (&elt, hash)) + return found->spec; return NULL_TREE; } @@ -1567,8 +1501,6 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, hashval_t hash) { tree fn; - spec_entry **slot = NULL; - spec_entry elt; gcc_assert ((TREE_CODE (tmpl) == TEMPLATE_DECL && DECL_P (spec)) || (TREE_CODE (tmpl) == FIELD_DECL @@ -1589,25 +1521,19 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, instantiation unless and until it is actually needed. */ return spec; - if (optimize_specialization_lookup_p (tmpl)) - /* We don't put these specializations in the hash table, but we might - want to give an error about a mismatch. */ - fn = retrieve_specialization (tmpl, args, 0); - else - { - elt.tmpl = tmpl; - elt.args = args; - elt.spec = spec; + spec_entry elt; + elt.tmpl = tmpl; + elt.args = args; + elt.spec = spec; - if (hash == 0) - hash = spec_hasher::hash (&elt); + if (hash == 0) + hash = spec_hasher::hash (&elt); - slot = decl_specializations->find_slot_with_hash (&elt, hash, INSERT); - if (*slot) - fn = (*slot)->spec; - else - fn = NULL_TREE; - } + spec_entry **slot = decl_specializations->find_slot_with_hash (&elt, hash, INSERT); + if (*slot) + fn = (*slot)->spec; + else + fn = NULL_TREE; /* We can sometimes try to re-register a specialization that we've already got. In particular, regenerate_decl_from_template calls @@ -1704,26 +1630,23 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, && !check_specialization_namespace (tmpl)) DECL_CONTEXT (spec) = DECL_CONTEXT (tmpl); - if (slot != NULL /* !optimize_specialization_lookup_p (tmpl) */) - { - spec_entry *entry = ggc_alloc (); - gcc_assert (tmpl && args && spec); - *entry = elt; - *slot = entry; - if ((TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec) - && PRIMARY_TEMPLATE_P (tmpl) - && DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE) - || variable_template_p (tmpl)) - /* If TMPL is a forward declaration of a template function, keep a list - of all specializations in case we need to reassign them to a friend - template later in tsubst_friend_function. - - Also keep a list of all variable template instantiations so that - process_partial_specialization can check whether a later partial - specialization would have used it. */ - DECL_TEMPLATE_INSTANTIATIONS (tmpl) - = tree_cons (args, spec, DECL_TEMPLATE_INSTANTIATIONS (tmpl)); - } + spec_entry *entry = ggc_alloc (); + gcc_assert (tmpl && args && spec); + *entry = elt; + *slot = entry; + if ((TREE_CODE (spec) == FUNCTION_DECL && DECL_NAMESPACE_SCOPE_P (spec) + && PRIMARY_TEMPLATE_P (tmpl) + && DECL_SAVED_TREE (DECL_TEMPLATE_RESULT (tmpl)) == NULL_TREE) + || variable_template_p (tmpl)) + /* If TMPL is a forward declaration of a template function, keep a list + of all specializations in case we need to reassign them to a friend + template later in tsubst_friend_function. + + Also keep a list of all variable template instantiations so that + process_partial_specialization can check whether a later partial + specialization would have used it. */ + DECL_TEMPLATE_INSTANTIATIONS (tmpl) + = tree_cons (args, spec, DECL_TEMPLATE_INSTANTIATIONS (tmpl)); return spec; } diff --git a/gcc/testsuite/g++.dg/modules/indirect-3_b.C b/gcc/testsuite/g++.dg/modules/indirect-3_b.C index 5bdfc1d..038b01e 100644 --- a/gcc/testsuite/g++.dg/modules/indirect-3_b.C +++ b/gcc/testsuite/g++.dg/modules/indirect-3_b.C @@ -23,7 +23,7 @@ namespace bar // { dg-final { scan-lang-dump {Lazily binding '::foo@foo:.::TPL'@'foo' section} module } } // { dg-final { scan-lang-dump {Wrote import:-[0-9]* template_decl:'::foo@foo:.::template TPL@foo:.'@foo} module } } -// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=specialization definition '::foo@foo:.::TPL<0x0>'\n \[1\]=specialization declaration '::foo@foo:.::TPL<0x0>::TPL<0x0>'\n( \[.\]=[^\n]* '\n)* \[.\]=decl definition '::foo@foo:.::TPL<0x0>::frob<0x0>'\n} module } } +// { dg-final { scan-lang-dump {Cluster members:\n \[0\]=specialization definition '::foo@foo:.::TPL<0x0>'\n \[1\]=specialization definition '::foo@foo:.::TPL<0x0>::frob<0x0>'\n \[2\]=specialization declaration '::foo@foo:.::TPL<0x0>::TPL<0x0>'} module } } // { dg-final { scan-lang-dump {Cluster members:\n \[0\]=specialization definition '::foo@foo:.::X@foo:.::frob<0x0>'} module } } // { dg-final { scan-lang-dump {Writing:-[0-9]*'s type spec merge key \(specialization\) type_decl:'::foo@foo:.::TPL<0x0>'} module } } diff --git a/gcc/testsuite/g++.dg/modules/tpl-spec-8_a.H b/gcc/testsuite/g++.dg/modules/tpl-spec-8_a.H new file mode 100644 index 0000000..5309130 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-spec-8_a.H @@ -0,0 +1,10 @@ +// { dg-additional-options -fmodule-header } +// { dg-module-cmi {} } + +template +struct A { + static void f() { T::nonexistent; } +}; + +template<> +inline void A::f() { } diff --git a/gcc/testsuite/g++.dg/modules/tpl-spec-8_b.C b/gcc/testsuite/g++.dg/modules/tpl-spec-8_b.C new file mode 100644 index 0000000..f23eb37 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-spec-8_b.C @@ -0,0 +1,8 @@ +// { dg-additional-options -fmodules-ts } +// { dg-do link } + +import "tpl-spec-8_a.H"; + +int main() { + A::f(); +} -- cgit v1.1 From fa258f6894801aef6785f0327594dc803da63fbd Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 6 Oct 2022 14:26:21 +0000 Subject: c: C2x typeof C2x adds typeof as a standard feature. In general this follows existing GNU C semantics very closely, but there are various ways in which the implementation involves more than simply enabling the keyword for C2x: * As well as typeof, there is a typeof_unqual variant, which removes all qualifiers and _Atomic from the resulting type (whereas typeof preserves qualifiers and _Atomic on qualified or atomic (lvalue or type name) operands). * The typeof keyword is disabled by -fno-asm, so enabling it for C2x needs to be implemented in a way that preserves the disabling by -fno-asm for older standard versions (which having -fno-asm having no effect on it in C2x mode). This is done via adding a new D_EXT11 mask (which is also where the C++ front-end change comes from, to handle D_EXT11 appropriately there for -fno-asm and -fno-gnu-keywords). * GNU typeof treats the noreturn property of a function (as specified in standard C with _Noreturn or [[noreturn]]) as being part of the type of a pointer to function, but it is not part of the type in standard terms. Thus a special case is needed in the typeof implementation, just like in the _Generic implementation, to avoid treating it as a type for standard typeof. It seems plausible this is being used when copying the type of one object to another using typeof, so the existing semantics are preserved for __typeof__, and for typeof in pre-C2x modes, while typeof for C2x or later has the standard semantics. * It turns out that, even after Martin Uecker's changes in this area, there were still cases where rvalues could wrongly have a qualified or atomic type in GCC. This applied to ++ and -- increment and decrement expressions, and also to calls to functions returning an atomic type. (For the latter, the working draft doesn't actually explicitly exclude the function call expression having an atomic type, but given all the changes that have gone into C17 and C2x to avoid rvalues ever having qualified types, and given that lvalue-to-rvalue conversion removes both qualifiers and _Atomic, it seems unlikely that this (or casts, where GCC already removes _Atomic) is actually intended as a route to allow an _Atomic-qualified rvalue; I've noted this to raise as an NB comment on the CD ballot.) Bootstrapped with no regressions for x86_64-pc-linux-gnu. OK to commit (C+ gcc/ * doc/invoke.texi (-fno-asm): Update description of effects on typeof keyword. gcc/c-family/ * c-common.cc (c_common_reswords): Mark typeof as D_EXT11. Add typeof_unqual. * c-common.h (enum rid): Add RID_TYPEOF_UNQUAL. (D_EXT11): New macro. Values of subsequent macros updated. gcc/c/ * c-parser.cc (c_parse_init): Add D_EXT11 to mask if flag_no_asm and not C2x. (c_keyword_starts_typename, c_token_starts_declspecs) (c_parser_declspecs, c_parser_objc_selector): Handle RID_TYPEOF_UNQUAL. (c_parser_typeof_specifier): Handle RID_TYPEOF_UNQUAL. Distinguish typeof for C2x from __typeof__ for all standard versions and typeof before C2x. * c-typeck.cc (build_function_call_vec): Use unqualified version of non-void return type. (build_unary_op): Use unqualified type for increment and decrement. gcc/cp/ * lex.cc (init_reswords): Handle D_EXT11. gcc/testsuite/ * gcc.dg/c11-typeof-1.c, gcc.dg/c2x-typeof-1.c, gcc.dg/c2x-typeof-2.c, gcc.dg/c2x-typeof-3.c, gcc.dg/gnu11-typeof-1.c, gcc.dg/gnu11-typeof-2.c, gcc.dg/gnu2x-typeof-1.c: New tests. --- gcc/c-family/c-common.cc | 3 +- gcc/c-family/c-common.h | 24 ++-- gcc/c/c-parser.cc | 46 +++++++- gcc/c/c-typeck.cc | 15 ++- gcc/cp/lex.cc | 4 +- gcc/doc/invoke.texi | 5 +- gcc/testsuite/gcc.dg/c11-typeof-1.c | 6 + gcc/testsuite/gcc.dg/c2x-typeof-1.c | 208 ++++++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c2x-typeof-2.c | 27 +++++ gcc/testsuite/gcc.dg/c2x-typeof-3.c | 7 ++ gcc/testsuite/gcc.dg/gnu11-typeof-1.c | 6 + gcc/testsuite/gcc.dg/gnu11-typeof-2.c | 39 +++++++ gcc/testsuite/gcc.dg/gnu2x-typeof-1.c | 39 +++++++ 13 files changed, 406 insertions(+), 23 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c11-typeof-1.c create mode 100644 gcc/testsuite/gcc.dg/c2x-typeof-1.c create mode 100644 gcc/testsuite/gcc.dg/c2x-typeof-2.c create mode 100644 gcc/testsuite/gcc.dg/c2x-typeof-3.c create mode 100644 gcc/testsuite/gcc.dg/gnu11-typeof-1.c create mode 100644 gcc/testsuite/gcc.dg/gnu11-typeof-2.c create mode 100644 gcc/testsuite/gcc.dg/gnu2x-typeof-1.c (limited to 'gcc') diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 4f9878d..ffe17ea 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -494,7 +494,8 @@ const struct c_common_resword c_common_reswords[] = { "typedef", RID_TYPEDEF, 0 }, { "typename", RID_TYPENAME, D_CXXONLY | D_CXXWARN }, { "typeid", RID_TYPEID, D_CXXONLY | D_CXXWARN }, - { "typeof", RID_TYPEOF, D_ASM | D_EXT }, + { "typeof", RID_TYPEOF, D_EXT11 }, + { "typeof_unqual", RID_TYPEOF_UNQUAL, D_CONLY | D_C2X }, { "union", RID_UNION, 0 }, { "unsigned", RID_UNSIGNED, 0 }, { "using", RID_USING, D_CXXONLY | D_CXXWARN }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 5f470d9..62ab4ba 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -104,7 +104,8 @@ enum rid RID_SIZEOF, /* C extensions */ - RID_ASM, RID_TYPEOF, RID_ALIGNOF, RID_ATTRIBUTE, RID_VA_ARG, + RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE, + RID_VA_ARG, 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, @@ -438,16 +439,17 @@ extern machine_mode c_default_pointer_mode; #define D_CXX11 0x0010 /* In C++, C++11 only. */ #define D_EXT 0x0020 /* GCC extension. */ #define D_EXT89 0x0040 /* GCC extension incorporated in C99. */ -#define D_ASM 0x0080 /* Disabled by -fno-asm. */ -#define D_OBJC 0x0100 /* In Objective C and neither C nor C++. */ -#define D_CXX_OBJC 0x0200 /* In Objective C, and C++, but not C. */ -#define D_CXXWARN 0x0400 /* In C warn with -Wcxx-compat. */ -#define D_CXX_CONCEPTS 0x0800 /* In C++, only with concepts. */ -#define D_TRANSMEM 0x1000 /* C++ transactional memory TS. */ -#define D_CXX_CHAR8_T 0x2000 /* In C++, only with -fchar8_t. */ -#define D_CXX20 0x4000 /* In C++, C++20 only. */ -#define D_CXX_COROUTINES 0x8000 /* In C++, only with coroutines. */ -#define D_CXX_MODULES 0x10000 /* In C++, only with modules. */ +#define D_EXT11 0x0080 /* GCC extension incorporated in C2X. */ +#define D_ASM 0x0100 /* Disabled by -fno-asm. */ +#define D_OBJC 0x0200 /* In Objective C and neither C nor C++. */ +#define D_CXX_OBJC 0x0400 /* In Objective C, and C++, but not C. */ +#define D_CXXWARN 0x0800 /* In C warn with -Wcxx-compat. */ +#define D_CXX_CONCEPTS 0x1000 /* In C++, only with concepts. */ +#define D_TRANSMEM 0x2000 /* C++ transactional memory TS. */ +#define D_CXX_CHAR8_T 0x4000 /* In C++, only with -fchar8_t. */ +#define D_CXX20 0x8000 /* In C++, C++20 only. */ +#define D_CXX_COROUTINES 0x10000 /* In C++, only with coroutines. */ +#define D_CXX_MODULES 0x20000 /* In C++, only with modules. */ #define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX_CONCEPTS #define D_CXX_CHAR8_T_FLAGS D_CXXONLY | D_CXX_CHAR8_T diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 67b919c..89e0587 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -127,6 +127,8 @@ c_parse_init (void) mask |= D_ASM | D_EXT; if (!flag_isoc99) mask |= D_EXT89; + if (!flag_isoc2x) + mask |= D_EXT11; } if (!c_dialect_objc ()) mask |= D_OBJC | D_CXX_OBJC; @@ -580,6 +582,7 @@ c_keyword_starts_typename (enum rid keyword) case RID_STRUCT: case RID_UNION: case RID_TYPEOF: + case RID_TYPEOF_UNQUAL: case RID_CONST: case RID_ATOMIC: case RID_VOLATILE: @@ -757,6 +760,7 @@ c_token_starts_declspecs (c_token *token) case RID_STRUCT: case RID_UNION: case RID_TYPEOF: + case RID_TYPEOF_UNQUAL: case RID_CONST: case RID_VOLATILE: case RID_RESTRICT: @@ -3081,6 +3085,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, declspecs_add_type (loc, specs, t); break; case RID_TYPEOF: + case RID_TYPEOF_UNQUAL: /* ??? The old parser rejected typeof after other type specifiers, but is a syntax error the best way of handling this? */ @@ -3768,22 +3773,38 @@ c_parser_struct_declaration (c_parser *parser) return decls; } -/* Parse a typeof specifier (a GNU extension). +/* Parse a typeof specifier (a GNU extension adopted in C2X). typeof-specifier: typeof ( expression ) typeof ( type-name ) + typeof_unqual ( expression ) + typeof_unqual ( type-name ) */ static struct c_typespec c_parser_typeof_specifier (c_parser *parser) { + bool is_unqual; + bool is_std; struct c_typespec ret; ret.kind = ctsk_typeof; ret.spec = error_mark_node; ret.expr = NULL_TREE; ret.expr_const_operands = true; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF)); + if (c_parser_next_token_is_keyword (parser, RID_TYPEOF)) + { + is_unqual = false; + tree spelling = c_parser_peek_token (parser)->value; + is_std = (flag_isoc2x + && strcmp (IDENTIFIER_POINTER (spelling), "typeof") == 0); + } + else + { + gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF_UNQUAL)); + is_unqual = true; + is_std = true; + } c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; in_typeof++; @@ -3825,6 +3846,24 @@ c_parser_typeof_specifier (c_parser *parser) pop_maybe_used (was_vm); } parens.skip_until_found_close (parser); + if (ret.spec != error_mark_node) + { + if (is_unqual && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED) + ret.spec = TYPE_MAIN_VARIANT (ret.spec); + if (is_std) + { + /* In ISO C terms, _Noreturn is not part of the type of + expressions such as &abort, but in GCC it is represented + internally as a type qualifier. */ + if (TREE_CODE (ret.spec) == FUNCTION_TYPE + && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED) + ret.spec = TYPE_MAIN_VARIANT (ret.spec); + else if (FUNCTION_POINTER_TYPE_P (ret.spec) + && TYPE_QUALS (TREE_TYPE (ret.spec)) != TYPE_UNQUALIFIED) + ret.spec + = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (ret.spec))); + } + } return ret; } @@ -11961,7 +12000,7 @@ c_parser_objc_synchronized_statement (c_parser *parser) identifier one of enum struct union if else while do for switch case default - break continue return goto asm sizeof typeof __alignof + break continue return goto asm sizeof typeof typeof_unqual __alignof unsigned long const short volatile signed restrict _Complex in out inout bycopy byref oneway int char float double void _Bool _Atomic @@ -12001,6 +12040,7 @@ c_parser_objc_selector (c_parser *parser) case RID_ASM: case RID_SIZEOF: case RID_TYPEOF: + case RID_TYPEOF_UNQUAL: case RID_ALIGNOF: case RID_UNSIGNED: case RID_LONG: diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index ac242b5..f919068 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -3187,6 +3187,7 @@ build_function_call_vec (location_t loc, vec arg_loc, /* fntype now gets the type of function pointed to. */ fntype = TREE_TYPE (fntype); + tree return_type = TREE_TYPE (fntype); /* Convert the parameters to the types declared in the function prototype, or apply default promotions. */ @@ -3203,8 +3204,6 @@ build_function_call_vec (location_t loc, vec arg_loc, && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL && !comptypes (fntype, TREE_TYPE (tem))) { - tree return_type = TREE_TYPE (fntype); - /* This situation leads to run-time undefined behavior. We can't, therefore, simply error unless we can prove that all possible executions of the program must execute the code. */ @@ -3229,22 +3228,25 @@ build_function_call_vec (location_t loc, vec arg_loc, bool warned_p = check_function_arguments (loc, fundecl, fntype, nargs, argarray, &arg_loc); + if (TYPE_QUALS (return_type) != TYPE_UNQUALIFIED + && !VOID_TYPE_P (return_type)) + return_type = c_build_qualified_type (return_type, TYPE_UNQUALIFIED); if (name != NULL_TREE && startswith (IDENTIFIER_POINTER (name), "__builtin_")) { if (require_constant_value) result - = fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype), + = fold_build_call_array_initializer_loc (loc, return_type, function, nargs, argarray); else - result = fold_build_call_array_loc (loc, TREE_TYPE (fntype), + result = fold_build_call_array_loc (loc, return_type, function, nargs, argarray); if (TREE_CODE (result) == NOP_EXPR && TREE_CODE (TREE_OPERAND (result, 0)) == INTEGER_CST) STRIP_TYPE_NOPS (result); } else - result = build_call_array_loc (loc, TREE_TYPE (fntype), + result = build_call_array_loc (loc, return_type, function, nargs, argarray); /* If -Wnonnull warning has been diagnosed, avoid diagnosing it again later. */ @@ -4831,6 +4833,9 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, else val = build2 (code, TREE_TYPE (arg), arg, inc); TREE_SIDE_EFFECTS (val) = 1; + if (TYPE_QUALS (TREE_TYPE (val)) != TYPE_UNQUALIFIED) + TREE_TYPE (val) = c_build_qualified_type (TREE_TYPE (val), + TYPE_UNQUALIFIED); ret = val; goto return_build_unary_op; } diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc index 0b121a9..22d1ab9 100644 --- a/gcc/cp/lex.cc +++ b/gcc/cp/lex.cc @@ -241,9 +241,9 @@ init_reswords (void) if (!flag_char8_t) mask |= D_CXX_CHAR8_T; if (flag_no_asm) - mask |= D_ASM | D_EXT; + mask |= D_ASM | D_EXT | D_EXT11; if (flag_no_gnu_keywords) - mask |= D_EXT; + mask |= D_EXT | D_EXT11; /* The Objective-C keywords are all context-dependent. */ mask |= D_OBJC; diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index e0c2c57..a2b0b96 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -2534,7 +2534,10 @@ this switch. You may want to use the @option{-fno-gnu-keywords} flag instead, which disables @code{typeof} but not @code{asm} and @code{inline}. In C99 mode (@option{-std=c99} or @option{-std=gnu99}), this switch only affects the @code{asm} and @code{typeof} keywords, -since @code{inline} is a standard keyword in ISO C99. +since @code{inline} is a standard keyword in ISO C99. In C2X mode +(@option{-std=c2x} or @option{-std=gnu2x}), this switch only affects +the @code{asm} keyword, since @code{typeof} is a standard keyword in +ISO C2X. @item -fno-builtin @itemx -fno-builtin-@var{function} diff --git a/gcc/testsuite/gcc.dg/c11-typeof-1.c b/gcc/testsuite/gcc.dg/c11-typeof-1.c new file mode 100644 index 0000000..a2abe8e --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-typeof-1.c @@ -0,0 +1,6 @@ +/* Test typeof and typeof_unqual not keywords in C11. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ + +int typeof = 1; +long typeof_unqual = 2; diff --git a/gcc/testsuite/gcc.dg/c2x-typeof-1.c b/gcc/testsuite/gcc.dg/c2x-typeof-1.c new file mode 100644 index 0000000..0b721fe --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-typeof-1.c @@ -0,0 +1,208 @@ +/* Test C2x typeof and typeof_unqual. Valid code. */ +/* { dg-do run } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +int i; +extern typeof (i) i; +extern typeof (int) i; +extern typeof_unqual (i) i; +extern typeof_unqual (int) i; + +volatile int vi; +extern typeof (volatile int) vi; +extern typeof (vi) vi; + +extern typeof_unqual (volatile int) i; +extern typeof_unqual (vi) i; +extern typeof ((const int) vi) i; +extern typeof ((volatile int) vi) i; + +const int ci; +extern typeof (const int) ci; +extern typeof (ci) ci; + +extern typeof_unqual (const int) i; +extern typeof_unqual (ci) i; +extern typeof ((const int) ci) i; +extern typeof (+ci) i; +extern typeof (0, ci) i; +extern typeof (1 ? ci : ci) i; +extern typeof (0) i; + +const int fci (void); +extern typeof (fci ()) i; + +_Atomic int ai; +extern typeof (_Atomic int) ai; +extern typeof (_Atomic (int)) ai; +extern typeof (ai) ai; + +extern typeof_unqual (_Atomic int) i; +extern typeof_unqual (_Atomic (int)) i; +extern typeof_unqual (ai) i; +extern typeof (+ai) i; +extern typeof ((_Atomic int) ai) i; +extern typeof (0, ai) i; +extern typeof (1 ? ai : ai) i; + +_Atomic int fai (void); +extern typeof (fai ()) i; + +_Atomic const volatile int acvi; +extern typeof (int volatile const _Atomic) acvi; +extern typeof (acvi) acvi; +extern const _Atomic volatile typeof (acvi) acvi; +extern _Atomic volatile typeof (ci) acvi; +extern _Atomic const typeof (vi) acvi; +extern const typeof (ai) volatile acvi; + +extern typeof_unqual (acvi) i; +extern typeof_unqual (typeof (acvi)) i; +extern typeof_unqual (_Atomic typeof_unqual (acvi)) i; + +extern _Atomic typeof_unqual (acvi) ai; + +char c; +volatile char vc; +volatile char *pvc; +volatile char *const cpvc; +const char *pcc; +const char *volatile vpcc; +typeof (*vpcc) cc; + +extern typeof (*cpvc) vc; +extern typeof_unqual (*cpvc) c; +extern typeof_unqual (cpvc) pvc; +extern typeof_unqual (vpcc) pcc; +extern const char cc; + +extern typeof (++vi) i; +extern typeof (++ai) i; +extern typeof (--vi) i; +extern typeof (--ai) i; +extern typeof (vi++) i; +extern typeof (ai++) i; +extern typeof (vi--) i; +extern typeof (ai--) i; + +bool b; +volatile bool vb; +_Atomic bool ab; +extern typeof (++vb) b; +extern typeof (++ab) b; +extern typeof (--vb) b; +extern typeof (--ab) b; +extern typeof (vb++) b; +extern typeof (ab++) b; +extern typeof (vb--) b; +extern typeof (ab--) b; + +extern typeof (vc = 1) c; +extern typeof (vpcc = 0) pcc; +extern typeof (ai *= 2) i; + +int s = sizeof (typeof (int (*)[++i])); + +void *vp; + +/* The non-returning property of a function is not part of the type given by + ISO C typeof. */ +_Noreturn void nf1 (void); +[[noreturn]] void nf2 (void); +void fg (void) {} +typeof (&nf1) pnf1 = fg; +typeof (&nf2) pnf2 = fg; +extern void (*pnf1) (void); +extern void (*pnf2) (void); +extern typeof (nf1) *pnf1; +extern typeof (nf1) *pnf2; +extern typeof (nf2) *pnf1; +extern typeof (nf2) *pnf2; +typeof (*&nf1) fg2, fg2a, fg2b; +typeof (*&nf2) fg3, fg3a, fg3b; +typeof (nf1) fg4, fg4a, fg4b; +typeof (nf2) fg5, fg5a, fg5b; + +extern void abort (void); +extern void exit (int); + +void fg2 (void) {} +_Noreturn void fg2a (void) { abort (); } +[[noreturn]] void fg2b (void) { abort (); } +void fg3 (void) {} +_Noreturn void fg3a (void) { abort (); } +[[noreturn]] void fg3b (void) { abort (); } +void fg4 (void) {} +_Noreturn void fg4a (void) { abort (); } +[[noreturn]] void fg4b (void) { abort (); } +void fg5 (void) {} +_Noreturn void fg5a (void) { abort (); } +[[noreturn]] void fg5b (void) { abort (); } + +extern int only_used_in_typeof; + +static int not_defined (void); + +typeof (i) +main (typeof (*vp)) +{ + volatile typeof (only_used_in_typeof) ii = 2; + if (ii != 2) + abort (); + const typeof (not_defined ()) jj = 3; + if (jj != 3) + abort (); + unsigned int u = 1; + typeof (u) u2 = 0; + typeof (int (*)[++u2]) p = 0; + if (u2 != 1) + abort (); + if (sizeof (*p) != sizeof (int)) + abort (); + typeof_unqual (int (*)[++u2]) q = 0; + if (u2 != 2) + abort (); + if (sizeof (*q) != 2 * sizeof (int)) + abort (); + if (sizeof (*p) != sizeof (int)) + abort (); + typeof (++u2) u3 = 1; + if (u2 != u + u3) + abort (); + typeof_unqual (++u2) u4 = 2; + if (u2 != u4) + abort (); + u = sizeof (typeof (int (*)[++u2])); + if (u2 != 2) + abort (); + u = sizeof (typeof_unqual (int (*)[++u2])); + if (u2 != 2) + abort (); + typeof ((int (*)[++u2]) 0) q2; + if (u2 != 3) + abort (); + typeof ((void) 0, (int (*)[++u2]) 0) q3; + if (u2 != 4) + abort (); + typeof ((int (*)[++u2]) 0, 0) q4; + if (u2 != 4) + abort (); + typeof_unqual ((int (*)[++u2]) 0) q5; + if (u2 != 5) + abort (); + typeof_unqual ((void) 0, (int (*)[++u2]) 0) q6; + if (u2 != 6) + abort (); + typeof_unqual ((int (*)[++u2]) 0, 0) q7; + if (u2 != 6) + abort (); + int a1[6], a2[6]; + int (*pa)[u2] = &a1; + typeof (pa = &a2) pp; + if (pa != &a2) + abort (); + typeof_unqual (pa = &a1) pp2; + if (pa != &a1) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/c2x-typeof-2.c b/gcc/testsuite/gcc.dg/c2x-typeof-2.c new file mode 100644 index 0000000..f1c30a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-typeof-2.c @@ -0,0 +1,27 @@ +/* Test C2x typeof and typeof_unqual. Invalid code. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +struct s { int i : 2; } x; +union u { unsigned int j : 1; } y; + +typeof (x.i) j; /* { dg-error "applied to a bit-field" } */ +typeof_unqual (x.i) j2; /* { dg-error "applied to a bit-field" } */ +typeof (y.j) j3; /* { dg-error "applied to a bit-field" } */ +typeof_unqual (y.j) j4; /* { dg-error "applied to a bit-field" } */ + +static int ok (void); +static int also_ok (void); +static int not_defined (void); /* { dg-error "used but never defined" } */ +static int also_not_defined (void); /* { dg-error "used but never defined" } */ + +void +f (void) +{ + typeof (ok ()) x = 2; + typeof_unqual (also_ok ()) y = 2; + int a[2]; + int (*p)[x] = &a; + typeof (p + not_defined ()) q; + typeof_unqual (p + also_not_defined ()) q2; +} diff --git a/gcc/testsuite/gcc.dg/c2x-typeof-3.c b/gcc/testsuite/gcc.dg/c2x-typeof-3.c new file mode 100644 index 0000000..c7a0577 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-typeof-3.c @@ -0,0 +1,7 @@ +/* Test C2x typeof and typeof_unqual. -fno-asm has no effect on keywords in + C2x mode. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x -pedantic-errors -fno-asm" } */ + +int i; +extern typeof (i) i; diff --git a/gcc/testsuite/gcc.dg/gnu11-typeof-1.c b/gcc/testsuite/gcc.dg/gnu11-typeof-1.c new file mode 100644 index 0000000..6477c78 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu11-typeof-1.c @@ -0,0 +1,6 @@ +/* Test typeof and typeof_unqual not keywords with -std=gnu11 -fno-asm. */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu11 -fno-asm" } */ + +int typeof = 1; +long typeof_unqual = 2; diff --git a/gcc/testsuite/gcc.dg/gnu11-typeof-2.c b/gcc/testsuite/gcc.dg/gnu11-typeof-2.c new file mode 100644 index 0000000..e60ad46 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu11-typeof-2.c @@ -0,0 +1,39 @@ +/* Test typeof propagation of noreturn function attributes with -std=gnu11: + these are part of the type of a function pointer with GNU typeof, but not + with C2x typeof. */ +/* { dg-do link } */ +/* { dg-options "-std=gnu11 -O2" } */ + +_Noreturn void f (void); + +typeof (&f) volatile p; +typeof (&p) volatile pp; + +void link_failure (void); + +void +g (void) +{ + (*p) (); + link_failure (); +} + +void +h (void) +{ + (**pp) (); + link_failure (); +} + +volatile int flag; +volatile int x; + +int +main (void) +{ + if (flag) + g (); + if (flag) + h (); + return x; +} diff --git a/gcc/testsuite/gcc.dg/gnu2x-typeof-1.c b/gcc/testsuite/gcc.dg/gnu2x-typeof-1.c new file mode 100644 index 0000000..f14b54f --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu2x-typeof-1.c @@ -0,0 +1,39 @@ +/* Test __typeof__ propagation of noreturn function attributes with -std=gnu2x: + these are part of the type of a function pointer with GNU __typeof__, but + not with C2x typeof. */ +/* { dg-do link } */ +/* { dg-options "-std=gnu2x -O2" } */ + +_Noreturn void f (void); + +__typeof__ (&f) volatile p; +__typeof__ (&p) volatile pp; + +void link_failure (void); + +void +g (void) +{ + (*p) (); + link_failure (); +} + +void +h (void) +{ + (**pp) (); + link_failure (); +} + +volatile int flag; +volatile int x; + +int +main (void) +{ + if (flag) + g (); + if (flag) + h (); + return x; +} -- cgit v1.1 From 50c35c691517291dbb77b1661761bc59950ba101 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Thu, 6 Oct 2022 18:42:32 +0200 Subject: openmp: Map holds clause to IFN_ASSUME for Fortran Same as r13-3107-g847f5addc4d07a2f3b95f5daa50ab4a64dfd957d did for C/C++. Convert '!$omp assume holds(cond)' to IFN_ASSUME (cond). gcc/fortran/ * trans-openmp.cc (gfc_trans_omp_assume): New. (gfc_trans_omp_directive): Call it. gcc/testsuite/ * gfortran.dg/gomp/assume-3.f90: New test. * gfortran.dg/gomp/assume-4.f90: New test. --- gcc/fortran/trans-openmp.cc | 37 ++++++++++++++++++++- gcc/testsuite/gfortran.dg/gomp/assume-3.f90 | 46 ++++++++++++++++++++++++++ gcc/testsuite/gfortran.dg/gomp/assume-4.f90 | 50 +++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gfortran.dg/gomp/assume-3.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/assume-4.f90 (limited to 'gcc') diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc index 2105369..8ea573f 100644 --- a/gcc/fortran/trans-openmp.cc +++ b/gcc/fortran/trans-openmp.cc @@ -4571,6 +4571,41 @@ static tree gfc_trans_omp_sections (gfc_code *, gfc_omp_clauses *); static tree gfc_trans_omp_workshare (gfc_code *, gfc_omp_clauses *); static tree +gfc_trans_omp_assume (gfc_code *code) +{ + stmtblock_t block; + gfc_init_block (&block); + gfc_omp_assumptions *assume = code->ext.omp_clauses->assume; + if (assume) + for (gfc_expr_list *el = assume->holds; el; el = el->next) + { + location_t loc = gfc_get_location (&el->expr->where); + gfc_se se; + gfc_init_se (&se, NULL); + gfc_conv_expr (&se, el->expr); + tree t; + if (se.pre.head == NULL_TREE && se.post.head == NULL_TREE) + t = se.expr; + else + { + tree var = gfc_create_var (TREE_TYPE (se.expr), NULL); + stmtblock_t block2; + gfc_init_block (&block2); + gfc_add_block_to_block (&block2, &se.pre); + gfc_add_modify_loc (loc, &block2, var, se.expr); + gfc_add_block_to_block (&block2, &se.post); + t = gfc_finish_block (&block2); + t = build4 (TARGET_EXPR, boolean_type_node, var, t, NULL, NULL); + } + t = build_call_expr_internal_loc (loc, IFN_ASSUME, + void_type_node, 1, t); + gfc_add_expr_to_block (&block, t); + } + gfc_add_expr_to_block (&block, gfc_trans_omp_code (code->block->next, true)); + return gfc_finish_block (&block); +} + +static tree gfc_trans_omp_atomic (gfc_code *code) { gfc_code *atomic_code = code->block; @@ -7488,7 +7523,7 @@ gfc_trans_omp_directive (gfc_code *code) switch (code->op) { case EXEC_OMP_ASSUME: - return gfc_trans_omp_code (code->block->next, true); + return gfc_trans_omp_assume (code); case EXEC_OMP_ATOMIC: return gfc_trans_omp_atomic (code); case EXEC_OMP_BARRIER: diff --git a/gcc/testsuite/gfortran.dg/gomp/assume-3.f90 b/gcc/testsuite/gfortran.dg/gomp/assume-3.f90 new file mode 100644 index 0000000..e5deace --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/assume-3.f90 @@ -0,0 +1,46 @@ +! { dg-do compile } +! { dg-options "-fopenmp -O2 -fdump-tree-optimized -fdump-tree-original" } + +! { dg-final { scan-tree-dump-times ".ASSUME \\(x == 42\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times ".ASSUME \\(x <= 41\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times ".ASSUME \\(y <= 6\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times ".ASSUME \\(y > 5\\);" 1 "original" } } + +! { dg-final { scan-tree-dump-times "return 42;" 3 "optimized" } } +! { dg-final { scan-tree-dump-not "return -1;" "optimized" } } + +integer function foo (x) + implicit none + integer, value :: x + integer :: y + !$omp assume holds (x == 42) + y = x; + !$omp end assume + foo = y +end + +integer function bar (x) + implicit none + integer, value :: x + !$omp assume holds (x < 42) + block + end block + if (x == 42) then + bar = -1 + return + end if + bar = 42 +end + +integer function foobar (y) + implicit none + integer, value :: y + !$omp assume holds(y > 5) holds (y < 7) + block + if (y == 6) then + foobar = 42 + return + end if + end block + foobar = -1 +end diff --git a/gcc/testsuite/gfortran.dg/gomp/assume-4.f90 b/gcc/testsuite/gfortran.dg/gomp/assume-4.f90 new file mode 100644 index 0000000..45857c4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/assume-4.f90 @@ -0,0 +1,50 @@ +! { dg-do compile } +! { dg-options "-fopenmp -O2 -fdump-tree-original -fdump-tree-optimized" } +! { dg-final { scan-tree-dump-times ".ASSUME \\(i_lower_bound \\(\\) < i\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times ".ASSUME \\(TARGET_EXPR i_lower_bound ()) + block + if (i > 4) then + f = 42 + else + f = -1 + end if + end block +contains + function i_lower_bound () + integer :: i_lower_bound + i_lower_bound = 5 + end function +end + +integer function g(j) + implicit none + integer, value :: j + + !$omp assume holds(j < j_upper_bound ()) + block + if (j < 10) then + g = 42 + else + g = -1 + end if + end block +contains + function j_upper_bound () + integer, allocatable :: j_upper_bound + j_upper_bound = 10 + end function +end -- cgit v1.1 From 30d6356773a838366f6272f7e9900bacb31c44de Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 6 Oct 2022 15:46:20 -0400 Subject: analyzer: fixes to call_summary_replay::dump_to_pp gcc/analyzer/ChangeLog: * call-summary.cc (call_summary_replay::dump_to_pp): Bulletproof against NULL caller regions/svalues. Signed-off-by: David Malcolm --- gcc/analyzer/call-summary.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc index bc50562..12ef82d 100644 --- a/gcc/analyzer/call-summary.cc +++ b/gcc/analyzer/call-summary.cc @@ -845,14 +845,20 @@ call_summary_replay::dump_to_pp (pretty_printer *pp, bool simple) const for (auto summary_reg : summary_regs) { pp_string (pp, "reg in summary: "); - summary_reg->dump_to_pp (pp, simple); + if (summary_reg) + summary_reg->dump_to_pp (pp, simple); + else + pp_string (pp, "(null)"); pp_newline (pp); const region *caller_reg = *((const_cast (m_map_region_from_summary_to_caller)).get (summary_reg)); pp_string (pp, " reg in caller: "); - caller_reg->dump_to_pp (pp, simple); + if (caller_reg) + caller_reg->dump_to_pp (pp, simple); + else + pp_string (pp, "(null)"); pp_newline (pp); } } -- cgit v1.1 From 629b4813e91aba0a8fc9b18434ec1808776a4b3d Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 6 Oct 2022 15:46:49 -0400 Subject: analyzer: fix another ICE in PR 107158 I overreduced PR analyzer/107158 in r13-3096-gef878564140cbc, and there was another ICE in the original reproducer, which this patch fixes. gcc/analyzer/ChangeLog: PR analyzer/107158 * store.cc (store::replay_call_summary_cluster): Eliminate special-casing of RK_HEAP_ALLOCATED in favor of sharing code with RK_DECL, avoiding an ICE due to attempting to bind a compound_svalue into a binding_cluster when an svalue in the summary cluster converts to a compound_svalue in the caller. gcc/testsuite/ChangeLog: PR analyzer/107158 * gcc.dg/analyzer/call-summaries-pr107158-2.c: New test. Signed-off-by: David Malcolm --- gcc/analyzer/store.cc | 34 ++----- .../gcc.dg/analyzer/call-summaries-pr107158-2.c | 108 +++++++++++++++++++++ 2 files changed, 114 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158-2.c (limited to 'gcc') diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index d2279b5..2631ea2 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -3238,6 +3238,8 @@ store::replay_call_summary_cluster (call_summary_replay &r, caller_sval, NULL /* uncertainty_t * */); } break; + + case RK_HEAP_ALLOCATED: case RK_DECL: { const region *caller_dest_reg @@ -3246,6 +3248,10 @@ store::replay_call_summary_cluster (call_summary_replay &r, return; const svalue *summary_sval = summary.get_any_binding (mgr, summary_base_reg); + if (!summary_sval) + summary_sval = reg_mgr->get_or_create_compound_svalue + (summary_base_reg->get_type (), + summary_cluster->get_map ()); const svalue *caller_sval = r.convert_svalue_from_summary (summary_sval); if (!caller_sval) @@ -3255,34 +3261,6 @@ store::replay_call_summary_cluster (call_summary_replay &r, caller_sval, NULL /* uncertainty_t * */); } break; - case RK_HEAP_ALLOCATED: - { - const region *caller_dest_reg - = r.convert_region_from_summary (summary_base_reg); - gcc_assert (caller_dest_reg); - binding_cluster *caller_cluster - = get_or_create_cluster (caller_dest_reg); - auto_vec summary_keys; - for (auto kv : *summary_cluster) - summary_keys.safe_push (kv.first); - summary_keys.qsort (binding_key::cmp_ptrs); - for (auto summary_key : summary_keys) - { - const binding_key *caller_key - = r.convert_key_from_summary (summary_key); - if (!caller_key) - continue; - const svalue *summary_sval - = summary_cluster->get_map ().get (summary_key); - const svalue *caller_sval - = r.convert_svalue_from_summary (summary_sval); - if (!caller_sval) - caller_sval = reg_mgr->get_or_create_unknown_svalue - (summary_sval->get_type ()); - caller_cluster->bind_key (caller_key, caller_sval); - } - } - break; case RK_ALLOCA: /* Ignore bindings of alloca regions in the summary. */ diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158-2.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158-2.c new file mode 100644 index 0000000..c2e9e2ba --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107158-2.c @@ -0,0 +1,108 @@ +/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-too-complex" } */ + +typedef __SIZE_TYPE__ size_t; +typedef struct _IO_FILE FILE; +extern char *fgets(char *__restrict __s, int __n, FILE *__restrict __stream) + __attribute__((__access__(__write_only__, 1, 2))); +extern void perror(const char *__s); +enum { + _ISspace = ((5) < 8 ? ((1 << (5)) << 8) : ((1 << (5)) >> 8)), +}; +extern const unsigned short int **__ctype_b_loc(void) + __attribute__((__nothrow__, __leaf__)) __attribute__((__const__)); +extern void *malloc(size_t __size) __attribute__((__nothrow__, __leaf__)) +__attribute__((__malloc__)) __attribute__((__alloc_size__(1))); +extern void exit(int __status) __attribute__((__nothrow__, __leaf__)) +__attribute__((__noreturn__)); +extern char *strcpy(char *__restrict __dest, const char *__restrict __src) + __attribute__((__nothrow__, __leaf__)) __attribute__((__nonnull__(1, 2))); +extern size_t strlen(const char *__s) __attribute__((__nothrow__, __leaf__)) +__attribute__((__pure__)) __attribute__((__nonnull__(1))); + +struct mydata { + struct mydata *link; + char *name; + char *type; +}; + +static struct mydata *all_data; +static int line_no; + +_Noreturn static void failed(const char *message) { + perror(message); + exit(1); +} + +static char *string_dup(const char *string) { + char *buf; + + if ((buf = malloc(strlen(string) + 1)) == ((void *)0)) + failed("malloc() failed"); + + return strcpy(buf, string); +} + +static void store_data(const char *name, const char *type) { + struct mydata *p, *q; + + if ((p = (struct mydata *)malloc(sizeof(struct mydata))) == ((void *)0)) + failed("malloc() failed"); + + p->link = ((void *)0); + p->name = string_dup(name); + p->type = string_dup(type); + + if ((q = all_data) == ((void *)0)) + all_data = p; + else { + while (q->link != ((void *)0)) + q = q->link; + q->link = p; + } +} + +static void parse_tbl(char *buffer) { + char *s = buffer; + char *t = s + strlen(s); + + do { + t--; + if (((*__ctype_b_loc())[(int)(((int)*t))] & (unsigned short int)_ISspace)) + *t = '\0'; + else + break; + } while (t > s); + while (((*__ctype_b_loc())[(int)(((int)*s))] & (unsigned short int)_ISspace)) + s++; + buffer = s; + + line_no++; + if (*buffer != ';' && *buffer != '\0') { + if (*buffer == '#') { + store_data(buffer, ""); /* { dg-bogus "leak" "PR analyzer/107158" { xfail *-*-* } } */ + } else { + + while (*s && !((*__ctype_b_loc())[(int)(((int)*s))] & + (unsigned short int)_ISspace)) + s++; + while ( + ((*__ctype_b_loc())[(int)(((int)*s))] & (unsigned short int)_ISspace)) + *s++ = '\0'; + store_data(buffer, s); /* { dg-bogus "leak" "PR analyzer/107158" { xfail *-*-* } } */ + } + } +} + +/* [...snip...] */ + +static void makecfg(FILE *ifp, FILE *ofp, FILE *ofp2) { + char buffer[8192]; + + /* [...snip...] */ + + line_no = 0; + while (fgets(buffer, sizeof(buffer) - 1, ifp)) + parse_tbl(buffer); + + /* [...snip...] */ +} -- cgit v1.1 From 49b9a8c8cc498b1ed2f566bee858e651e14ba37b Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Thu, 6 Oct 2022 19:11:08 +0200 Subject: [PR107170] Avoid copying incompatible types in legacy VRP. Legacy VRP is calling ranger deep inside the bowels, and then trying to copy an incompatible type. My previous patch in this area assumed that the only possibility out of vr_values::get_value_range for an unsupported type was VARYING, but UNDEFINED can also be returned. PR tree-optimization/107170 gcc/ChangeLog: * vr-values.cc (vr_values::range_of_expr): Do not die on unsupported types. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr107170.c: New test. --- gcc/testsuite/gcc.dg/tree-ssa/pr107170.c | 8 ++++++++ gcc/vr-values.cc | 24 +++++++++++++----------- 2 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr107170.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr107170.c b/gcc/testsuite/gcc.dg/tree-ssa/pr107170.c new file mode 100644 index 0000000..7a5a4a3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr107170.c @@ -0,0 +1,8 @@ +// { dg-do compile } +// { dg-options "-O2" } + +int main() { + double a; + if (__builtin_signbit(a)) + __builtin_abort(); +} diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc index 626a918..71fed1e 100644 --- a/gcc/vr-values.cc +++ b/gcc/vr-values.cc @@ -184,21 +184,23 @@ vr_values::range_of_expr (vrange &r, tree expr, gimple *stmt) if (const value_range *vr = get_value_range (expr, stmt)) { + if (!vr->supports_type_p (TREE_TYPE (expr))) + { + // vr_values::extract_range_basic() use of ranger's + // fold_range() can create a situation where we are asked + // for the range of an unsupported legacy type. Since + // get_value_range() above will return varying or undefined + // for such types, avoid copying incompatible range types. + if (vr->undefined_p ()) + r.set_undefined (); + else + r.set_varying (TREE_TYPE (expr)); + return true; + } if (vr->undefined_p () || vr->constant_p ()) r = *vr; else { - if (!vr->supports_type_p (TREE_TYPE (expr))) - { - // vr_values::extract_range_basic() use of ranger's - // fold_range() can create a situation where we are - // asked for the range of an unsupported legacy type. - // Since get_value_range() above will return varying for - // such types, avoid copying incompatible range types. - gcc_checking_assert (vr->varying_p ()); - r.set_varying (TREE_TYPE (expr)); - return true; - } value_range tmp = *vr; tmp.normalize_symbolics (); r = tmp; -- cgit v1.1 From 0143b277c9b17215ab3d4b361e1aef431799e813 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 30 Sep 2022 10:04:22 -0400 Subject: c++: fix broken conversion in coroutines You can't use CONVERT_EXPR to convert between two class types. VIEW_CONVERT_EXPR takes liberties with the C++ type system, but is probably safe in this context. Let's also only use it when the type isn't already what we want. gcc/cp/ChangeLog: * coroutines.cc (expand_one_await_expression): Change conversion to VIEW_CONVERT_EXPR. * cp-gimplify.cc (cp_genericize_r) [CONVERT_EXPR]: Add assert. --- gcc/cp/coroutines.cc | 5 ++++- gcc/cp/cp-gimplify.cc | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index eca01ab..60b8466 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1728,7 +1728,10 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d) } else { - r = build1_loc (loc, CONVERT_EXPR, void_coro_handle_type, suspend); + r = suspend; + if (!same_type_ignoring_top_level_qualifiers_p (susp_type, + void_coro_handle_type)) + r = build1_loc (loc, VIEW_CONVERT_EXPR, void_coro_handle_type, r); r = build2_loc (loc, INIT_EXPR, void_coro_handle_type, data->conthand, r); r = build1 (CONVERT_EXPR, void_type_node, r); append_to_statement_list (r, &body_list); diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index b4599fc3..5d26e59 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -1589,6 +1589,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) break; case CONVERT_EXPR: + gcc_checking_assert (!AGGREGATE_TYPE_P (TREE_TYPE (stmt))); gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt)); break; -- cgit v1.1 From 629d04d35d819bdc26c30d215bc4ea66a74af15b Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 7 Oct 2022 00:17:52 +0000 Subject: Daily bump. --- gcc/ChangeLog | 99 ++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/ada/ChangeLog | 147 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/analyzer/ChangeLog | 14 +++++ gcc/c-family/ChangeLog | 15 +++++ gcc/c/ChangeLog | 32 +++++++++++ gcc/cp/ChangeLog | 54 ++++++++++++++++++ gcc/fortran/ChangeLog | 5 ++ gcc/testsuite/ChangeLog | 77 +++++++++++++++++++++++++ 9 files changed, 444 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e40b049..ad2c6e7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,102 @@ +2022-10-06 Aldy Hernandez + + PR tree-optimization/107170 + * vr-values.cc (vr_values::range_of_expr): Do not die on + unsupported types. + +2022-10-06 Joseph Myers + + * doc/invoke.texi (-fno-asm): Update description of effects on + typeof keyword. + +2022-10-06 Eric Botcazou + + * gimple-loop-jam.cc (tree_loop_unroll_and_jam): Bail out for a self + dependency that is a write-after-write if the access function is not + affine or constant. + +2022-10-06 Eric Botcazou + + * df-scan.cc (df_ref_create_structure): Minor cleanup. + +2022-10-06 Richard Biener + + PR middle-end/107115 + * expr.cc (store_expr): Check mems_same_for_tbaa_p before + eliding a seemingly redundant store. + +2022-10-06 Kyrylo Tkachov + + * config/aarch64/atomics.md (*atomic_load_zext): + New pattern. + +2022-10-06 Philipp Tomsich + + * config/aarch64/aarch64-cores.def (AARCH64_CORE): Update + Ampere-1 core entry. + +2022-10-06 Philipp Tomsich + + * config/aarch64/driver-aarch64.cc (readline): Fix off-by-one. + +2022-10-06 Richard Biener + + PR tree-optimization/107107 + * tree-ssa-sccvn.cc (visit_reference_op_store): Do not + affect value-numbering when doing the tail merging + MODIFY_EXPR lookup. + +2022-10-06 Claudiu Zissulescu + + * config/arc/linux.h (LINK_SPEC): Remove max-page-size and + common-pave-size. + +2022-10-06 Jakub Jelinek + + PR c++/106654 + * internal-fn.def (ASSUME): New internal function. + * internal-fn.h (expand_ASSUME): Declare. + * internal-fn.cc (expand_ASSUME): Define. + * gimplify.cc (gimplify_call_expr): Gimplify IFN_ASSUME. + * fold-const.h (simple_condition_p): Declare. + * fold-const.cc (simple_operand_p_2): Rename to ... + (simple_condition_p): ... this. Remove forward declaration. + No longer static. Adjust function comment and fix a typo in it. + Adjust recursive call. + (simple_operand_p): Adjust function comment. + (fold_truth_andor): Adjust simple_operand_p_2 callers to call + simple_condition_p. + * doc/extend.texi: Document assume attribute. Move fallthrough + attribute example to its section. + +2022-10-06 Stefan Schulze Frielinghaus + + PR rtl-optimization/107088 + * cselib.cc (new_cselib_val): Skip BImode while keeping track of + subvalue relations. + +2022-10-06 Aldy Hernandez + + * value-range.cc (frange::set): Call set_nan unconditionally. + (range_tests_nan): Adjust tests. + (range_tests_signed_zeros): Same. + (range_tests_floats): Same. + * value-range.h (frange::update_nan): Guard with HONOR_NANS. + (frange::set_nan): Set undefined if !HONOR_NANS. + +2022-10-06 Aldy Hernandez + + * range-op-float.cc (foperator_lt::fold_range): Remove extra check + to finite_operands_p. + (foperator_le::fold_range): Same. + (foperator_gt::fold_range): Same. + (foperator_ge::fold_range): Same. + +2022-10-06 Aldy Hernandez + + * value-range-pretty-print.cc (vrange_printer::print_real_value): + Avoid printing INF and NAN twice. + 2022-10-05 Segher Boessenkool * config/rs6000/constraints.md (wD): Delete. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 5ba2bc5..12abceb7 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20221006 +20221007 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index be8371d..fc3bc97 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,150 @@ +2022-10-06 Eric Botcazou + + * gcc-interface/ada-tree.def (LOAD_EXPR): New expression code. + * gcc-interface/gigi.h (build_storage_model_load): Declare. + (build_storage_model_store): Likewise. + (instantiate_load_in_expr): Likewise. + (INSTANTIATE_LOAD_IN_EXPR): New macro. + (instantiate_load_in_array_ref): Declare. + * gcc-interface/decl.cc (gnat_to_gnu_entity) : Set a + fake discriminant number on the fields of the template type. + (gnat_to_gnu_field): Use integer for DECL_DISCRIMINANT_NUMBER. + * gcc-interface/misc.cc (gnat_init_ts): Mark LOAD_EXPR as typed. + * gcc-interface/trans.cc (fold_constant_decl_in_expr) : + Also preserve the 4th operand. + (Attribute_to_gnu): Deal with LOAD_EXPR of unconstrained array type. + : Call INSTANTIATE_LOAD_IN_EXPR for a storage model. + : Likewise. + : Likewise. + (get_storage_model): New function. + (get_storage_model_access): Likewise. + (storage_model_access_required_p): Likewise. + (Call_to_gnu): Add GNAT_STORAGE_MODEL parameter and deal with it. + Also deal with actual parameters that have a storage model. + (gnat_to_gnu) : Adjust call to Call_to_gnu. + : Deal with a storage model access. + : Likewise. + : Likewise. + : Likewise. + : Adjust call to Call_to_gnu. Deal with a + storage model access either on the LHS, on the RHS or on both. + : Adjust call to Call_to_gnu. + : Deal with a pool that is a storage model. + Replace test for UNCONSTRAINED_ARRAY_REF with test on the type. + (gnat_gimplify_expr) : Tidy up. + : New case. + : Move down. + * gcc-interface/utils.cc (maybe_unconstrained_array): Deal with a + LOAD_EXPR by recursing on its first operand. + * gcc-interface/utils2.cc (build_allocator): Deal with a pool that + is a storage model. + (build_storage_model_copy): New function. + (build_storage_model_load): Likewise. + (build_storage_model_store): Likewise. + (instantiate_load_in_expr): Likewise. + (instantiate_load_in_array_ref): Likewise. + (gnat_rewrite_reference) : Also preserve the 4th operand. + (get_inner_constant_reference) : Remove useless test. + (gnat_invariant_expr) : Rewrite test. + +2022-10-06 Steve Baird + + * sem_ch6.adb + (Analyze_Procedure_Call): Replace "return;" with "goto Leave;", as + per comment preceding body of Analyze_Procedure_Call. + +2022-10-06 Piotr Trojanek + + * sem_ch9.adb (Allows_Lock_Free_Implementation): Reject + conditional goto statements. + +2022-10-06 Piotr Trojanek + + * doc/gnat_rm/implementation_defined_pragmas.rst + (Lock_Free): Remove inconsistent periods that end item + descriptions. + * sem_ch9.adb + (Allows_Lock_Free_Implementation): Remove unnecessary guard + against an empty list of parameters; replace low-level entity kind + membership test with a high-level query; refill error message. + * gnat_rm.texi: Regenerate. + +2022-10-06 Alexandre Oliva + + * doc/gnat_rm/security_hardening_features.rst: Add examples of + codegen changes in hardened conditionals. + * gnat_rm.texi: Regenerate. + +2022-10-06 Alexandre Oliva + + * doc/gnat_rm/security_hardening_features.rst: Add examples of + codegen changes in hardened booleans. Mention that C traps where + Ada raises exceptions. + * gnat_rm.texi: Regenerate. + +2022-10-06 Alexandre Oliva + + * doc/gnat_rm/security_hardening_features.rst: Add examples of + codegen changes in stack scrubbing. + * gnat_rm.texi: Regenerate. + +2022-10-06 Piotr Trojanek + + * exp_ch9.adb (Build_Lock_Free_Protected_Subprogram_Body): Replace + shallow copy of protected statements with a deep copy. + +2022-10-06 Marc Poulhiès + + * fe.h (Has_Storage_Model_Type_Aspect) + (Has_Designated_Storage_Model_Aspect, Storage_Model_Object) + (Storage_Model_Copy_From, Storage_Model_Copy_To): Add + declarations. + * sem_util.ads: Add WARNING markers for functions for which a new + C declaration has been added in fe.h + +2022-10-06 Steve Baird + + * exp_util.adb + (Get_Current_Value_Condition): Treat references occurring within + the condition of an if statement, an elsif, or a while loop in the + same way as references that occur before the start of that + enclosing construct. + +2022-10-06 Gary Dismukes + + * sem_ch4.adb (Analyze_Call): Add test of Comes_From_Source on the + enclosing subprogram's Entity_Id for determining whether to + perform the compile-time accessibility check on actuals passed to + aliased formals in a function call occurring within a return + statement. That test excludes cases where the call occurs within + the return statement of a Pre'Class wrapper function. + +2022-10-06 Bob Duff + + * exp_ch5.adb + (Expand_Assign_Array_Loop_Or_Bitfield): Minor cleanups. + +2022-10-06 Yannick Moy + + * sem_prag.adb (Analyze_Pragma): Ignore one variant of pragma + Warnings in GNATprove mode. + +2022-10-06 Bob Duff + + * exp_ch5.adb + (Expand_Assign_Array_Loop_Or_Bitfield): Disable the + Fast_Copy_Bitfield optimization in certain cases. + +2022-10-06 Piotr Trojanek + + * sem_prag.adb + (Sig_Pragma): Change flag for pragma Refined_State to mean "not + significant"; this is primarily for documentation, because the + exact value of the flag is not really taken into account for + Refined_State. + (Is_Non_Significant_Pragma_Reference): Add special handling for + pragma Refined_State. + 2022-09-29 Ronan Desplanques * einfo.ads: remove documentation duplicate diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 627d9d7..70e9289 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,17 @@ +2022-10-06 David Malcolm + + PR analyzer/107158 + * store.cc (store::replay_call_summary_cluster): Eliminate + special-casing of RK_HEAP_ALLOCATED in favor of sharing code with + RK_DECL, avoiding an ICE due to attempting to bind a + compound_svalue into a binding_cluster when an svalue in the + summary cluster converts to a compound_svalue in the caller. + +2022-10-06 David Malcolm + + * call-summary.cc (call_summary_replay::dump_to_pp): Bulletproof + against NULL caller regions/svalues. + 2022-10-05 David Malcolm * analysis-plan.cc: Simplify includes. diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index c062fe1..75ff47d 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,18 @@ +2022-10-06 Joseph Myers + + * c-common.cc (c_common_reswords): Mark typeof as D_EXT11. Add + typeof_unqual. + * c-common.h (enum rid): Add RID_TYPEOF_UNQUAL. + (D_EXT11): New macro. Values of subsequent macros updated. + +2022-10-06 Jakub Jelinek + + PR c++/106654 + * c-attribs.cc (handle_assume_attribute): New function. + (c_common_attribute_table): Add entry for assume attribute. + * c-lex.cc (c_common_has_attribute): Handle + __have_cpp_attribute (assume). + 2022-10-04 Jakub Jelinek * c-omp.cc (c_omp_directives): Uncomment begin declare target diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 48eb23e..325b1f8 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,35 @@ +2022-10-06 Joseph Myers + + * c-parser.cc (c_parse_init): Add D_EXT11 to mask if flag_no_asm + and not C2x. + (c_keyword_starts_typename, c_token_starts_declspecs) + (c_parser_declspecs, c_parser_objc_selector): Handle + RID_TYPEOF_UNQUAL. + (c_parser_typeof_specifier): Handle RID_TYPEOF_UNQUAL. + Distinguish typeof for C2x from __typeof__ for all standard + versions and typeof before C2x. + * c-typeck.cc (build_function_call_vec): Use unqualified version + of non-void return type. + (build_unary_op): Use unqualified type for increment and + decrement. + +2022-10-06 Jakub Jelinek + + * c-parser.cc (c_parser_omp_assumption_clauses): Emit IFN_ASSUME + call for holds clause on assume construct. + +2022-10-06 Jakub Jelinek + + PR c++/106654 + * c-parser.cc (handle_assume_attribute): New function. + (c_parser_declaration_or_fndef): Handle assume attribute. + (c_parser_attribute_arguments): Add assume_attr argument, + if true, parse first argument as conditional expression. + (c_parser_gnu_attribute, c_parser_std_attribute): Adjust + c_parser_attribute_arguments callers. + (c_parser_statement_after_labels) : Handle + assume attribute. + 2022-10-04 Jakub Jelinek * c-lang.h (struct c_omp_declare_target_attr): New type. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1fc0799..0fe21fd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,57 @@ +2022-10-06 Jason Merrill + + * coroutines.cc (expand_one_await_expression): Change conversion + to VIEW_CONVERT_EXPR. + * cp-gimplify.cc (cp_genericize_r) [CONVERT_EXPR]: Add assert. + +2022-10-06 Joseph Myers + + * lex.cc (init_reswords): Handle D_EXT11. + +2022-10-06 Patrick Palka + + * pt.cc (optimize_specialization_lookup_p): Remove. + (retrieve_specialization): Assume the above returns false + and simplify accordingly. + (register_specialization): Likewise. + +2022-10-06 Jakub Jelinek + + * parser.cc (cp_parser_omp_assumption_clauses): Emit IFN_ASSUME + call for holds clause on assume construct. + +2022-10-06 Jakub Jelinek + + PR c++/106654 + * cp-tree.h (process_stmt_assume_attribute): Implement C++23 + P1774R8 - Portable assumptions. Declare. + (diagnose_failing_condition): Declare. + (find_failing_clause): Likewise. + * parser.cc (assume_attr): New enumerator. + (cp_parser_parenthesized_expression_list): Handle assume_attr. + Remove identifier variable, for id_attr push the identifier into + expression_list right away instead of inserting it before all the + others at the end. + (cp_parser_conditional_expression): New function. + (cp_parser_constant_expression): Use it. + (cp_parser_statement): Handle assume attribute. + (cp_parser_expression_statement): Likewise. + (cp_parser_gnu_attribute_list): Use assume_attr for assume + attribute. + (cp_parser_std_attribute): Likewise. Handle standard assume + attribute like gnu::assume. + * cp-gimplify.cc (process_stmt_assume_attribute): New function. + * constexpr.cc: Include fold-const.h. + (find_failing_clause_r, find_failing_clause): New functions, + moved from semantics.cc with ctx argument added and if non-NULL, + call cxx_eval_constant_expression rather than fold_non_dependent_expr. + (cxx_eval_internal_function): Handle IFN_ASSUME. + (potential_constant_expression_1): Likewise. + * pt.cc (tsubst_copy_and_build): Likewise. + * semantics.cc (diagnose_failing_condition): New function. + (find_failing_clause_r, find_failing_clause): Moved to constexpr.cc. + (finish_static_assert): Use it. Add auto_diagnostic_group. + 2022-10-05 Jason Merrill * tree.cc (lvalue_kind) [VIEW_CONVERT_EXPR]: Change prvalue to diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f359f12..535b9ae 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,8 @@ +2022-10-06 Tobias Burnus + + * trans-openmp.cc (gfc_trans_omp_assume): New. + (gfc_trans_omp_directive): Call it. + 2022-10-05 Tobias Burnus * dump-parse-tree.cc (show_omp_assumes): New. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 584fba4c..9577fc1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,80 @@ +2022-10-06 Aldy Hernandez + + PR tree-optimization/107170 + * gcc.dg/tree-ssa/pr107170.c: New test. + +2022-10-06 David Malcolm + + PR analyzer/107158 + * gcc.dg/analyzer/call-summaries-pr107158-2.c: New test. + +2022-10-06 Tobias Burnus + + * gfortran.dg/gomp/assume-3.f90: New test. + * gfortran.dg/gomp/assume-4.f90: New test. + +2022-10-06 Joseph Myers + + * gcc.dg/c11-typeof-1.c, gcc.dg/c2x-typeof-1.c, + gcc.dg/c2x-typeof-2.c, gcc.dg/c2x-typeof-3.c, + gcc.dg/gnu11-typeof-1.c, gcc.dg/gnu11-typeof-2.c, + gcc.dg/gnu2x-typeof-1.c: New tests. + +2022-10-06 Patrick Palka + + * g++.dg/modules/indirect-3_b.C: Expect that the entity + foo::TPL<0>::frob is tagged as a specialization instead + of as a declaration. + * g++.dg/modules/tpl-spec-8_a.H: New test. + * g++.dg/modules/tpl-spec-8_b.C: New test. + +2022-10-06 Eric Botcazou + + * gcc.c-torture/execute/20221006-1.c: New test. + +2022-10-06 Richard Biener + + PR middle-end/107115 + * gcc.dg/torture/pr107115.c: New testcase. + +2022-10-06 Kyrylo Tkachov + + * gcc.target/aarch64/ldar_2.c: New test. + +2022-10-06 Kyrylo Tkachov + + * gcc.target/aarch64/ldar_1.c: New test. + +2022-10-06 Philipp Tomsich + + * gcc.target/aarch64/cpunative/info_18: New test. + * gcc.target/aarch64/cpunative/native_cpu_18.c: New test. + +2022-10-06 Richard Biener + + PR tree-optimization/107107 + * gcc.dg/pr107107.c: New testcase. + +2022-10-06 Jakub Jelinek + + * c-c++-common/gomp/assume-4.c: New test. + +2022-10-06 Jakub Jelinek + + PR c++/106654 + * gcc.dg/attr-assume-1.c: New test. + * gcc.dg/attr-assume-2.c: New test. + * gcc.dg/attr-assume-3.c: New test. + * g++.dg/cpp2a/feat-cxx2a.C: Add colon to C++20 features + comment, add C++20 attributes comment and move C++20 + new features after the attributes before them. + * g++.dg/cpp23/feat-cxx2b.C: Likewise. Test + __has_cpp_attribute(assume). + * g++.dg/cpp23/attr-assume1.C: New test. + * g++.dg/cpp23/attr-assume2.C: New test. + * g++.dg/cpp23/attr-assume3.C: New test. + * g++.dg/cpp23/attr-assume4.C: New test. + 2022-10-05 David Malcolm PR analyzer/107158 -- cgit v1.1 From 8a9e92b249c9c5a5371588b1e939a90a677b4fd3 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Thu, 6 Oct 2022 15:58:59 -0400 Subject: compiler: better arg type checking for selected builtins Tighten up the argument type checking for Builtin_call_expression to catch erroneous cases such as panic(panic("bad"))) where an argument void type is being passed to panic/alignof/sizeof. Fixes golang/go#56071. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/439815 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 4793c82..10ed3fe 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -8f1a91aeff400d572857895b7f5e863ec5a4d93e +50707b4b51266166ce9bcf9de187e35760ec50f9 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 2492d9f..247ae1b 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -10316,7 +10316,12 @@ Builtin_call_expression::do_check_types(Gogo*) case BUILTIN_PANIC: case BUILTIN_SIZEOF: case BUILTIN_ALIGNOF: - this->check_one_arg(); + if (this->check_one_arg()) + { + Expression* arg = this->one_arg(); + if (arg->type()->is_void_type()) + this->report_error(_("argument to builtin has void type")); + } break; case BUILTIN_RECOVER: -- cgit v1.1 From 8307b7d6d0335da952a87bf56015f830072ac431 Mon Sep 17 00:00:00 2001 From: Olivier Hainque Date: Fri, 28 Jan 2022 16:34:50 +0000 Subject: undef offsetof before defining it in stddef.h This prevents redefinition warnings by -Wsystem-headers on OSses where system headers happen to provide a definition of their own, such as VxWorks. 2022-02-15 Olivier Hainque gcc/ * ginclude/stddef.h: #undef offsetof before #define. --- gcc/ginclude/stddef.h | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc') diff --git a/gcc/ginclude/stddef.h b/gcc/ginclude/stddef.h index 3d29213..2767edf 100644 --- a/gcc/ginclude/stddef.h +++ b/gcc/ginclude/stddef.h @@ -412,6 +412,7 @@ typedef __WINT_TYPE__ wint_t; #ifdef _STDDEF_H /* Offset of member MEMBER in a struct of type TYPE. */ +#undef offsetof /* in case a system header has defined it. */ #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER) #if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \ -- cgit v1.1 From 8dffd0e9621d93faabb6676e7a018cb5267dfa22 Mon Sep 17 00:00:00 2001 From: Olivier Hainque Date: Mon, 26 Sep 2022 16:05:48 +0000 Subject: Introduce DWARF_VERSION_DEFAULT and redefine for VxWorks This change introduces a target overridable macro to replace the hardcoded value used to initialize dwarf_version from common.opt. The main advantage compared to special code in a target override_options hook is that redefinitions by target config files are visible by both the compiler proper and by the driver, which might refer to dwarf_version in ASM_DEBUG_SPECs and friends. This is useful at least on VxWorks, where we usually need to default to dwarf 4 or even 2 to accommodate non-gdb debuggers provided by the environment, including for assembly sources used in libgcc for some ports (witnessed with lse.S on aarch64). 2022-02-28 Olivier Hainque gcc/ * defaults.h (DWARF_DEFAULT_VERSION): Define if not defined already. * common.opt (gdwarf-): Use it. * doc/tm.texi.in (DWARF_DEFAULT_VERSION): Document. * doc/tm.texi: Update accordingly. * config/vxworks.h (DWARF_DEFAULT_VERSION): Redefine. * config/vxworks.cc: Remove code setting dwarf_version, now handled by the DWARF_DEFAULT_VERSION redefinition. --- gcc/common.opt | 2 +- gcc/config/vxworks.cc | 10 ++-------- gcc/config/vxworks.h | 8 ++++---- gcc/defaults.h | 6 ++++++ gcc/doc/tm.texi | 6 ++++++ gcc/doc/tm.texi.in | 6 ++++++ 6 files changed, 25 insertions(+), 13 deletions(-) (limited to 'gcc') diff --git a/gcc/common.opt b/gcc/common.opt index 58dc1a0..3a97e67 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -3317,7 +3317,7 @@ Common Driver JoinedOrMissing Negative(gdwarf-) Generate debug information in default version of DWARF format. gdwarf- -Common Driver Joined UInteger Var(dwarf_version) Init(5) +Common Driver Joined UInteger Var(dwarf_version) Init(DWARF_VERSION_DEFAULT) Generate debug information in DWARF v2 (or later) format. gdwarf32 diff --git a/gcc/config/vxworks.cc b/gcc/config/vxworks.cc index 9d25873..f0c0df2 100644 --- a/gcc/config/vxworks.cc +++ b/gcc/config/vxworks.cc @@ -164,16 +164,10 @@ vxworks_override_options (void) if (flag_pic > 0 && !TARGET_VXWORKS_RTP) error ("PIC is only supported for RTPs"); - /* VxWorks comes with non-gdb debuggers which only support strict - dwarf up to certain version. Default dwarf control to friendly - values for these. */ - + /* VxWorks comes with non-gdb debuggers which only support strict dwarf + up to certain versions, as controlled by DWARF_VERSION_DEFAULT. */ if (!OPTION_SET_P (dwarf_strict)) dwarf_strict = 1; - - if (!OPTION_SET_P (dwarf_version)) - dwarf_version = VXWORKS_DWARF_VERSION_DEFAULT; - } /* We don't want to use library symbol __clear_cache on SR0640. Avoid diff --git a/gcc/config/vxworks.h b/gcc/config/vxworks.h index 84a9c93..d6ac83b 100644 --- a/gcc/config/vxworks.h +++ b/gcc/config/vxworks.h @@ -376,11 +376,11 @@ extern void vxworks_asm_out_destructor (rtx symbol, int priority); vxworks_emit_call_builtin___clear_cache extern void vxworks_emit_call_builtin___clear_cache (rtx begin, rtx end); -/* Default dwarf control values, for non-gdb debuggers that come with - VxWorks. */ +/* Default dwarf control values, accounting for non-gdb debuggers that come + with VxWorks. */ -#undef VXWORKS_DWARF_VERSION_DEFAULT -#define VXWORKS_DWARF_VERSION_DEFAULT (TARGET_VXWORKS7 ? 4 : 2) +#undef DWARF_VERSION_DEFAULT +#define DWARF_VERSION_DEFAULT (TARGET_VXWORKS7 ? 4 : 2) #undef DWARF_GNAT_ENCODINGS_DEFAULT #define DWARF_GNAT_ENCODINGS_DEFAULT \ diff --git a/gcc/defaults.h b/gcc/defaults.h index 953605c..376687d 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -1441,6 +1441,12 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define DWARF_GNAT_ENCODINGS_DEFAULT DWARF_GNAT_ENCODINGS_GDB #endif +/* When generating dwarf info, the default standard version we'll honor + and advertise in absence of -gdwarf- on the command line. */ +#ifndef DWARF_VERSION_DEFAULT +#define DWARF_VERSION_DEFAULT 5 +#endif + #ifndef USED_FOR_TARGET /* Done this way to keep gengtype happy. */ #if BITS_PER_UNIT == 8 diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 7590924f..110f8df 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -3294,6 +3294,12 @@ someone decided it was a good idea to use that register number to terminate the stack backtrace. New ports should avoid this. @end defmac +@defmac DWARF_VERSION_DEFAULT +A C expression whose value is the default dwarf standard version we'll honor +and advertise when generating dwarf debug information, in absence of +an explicit @option{-gdwarf-@var{version}} option on the command line. +@end defmac + @deftypefn {Target Hook} void TARGET_DWARF_HANDLE_FRAME_UNSPEC (const char *@var{label}, rtx @var{pattern}, int @var{index}) This target hook allows the backend to emit frame-related insns that contain UNSPECs or UNSPEC_VOLATILEs. The DWARF 2 call frame debugging diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 21b849e..501ddf1 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -2575,6 +2575,12 @@ someone decided it was a good idea to use that register number to terminate the stack backtrace. New ports should avoid this. @end defmac +@defmac DWARF_VERSION_DEFAULT +A C expression whose value is the default dwarf standard version we'll honor +and advertise when generating dwarf debug information, in absence of +an explicit @option{-gdwarf-@var{version}} option on the command line. +@end defmac + @hook TARGET_DWARF_HANDLE_FRAME_UNSPEC @hook TARGET_DWARF_POLY_INDETERMINATE_VALUE -- cgit v1.1 From b6ab375cbd07f71edb481358c3bcf5916df9aadf Mon Sep 17 00:00:00 2001 From: Olivier Hainque Date: Thu, 3 Mar 2022 16:58:51 +0000 Subject: Downgrade DWARF_VERSION_DEFAULT to 3 for VxWorks >= 7 Using 4 as the DWARF_VERSION_DEFAULT value for VxWorks observably still hangs recent system debuggers on tbreak for some contructs, and downgrading to 3 improves the situation. 2022-03-06 Olivier Hainque gcc/ * config/vxworks.h (DWARF_VERSION_DEFAULT): Adjust from 4 to 3 for VxWorks >= 7. --- gcc/config/vxworks.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/vxworks.h b/gcc/config/vxworks.h index d6ac83b..075a451 100644 --- a/gcc/config/vxworks.h +++ b/gcc/config/vxworks.h @@ -380,7 +380,7 @@ extern void vxworks_emit_call_builtin___clear_cache (rtx begin, rtx end); with VxWorks. */ #undef DWARF_VERSION_DEFAULT -#define DWARF_VERSION_DEFAULT (TARGET_VXWORKS7 ? 4 : 2) +#define DWARF_VERSION_DEFAULT (TARGET_VXWORKS7 ? 3 : 2) #undef DWARF_GNAT_ENCODINGS_DEFAULT #define DWARF_GNAT_ENCODINGS_DEFAULT \ -- cgit v1.1 From 88f04e90f63f08620cc9cd2f059a1315b70bed3b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 7 Oct 2022 09:01:04 +0200 Subject: c++: Improve handling of foreigner namespace attributes In some cases we want to look up or remove both standard attributes and attributes from gnu namespace but not others. This patch arranges for ATTR_NS of "" to stand for ATTR_NS NULL or "gnu", so that we don't need 2 separate calls, and introduces is_attribute_namespace_p function which allows testing the namespace of an attribute similar way. The patch also uses the new lookup_attribute overload and extra tests to avoid emitting weird warnings on foreign namespace attributes which we should just ignore (perhaps with a warning), but shouldn't imply any meaning to them just because they have a name matching some standard or gnu attribute name. 2022-10-07 Jakub Jelinek gcc/ * attribs.h (is_attribute_namespace_p): New inline function. (lookup_attribute): Document meaning of ATTR_NS equal to "". * attribs.cc (remove_attribute): Use is_attribute_namespace_p. (private_lookup_attribute): For ATTR_NS "" match either standard attribute or "gnu" namespace one. gcc/c-family/ * c-common.cc (attribute_fallthrough_p): Lookup fallthrough attribute only in gnu namespace or as standard attribute, treat fallthrough attributes in other namespaces like any other unknown attribute. gcc/cp/ * parser.cc (cp_parser_check_std_attribute): Only do checks if attribute is a standard attribute or in gnu namespace and only lookup other attributes in those namespaces. * cp-gimplify.cc (lookup_hotness_attribute): Adjust function comment. Only return true for standard attribute or gnu namespace attribute. (remove_hotness_attribute): Only remove hotness attributes when they are standard or in gnu namespace, implement it in a single loop rather than former 4 now 8 remove_attribute calls. gcc/testsuite/ * g++.dg/cpp1z/fallthrough2.C: New test. * g++.dg/cpp2a/attr-likely7.C: New test. --- gcc/attribs.cc | 27 ++++++++++++---------- gcc/attribs.h | 19 +++++++++++++++- gcc/c-family/c-common.cc | 7 +++--- gcc/cp/cp-gimplify.cc | 32 ++++++++++++++++++-------- gcc/cp/parser.cc | 3 ++- gcc/testsuite/g++.dg/cpp1z/fallthrough2.C | 24 +++++++++++++++++++ gcc/testsuite/g++.dg/cpp2a/attr-likely7.C | 38 +++++++++++++++++++++++++++++++ 7 files changed, 123 insertions(+), 27 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/fallthrough2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/attr-likely7.C (limited to 'gcc') diff --git a/gcc/attribs.cc b/gcc/attribs.cc index 38f3e926..27dea74 100644 --- a/gcc/attribs.cc +++ b/gcc/attribs.cc @@ -1645,7 +1645,8 @@ remove_attribute (const char *attr_name, tree list) return list; } -/* Similarly but also match namespace on the removed attributes. */ +/* Similarly but also match namespace on the removed attributes. + ATTR_NS "" stands for NULL or "gnu" namespace. */ tree remove_attribute (const char *attr_ns, const char *attr_name, tree list) @@ -1659,15 +1660,11 @@ remove_attribute (const char *attr_ns, const char *attr_name, tree list) tree l = *p; tree attr = get_attribute_name (l); - if (is_attribute_p (attr_name, attr)) + if (is_attribute_p (attr_name, attr) + && is_attribute_namespace_p (attr_ns, l)) { - tree ns = get_attribute_namespace (l); - if ((ns == NULL_TREE && attr_ns == NULL) - || (ns && attr_ns && is_attribute_p (attr_ns, ns))) - { - *p = TREE_CHAIN (l); - continue; - } + *p = TREE_CHAIN (l); + continue; } p = &TREE_CHAIN (l); } @@ -2088,14 +2085,20 @@ private_lookup_attribute (const char *attr_ns, const char *attr_name, tree ns = get_attribute_namespace (list); if (ns == NULL_TREE) { - if (attr_ns == NULL) + if (attr_ns_len == 0) break; } else if (attr_ns) { ident_len = IDENTIFIER_LENGTH (ns); - if (cmp_attribs (attr_ns, attr_ns_len, IDENTIFIER_POINTER (ns), - ident_len)) + if (attr_ns_len == 0) + { + if (cmp_attribs ("gnu", strlen ("gnu"), + IDENTIFIER_POINTER (ns), ident_len)) + break; + } + else if (cmp_attribs (attr_ns, attr_ns_len, + IDENTIFIER_POINTER (ns), ident_len)) break; } } diff --git a/gcc/attribs.h b/gcc/attribs.h index 121b9eb..1dc16e4 100644 --- a/gcc/attribs.h +++ b/gcc/attribs.h @@ -188,6 +188,22 @@ is_attribute_p (const char *attr_name, const_tree ident) IDENTIFIER_POINTER (ident), IDENTIFIER_LENGTH (ident)); } +/* Given an attribute ATTR and a string ATTR_NS, return true + if the attribute namespace is valid for the string. ATTR_NS "" stands + for standard attribute (NULL get_attribute_namespace) or "gnu" + namespace. */ + +static inline bool +is_attribute_namespace_p (const char *attr_ns, const_tree attr) +{ + tree ident = get_attribute_namespace (attr); + if (attr_ns == NULL) + return ident == NULL_TREE; + if (attr_ns[0]) + return ident && is_attribute_p (attr_ns, ident); + return ident == NULL_TREE || is_attribute_p ("gnu", ident); +} + /* Given an attribute name ATTR_NAME and a list of attributes LIST, return a pointer to the attribute's list element if the attribute is part of the list, or NULL_TREE if not found. If the attribute @@ -217,7 +233,8 @@ lookup_attribute (const char *attr_name, tree list) } } -/* Similar to lookup_attribute, but also match the attribute namespace. */ +/* Similar to lookup_attribute, but also match the attribute namespace. + ATTR_NS "" stands for either standard attribute or "gnu" namespace. */ static inline tree lookup_attribute (const char *attr_ns, const char *attr_name, tree list) diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index ffe17ea..9ec9100 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -6008,12 +6008,12 @@ attribute_fallthrough_p (tree attr) { if (attr == error_mark_node) return false; - tree t = lookup_attribute ("fallthrough", attr); + tree t = lookup_attribute ("", "fallthrough", attr); if (t == NULL_TREE) return false; /* It is no longer true that "this attribute shall appear at most once in each attribute-list", but we still give a warning. */ - if (lookup_attribute ("fallthrough", TREE_CHAIN (t))) + if (lookup_attribute ("", "fallthrough", TREE_CHAIN (t))) warning (OPT_Wattributes, "attribute % specified multiple " "times"); /* No attribute-argument-clause shall be present. */ @@ -6024,7 +6024,8 @@ attribute_fallthrough_p (tree attr) for (t = attr; t != NULL_TREE; t = TREE_CHAIN (t)) { tree name = get_attribute_name (t); - if (!is_attribute_p ("fallthrough", name)) + if (!is_attribute_p ("fallthrough", name) + || !is_attribute_namespace_p ("", t)) { if (!c_dialect_cxx () && get_attribute_namespace (t) == NULL_TREE) /* The specifications of standard attributes in C mean diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index 5d26e59..cb8bbd8 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -3028,7 +3028,7 @@ cp_fold (tree x) return x; } -/* Look up either "hot" or "cold" in attribute list LIST. */ +/* Look up "hot", "cold", "likely" or "unlikely" in attribute list LIST. */ tree lookup_hotness_attribute (tree list) @@ -3036,24 +3036,36 @@ lookup_hotness_attribute (tree list) for (; list; list = TREE_CHAIN (list)) { tree name = get_attribute_name (list); - if (is_attribute_p ("hot", name) - || is_attribute_p ("cold", name) - || is_attribute_p ("likely", name) - || is_attribute_p ("unlikely", name)) + if ((is_attribute_p ("hot", name) + || is_attribute_p ("cold", name) + || is_attribute_p ("likely", name) + || is_attribute_p ("unlikely", name)) + && is_attribute_namespace_p ("", list)) break; } return list; } -/* Remove both "hot" and "cold" attributes from LIST. */ +/* Remove "hot", "cold", "likely" and "unlikely" attributes from LIST. */ static tree remove_hotness_attribute (tree list) { - list = remove_attribute ("hot", list); - list = remove_attribute ("cold", list); - list = remove_attribute ("likely", list); - list = remove_attribute ("unlikely", list); + for (tree *p = &list; *p; ) + { + tree l = *p; + tree name = get_attribute_name (l); + if ((is_attribute_p ("hot", name) + || is_attribute_p ("cold", name) + || is_attribute_p ("likely", name) + || is_attribute_p ("unlikely", name)) + && is_attribute_namespace_p ("", l)) + { + *p = TREE_CHAIN (l); + continue; + } + p = &TREE_CHAIN (l); + } return list; } diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 90e06f9..555476e 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -29265,7 +29265,8 @@ cp_parser_check_std_attribute (location_t loc, tree attributes, tree attribute) if (attributes) for (const auto &a : alist) if (is_attribute_p (a, get_attribute_name (attribute)) - && lookup_attribute (a, attributes)) + && is_attribute_namespace_p ("", attribute) + && lookup_attribute ("", a, attributes)) { if (!from_macro_expansion_at (loc)) warning_at (loc, OPT_Wattributes, "attribute %qs specified " diff --git a/gcc/testsuite/g++.dg/cpp1z/fallthrough2.C b/gcc/testsuite/g++.dg/cpp1z/fallthrough2.C new file mode 100644 index 0000000..b74323f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/fallthrough2.C @@ -0,0 +1,24 @@ +// { dg-do compile { target c++17 } } +// { dg-options "-Wextra -Wall -Wpedantic" } + +int +foo (int i) +{ + switch (i) + { + case 2: + ++i; + [[fallthrough, whatever::fallthrough]]; // { dg-bogus "attribute 'fallthrough' specified multiple times" } + case 3: // { dg-warning "'fallthrough' attribute ignored" "" { target *-*-* } .-1 } + ++i; + [[fallthrough, whatever2::fallthrough(1, 2, 3)]]; // { dg-bogus "attribute 'fallthrough' specified multiple times" } + case 4: // { dg-warning "'fallthrough' attribute ignored" "" { target *-*-* } .-1 } + [[whatever3::fallthrough("abcd")]]; // { dg-warning "attributes at the beginning of statement are ignored" } + case 5: + [[whatever4::fallthrough]]; // { dg-bogus "attribute 'fallthrough' not preceding a case label or default label" } + ++i; // { dg-warning "attributes at the beginning of statement are ignored" "" { target *-*-* } .-1 } + default: + break; + } + return i; +} diff --git a/gcc/testsuite/g++.dg/cpp2a/attr-likely7.C b/gcc/testsuite/g++.dg/cpp2a/attr-likely7.C new file mode 100644 index 0000000..638a6d9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/attr-likely7.C @@ -0,0 +1,38 @@ +// { dg-do compile { target c++20 } } +// { dg-additional-options -fdump-tree-gimple } +// { dg-final { scan-tree-dump-times "hot label" 5 "gimple" } } +// { dg-final { scan-tree-dump-times "cold label" 3 "gimple" } } + +bool b; + +template int f() +{ + if (b) + [[likely, whatever::unlikely ("abcd")]] return 0; // { dg-bogus "ignoring attribute 'unlikely' after earlier 'likely'" } + else // { dg-warning "attributes at the beginning of statement are ignored" "" { target *-*-* } .-1 } + [[unlikely, whatever2::hot]] flabel: return 1; // { dg-warning "'whatever2::hot' scoped attribute directive ignored" } + switch (b) + { + [[likely, whatever3::cold (1, 2, 3)]] case true: break; // { dg-warning "'whatever3::cold' scoped attribute directive ignored" } + }; + return 1; +} + +int main() +{ + if (b) + [[whatever4::unlikely (1), likely]] return 0; // { dg-bogus "ignoring attribute 'likely' after earlier 'unlikely'" } + else if (b) // { dg-warning "attributes at the beginning of statement are ignored" "" { target *-*-* } .-1 } + [[whatever5::hot, unlikely]] elabel: // { dg-warning "'whatever5::hot' scoped attribute directive ignored" } + return 1; + else + [[whatever6::cold, likely]] b = false; // { dg-bogus "ignoring attribute 'likely' after earlier 'cold'" } + // { dg-warning "attributes at the beginning of statement are ignored" "" { target *-*-* } .-1 } + f(); + + switch (b) + { + [[whatever7::unlikely (1), likely]] case true: break; // { dg-warning "'whatever7::unlikely' scoped attribute directive ignored" } + [[whatever8::unlikely, unlikely]] case false: break; // { dg-bogus "attribute 'unlikely' specified multiple times" } + }; // { dg-warning "'whatever8::unlikely' scoped attribute directive ignored" "" { target *-*-* } .-1 } +} -- cgit v1.1 From e66236c6e9eb83730dde15f359f2a21cb603887b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 7 Oct 2022 09:08:46 +0200 Subject: Fix comment typos When looking at tree-inline.cc I've noticed a comment typo and grepped for similar typos elsewhere. 2022-10-07 Jakub Jelinek * ipa-prop.h (ipa_constant_data): Fix comment typo. * value-range.cc (irange::irange_contains_p): Likewise. * value-relation.cc (dom_oracle::set_one_relation): Likewise. * gimple-predicate-analysis.cc (predicate::simplify_4): Likewise. * tree-inline.cc (remap_ssa_name): Likewise. --- gcc/gimple-predicate-analysis.cc | 2 +- gcc/ipa-prop.h | 2 +- gcc/tree-inline.cc | 2 +- gcc/value-range.cc | 2 +- gcc/value-relation.cc | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-predicate-analysis.cc b/gcc/gimple-predicate-analysis.cc index bc9ed84..5013a44 100644 --- a/gcc/gimple-predicate-analysis.cc +++ b/gcc/gimple-predicate-analysis.cc @@ -1369,7 +1369,7 @@ predicate::simplify_3 () /* Implement rule 4 for the OR predicate PREDS: 2) ((x AND y) != 0) OR (x != 0 AND y != 0) is equivalent to - (x != 0 ANd y != 0). */ + (x != 0 AND y != 0). */ bool predicate::simplify_4 () diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index 8811e0e..e54842d 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -78,7 +78,7 @@ struct ipa_cst_ref_desc; /* Structure holding data required to describe a constant jump function. */ struct GTY(()) ipa_constant_data { - /* THe value of the constant. */ + /* The value of the constant. */ tree value; /* Pointer to the structure that describes the reference. */ struct ipa_cst_ref_desc GTY((skip)) *rdesc; diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc index 043e1d5..01d4700 100644 --- a/gcc/tree-inline.cc +++ b/gcc/tree-inline.cc @@ -171,7 +171,7 @@ remap_ssa_name (tree name, copy_body_data *id) n = id->decl_map->get (name); if (n) { - /* WHen we perform edge redirection as part of CFG copy, IPA-SRA can + /* When we perform edge redirection as part of CFG copy, IPA-SRA can remove an unused LHS from a call statement. Such LHS can however still appear in debug statements, but their value is lost in this function and we do not want to map them. */ diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 87239fa..727ca7d 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -2508,7 +2508,7 @@ irange::irange_contains_p (const irange &r) const // Otherwise, check if this's pair occurs before R's. if (wi::lt_p (wi::to_wide (u), wi::to_wide (rl), sign)) { - // THere's still at leats one pair of R left. + // There's still at leats one pair of R left. if (++i >= num_pairs ()) return false; l = m_base[i * 2]; diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc index e6f5ef4..1ee6da1 100644 --- a/gcc/value-relation.cc +++ b/gcc/value-relation.cc @@ -955,7 +955,7 @@ dom_oracle::set_one_relation (basic_block bb, relation_kind k, tree op1, ptr->dump (dump_file); } // Check into whether we can simply replace the relation rather than - // intersecting it. THis may help with some optimistic iterative + // intersecting it. This may help with some optimistic iterative // updating algorithms. bool new_rel = ptr->intersect (vr); if (dump_file && (dump_flags & TDF_DETAILS)) -- cgit v1.1 From bd0e35188f2a40a428314ad10e10ab5b0926f935 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 7 Oct 2022 10:10:30 +0200 Subject: remove dead variables Remove unused variables that are modified but not used. gcc/ChangeLog: * auto-profile.cc (get_inline_stack): Remove unused variable. gcc/objc/ChangeLog: * objc-gnu-runtime-abi-01.cc (generate_static_references): Remove unused variable. --- gcc/auto-profile.cc | 2 -- gcc/objc/objc-gnu-runtime-abi-01.cc | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/auto-profile.cc b/gcc/auto-profile.cc index 6533722..ca48404 100644 --- a/gcc/auto-profile.cc +++ b/gcc/auto-profile.cc @@ -388,7 +388,6 @@ get_inline_stack (location_t locus, inline_stack *stack) tree block = LOCATION_BLOCK (locus); if (block && TREE_CODE (block) == BLOCK) { - int level = 0; for (block = BLOCK_SUPERCONTEXT (block); block && (TREE_CODE (block) == BLOCK); block = BLOCK_SUPERCONTEXT (block)) @@ -401,7 +400,6 @@ get_inline_stack (location_t locus, inline_stack *stack) stack->safe_push ( std::make_pair (decl, get_combined_location (locus, decl))); locus = tmp_locus; - level++; } } stack->safe_push ( diff --git a/gcc/objc/objc-gnu-runtime-abi-01.cc b/gcc/objc/objc-gnu-runtime-abi-01.cc index 9413314..e76c486 100644 --- a/gcc/objc/objc-gnu-runtime-abi-01.cc +++ b/gcc/objc/objc-gnu-runtime-abi-01.cc @@ -1852,7 +1852,7 @@ generate_static_references (void) tree class_name, klass, decl; tree cl_chain, in_chain, type = build_array_type (build_pointer_type (void_type_node), NULL_TREE); - int num_inst, num_class; + int num_class; char buf[BUFSIZE]; vec *decls = NULL; @@ -1861,8 +1861,8 @@ generate_static_references (void) { vec *v = NULL; - for (num_inst = 0, in_chain = TREE_PURPOSE (cl_chain); - in_chain; num_inst++, in_chain = TREE_CHAIN (in_chain)); + for (in_chain = TREE_PURPOSE (cl_chain); + in_chain; in_chain = TREE_CHAIN (in_chain)); snprintf (buf, BUFSIZE, "_OBJC_STATIC_INSTANCES_%d", num_class); decl = start_var_decl (type, buf); -- cgit v1.1 From e1d1842b5432472330384d1523bb3c3132c4fea0 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 7 Oct 2022 10:22:24 +0200 Subject: fix clang warnings Fixes: gcc/c-family/name-hint.h:109:66: warning: unqualified call to 'std::move' [-Wunqualified-std-cast-call] gcc/config/i386/i386-expand.cc:1351:9: warning: argument 'operands' of type 'rtx[3]' (aka 'rtx_def *[3]') with mismatched bound [-Warray-parameter] gcc/config/i386/i386.cc:15635:8: warning: argument 'operands' of type 'rtx[2]' (aka 'rtx_def *[2]') with mismatched bound [-Warray-parameter] gcc/cp/module.cc:17482:51: warning: argument 'counts' of type 'unsigned int[8]' with mismatched bound [-Warray-parameter] gcc/cp/module.cc:17508:37: warning: argument 'counts' of type 'unsigned int[8]' with mismatched bound [-Warray-parameter] gcc/cp/name-lookup.cc:6385:16: warning: unqualified call to 'std::move' [-Wunqualified-std-cast-call] gcc/c-family/ChangeLog: * name-hint.h: Use std::move. gcc/ChangeLog: * config/i386/i386-protos.h (ix86_binary_operator_ok): Add array size to function parameter. (ix86_unary_operator_ok): Likewise. gcc/cp/ChangeLog: * module.cc (enum module_state_counts): Use array size. * name-lookup.cc (class namespace_limit_reached): Likewise. (class module_state): Move up in the file. --- gcc/c-family/name-hint.h | 2 +- gcc/config/i386/i386-protos.h | 4 ++-- gcc/cp/module.cc | 32 ++++++++++++++++---------------- gcc/cp/name-lookup.cc | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) (limited to 'gcc') diff --git a/gcc/c-family/name-hint.h b/gcc/c-family/name-hint.h index df733e7..98392ce 100644 --- a/gcc/c-family/name-hint.h +++ b/gcc/c-family/name-hint.h @@ -106,7 +106,7 @@ public: /* Take ownership of this name_hint's deferred_diagnostic, for use in chaining up deferred diagnostics. */ - std::unique_ptr take_deferred () { return move (m_deferred); } + std::unique_ptr take_deferred () { return std::move (m_deferred); } /* Call this on a name_hint if the corresponding warning was not emitted, in which case we should also not emit the deferred_diagnostic. */ diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 3b94efe..5318fc7 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -109,7 +109,7 @@ extern void ix86_expand_binary_operator (enum rtx_code, machine_mode, rtx[]); extern void ix86_expand_vector_logical_operator (enum rtx_code, machine_mode, rtx[]); -extern bool ix86_binary_operator_ok (enum rtx_code, machine_mode, rtx[]); +extern bool ix86_binary_operator_ok (enum rtx_code, machine_mode, rtx[3]); extern bool ix86_avoid_lea_for_add (rtx_insn *, rtx[]); extern bool ix86_use_lea_for_mov (rtx_insn *, rtx[]); extern bool ix86_avoid_lea_for_addr (rtx_insn *, rtx[]); @@ -140,7 +140,7 @@ extern void ix86_split_fp_absneg_operator (enum rtx_code, machine_mode, rtx[]); extern void ix86_expand_copysign (rtx []); extern void ix86_expand_xorsign (rtx []); -extern bool ix86_unary_operator_ok (enum rtx_code, machine_mode, rtx[]); +extern bool ix86_unary_operator_ok (enum rtx_code, machine_mode, rtx[2]); extern bool ix86_match_ccmode (rtx, machine_mode); extern void ix86_expand_branch (enum rtx_code, rtx, rtx, rtx); extern void ix86_expand_setcc (rtx, enum rtx_code, rtx, rtx); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 500ac06..c5eff21 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -3469,6 +3469,20 @@ enum streamed_extensions { SE_BITS = 1 }; +/* Counter indices. */ +enum module_state_counts +{ + MSC_sec_lwm, + MSC_sec_hwm, + MSC_pendings, + MSC_entities, + MSC_namespaces, + MSC_bindings, + MSC_macros, + MSC_inits, + MSC_HWM +}; + /********************************************************************/ struct module_state_config; @@ -3666,8 +3680,8 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state { private: void write_config (elf_out *to, struct module_state_config &, unsigned crc); bool read_config (struct module_state_config &); - static void write_counts (elf_out *to, unsigned [], unsigned *crc_ptr); - bool read_counts (unsigned []); + static void write_counts (elf_out *to, unsigned [MSC_HWM], unsigned *crc_ptr); + bool read_counts (unsigned *); public: void note_cmi_name (); @@ -14541,20 +14555,6 @@ module_state::read_partitions (unsigned count) return true; } -/* Counter indices. */ -enum module_state_counts -{ - MSC_sec_lwm, - MSC_sec_hwm, - MSC_pendings, - MSC_entities, - MSC_namespaces, - MSC_bindings, - MSC_macros, - MSC_inits, - MSC_HWM -}; - /* Data for config reading and writing. */ struct module_state_config { const char *dialect_str; diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index d6757d1..25657cf 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -6382,7 +6382,7 @@ class namespace_limit_reached : public deferred_diagnostic std::unique_ptr wrapped) : deferred_diagnostic (loc), m_limit (limit), m_name (name), - m_wrapped (move (wrapped)) + m_wrapped (std::move (wrapped)) { } -- cgit v1.1 From ffaf244c442c575aadbe1c947e22f791a6f14c96 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 7 Oct 2022 09:57:32 +0200 Subject: Convert nonzero mask back to tree. Having nonzero masks always set had a performance penalty of 10% in VRP, so mask==NULL is a shortcut to all bits set. gcc/ChangeLog: * value-range.cc (irange::irange_set): Convert nonzero mask to tree. (irange::irange_set_anti_range): Same. (irange::set): Same. (irange::verify_range): Same. (irange::contains_p): Same. (irange::invert): Same. (irange::set_range_from_nonzero_bits): Same. (irange::set_nonzero_bits): Same. (mask_to_wi): Same. (irange::intersect_nonzero_bits): Same. (irange::union_nonzero_bits): Same. * value-range.h (irange::varying_compatible_p): Same. (gt_ggc_mx): Same. (gt_pch_nx): Same. (irange::set_undefined): Same. (irange::set_varying): Same. --- gcc/value-range.cc | 85 ++++++++++++++++++++++++++++++++++++++++++------------ gcc/value-range.h | 19 +++++++----- 2 files changed, 77 insertions(+), 27 deletions(-) (limited to 'gcc') diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 727ca7d..16105f8 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -935,7 +935,7 @@ irange::irange_set (tree min, tree max) m_base[1] = max; m_num_ranges = 1; m_kind = VR_RANGE; - m_nonzero_mask = wi::shwi (-1, TYPE_PRECISION (TREE_TYPE (min))); + m_nonzero_mask = NULL; normalize_kind (); if (flag_checking) @@ -1009,7 +1009,7 @@ irange::irange_set_anti_range (tree min, tree max) } m_kind = VR_RANGE; - m_nonzero_mask = wi::shwi (-1, TYPE_PRECISION (TREE_TYPE (min))); + m_nonzero_mask = NULL; normalize_kind (); if (flag_checking) @@ -1066,7 +1066,7 @@ irange::set (tree min, tree max, value_range_kind kind) m_base[0] = min; m_base[1] = max; m_num_ranges = 1; - m_nonzero_mask = wi::shwi (-1, TYPE_PRECISION (TREE_TYPE (min))); + m_nonzero_mask = NULL; return; } @@ -1116,7 +1116,7 @@ irange::set (tree min, tree max, value_range_kind kind) m_base[0] = min; m_base[1] = max; m_num_ranges = 1; - m_nonzero_mask = wi::shwi (-1, TYPE_PRECISION (TREE_TYPE (min))); + m_nonzero_mask = NULL; normalize_kind (); if (flag_checking) verify_range (); @@ -1135,7 +1135,8 @@ irange::verify_range () } if (m_kind == VR_VARYING) { - gcc_checking_assert (m_nonzero_mask == -1); + gcc_checking_assert (!m_nonzero_mask + || wi::to_wide (m_nonzero_mask) == -1); gcc_checking_assert (m_num_ranges == 1); gcc_checking_assert (varying_compatible_p ()); return; @@ -1409,10 +1410,10 @@ irange::contains_p (tree cst) const gcc_checking_assert (TREE_CODE (cst) == INTEGER_CST); // See if we can exclude CST based on the nonzero bits. - if (m_nonzero_mask != -1) + if (m_nonzero_mask) { wide_int cstw = wi::to_wide (cst); - if (cstw != 0 && wi::bit_and (m_nonzero_mask, cstw) == 0) + if (cstw != 0 && wi::bit_and (wi::to_wide (m_nonzero_mask), cstw) == 0) return false; } @@ -2776,7 +2777,7 @@ irange::invert () signop sign = TYPE_SIGN (ttype); wide_int type_min = wi::min_value (prec, sign); wide_int type_max = wi::max_value (prec, sign); - m_nonzero_mask = wi::shwi (-1, prec); + m_nonzero_mask = NULL; if (m_num_ranges == m_max_ranges && lower_bound () != type_min && upper_bound () != type_max) @@ -2878,20 +2879,22 @@ bool irange::set_range_from_nonzero_bits () { gcc_checking_assert (!undefined_p ()); - unsigned popcount = wi::popcount (m_nonzero_mask); + if (!m_nonzero_mask) + return false; + unsigned popcount = wi::popcount (wi::to_wide (m_nonzero_mask)); // If we have only one bit set in the mask, we can figure out the // range immediately. if (popcount == 1) { // Make sure we don't pessimize the range. - if (!contains_p (wide_int_to_tree (type (), m_nonzero_mask))) + if (!contains_p (m_nonzero_mask)) return false; bool has_zero = contains_p (build_zero_cst (type ())); - wide_int bits = m_nonzero_mask; - set (type (), bits, bits); - m_nonzero_mask = bits; + tree nz = m_nonzero_mask; + set (nz, nz); + m_nonzero_mask = nz; if (has_zero) { int_range<2> zero; @@ -2909,11 +2912,21 @@ irange::set_nonzero_bits (const wide_int_ref &bits) gcc_checking_assert (!undefined_p ()); unsigned prec = TYPE_PRECISION (type ()); + if (bits == -1) + { + m_nonzero_mask = NULL; + normalize_kind (); + if (flag_checking) + verify_range (); + return; + } + // Drop VARYINGs with a nonzero mask to a plain range. if (m_kind == VR_VARYING && bits != -1) m_kind = VR_RANGE; - m_nonzero_mask = wide_int::from (bits, prec, TYPE_SIGN (type ())); + wide_int nz = wide_int::from (bits, prec, TYPE_SIGN (type ())); + m_nonzero_mask = wide_int_to_tree (type (), nz); if (set_range_from_nonzero_bits ()) return; @@ -2937,7 +2950,21 @@ irange::get_nonzero_bits () const // the mask precisely up to date at all times. Instead, we default // to -1 and set it when explicitly requested. However, this // function will always return the correct mask. - return m_nonzero_mask & get_nonzero_bits_from_range (); + if (m_nonzero_mask) + return wi::to_wide (m_nonzero_mask) & get_nonzero_bits_from_range (); + else + return get_nonzero_bits_from_range (); +} + +// Convert tree mask to wide_int. Returns -1 for NULL masks. + +inline wide_int +mask_to_wi (tree mask, tree type) +{ + if (mask) + return wi::to_wide (mask); + else + return wi::shwi (-1, TYPE_PRECISION (type)); } // Intersect the nonzero bits in R into THIS and normalize the range. @@ -2948,10 +2975,20 @@ irange::intersect_nonzero_bits (const irange &r) { gcc_checking_assert (!undefined_p () && !r.undefined_p ()); + if (!m_nonzero_mask && !r.m_nonzero_mask) + { + normalize_kind (); + if (flag_checking) + verify_range (); + return false; + } + bool changed = false; - if (m_nonzero_mask != r.m_nonzero_mask) + tree t = type (); + if (mask_to_wi (m_nonzero_mask, t) != mask_to_wi (r.m_nonzero_mask, t)) { - m_nonzero_mask = get_nonzero_bits () & r.get_nonzero_bits (); + wide_int nz = get_nonzero_bits () & r.get_nonzero_bits (); + m_nonzero_mask = wide_int_to_tree (t, nz); if (set_range_from_nonzero_bits ()) return true; changed = true; @@ -2970,10 +3007,20 @@ irange::union_nonzero_bits (const irange &r) { gcc_checking_assert (!undefined_p () && !r.undefined_p ()); + if (!m_nonzero_mask && !r.m_nonzero_mask) + { + normalize_kind (); + if (flag_checking) + verify_range (); + return false; + } + bool changed = false; - if (m_nonzero_mask != r.m_nonzero_mask) + tree t = type (); + if (mask_to_wi (m_nonzero_mask, t) != mask_to_wi (r.m_nonzero_mask, t)) { - m_nonzero_mask = get_nonzero_bits () | r.get_nonzero_bits (); + wide_int nz = get_nonzero_bits () | r.get_nonzero_bits (); + m_nonzero_mask = wide_int_to_tree (t, nz); // No need to call set_range_from_nonzero_bits, because we'll // never narrow the range. Besides, it would cause endless // recursion because of the union_ in diff --git a/gcc/value-range.h b/gcc/value-range.h index b06ca74..484f911 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -215,7 +215,7 @@ private: bool intersect (const wide_int& lb, const wide_int& ub); unsigned char m_num_ranges; unsigned char m_max_ranges; - wide_int m_nonzero_mask; + tree m_nonzero_mask; tree *m_base; }; @@ -683,11 +683,11 @@ irange::varying_compatible_p () const if (INTEGRAL_TYPE_P (t)) return (wi::to_wide (l) == wi::min_value (prec, sign) && wi::to_wide (u) == wi::max_value (prec, sign) - && m_nonzero_mask == -1); + && (!m_nonzero_mask || wi::to_wide (m_nonzero_mask) == -1)); if (POINTER_TYPE_P (t)) return (wi::to_wide (l) == 0 && wi::to_wide (u) == wi::max_value (prec, sign) - && m_nonzero_mask == -1); + && (!m_nonzero_mask || wi::to_wide (m_nonzero_mask) == -1)); return true; } @@ -754,6 +754,8 @@ gt_ggc_mx (irange *x) gt_ggc_mx (x->m_base[i * 2]); gt_ggc_mx (x->m_base[i * 2 + 1]); } + if (x->m_nonzero_mask) + gt_ggc_mx (x->m_nonzero_mask); } inline void @@ -764,6 +766,8 @@ gt_pch_nx (irange *x) gt_pch_nx (x->m_base[i * 2]); gt_pch_nx (x->m_base[i * 2 + 1]); } + if (x->m_nonzero_mask) + gt_pch_nx (x->m_nonzero_mask); } inline void @@ -774,6 +778,8 @@ gt_pch_nx (irange *x, gt_pointer_operator op, void *cookie) op (&x->m_base[i * 2], NULL, cookie); op (&x->m_base[i * 2 + 1], NULL, cookie); } + if (x->m_nonzero_mask) + op (&x->m_nonzero_mask, NULL, cookie); } template @@ -868,6 +874,7 @@ irange::set_undefined () { m_kind = VR_UNDEFINED; m_num_ranges = 0; + m_nonzero_mask = NULL; } inline void @@ -875,11 +882,7 @@ irange::set_varying (tree type) { m_kind = VR_VARYING; m_num_ranges = 1; - - if (type == error_mark_node) - m_nonzero_mask = wi::shwi (-1, 1); - else - m_nonzero_mask = wi::shwi (-1, TYPE_PRECISION (type)); + m_nonzero_mask = NULL; if (INTEGRAL_TYPE_P (type)) { -- cgit v1.1 From 7b8a77eba5efbc6d9556f026774fa1447675602c Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Fri, 7 Oct 2022 12:14:30 +0200 Subject: Reduce DF computation at -O0 Even at -O0 there may be a fair amount of DF computation performed when compiling large units and part of it appears to be useless. gcc/ * function.cc (thread_prologue_and_epilogue_insns): Update only entry and exit blocks when not optimizing. Remove dead statement. --- gcc/function.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/function.cc b/gcc/function.cc index 5498a71..6474a66 100644 --- a/gcc/function.cc +++ b/gcc/function.cc @@ -6249,10 +6249,15 @@ thread_prologue_and_epilogue_insns (void) } } - /* Threading the prologue and epilogue changes the artificial refs - in the entry and exit blocks. */ - epilogue_completed = 1; - df_update_entry_exit_and_calls (); + /* Threading the prologue and epilogue changes the artificial refs in the + entry and exit blocks, and may invalidate DF info for tail calls. */ + if (optimize) + df_update_entry_exit_and_calls (); + else + { + df_update_entry_block_defs (); + df_update_exit_block_uses (); + } } /* Reposition the prologue-end and epilogue-begin notes after -- cgit v1.1 From df78e15233c1dcf9b935c7380fc95359ebcc5562 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 7 Oct 2022 12:20:36 +0100 Subject: gcc: Fix comment typo gcc/ChangeLog: * value-range.cc (irange::irange_contains_p): Fix comment typo. --- gcc/value-range.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 16105f8..a14f9bc 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -2509,7 +2509,7 @@ irange::irange_contains_p (const irange &r) const // Otherwise, check if this's pair occurs before R's. if (wi::lt_p (wi::to_wide (u), wi::to_wide (rl), sign)) { - // There's still at leats one pair of R left. + // There's still at least one pair of R left. if (++i >= num_pairs ()) return false; l = m_base[i * 2]; -- cgit v1.1 From 89228e3985c5cdf6be58a3b5b1afcad91e9e3422 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 7 Oct 2022 10:28:56 +0200 Subject: tree-optimization/107153 - autopar SSA update issue autopar performs insertion of stores, eventually requiring a virtual loop PHI and assorted LC PHI adjustments which we intend to do once after the pass finishes. But we also perform intermediate update_ssa after loop duplication which can lose this fact. The following forces renaming of the virtual operand before the final SSA update to fix that. It also removes the explicit update_ssa call from the gimple_duplicate_sese_tail utility as has been done for all other such utilities and instead performs the SSA update from autopar. PR tree-optimization/107153 * tree-cfg.cc (gimple_duplicate_sese_tail): Do not update SSA form here. * tree-parloops.cc (gen_parallel_loop): Update SSA form after to-exit-first transform, no PHI insertion is necessary. (pass_parallelize_loops::execute): Force re-write of the virtual operand SSA web. * gcc.dg/autopar/pr107153.c: New testcase. --- gcc/testsuite/gcc.dg/autopar/pr107153.c | 17 +++++++++++++++++ gcc/tree-cfg.cc | 2 -- gcc/tree-parloops.cc | 5 +++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/autopar/pr107153.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/autopar/pr107153.c b/gcc/testsuite/gcc.dg/autopar/pr107153.c new file mode 100644 index 0000000..2391a67 --- /dev/null +++ b/gcc/testsuite/gcc.dg/autopar/pr107153.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -floop-parallelize-all -ftree-parallelize-loops=2 -fno-tree-dominator-opts" } */ + +void +foo (int x, int y) +{ + int i; + + for (i = 0; i < 2; i++) + { + } + + while (x) + if (!y) + while (y) + ++y; +} diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index 09fa7b6..42f40f1 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -6926,8 +6926,6 @@ gimple_duplicate_sese_tail (edge entry, edge exit, /* Anything that is outside of the region, but was dominated by something inside needs to update dominance info. */ iterate_fix_dominators (CDI_DOMINATORS, doms, false); - /* Update the SSA web. */ - update_ssa (TODO_update_ssa); if (free_region_copy) free (region_copy); diff --git a/gcc/tree-parloops.cc b/gcc/tree-parloops.cc index e4a148b..e680d97 100644 --- a/gcc/tree-parloops.cc +++ b/gcc/tree-parloops.cc @@ -3131,6 +3131,7 @@ gen_parallel_loop (class loop *loop, to the exit of the loop. */ transform_to_exit_first_loop (loop, reduction_list, nit); } + update_ssa (TODO_update_ssa_no_phi); /* Generate initializations for reductions. */ if (!reduction_list->is_empty ()) @@ -4215,6 +4216,10 @@ pass_parallelize_loops::execute (function *fun) checking_verify_loop_structure (); + /* ??? Intermediate SSA updates with no PHIs might have lost + the virtual operand renaming needed by separate_decls_in_region, + make sure to rename them again. */ + mark_virtual_operands_for_renaming (fun); update_ssa (TODO_update_ssa); if (in_loop_pipeline) rewrite_into_loop_closed_ssa (NULL, 0); -- cgit v1.1 From d3e5465757c599ea64f611290b7793d3141a6b7c Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 5 Oct 2022 11:50:59 -0400 Subject: gimplify: prevent some C++ temporary elision In this testcase, we were optimizing away the temporary for f(), but C++17 and above are clear that there is a temporary, and because its destructor has visible side-effects we can't optimize it away under the as-if rule. So disable this optimization for TREE_ADDRESSABLE type. I moved the declaration of volatile_p after the call to gimple_fold_indirect_ref_rhs to minimize indentation changes; I don't see any way the value of that flag could be affected by the call. gcc/ChangeLog: * gimplify.cc (gimplify_modify_expr_rhs): Don't optimize x = *(A*)& to x = for a TREE_ADDRESSABLE type. gcc/testsuite/ChangeLog: * g++.dg/init/elide9.C: New test. --- gcc/gimplify.cc | 15 ++++++++------- gcc/testsuite/g++.dg/init/elide9.C | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/init/elide9.C (limited to 'gcc') diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 95e16f6..d4209ea 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -5620,7 +5620,7 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, } break; case INDIRECT_REF: - { + if (!TREE_ADDRESSABLE (TREE_TYPE (*from_p))) /* If we have code like *(const A*)(A*)&x @@ -5629,11 +5629,13 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, of "A"), treat the entire expression as identical to "x". This kind of code arises in C++ when an object is bound to a const reference, and if "x" is a TARGET_EXPR we want - to take advantage of the optimization below. */ - bool volatile_p = TREE_THIS_VOLATILE (*from_p); - tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0)); - if (t) + to take advantage of the optimization below. But not if + the type is TREE_ADDRESSABLE; then C++17 says that the + TARGET_EXPR needs to be a temporary. */ + if (tree t + = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0))) { + bool volatile_p = TREE_THIS_VOLATILE (*from_p); if (TREE_THIS_VOLATILE (t) != volatile_p) { if (DECL_P (t)) @@ -5646,8 +5648,7 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, ret = GS_OK; changed = true; } - break; - } + break; case TARGET_EXPR: { diff --git a/gcc/testsuite/g++.dg/init/elide9.C b/gcc/testsuite/g++.dg/init/elide9.C new file mode 100644 index 0000000..810d60a --- /dev/null +++ b/gcc/testsuite/g++.dg/init/elide9.C @@ -0,0 +1,25 @@ +// The static_cast should prevent temporary elision. +// { dg-do run { target c++11 } } + +int d; +struct A +{ + int i; + A() { } + ~A() { ++d; } +}; + +A f() { return A(); } + +struct B +{ + A a; + B(): a(static_cast(f())) {} +}; + +int main() +{ + { B b; } + if (d != 2) + return -1; +} -- cgit v1.1 From edbb2551d156d69a2e337dcd8daa69f2680d57ea Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 7 Oct 2022 09:32:45 -0400 Subject: c++ modules: static var in inline function [PR104433] The below testcase fails to link with the error undefined reference to `f()::y' ultimately because during stream out for the static VAR_DECL y we override DECL_EXTERNAL to true, which later during IPA confuses symbol_table::remove_unreachable_nodes into thinking it's safe to not emit the symbol. The streaming code here already avoids overriding DECL_EXTERNAL for inline vars and functions, so it seems natural to extend this to static vars from an inline function. PR c++/104433 gcc/cp/ChangeLog: * module.cc (trees_out::core_bools): Don't override DECL_EXTERNAL to true for static variables from an inline function. gcc/testsuite/ChangeLog: * g++.dg/modules/static-2_a.H: New test. * g++.dg/modules/static-2_b.C: New test. --- gcc/cp/module.cc | 3 +++ gcc/testsuite/g++.dg/modules/static-2_a.H | 8 ++++++++ gcc/testsuite/g++.dg/modules/static-2_b.C | 9 +++++++++ 3 files changed, 20 insertions(+) create mode 100644 gcc/testsuite/g++.dg/modules/static-2_a.H create mode 100644 gcc/testsuite/g++.dg/modules/static-2_b.C (limited to 'gcc') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index c5eff21..cb1929b 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -5411,6 +5411,9 @@ trees_out::core_bools (tree t) case VAR_DECL: if (TREE_PUBLIC (t) + && !(TREE_STATIC (t) + && DECL_FUNCTION_SCOPE_P (t) + && DECL_DECLARED_INLINE_P (DECL_CONTEXT (t))) && !DECL_VAR_DECLARED_INLINE_P (t)) is_external = true; break; diff --git a/gcc/testsuite/g++.dg/modules/static-2_a.H b/gcc/testsuite/g++.dg/modules/static-2_a.H new file mode 100644 index 0000000..65c7619 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/static-2_a.H @@ -0,0 +1,8 @@ +// PR c++/104433 +// { dg-additional-options -fmodule-header } +// { dg-module-cmi {} } + +inline int* f() { + static int y; + return &y; +} diff --git a/gcc/testsuite/g++.dg/modules/static-2_b.C b/gcc/testsuite/g++.dg/modules/static-2_b.C new file mode 100644 index 0000000..bfd35b0 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/static-2_b.C @@ -0,0 +1,9 @@ +// PR c++/104433 +// { dg-additional-options -fmodules-ts } +// { dg-do link } + +import "static-2_a.H"; + +int main() { + f(); +} -- cgit v1.1 From 1a308905c1baf64d0ea4d09d7d92b55e79a2a339 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 5 Oct 2022 11:15:36 +0200 Subject: IPA: support -flto + -flive-patching=inline-clone There's no fundamental reason why -flive-patching=inline-clone can't coexist with -flto. Yes, one can theoretically have many more clone function that includes a live patch. It is pretty much the same as in-module inlining. gcc/ChangeLog: * opts.cc (finish_options): Print sorry message only for -flive-patching=inline-only-static. gcc/testsuite/ChangeLog: * gcc.dg/live-patching-2.c: Update scanned pattern. * gcc.dg/live-patching-5.c: New test. --- gcc/opts.cc | 5 +++-- gcc/testsuite/gcc.dg/live-patching-2.c | 4 ++-- gcc/testsuite/gcc.dg/live-patching-5.c | 8 ++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/live-patching-5.c (limited to 'gcc') diff --git a/gcc/opts.cc b/gcc/opts.cc index eb5db01..ae079fc 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -1288,8 +1288,9 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, "%<-fsanitize=kernel-address%>"); /* Currently live patching is not support for LTO. */ - if (opts->x_flag_live_patching && opts->x_flag_lto) - sorry ("live patching is not supported with LTO"); + if (opts->x_flag_live_patching == LIVE_PATCHING_INLINE_ONLY_STATIC && opts->x_flag_lto) + sorry ("live patching (with %qs) is not supported with LTO", + "inline-only-static"); /* Currently vtable verification is not supported for LTO */ if (opts->x_flag_vtable_verify && opts->x_flag_lto) diff --git a/gcc/testsuite/gcc.dg/live-patching-2.c b/gcc/testsuite/gcc.dg/live-patching-2.c index 0dde4e9..1c4f922 100644 --- a/gcc/testsuite/gcc.dg/live-patching-2.c +++ b/gcc/testsuite/gcc.dg/live-patching-2.c @@ -1,10 +1,10 @@ /* { dg-do compile } */ /* { dg-require-effective-target lto } */ -/* { dg-options "-O2 -flive-patching -flto" } */ +/* { dg-options "-O2 -flive-patching=inline-only-static -flto" } */ int main() { return 0; } -/* { dg-message "sorry, unimplemented: live patching is not supported with LTO" "-flive-patching and -flto together" { target *-*-* } 0 } */ +/* { dg-message "sorry, unimplemented: live patching \\(with 'inline-only-static'\\) is not supported with LTO" "-flive-patching and -flto together" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/live-patching-5.c b/gcc/testsuite/gcc.dg/live-patching-5.c new file mode 100644 index 0000000..098047a --- /dev/null +++ b/gcc/testsuite/gcc.dg/live-patching-5.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target lto } */ +/* { dg-options "-O2 -flive-patching -flto" } */ + +int main() +{ + return 0; +} -- cgit v1.1 From f8ba88b6a811ca9bb4b8411d3f65c329fb480ee1 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 6 Oct 2022 21:10:52 -0400 Subject: c++: catch parm initialization tweak We want to push the INIT_EXPR inside the CLEANUP_POINT_EXPR for the same reason we want to push it into the MUST_NOT_THROW_EXPR: any cleanups follow the initialization. gcc/cp/ChangeLog: * init.cc (expand_default_init): Also push the INIT_EXPR inside a CLEANUP_POINT_EXPR. --- gcc/cp/init.cc | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index bf46578..0ab0aaa 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -2124,19 +2124,20 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, return false; } - if (TREE_CODE (init) == MUST_NOT_THROW_EXPR) - /* We need to protect the initialization of a catch parm with a - call to terminate(), which shows up as a MUST_NOT_THROW_EXPR - around the TARGET_EXPR for the copy constructor. See - initialize_handler_parm. */ + /* We need to protect the initialization of a catch parm with a + call to terminate(), which shows up as a MUST_NOT_THROW_EXPR + around the TARGET_EXPR for the copy constructor. See + initialize_handler_parm. */ + tree *p = &init; + while (TREE_CODE (*p) == MUST_NOT_THROW_EXPR + || TREE_CODE (*p) == CLEANUP_POINT_EXPR) { - TREE_OPERAND (init, 0) = build2 (INIT_EXPR, TREE_TYPE (exp), exp, - TREE_OPERAND (init, 0)); - TREE_TYPE (init) = void_type_node; + /* Avoid voidify_wrapper_expr making a temporary. */ + TREE_TYPE (*p) = void_type_node; + p = &TREE_OPERAND (*p, 0); } - else - init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init); - TREE_SIDE_EFFECTS (init) = 1; + *p = build2 (INIT_EXPR, TREE_TYPE (exp), exp, *p); + TREE_SIDE_EFFECTS (*p) = 1; finish_expr_stmt (init); return true; } -- cgit v1.1 From f7f4628054358a92a55d52645cf107aa26ff6765 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 7 Oct 2022 12:01:58 -0400 Subject: c++ modules: ICE with bitfield in class template According to grokbitfield, DECL_BIT_FIELD_REPRESENTATIVE contains the width of the bitfield until we layout the class type (after which it'll contain a decl). Thus for a bitfield in a class template it'll always be the width, and this patch makes us avoid ICEing from mark_class_def in this case. gcc/cp/ChangeLog: * module.cc (trees_out::mark_class_def): Guard against DECL_BIT_FIELD_REPRESENTATIVE not being a decl. gcc/testsuite/ChangeLog: * g++.dg/modules/bfield-3.H: New test. --- gcc/cp/module.cc | 6 +++++- gcc/testsuite/g++.dg/modules/bfield-3.H | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/modules/bfield-3.H (limited to 'gcc') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index cb1929b..94fbee8 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -11919,7 +11919,11 @@ trees_out::mark_class_def (tree defn) mark_class_member (member); if (TREE_CODE (member) == FIELD_DECL) if (tree repr = DECL_BIT_FIELD_REPRESENTATIVE (member)) - mark_declaration (repr, false); + /* If we're marking a class template definition, then + this'll contain the width (as set by grokbitfield) + instead of a decl. */ + if (DECL_P (repr)) + mark_declaration (repr, false); } /* Mark the binfo hierarchy. */ diff --git a/gcc/testsuite/g++.dg/modules/bfield-3.H b/gcc/testsuite/g++.dg/modules/bfield-3.H new file mode 100644 index 0000000..4fd4db7 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/bfield-3.H @@ -0,0 +1,8 @@ +// { dg-additional-options -fmodule-header } +// { dg-module-cmi {} } + +template +struct A { + int x : 1; + int y : N; +}; -- cgit v1.1 From f09b99550a3c6cd16f5e9150ebd4b1d87033dcbd Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 7 Oct 2022 12:41:59 -0400 Subject: analyzer: extract bits from integer constants [PR105783] Fix a false positive from -Wanalyzer-null-dereference due to -fanalyzer failing to grok the value of a particular boolean field initialized to a constant. gcc/analyzer/ChangeLog: PR analyzer/105783 * region-model.cc (selftest::get_bit): New function. (selftest::test_bits_within_svalue_folding): New. (selfftest::analyzer_region_model_cc_tests): Call it. * svalue.cc (constant_svalue::maybe_fold_bits_within): Handle the case of extracting a single bit. gcc/testsuite/ChangeLog: PR analyzer/105783 * gcc.dg/analyzer/pr105783.c: New test. Signed-off-by: David Malcolm --- gcc/analyzer/region-model.cc | 52 ++++++++++++++++++++++++++++++++ gcc/analyzer/svalue.cc | 17 ++++++++++- gcc/testsuite/gcc.dg/analyzer/pr105783.c | 26 ++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr105783.c (limited to 'gcc') diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index c50f5c6..81ef41e 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -7132,6 +7132,57 @@ test_sub_svalue_folding () ASSERT_EQ (sub->get_type (), TREE_TYPE (ct.m_x_field)); } +/* Get BIT within VAL as a symbolic value within MGR. */ + +static const svalue * +get_bit (region_model_manager *mgr, + bit_offset_t bit, + unsigned HOST_WIDE_INT val) +{ + const svalue *inner_svalue + = mgr->get_or_create_int_cst (unsigned_type_node, val); + return mgr->get_or_create_bits_within (boolean_type_node, + bit_range (bit, 1), + inner_svalue); +} + +/* Verify that bits_within_svalues are folded as expected. */ + +static void +test_bits_within_svalue_folding () +{ + region_model_manager mgr; + + const svalue *zero = mgr.get_or_create_int_cst (boolean_type_node, 0); + const svalue *one = mgr.get_or_create_int_cst (boolean_type_node, 1); + + { + const unsigned val = 0x0000; + for (unsigned bit = 0; bit < 16; bit++) + ASSERT_EQ (get_bit (&mgr, bit, val), zero); + } + + { + const unsigned val = 0x0001; + ASSERT_EQ (get_bit (&mgr, 0, val), one); + for (unsigned bit = 1; bit < 16; bit++) + ASSERT_EQ (get_bit (&mgr, bit, val), zero); + } + + { + const unsigned val = 0x8000; + for (unsigned bit = 0; bit < 15; bit++) + ASSERT_EQ (get_bit (&mgr, bit, val), zero); + ASSERT_EQ (get_bit (&mgr, 15, val), one); + } + + { + const unsigned val = 0xFFFF; + for (unsigned bit = 0; bit < 16; bit++) + ASSERT_EQ (get_bit (&mgr, bit, val), one); + } +} + /* Test that region::descendent_of_p works as expected. */ static void @@ -8488,6 +8539,7 @@ analyzer_region_model_cc_tests () test_unaryop_svalue_folding (); test_binop_svalue_folding (); test_sub_svalue_folding (); + test_bits_within_svalue_folding (); test_descendent_of_p (); test_bit_range_regions (); test_assignment (); diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc index 9ec46d6..a0838c0 100644 --- a/gcc/analyzer/svalue.cc +++ b/gcc/analyzer/svalue.cc @@ -868,7 +868,7 @@ constant_svalue::eval_condition (const constant_svalue *lhs, const svalue * constant_svalue::maybe_fold_bits_within (tree type, - const bit_range &, + const bit_range &bits, region_model_manager *mgr) const { /* Bits within an all-zero value are also all zero. */ @@ -879,6 +879,21 @@ constant_svalue::maybe_fold_bits_within (tree type, else return this; } + + /* Handle the case of extracting a single bit. */ + if (bits.m_size_in_bits == 1 + && TREE_CODE (m_cst_expr) == INTEGER_CST + && type + && INTEGRAL_TYPE_P (type)) + { + unsigned HOST_WIDE_INT bit = bits.m_start_bit_offset.to_uhwi (); + unsigned HOST_WIDE_INT mask = (1 << bit); + unsigned HOST_WIDE_INT val_as_hwi = tree_to_uhwi (m_cst_expr); + unsigned HOST_WIDE_INT masked_val = val_as_hwi & mask; + int result = masked_val ? 1 : 0; + return mgr->get_or_create_int_cst (type, result); + } + /* Otherwise, don't fold. */ return NULL; } diff --git a/gcc/testsuite/gcc.dg/analyzer/pr105783.c b/gcc/testsuite/gcc.dg/analyzer/pr105783.c new file mode 100644 index 0000000..00f44d0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/pr105783.c @@ -0,0 +1,26 @@ +/* { dg-additional-options "-O" } */ + +struct ss_s { + union out_or_counting_u { + char *newstr; + unsigned long long cnt; + } uu; + _Bool counting; +}; + +struct ss_s ss_init(void) { + struct ss_s rr = { .counting = 1 }; + return rr; +} + +void ss_out(struct ss_s *t, char cc) { + if (!t->counting) { + *t->uu.newstr++ = cc; + } +} + +int main() { + struct ss_s ss = ss_init(); + ss_out(&ss, 'a'); +} + -- cgit v1.1 From 21e51a55e9714d14a6df0e8e83ae005eb19f0f02 Mon Sep 17 00:00:00 2001 From: Olivier Hainque Date: Fri, 7 Oct 2022 10:12:26 +0000 Subject: Specialize paths to version.h in _vxworks-versions.h The _vxworks-versions.h runtime file helps us control the compilation of some library components depending on the OS version extracted out of a system header. The system header name is "version.h", and gcc has a "version.h" file of its own. gcc's version.h is now generated and the current instance instead of the OS one, resulting in build failures from #if !defined(_WRS_VXWORKS_MAJOR) #error "_WRS_VXWORKS_MAJOR undefined" #endif This change introduces a twist in the way _vxworks-versions.h #includes version.h, using a relative path with components that will match in the OS include dirs only. The actual relative path is conditioned on _VSB_CONFIG_FILE to accommodate a change in the include dirs organisation between VxWorks 6 and 7. 2022-10-07 Olivier Hainque gcc/ * config/vxworks/_vxworks-versions.h: Use OS specific paths in #include of version.h. --- gcc/config/vxworks/_vxworks-versions.h | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/config/vxworks/_vxworks-versions.h b/gcc/config/vxworks/_vxworks-versions.h index 15e8bfe..994dda9 100644 --- a/gcc/config/vxworks/_vxworks-versions.h +++ b/gcc/config/vxworks/_vxworks-versions.h @@ -23,15 +23,24 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define _VXWORKS_VERSIONS_H 1 /* All we need is access to the bare _WRS_VXWORKS_MAJOR/MINOR macros, - exposed by version.h or already provided somehow (e.g. with a self - spec for some reason). When resorting to system headers, cheat a - bit to make sure we don't drag additional header files, which can - easily cause #include ordering nightmares. */ + exposed by version.h or already provided somehow (e.g. with a self spec + for some reason). When resorting to system headers, use typical os + paths to prevent possible confusion with a gcc version of version.h + visible during the build and temporarily #undef _WRS_KERNEL to prevent + indirect inclusion of internal header files, which can easily cause + #include ordering nightmares. */ #if !defined(_WRS_VXWORKS_MAJOR) + +#if defined(_VSB_CONFIG_FILE) +#define _VXWORKS_VERSION_H <../public/version.h> +#else +#define _VXWORKS_VERSION_H <../h/version.h> +#endif + #pragma push_macro("_WRS_KERNEL") #undef _WRS_KERNEL -#include +#include _VXWORKS_VERSION_H #pragma pop_macro("_WRS_KERNEL") #endif -- cgit v1.1 From 1879e48f3d8595bc9e7f583bbd12df3c6f5c42dc Mon Sep 17 00:00:00 2001 From: Qing Zhao Date: Fri, 7 Oct 2022 14:58:20 +0000 Subject: Add a new option -fstrict-flex-arrays[=n] and new attribute strict_flex_array Add the following new option -fstrict-flex-arrays[=n] and a corresponding attribute strict_flex_array to GCC: '-fstrict-flex-arrays' Control when to treat the trailing array of a structure as a flexible array member for the purpose of accessing the elements of such an array. The positive form is equivalent to '-fstrict-flex-arrays=3', which is the strictest. A trailing array is treated as a flexible array member only when it declared as a flexible array member per C99 standard onwards. The negative form is equivalent to '-fstrict-flex-arrays=0', which is the least strict. All trailing arrays of structures are treated as flexible array members. '-fstrict-flex-arrays=LEVEL' Control when to treat the trailing array of a structure as a flexible array member for the purpose of accessing the elements of such an array. The value of LEVEL controls the level of strictness The possible values of LEVEL are the same as for the 'strict_flex_array' attribute (*note Variable Attributes::). You can control this behavior for a specific trailing array field of a structure by using the variable attribute 'strict_flex_array' attribute (*note Variable Attributes::). 'strict_flex_array (LEVEL)' The 'strict_flex_array' attribute should be attached to the trailing array field of a structure. It controls when to treat the trailing array field of a structure as a flexible array member for the purposes of accessing the elements of such an array. LEVEL must be an integer betwen 0 to 3. LEVEL=0 is the least strict level, all trailing arrays of structures are treated as flexible array members. LEVEL=3 is the strictest level, only when the trailing array is declared as a flexible array member per C99 standard onwards ('[]'), it is treated as a flexible array member. There are two more levels in between 0 and 3, which are provided to support older codes that use GCC zero-length array extension ('[0]') or one-element array as flexible array members('[1]'): When LEVEL is 1, the trailing array is treated as a flexible array member when it is declared as either '[]', '[0]', or '[1]'; When LEVEL is 2, the trailing array is treated as a flexible array member when it is declared as either '[]', or '[0]'. This attribute can be used with or without the '-fstrict-flex-arrays'. When both the attribute and the option present at the same time, the level of the strictness for the specific trailing array field is determined by the attribute. gcc/c-family/ChangeLog: * c-attribs.cc (handle_strict_flex_array_attribute): New function. (c_common_attribute_table): New item for strict_flex_array. * c.opt: (fstrict-flex-arrays): New option. (fstrict-flex-arrays=): New option. gcc/c/ChangeLog: * c-decl.cc (flexible_array_member_type_p): New function. (one_element_array_type_p): Likewise. (zero_length_array_type_p): Likewise. (add_flexible_array_elts_to_size): Call new utility routine flexible_array_member_type_p. (is_flexible_array_member_p): New function. (finish_struct): Set the new DECL_NOT_FLEXARRAY flag. gcc/cp/ChangeLog: * module.cc (trees_out::core_bools): Stream out new bit decl_not_flexarray. (trees_in::core_bools): Stream in new bit decl_not_flexarray. gcc/ChangeLog: * doc/extend.texi: Document strict_flex_array attribute. * doc/invoke.texi: Document -fstrict-flex-arrays[=n] option. * print-tree.cc (print_node): Print new bit decl_not_flexarray. * tree-core.h (struct tree_decl_common): New bit field decl_not_flexarray. * tree-streamer-in.cc (unpack_ts_decl_common_value_fields): Stream in new bit decl_not_flexarray. * tree-streamer-out.cc (pack_ts_decl_common_value_fields): Stream out new bit decl_not_flexarray. * tree.cc (array_at_struct_end_p): Update it with the new bit field decl_not_flexarray. * tree.h (DECL_NOT_FLEXARRAY): New flag. gcc/testsuite/ChangeLog: * g++.dg/strict-flex-array-1.C: New test. * gcc.dg/strict-flex-array-1.c: New test. --- gcc/c-family/c-attribs.cc | 47 +++++++++++ gcc/c-family/c.opt | 7 ++ gcc/c/c-decl.cc | 130 +++++++++++++++++++++++++++-- gcc/cp/module.cc | 2 + gcc/doc/extend.texi | 26 ++++++ gcc/doc/invoke.texi | 28 ++++++- gcc/print-tree.cc | 8 +- gcc/testsuite/g++.dg/strict-flex-array-1.C | 31 +++++++ gcc/testsuite/gcc.dg/strict-flex-array-1.c | 33 ++++++++ gcc/tree-core.h | 5 +- gcc/tree-streamer-in.cc | 1 + gcc/tree-streamer-out.cc | 1 + gcc/tree.cc | 45 +++++++--- gcc/tree.h | 14 +++- 14 files changed, 350 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/g++.dg/strict-flex-array-1.C create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-1.c (limited to 'gcc') diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 671ea38..92ac93b 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -101,6 +101,8 @@ static tree handle_special_var_sec_attribute (tree *, tree, tree, int, bool *); static tree handle_aligned_attribute (tree *, tree, tree, int, bool *); static tree handle_warn_if_not_aligned_attribute (tree *, tree, tree, int, bool *); +static tree handle_strict_flex_array_attribute (tree *, tree, tree, + int, bool *); static tree handle_weak_attribute (tree *, tree, tree, int, bool *) ; static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ; static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *); @@ -369,6 +371,8 @@ const struct attribute_spec c_common_attribute_table[] = attr_aligned_exclusions }, { "warn_if_not_aligned", 0, 1, false, false, false, false, handle_warn_if_not_aligned_attribute, NULL }, + { "strict_flex_array", 1, 1, true, false, false, false, + handle_strict_flex_array_attribute, NULL }, { "weak", 0, 0, true, false, false, false, handle_weak_attribute, NULL }, { "noplt", 0, 0, true, false, false, false, @@ -2508,6 +2512,49 @@ handle_warn_if_not_aligned_attribute (tree *node, tree name, no_add_attrs, true); } +/* Handle a "strict_flex_array" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_strict_flex_array_attribute (tree *node, tree name, + tree args, int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + tree decl = *node; + tree argval = TREE_VALUE (args); + + /* This attribute only applies to field decls of a structure. */ + if (TREE_CODE (decl) != FIELD_DECL) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qE attribute may not be specified for %q+D", name, decl); + *no_add_attrs = true; + } + /* This attribute only applies to field with array type. */ + else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qE attribute may not be specified for a non-array field", + name); + *no_add_attrs = true; + } + else if (TREE_CODE (argval) != INTEGER_CST) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qE attribute argument not an integer", name); + *no_add_attrs = true; + } + else if (!tree_fits_uhwi_p (argval) || tree_to_uhwi (argval) > 3) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qE attribute argument %qE is not an integer constant" + " between 0 and 3", name, argval); + *no_add_attrs = true; + } + + return NULL_TREE; +} + /* Handle a "weak" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 1c7f89e..01d4807 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -2076,6 +2076,13 @@ fsized-deallocation C++ ObjC++ Var(flag_sized_deallocation) Init(-1) Enable C++14 sized deallocation support. +fstrict-flex-arrays +C C++ Common Alias(fstrict-flex-arrays=,3,0) + +fstrict-flex-arrays= +C C++ Common Joined RejectNegative UInteger Var(flag_strict_flex_arrays) Init(0) IntegerRange(0,3) +-fstrict-flex-arrays= Control when to treat the trailing array of a structure as a flexible array member for the purposes of accessing the elements of such an array. The default is treating all trailing arrays of structures as flexible array members. + fsquangle C++ ObjC++ WarnRemoved diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index ffa63dc..193e268 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -5034,6 +5034,41 @@ set_array_declarator_inner (struct c_declarator *decl, return decl; } +/* Determine whether TYPE is a ISO C99 flexible array memeber type "[]". */ +static bool +flexible_array_member_type_p (const_tree type) +{ + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_SIZE (type) == NULL_TREE + && TYPE_DOMAIN (type) != NULL_TREE + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE) + return true; + + return false; +} + +/* Determine whether TYPE is a one-element array type "[1]". */ +static bool +one_element_array_type_p (const_tree type) +{ + if (TREE_CODE (type) != ARRAY_TYPE) + return false; + return integer_zerop (array_type_nelts (type)); +} + +/* Determine whether TYPE is a zero-length array type "[0]". */ +static bool +zero_length_array_type_p (const_tree type) +{ + if (TREE_CODE (type) == ARRAY_TYPE) + if (tree type_size = TYPE_SIZE_UNIT (type)) + if ((integer_zerop (type_size)) + && TYPE_DOMAIN (type) != NULL_TREE + && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE) + return true; + return false; +} + /* INIT is a constructor that forms DECL's initializer. If the final element initializes a flexible array field, add the size of that initializer to DECL's size. */ @@ -5048,10 +5083,7 @@ add_flexible_array_elts_to_size (tree decl, tree init) elt = CONSTRUCTOR_ELTS (init)->last ().value; type = TREE_TYPE (elt); - if (TREE_CODE (type) == ARRAY_TYPE - && TYPE_SIZE (type) == NULL_TREE - && TYPE_DOMAIN (type) != NULL_TREE - && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE) + if (flexible_array_member_type_p (type)) { complete_array_type (&type, elt, false); DECL_SIZE (decl) @@ -8755,6 +8787,81 @@ finish_incomplete_vars (tree incomplete_vars, bool toplevel) } } + +/* Determine whether the FIELD_DECL X is a flexible array member according to + the following info: + A. whether the FIELD_DECL X is the last field of the DECL_CONTEXT; + B. whether the FIELD_DECL is an array that is declared as "[]", "[0]", + or "[1]"; + C. flag_strict_flex_arrays; + D. the attribute strict_flex_array that is attached to the field + if presenting. + Return TRUE when it's a flexible array member, FALSE otherwise. */ + +static bool +is_flexible_array_member_p (bool is_last_field, + tree x) +{ + /* If not the last field, return false. */ + if (!is_last_field) + return false; + + /* If not an array field, return false. */ + if (TREE_CODE (TREE_TYPE (x)) != ARRAY_TYPE) + return false; + + bool is_zero_length_array = zero_length_array_type_p (TREE_TYPE (x)); + bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x)); + bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x)); + + unsigned int strict_flex_array_level = flag_strict_flex_arrays; + + tree attr_strict_flex_array = lookup_attribute ("strict_flex_array", + DECL_ATTRIBUTES (x)); + /* If there is a strict_flex_array attribute attached to the field, + override the flag_strict_flex_arrays. */ + if (attr_strict_flex_array) + { + /* Get the value of the level first from the attribute. */ + unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0; + gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE); + attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array); + gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE); + attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array); + gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array)); + attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array); + + /* The attribute has higher priority than flag_struct_flex_array. */ + strict_flex_array_level = attr_strict_flex_array_level; + } + + switch (strict_flex_array_level) + { + case 0: + /* Default, all trailing arrays are flexible array members. */ + return true; + case 1: + /* Level 1: all "[1]", "[0]", and "[]" are flexible array members. */ + if (is_one_element_array) + return true; + /* FALLTHROUGH. */ + case 2: + /* Level 2: all "[0]", and "[]" are flexible array members. */ + if (is_zero_length_array) + return true; + /* FALLTHROUGH. */ + case 3: + /* Level 3: Only "[]" are flexible array members. */ + if (is_flexible_array) + return true; + break; + default: + gcc_unreachable (); + } + return false; +} + + /* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T. LOC is the location of the RECORD_TYPE or UNION_TYPE's definition. FIELDLIST is a chain of FIELD_DECL nodes for the fields. @@ -8816,6 +8923,11 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, bool saw_named_field = false; for (x = fieldlist; x; x = DECL_CHAIN (x)) { + /* Whether this field is the last field of the structure or union. + for UNION, any field is the last field of it. */ + bool is_last_field = (DECL_CHAIN (x) == NULL_TREE) + || (TREE_CODE (t) == UNION_TYPE); + if (TREE_TYPE (x) == error_mark_node) continue; @@ -8854,10 +8966,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, DECL_PACKED (x) = 1; /* Detect flexible array member in an invalid context. */ - if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE - && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE - && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE - && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE) + if (flexible_array_member_type_p (TREE_TYPE (x))) { if (TREE_CODE (t) == UNION_TYPE) { @@ -8865,7 +8974,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, "flexible array member in union"); TREE_TYPE (x) = error_mark_node; } - else if (DECL_CHAIN (x) != NULL_TREE) + else if (!is_last_field) { error_at (DECL_SOURCE_LOCATION (x), "flexible array member not at end of struct"); @@ -8885,6 +8994,9 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, "invalid use of structure with flexible array member"); + /* Set DECL_NOT_FLEXARRAY flag for FIELD_DECL x. */ + DECL_NOT_FLEXARRAY (x) = !is_flexible_array_member_p (is_last_field, x); + if (DECL_NAME (x) || RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) saw_named_field = true; diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 94fbee8..4d27ceb 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -5433,6 +5433,7 @@ trees_out::core_bools (tree t) WB (t->decl_common.decl_by_reference_flag); WB (t->decl_common.decl_read_flag); WB (t->decl_common.decl_nonshareable_flag); + WB (t->decl_common.decl_not_flexarray); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) @@ -5577,6 +5578,7 @@ trees_in::core_bools (tree t) RB (t->decl_common.decl_by_reference_flag); RB (t->decl_common.decl_read_flag); RB (t->decl_common.decl_nonshareable_flag); + RB (t->decl_common.decl_not_flexarray); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 9ddfcf7..cfbe32a 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -7459,6 +7459,32 @@ This warning can be disabled by @option{-Wno-if-not-aligned}. The @code{warn_if_not_aligned} attribute can also be used for types (@pxref{Common Type Attributes}.) +@cindex @code{strict_flex_array} variable attribute +@item strict_flex_array (@var{level}) +The @code{strict_flex_array} attribute should be attached to the trailing +array field of a structure. It controls when to treat the trailing array +field of a structure as a flexible array member for the purposes of accessing +the elements of such an array. +@var{level} must be an integer betwen 0 to 3. + +@var{level}=0 is the least strict level, all trailing arrays of structures +are treated as flexible array members. @var{level}=3 is the strictest level, +only when the trailing array is declared as a flexible array member per C99 +standard onwards (@samp{[]}), it is treated as a flexible array member. + +There are two more levels in between 0 and 3, which are provided to support +older codes that use GCC zero-length array extension (@samp{[0]}) or one-element +array as flexible array members (@samp{[1]}): +When @var{level} is 1, the trailing array is treated as a flexible array member +when it is declared as either @samp{[]}, @samp{[0]}, or @samp{[1]}; +When @var{level} is 2, the trailing array is treated as a flexible array member +when it is declared as either @samp{[]}, or @samp{[0]}. + +This attribute can be used with or without the @option{-fstrict-flex-arrays}. +When both the attribute and the option present at the same time, the level of +the strictness for the specific trailing array field is determined by the +attribute. + @item alloc_size (@var{position}) @itemx alloc_size (@var{position-1}, @var{position-2}) @cindex @code{alloc_size} variable attribute diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index a2b0b96..1eeaec1 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -207,7 +207,8 @@ in the following sections. -fopenmp -fopenmp-simd @gol -fpermitted-flt-eval-methods=@var{standard} @gol -fplan9-extensions -fsigned-bitfields -funsigned-bitfields @gol --fsigned-char -funsigned-char -fsso-struct=@var{endianness}} +-fsigned-char -funsigned-char -fstrict-flex-arrays[=@var{n}] @gol +-fsso-struct=@var{endianness}} @item C++ Language Options @xref{C++ Dialect Options,,Options Controlling C++ Dialect}. @@ -2835,6 +2836,31 @@ The type @code{char} is always a distinct type from each of @code{signed char} or @code{unsigned char}, even though its behavior is always just like one of those two. +@item -fstrict-flex-arrays +@opindex fstrict-flex-arrays +@opindex fno-strict-flex-arrays +Control when to treat the trailing array of a structure as a flexible array +member for the purpose of accessing the elements of such an array. +The positive form is equivalent to @option{-fstrict-flex-arrays=3}, which is the +strictest. A trailing array is treated as a flexible array member only when it +is declared as a flexible array member per C99 standard onwards. +The negative form is equivalent to @option{-fstrict-flex-arrays=0}, which is the +least strict. All trailing arrays of structures are treated as flexible array +members. + +@item -fstrict-flex-arrays=@var{level} +@opindex fstrict-flex-arrays=@var{level} +Control when to treat the trailing array of a structure as a flexible array +member for the purpose of accessing the elements of such an array. The value +of @var{level} controls the level of strictness. + +The possible values of @var{level} are the same as for the +@code{strict_flex_array} attribute (@pxref{Variable Attributes}). + +You can control this behavior for a specific trailing array field of a +structure by using the variable attribute @code{strict_flex_array} attribute +(@pxref{Variable Attributes}). + @item -fsso-struct=@var{endianness} @opindex fsso-struct Set the default scalar storage order of structures and unions to the diff --git a/gcc/print-tree.cc b/gcc/print-tree.cc index 6d45a4a..58a9825 100644 --- a/gcc/print-tree.cc +++ b/gcc/print-tree.cc @@ -517,8 +517,12 @@ print_node (FILE *file, const char *prefix, tree node, int indent, fprintf (file, " align:%d warn_if_not_align:%d", DECL_ALIGN (node), DECL_WARN_IF_NOT_ALIGN (node)); if (code == FIELD_DECL) - fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED, - DECL_OFFSET_ALIGN (node)); + { + fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED, + DECL_OFFSET_ALIGN (node)); + fprintf (file, " decl_not_flexarray: %d", + DECL_NOT_FLEXARRAY (node)); + } if (code == FUNCTION_DECL && fndecl_built_in_p (node)) { diff --git a/gcc/testsuite/g++.dg/strict-flex-array-1.C b/gcc/testsuite/g++.dg/strict-flex-array-1.C new file mode 100644 index 0000000..92fcffe --- /dev/null +++ b/gcc/testsuite/g++.dg/strict-flex-array-1.C @@ -0,0 +1,31 @@ +/* testing the correct usage of attribute strict_flex_array. */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + + +int x __attribute__ ((strict_flex_array (1))); /* { dg-error "'strict_flex_array' attribute may not be specified for 'x'" } */ + +struct trailing { + int a; + int c __attribute ((strict_flex_array)); /* { dg-error "wrong number of arguments specified for 'strict_flex_array' attribute" } */ +}; + +struct trailing_1 { + int a; + int b; + int c __attribute ((strict_flex_array (2))); /* { dg-error "'strict_flex_array' attribute may not be specified for a non-array field" } */ +}; + +extern int d; + +struct trailing_array_2 { + int a; + int b; + int c[1] __attribute ((strict_flex_array (d))); /* { dg-error "'strict_flex_array' attribute argument not an integer" } */ +}; + +struct trailing_array_3 { + int a; + int b; + int c[0] __attribute ((strict_flex_array (5))); /* { dg-error "'strict_flex_array' attribute argument '5' is not an integer constant between 0 and 3" } */ +}; diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-1.c b/gcc/testsuite/gcc.dg/strict-flex-array-1.c new file mode 100644 index 0000000..5b8a793 --- /dev/null +++ b/gcc/testsuite/gcc.dg/strict-flex-array-1.c @@ -0,0 +1,33 @@ +/* testing the correct usage of attribute strict_flex_array. */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + + +int x __attribute__ ((strict_flex_array (1))); /* { dg-error "'strict_flex_array' attribute may not be specified for 'x'" } */ + +int [[gnu::strict_flex_array(1)]] x; /* { dg-warning "'strict_flex_array' attribute does not apply to types" } */ + +struct trailing { + int a; + int c __attribute ((strict_flex_array)); /* { dg-error "wrong number of arguments specified for 'strict_flex_array' attribute" } */ +}; + +struct trailing_1 { + int a; + int b; + int c __attribute ((strict_flex_array (2))); /* { dg-error "'strict_flex_array' attribute may not be specified for a non-array field" } */ +}; + +extern int d; + +struct trailing_array_2 { + int a; + int b; + int c[1] __attribute ((strict_flex_array (d))); /* { dg-error "'strict_flex_array' attribute argument not an integer" } */ +}; + +struct trailing_array_3 { + int a; + int b; + int c[0] __attribute ((strict_flex_array (5))); /* { dg-error "'strict_flex_array' attribute argument '5' is not an integer constant between 0 and 3" } */ +}; diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 55807fe..c4f2cea 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1827,7 +1827,10 @@ struct GTY(()) tree_decl_common { TYPE_WARN_IF_NOT_ALIGN. */ unsigned int warn_if_not_align : 6; - /* 14 bits unused. */ + /* In FIELD_DECL, this is DECL_NOT_FLEXARRAY. */ + unsigned int decl_not_flexarray : 1; + + /* 13 bits unused. */ /* UID for points-to sets, stable over copying from inlining. */ unsigned int pt_uid; diff --git a/gcc/tree-streamer-in.cc b/gcc/tree-streamer-in.cc index 219cf5e..57923da 100644 --- a/gcc/tree-streamer-in.cc +++ b/gcc/tree-streamer-in.cc @@ -261,6 +261,7 @@ unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr) else SET_DECL_FIELD_ABI_IGNORED (expr, val); expr->decl_common.off_align = bp_unpack_value (bp, 8); + DECL_NOT_FLEXARRAY (expr) = (unsigned) bp_unpack_value (bp, 1); } else if (VAR_P (expr)) diff --git a/gcc/tree-streamer-out.cc b/gcc/tree-streamer-out.cc index 9b114dc..68a2818 100644 --- a/gcc/tree-streamer-out.cc +++ b/gcc/tree-streamer-out.cc @@ -229,6 +229,7 @@ pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr) else bp_pack_value (bp, DECL_FIELD_ABI_IGNORED (expr), 1); bp_pack_value (bp, expr->decl_common.off_align, 8); + bp_pack_value (bp, DECL_NOT_FLEXARRAY (expr), 1); } else if (VAR_P (expr)) diff --git a/gcc/tree.cc b/gcc/tree.cc index f8d24b5..c4ead94 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -12691,14 +12691,30 @@ array_ref_up_bound (tree exp) } /* Returns true if REF is an array reference, component reference, - or memory reference to an array at the end of a structure. - If this is the case, the array may be allocated larger - than its upper bound implies. */ + or memory reference to an array whose actual size might be larger + than its upper bound implies, there are multiple cases: + A. a ref to a flexible array member at the end of a structure; + B. a ref to an array with a different type against the original decl; + for example: + short a[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + (*((char(*)[16])&a[0]))[i+8] + + C. a ref to an array that was passed as a parameter; + for example: + + int test (uint8_t *p, uint32_t t[1][1], int n) { + for (int i = 0; i < 4; i++, p++) + t[i][0] = ...; + + FIXME, the name of this routine need to be changed to be more accurate. */ bool array_at_struct_end_p (tree ref) { - tree atype; + /* the TYPE for this array referece. */ + tree atype = NULL_TREE; + /* the FIELD_DECL for the array field in the containing structure. */ + tree afield_decl = NULL_TREE; if (TREE_CODE (ref) == ARRAY_REF || TREE_CODE (ref) == ARRAY_RANGE_REF) @@ -12708,7 +12724,10 @@ array_at_struct_end_p (tree ref) } else if (TREE_CODE (ref) == COMPONENT_REF && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE) - atype = TREE_TYPE (TREE_OPERAND (ref, 1)); + { + atype = TREE_TYPE (TREE_OPERAND (ref, 1)); + afield_decl = TREE_OPERAND (ref, 1); + } else if (TREE_CODE (ref) == MEM_REF) { tree arg = TREE_OPERAND (ref, 0); @@ -12720,6 +12739,7 @@ array_at_struct_end_p (tree ref) if (tree fld = last_field (argtype)) { atype = TREE_TYPE (fld); + afield_decl = fld; if (TREE_CODE (atype) != ARRAY_TYPE) return false; if (VAR_P (arg) && DECL_SIZE (fld)) @@ -12773,13 +12793,16 @@ array_at_struct_end_p (tree ref) ref = TREE_OPERAND (ref, 0); } - /* The array now is at struct end. Treat flexible arrays as + gcc_assert (!afield_decl + || (afield_decl && TREE_CODE (afield_decl) == FIELD_DECL)); + + /* The array now is at struct end. Treat flexible array member as always subject to extend, even into just padding constrained by an underlying decl. */ if (! TYPE_SIZE (atype) || ! TYPE_DOMAIN (atype) || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) - return true; + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; /* If the reference is based on a declared entity, the size of the array is constrained by its given domain. (Do not trust commons PR/69368). */ @@ -12801,9 +12824,9 @@ array_at_struct_end_p (tree ref) if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (atype))) != INTEGER_CST || TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST) - return true; + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; if (! get_addr_base_and_unit_offset (ref_to_array, &offset)) - return true; + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; /* If at least one extra element fits it is a flexarray. */ if (known_le ((wi::to_offset (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) @@ -12811,12 +12834,12 @@ array_at_struct_end_p (tree ref) + 2) * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))), wi::to_offset (DECL_SIZE_UNIT (ref)) - offset)) - return true; + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; return false; } - return true; + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true; } /* Return a tree representing the offset, in bytes, of the field referenced diff --git a/gcc/tree.h b/gcc/tree.h index 95285e4..142e9c9 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3005,6 +3005,12 @@ extern void decl_value_expr_insert (tree, tree); #define DECL_PADDING_P(NODE) \ (FIELD_DECL_CHECK (NODE)->decl_common.decl_flag_3) +/* Used in a FIELD_DECL to indicate whether this field is not a flexible + array member. This is only valid for the last array type field of a + structure. */ +#define DECL_NOT_FLEXARRAY(NODE) \ + (FIELD_DECL_CHECK (NODE)->decl_common.decl_not_flexarray) + /* A numeric unique identifier for a LABEL_DECL. The UID allocation is dense, unique within any one function, and may be used to index arrays. If the value is -1, then no UID has been assigned. */ @@ -5547,10 +5553,10 @@ extern tree component_ref_field_offset (tree); returns null. */ enum struct special_array_member { - none, /* Not a special array member. */ - int_0, /* Interior array member with size zero. */ - trail_0, /* Trailing array member with size zero. */ - trail_1 /* Trailing array member with one element. */ + none, /* Not a special array member. */ + int_0, /* Interior array member with size zero. */ + trail_0, /* Trailing array member with size zero. */ + trail_1 /* Trailing array member with one element. */ }; /* Return the size of the member referenced by the COMPONENT_REF, using -- cgit v1.1 From b9ad850e86b863c24f6f4f5acf08d49944cc7bbe Mon Sep 17 00:00:00 2001 From: Qing Zhao Date: Fri, 7 Oct 2022 14:59:01 +0000 Subject: Use array_at_struct_end_p in __builtin_object_size [PR101836] Use array_at_struct_end_p to determine whether the trailing array of a structure is flexible array member in __builtin_object_size. gcc/ChangeLog: PR tree-optimization/101836 * tree-object-size.cc (addr_object_size): Use array_at_struct_end_p to determine a flexible array member reference. gcc/testsuite/ChangeLog: PR tree-optimization/101836 * gcc.dg/pr101836.c: New test. * gcc.dg/pr101836_1.c: New test. * gcc.dg/pr101836_2.c: New test. * gcc.dg/pr101836_3.c: New test. * gcc.dg/pr101836_4.c: New test. * gcc.dg/pr101836_5.c: New test. * gcc.dg/strict-flex-array-2.c: New test. * gcc.dg/strict-flex-array-3.c: New test. --- gcc/testsuite/gcc.dg/pr101836.c | 60 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/pr101836_1.c | 60 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/pr101836_2.c | 60 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/pr101836_3.c | 60 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/pr101836_4.c | 60 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/pr101836_5.c | 60 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/strict-flex-array-2.c | 60 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/strict-flex-array-3.c | 60 ++++++++++++++++++++++++++++++ gcc/tree-object-size.cc | 16 ++++---- 9 files changed, 487 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr101836.c create mode 100644 gcc/testsuite/gcc.dg/pr101836_1.c create mode 100644 gcc/testsuite/gcc.dg/pr101836_2.c create mode 100644 gcc/testsuite/gcc.dg/pr101836_3.c create mode 100644 gcc/testsuite/gcc.dg/pr101836_4.c create mode 100644 gcc/testsuite/gcc.dg/pr101836_5.c create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-2.c create mode 100644 gcc/testsuite/gcc.dg/strict-flex-array-3.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/pr101836.c b/gcc/testsuite/gcc.dg/pr101836.c new file mode 100644 index 0000000..efad02c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101836.c @@ -0,0 +1,60 @@ +/* -fstrict-flex-arrays is aliased with -ftrict-flex-arrays=3, which is the + strictest, only [] is treated as flexible array. */ +/* PR tree-optimization/101836 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fstrict-flex-arrays" } */ + +#include + +#define expect(p, _v) do { \ + size_t v = _v; \ + if (p == v) \ + printf("ok: %s == %zd\n", #p, p); \ + else \ + { \ + printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \ + __builtin_abort (); \ + } \ +} while (0); + +struct trailing_array_1 { + int a; + int b; + int c[4]; +}; + +struct trailing_array_2 { + int a; + int b; + int c[1]; +}; + +struct trailing_array_3 { + int a; + int b; + int c[0]; +}; +struct trailing_array_4 { + int a; + int b; + int c[]; +}; + +void __attribute__((__noinline__)) stuff( + struct trailing_array_1 *normal, + struct trailing_array_2 *trailing_1, + struct trailing_array_3 *trailing_0, + struct trailing_array_4 *trailing_flex) +{ + expect(__builtin_object_size(normal->c, 1), 16); + expect(__builtin_object_size(trailing_1->c, 1), 4); + expect(__builtin_object_size(trailing_0->c, 1), 0); + expect(__builtin_object_size(trailing_flex->c, 1), -1); +} + +int main(int argc, char *argv[]) +{ + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr101836_1.c b/gcc/testsuite/gcc.dg/pr101836_1.c new file mode 100644 index 0000000..e2931ce --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101836_1.c @@ -0,0 +1,60 @@ +/* -fstrict-flex-arrays=3 is the strictest, only [] is treated as + flexible array. */ +/* PR tree-optimization/101836 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fstrict-flex-arrays=3" } */ + +#include + +#define expect(p, _v) do { \ + size_t v = _v; \ + if (p == v) \ + printf("ok: %s == %zd\n", #p, p); \ + else \ + { \ + printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \ + __builtin_abort (); \ + } \ +} while (0); + +struct trailing_array_1 { + int a; + int b; + int c[4]; +}; + +struct trailing_array_2 { + int a; + int b; + int c[1]; +}; + +struct trailing_array_3 { + int a; + int b; + int c[0]; +}; +struct trailing_array_4 { + int a; + int b; + int c[]; +}; + +void __attribute__((__noinline__)) stuff( + struct trailing_array_1 *normal, + struct trailing_array_2 *trailing_1, + struct trailing_array_3 *trailing_0, + struct trailing_array_4 *trailing_flex) +{ + expect(__builtin_object_size(normal->c, 1), 16); + expect(__builtin_object_size(trailing_1->c, 1), 4); + expect(__builtin_object_size(trailing_0->c, 1), 0); + expect(__builtin_object_size(trailing_flex->c, 1), -1); +} + +int main(int argc, char *argv[]) +{ + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr101836_2.c b/gcc/testsuite/gcc.dg/pr101836_2.c new file mode 100644 index 0000000..7897418 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101836_2.c @@ -0,0 +1,60 @@ +/* When -fstrict-flex-arrays=2, only [] and [0] are treated as flexiable + arrays. */ +/* PR tree-optimization/101836 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fstrict-flex-arrays=2" } */ + +#include + +#define expect(p, _v) do { \ + size_t v = _v; \ + if (p == v) \ + printf("ok: %s == %zd\n", #p, p); \ + else \ + { \ + printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \ + __builtin_abort (); \ + } \ +} while (0); + +struct trailing_array_1 { + int a; + int b; + int c[4]; +}; + +struct trailing_array_2 { + int a; + int b; + int c[1]; +}; + +struct trailing_array_3 { + int a; + int b; + int c[0]; +}; +struct trailing_array_4 { + int a; + int b; + int c[]; +}; + +void __attribute__((__noinline__)) stuff( + struct trailing_array_1 *normal, + struct trailing_array_2 *trailing_1, + struct trailing_array_3 *trailing_0, + struct trailing_array_4 *trailing_flex) +{ + expect(__builtin_object_size(normal->c, 1), 16); + expect(__builtin_object_size(trailing_1->c, 1), 4); + expect(__builtin_object_size(trailing_0->c, 1), -1); + expect(__builtin_object_size(trailing_flex->c, 1), -1); +} + +int main(int argc, char *argv[]) +{ + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr101836_3.c b/gcc/testsuite/gcc.dg/pr101836_3.c new file mode 100644 index 0000000..0e69388 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101836_3.c @@ -0,0 +1,60 @@ +/* When -fstrict-flex-arrays=1, [], [0], and [1] are treated as flexible + arrays. */ +/* PR tree-optimization/101836 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fstrict-flex-arrays=1" } */ + +#include + +#define expect(p, _v) do { \ + size_t v = _v; \ + if (p == v) \ + printf("ok: %s == %zd\n", #p, p); \ + else \ + { \ + printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \ + __builtin_abort (); \ + } \ +} while (0); + +struct trailing_array_1 { + int a; + int b; + int c[4]; +}; + +struct trailing_array_2 { + int a; + int b; + int c[1]; +}; + +struct trailing_array_3 { + int a; + int b; + int c[0]; +}; +struct trailing_array_4 { + int a; + int b; + int c[]; +}; + +void __attribute__((__noinline__)) stuff( + struct trailing_array_1 *normal, + struct trailing_array_2 *trailing_1, + struct trailing_array_3 *trailing_0, + struct trailing_array_4 *trailing_flex) +{ + expect(__builtin_object_size(normal->c, 1), 16); + expect(__builtin_object_size(trailing_1->c, 1), -1); + expect(__builtin_object_size(trailing_0->c, 1), -1); + expect(__builtin_object_size(trailing_flex->c, 1), -1); +} + +int main(int argc, char *argv[]) +{ + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr101836_4.c b/gcc/testsuite/gcc.dg/pr101836_4.c new file mode 100644 index 0000000..e0025aa --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101836_4.c @@ -0,0 +1,60 @@ +/* when -fstrict-flex-arrays=0, all trailing arrays are treated as + flexible arrays. */ +/* PR tree-optimization/101836 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fstrict-flex-arrays=0" } */ + +#include + +#define expect(p, _v) do { \ + size_t v = _v; \ + if (p == v) \ + printf("ok: %s == %zd\n", #p, p); \ + else \ + { \ + printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \ + __builtin_abort (); \ + } \ +} while (0); + +struct trailing_array_1 { + int a; + int b; + int c[4]; +}; + +struct trailing_array_2 { + int a; + int b; + int c[1]; +}; + +struct trailing_array_3 { + int a; + int b; + int c[0]; +}; +struct trailing_array_4 { + int a; + int b; + int c[]; +}; + +void __attribute__((__noinline__)) stuff( + struct trailing_array_1 *normal, + struct trailing_array_2 *trailing_1, + struct trailing_array_3 *trailing_0, + struct trailing_array_4 *trailing_flex) +{ + expect(__builtin_object_size(normal->c, 1), -1); + expect(__builtin_object_size(trailing_1->c, 1), -1); + expect(__builtin_object_size(trailing_0->c, 1), -1); + expect(__builtin_object_size(trailing_flex->c, 1), -1); +} + +int main(int argc, char *argv[]) +{ + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr101836_5.c b/gcc/testsuite/gcc.dg/pr101836_5.c new file mode 100644 index 0000000..0ad8bbf --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101836_5.c @@ -0,0 +1,60 @@ +/* -fno-strict-flex-arrays is aliased to -fstrict-flex-arrays=0, + all trailing arrays are treated as flexible array. */ +/* PR tree-optimization/101836 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fno-strict-flex-arrays" } */ + +#include + +#define expect(p, _v) do { \ + size_t v = _v; \ + if (p == v) \ + printf("ok: %s == %zd\n", #p, p); \ + else \ + { \ + printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \ + __builtin_abort (); \ + } \ +} while (0); + +struct trailing_array_1 { + int a; + int b; + int c[4]; +}; + +struct trailing_array_2 { + int a; + int b; + int c[1]; +}; + +struct trailing_array_3 { + int a; + int b; + int c[0]; +}; +struct trailing_array_4 { + int a; + int b; + int c[]; +}; + +void __attribute__((__noinline__)) stuff( + struct trailing_array_1 *normal, + struct trailing_array_2 *trailing_1, + struct trailing_array_3 *trailing_0, + struct trailing_array_4 *trailing_flex) +{ + expect(__builtin_object_size(normal->c, 1), -1); + expect(__builtin_object_size(trailing_1->c, 1), -1); + expect(__builtin_object_size(trailing_0->c, 1), -1); + expect(__builtin_object_size(trailing_flex->c, 1), -1); +} + +int main(int argc, char *argv[]) +{ + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-2.c b/gcc/testsuite/gcc.dg/strict-flex-array-2.c new file mode 100644 index 0000000..2b80c23 --- /dev/null +++ b/gcc/testsuite/gcc.dg/strict-flex-array-2.c @@ -0,0 +1,60 @@ +/* test the combination of attribute strict_flex_array and option + -fstrict-flex-arrays: when both attribute and option specified, + attribute will have higher priority. */ +/* { dg-do run } */ +/* { dg-options "-O2 -fstrict-flex-arrays=3" } */ + +#include + +#define expect(p, _v) do { \ + size_t v = _v; \ + if (p == v) \ + printf("ok: %s == %zd\n", #p, p); \ + else \ + { \ + printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \ + __builtin_abort (); \ + } \ +} while (0); + +struct trailing_array_1 { + int a; + int b; + int c[4] __attribute__ ((strict_flex_array (0))); +}; + +struct trailing_array_2 { + int a; + int b; + int c[1] __attribute__ ((strict_flex_array (1))); +}; + +struct trailing_array_3 { + int a; + int b; + int c[0] __attribute__ ((strict_flex_array (2))); +}; +struct trailing_array_4 { + int a; + int b; + int c[]; +}; + +void __attribute__((__noinline__)) stuff( + struct trailing_array_1 *normal, + struct trailing_array_2 *trailing_1, + struct trailing_array_3 *trailing_0, + struct trailing_array_4 *trailing_flex) +{ + expect(__builtin_object_size(normal->c, 1), -1); + expect(__builtin_object_size(trailing_1->c, 1), -1); + expect(__builtin_object_size(trailing_0->c, 1), -1); + expect(__builtin_object_size(trailing_flex->c, 1), -1); +} + +int main(int argc, char *argv[]) +{ + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/strict-flex-array-3.c b/gcc/testsuite/gcc.dg/strict-flex-array-3.c new file mode 100644 index 0000000..602f99d --- /dev/null +++ b/gcc/testsuite/gcc.dg/strict-flex-array-3.c @@ -0,0 +1,60 @@ +/* test the combination of attribute strict_flex_array and option + -fstrict-flex-arrays: when both attribute and option specified, + attribute will have higher priority. */ +/* { dg-do run } */ +/* { dg-options "-O2 -fstrict-flex-arrays=0" } */ + +#include + +#define expect(p, _v) do { \ + size_t v = _v; \ + if (p == v) \ + printf("ok: %s == %zd\n", #p, p); \ + else \ + { \ + printf("WAT: %s == %zd (expected %zd)\n", #p, p, v); \ + __builtin_abort (); \ + } \ +} while (0); + +struct trailing_array_1 { + int a; + int b; + int c[4] __attribute__ ((strict_flex_array (1))); +}; + +struct trailing_array_2 { + int a; + int b; + int c[1] __attribute__ ((strict_flex_array (2))); +}; + +struct trailing_array_3 { + int a; + int b; + int c[0] __attribute__ ((strict_flex_array (3))); +}; +struct trailing_array_4 { + int a; + int b; + int c[]; +}; + +void __attribute__((__noinline__)) stuff( + struct trailing_array_1 *normal, + struct trailing_array_2 *trailing_1, + struct trailing_array_3 *trailing_0, + struct trailing_array_4 *trailing_flex) +{ + expect(__builtin_object_size(normal->c, 1), 16); + expect(__builtin_object_size(trailing_1->c, 1), 4); + expect(__builtin_object_size(trailing_0->c, 1), 0); + expect(__builtin_object_size(trailing_flex->c, 1), -1); +} + +int main(int argc, char *argv[]) +{ + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]); + + return 0; +} diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc index 4eb454a..1f04cb8 100644 --- a/gcc/tree-object-size.cc +++ b/gcc/tree-object-size.cc @@ -604,9 +604,9 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, else if (var != pt_var && TREE_CODE (pt_var) == MEM_REF) { tree v = var; - /* For &X->fld, compute object size only if fld isn't the last - field, as struct { int i; char c[1]; } is often used instead - of flexible array member. */ + /* For &X->fld, compute object size if fld isn't a flexible array + member. */ + bool is_flexible_array_mem_ref = false; while (v && v != pt_var) switch (TREE_CODE (v)) { @@ -633,6 +633,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, v = NULL_TREE; break; } + is_flexible_array_mem_ref = array_at_struct_end_p (v); while (v != pt_var && TREE_CODE (v) == COMPONENT_REF) if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) != UNION_TYPE @@ -645,12 +646,9 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) == RECORD_TYPE) { - tree fld_chain = DECL_CHAIN (TREE_OPERAND (v, 1)); - for (; fld_chain; fld_chain = DECL_CHAIN (fld_chain)) - if (TREE_CODE (fld_chain) == FIELD_DECL) - break; - - if (fld_chain) + /* compute object size only if v is not a + flexible array member. */ + if (!is_flexible_array_mem_ref) { v = NULL_TREE; break; -- cgit v1.1 From f30e9fd33e56a5a721346ea6140722e1b193db42 Mon Sep 17 00:00:00 2001 From: Eugene Rozenfeld Date: Thu, 21 Apr 2022 16:43:24 -0700 Subject: Set discriminators for call stmts on the same line within the same basic block. Call statements are possible split points of a basic block so they may end up in different basic blocks by the time pass_ipa_auto_profile executes. This change will also simplify call site lookups since now location with discriminator will uniquely identify the call site (no callee function name is needed). This change is based on commit 1e6c4a7a8fb8e20545bb9f9032d3854f3f794c18 by Dehao Chen in vendors/google/heads/gcc-4_8. Tested on x86_64-pc-linux-gnu. gcc/ChangeLog: * tree-cfg.cc (assign_discriminators): Set discriminators for call stmts on the same line within the same basic block. --- gcc/tree-cfg.cc | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'gcc') diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index 42f40f1..41f2925 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -1203,8 +1203,40 @@ assign_discriminators (void) { edge e; edge_iterator ei; + gimple_stmt_iterator gsi; gimple *last = last_stmt (bb); location_t locus = last ? gimple_location (last) : UNKNOWN_LOCATION; + location_t curr_locus = UNKNOWN_LOCATION; + int curr_discr = 0; + + /* Traverse the basic block, if two function calls within a basic block + are mapped to the same line, assign a new discriminator because a call + stmt could be a split point of a basic block. */ + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + expanded_location curr_locus_e; + if (curr_locus == UNKNOWN_LOCATION) + { + curr_locus = gimple_location (stmt); + curr_locus_e = expand_location (curr_locus); + } + else if (!same_line_p (curr_locus, &curr_locus_e, gimple_location (stmt))) + { + curr_locus = gimple_location (stmt); + curr_locus_e = expand_location (curr_locus); + curr_discr = 0; + } + else if (curr_discr != 0) + { + location_t loc = gimple_location (stmt); + location_t dloc = location_with_discriminator (loc, curr_discr); + gimple_set_location (stmt, dloc); + } + /* Allocate a new discriminator for CALL stmt. */ + if (gimple_code (stmt) == GIMPLE_CALL) + curr_discr = next_discriminator_for_locus (curr_locus); + } if (locus == UNKNOWN_LOCATION) continue; -- cgit v1.1 From 895dd027d5dda51a95d242aec8a49a6dfa5db58d Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 5 Oct 2022 15:51:30 -0400 Subject: c++: fixes for derived-to-base reference binding [PR107085] This PR reports that struct Base {}; struct Derived : Base {}; static_assert(__reference_constructs_from_temporary(Base const&, Derived)); doesn't pass, which it should: it's just like const Base& b(Derived{}); where we bind 'b' to the Base subobject of a temporary object of type Derived. The ck_base conversion didn't have ->need_temporary_p set because we didn't need to create a temporary object just for the base, but the whole object is a temporary so we're still binding to a temporary. Since the Base subobject is an xvalue, a new function is introduced. PR c++/107085 gcc/cp/ChangeLog: * call.cc (conv_binds_ref_to_temporary): New. (ref_conv_binds_directly): Rename to... (ref_conv_binds_to_temporary): ...this. Use conv_binds_ref_to_temporary. * cp-tree.h (ref_conv_binds_directly): Rename to... (ref_conv_binds_to_temporary): ...this. * method.cc (ref_xes_from_temporary): Use ref_conv_binds_to_temporary. * parser.cc (warn_for_range_copy): Likewise. gcc/testsuite/ChangeLog: * g++.dg/ext/reference_constructs_from_temporary1.C: Adjust expected result. * g++.dg/ext/reference_converts_from_temporary1.C: Likewise. * g++.dg/cpp0x/elision4.C: New test. --- gcc/cp/call.cc | 44 +++++++++++++++++++--- gcc/cp/cp-tree.h | 2 +- gcc/cp/method.cc | 2 +- gcc/cp/parser.cc | 5 ++- gcc/testsuite/g++.dg/cpp0x/elision4.C | 15 ++++++++ .../ext/reference_constructs_from_temporary1.C | 2 +- .../ext/reference_converts_from_temporary1.C | 2 +- 7 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/elision4.C (limited to 'gcc') diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index bd04a1d..7771d80 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -9210,15 +9210,47 @@ conv_binds_ref_to_prvalue (conversion *c) return conv_is_prvalue (next_conversion (c)); } -/* Return tristate::TS_TRUE if converting EXPR to a reference type TYPE does - not involve creating a temporary. Return tristate::TS_FALSE if converting - EXPR to a reference type TYPE binds the reference to a temporary. If the - conversion is invalid or bad, return tristate::TS_UNKNOWN. DIRECT_INIT_P +/* True iff C is a conversion that binds a reference to a temporary. + This is a superset of conv_binds_ref_to_prvalue: here we're also + interested in xvalues. */ + +static bool +conv_binds_ref_to_temporary (conversion *c) +{ + if (conv_binds_ref_to_prvalue (c)) + return true; + if (c->kind != ck_ref_bind) + return false; + c = next_conversion (c); + /* This is the case for + struct Base {}; + struct Derived : Base {}; + const Base& b(Derived{}); + where we bind 'b' to the Base subobject of a temporary object of type + Derived. The subobject is an xvalue; the whole object is a prvalue. */ + if (c->kind != ck_base) + return false; + c = next_conversion (c); + if (c->kind == ck_identity && c->u.expr) + { + tree expr = c->u.expr; + while (handled_component_p (expr)) + expr = TREE_OPERAND (expr, 0); + if (TREE_CODE (expr) == TARGET_EXPR) + return true; + } + return false; +} + +/* Return tristate::TS_TRUE if converting EXPR to a reference type TYPE binds + the reference to a temporary. Return tristate::TS_FALSE if converting + EXPR to a reference type TYPE doesn't bind the reference to a temporary. If + the conversion is invalid or bad, return tristate::TS_UNKNOWN. DIRECT_INIT_P says whether the conversion should be done in direct- or copy-initialization context. */ tristate -ref_conv_binds_directly (tree type, tree expr, bool direct_init_p /*= false*/) +ref_conv_binds_to_temporary (tree type, tree expr, bool direct_init_p/*=false*/) { gcc_assert (TYPE_REF_P (type)); @@ -9230,7 +9262,7 @@ ref_conv_binds_directly (tree type, tree expr, bool direct_init_p /*= false*/) /*c_cast_p=*/false, flags, tf_none); tristate ret (tristate::TS_UNKNOWN); if (conv && !conv->bad_p) - ret = tristate (!conv_binds_ref_to_prvalue (conv)); + ret = tristate (conv_binds_ref_to_temporary (conv)); /* Free all the conversions we allocated. */ obstack_free (&conversion_obstack, p); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8bc1c2d..469eb2f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6534,7 +6534,7 @@ extern bool sufficient_parms_p (const_tree); extern tree type_decays_to (tree); extern tree extract_call_expr (tree); extern tree build_trivial_dtor_call (tree, bool = false); -extern tristate ref_conv_binds_directly (tree, tree, bool = false); +extern tristate ref_conv_binds_to_temporary (tree, tree, bool = false); extern tree build_user_type_conversion (tree, tree, int, tsubst_flags_t); extern tree build_new_function_call (tree, vec **, diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 55af5c4..622e1b9 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -2233,7 +2233,7 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p) tree val = build_stub_object (from); if (!TYPE_REF_P (from) && TREE_CODE (from) != FUNCTION_TYPE) val = CLASS_TYPE_P (from) ? force_rvalue (val, tf_none) : rvalue (val); - return ref_conv_binds_directly (to, val, direct_init_p).is_false (); + return ref_conv_binds_to_temporary (to, val, direct_init_p).is_true (); } /* Worker for is_{,nothrow_}convertible. Attempt to perform an implicit diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 555476e..dc3d17c 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -13731,7 +13731,8 @@ warn_for_range_copy (tree decl, tree expr) if (TYPE_REF_P (type)) { - if (glvalue_p (expr) && ref_conv_binds_directly (type, expr).is_false ()) + if (glvalue_p (expr) + && ref_conv_binds_to_temporary (type, expr).is_true ()) { auto_diagnostic_group d; if (warning_at (loc, OPT_Wrange_loop_construct, @@ -13762,7 +13763,7 @@ warn_for_range_copy (tree decl, tree expr) /* If we can initialize a reference directly, suggest that to avoid the copy. */ tree rtype = cp_build_reference_type (type, /*rval*/false); - if (ref_conv_binds_directly (rtype, expr).is_true ()) + if (ref_conv_binds_to_temporary (rtype, expr).is_false ()) { auto_diagnostic_group d; if (warning_at (loc, OPT_Wrange_loop_construct, diff --git a/gcc/testsuite/g++.dg/cpp0x/elision4.C b/gcc/testsuite/g++.dg/cpp0x/elision4.C new file mode 100644 index 0000000..3cc2e3a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/elision4.C @@ -0,0 +1,15 @@ +// PR c++/107085 +// { dg-do compile { target c++11 } } + +struct X { + X(); + X(X&&); +}; +struct Z : X {}; +X x1 = Z(); +X x2 = X(Z()); + +struct B { }; +struct D : B { }; +B b1 = D(); +B b2 = B(D()); diff --git a/gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C b/gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C index 76de905..5354b1d 100644 --- a/gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C +++ b/gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C @@ -201,7 +201,7 @@ SA(!__reference_constructs_from_temporary(const int&, H)); SA(!__reference_constructs_from_temporary(int&&, G2)); SA(!__reference_constructs_from_temporary(const int&, H2)); -SA(!__reference_constructs_from_temporary(const Base&, Der)); +SA(__reference_constructs_from_temporary(const Base&, Der)); // This fails because std::is_constructible_v> is false. SA(!__reference_constructs_from_temporary(int&&, id)); diff --git a/gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C b/gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C index 90196c3..e6c159e 100644 --- a/gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C +++ b/gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C @@ -201,7 +201,7 @@ SA( __reference_converts_from_temporary(const int&, H)); SA(!__reference_converts_from_temporary(int&&, G2)); SA(!__reference_converts_from_temporary(const int&, H2)); -SA(!__reference_converts_from_temporary(const Base&, Der)); +SA(__reference_converts_from_temporary(const Base&, Der)); // This fails because std::is_constructible_v> is false. SA(!__reference_converts_from_temporary(int&&, id)); -- cgit v1.1 From 9ff6c33e2ec0d75958d3f19089519034e8f96a30 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 8 Oct 2022 00:17:29 +0000 Subject: Daily bump. --- gcc/ChangeLog | 126 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/analyzer/ChangeLog | 9 ++++ gcc/c-family/ChangeLog | 17 +++++++ gcc/c/ChangeLog | 10 ++++ gcc/cp/ChangeLog | 52 ++++++++++++++++++++ gcc/objc/ChangeLog | 5 ++ gcc/testsuite/ChangeLog | 59 +++++++++++++++++++++++ 8 files changed, 279 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ad2c6e7..5086463 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,129 @@ +2022-10-07 Eugene Rozenfeld + + * tree-cfg.cc (assign_discriminators): Set discriminators for call stmts + on the same line within the same basic block. + +2022-10-07 Qing Zhao + + PR tree-optimization/101836 + * tree-object-size.cc (addr_object_size): Use array_at_struct_end_p + to determine a flexible array member reference. + +2022-10-07 Qing Zhao + + * doc/extend.texi: Document strict_flex_array attribute. + * doc/invoke.texi: Document -fstrict-flex-arrays[=n] option. + * print-tree.cc (print_node): Print new bit decl_not_flexarray. + * tree-core.h (struct tree_decl_common): New bit field + decl_not_flexarray. + * tree-streamer-in.cc (unpack_ts_decl_common_value_fields): Stream + in new bit decl_not_flexarray. + * tree-streamer-out.cc (pack_ts_decl_common_value_fields): Stream + out new bit decl_not_flexarray. + * tree.cc (array_at_struct_end_p): Update it with the new bit field + decl_not_flexarray. + * tree.h (DECL_NOT_FLEXARRAY): New flag. + +2022-10-07 Olivier Hainque + + * config/vxworks/_vxworks-versions.h: Use OS specific + paths in #include of version.h. + +2022-10-07 Martin Liska + + * opts.cc (finish_options): Print sorry message only + for -flive-patching=inline-only-static. + +2022-10-07 Jason Merrill + + * gimplify.cc (gimplify_modify_expr_rhs): Don't optimize + x = *(A*)& to x = for a TREE_ADDRESSABLE type. + +2022-10-07 Richard Biener + + PR tree-optimization/107153 + * tree-cfg.cc (gimple_duplicate_sese_tail): Do not update + SSA form here. + * tree-parloops.cc (gen_parallel_loop): Update SSA form + after to-exit-first transform, no PHI insertion is necessary. + (pass_parallelize_loops::execute): Force re-write of the + virtual operand SSA web. + +2022-10-07 Jonathan Wakely + + * value-range.cc (irange::irange_contains_p): Fix comment typo. + +2022-10-07 Eric Botcazou + + * function.cc (thread_prologue_and_epilogue_insns): Update only + entry and exit blocks when not optimizing. Remove dead statement. + +2022-10-07 Aldy Hernandez + + * value-range.cc (irange::irange_set): Convert nonzero mask to + tree. + (irange::irange_set_anti_range): Same. + (irange::set): Same. + (irange::verify_range): Same. + (irange::contains_p): Same. + (irange::invert): Same. + (irange::set_range_from_nonzero_bits): Same. + (irange::set_nonzero_bits): Same. + (mask_to_wi): Same. + (irange::intersect_nonzero_bits): Same. + (irange::union_nonzero_bits): Same. + * value-range.h (irange::varying_compatible_p): Same. + (gt_ggc_mx): Same. + (gt_pch_nx): Same. + (irange::set_undefined): Same. + (irange::set_varying): Same. + +2022-10-07 Martin Liska + + * config/i386/i386-protos.h (ix86_binary_operator_ok): Add array + size to function parameter. + (ix86_unary_operator_ok): Likewise. + +2022-10-07 Martin Liska + + * auto-profile.cc (get_inline_stack): Remove unused variable. + +2022-10-07 Jakub Jelinek + + * ipa-prop.h (ipa_constant_data): Fix comment typo. + * value-range.cc (irange::irange_contains_p): Likewise. + * value-relation.cc (dom_oracle::set_one_relation): Likewise. + * gimple-predicate-analysis.cc (predicate::simplify_4): Likewise. + * tree-inline.cc (remap_ssa_name): Likewise. + +2022-10-07 Jakub Jelinek + + * attribs.h (is_attribute_namespace_p): New inline function. + (lookup_attribute): Document meaning of ATTR_NS equal to "". + * attribs.cc (remove_attribute): Use is_attribute_namespace_p. + (private_lookup_attribute): For ATTR_NS "" match either standard + attribute or "gnu" namespace one. + +2022-10-07 Olivier Hainque + + * config/vxworks.h (DWARF_VERSION_DEFAULT): Adjust from + 4 to 3 for VxWorks >= 7. + +2022-10-07 Olivier Hainque + + * defaults.h (DWARF_DEFAULT_VERSION): Define if not + defined already. + * common.opt (gdwarf-): Use it. + * doc/tm.texi.in (DWARF_DEFAULT_VERSION): Document. + * doc/tm.texi: Update accordingly. + * config/vxworks.h (DWARF_DEFAULT_VERSION): Redefine. + * config/vxworks.cc: Remove code setting dwarf_version, now + handled by the DWARF_DEFAULT_VERSION redefinition. + +2022-10-07 Olivier Hainque + + * ginclude/stddef.h: #undef offsetof before #define. + 2022-10-06 Aldy Hernandez PR tree-optimization/107170 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 12abceb7..ab0c096 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20221007 +20221008 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 70e9289..33477da 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,12 @@ +2022-10-07 David Malcolm + + PR analyzer/105783 + * region-model.cc (selftest::get_bit): New function. + (selftest::test_bits_within_svalue_folding): New. + (selfftest::analyzer_region_model_cc_tests): Call it. + * svalue.cc (constant_svalue::maybe_fold_bits_within): Handle the + case of extracting a single bit. + 2022-10-06 David Malcolm PR analyzer/107158 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 75ff47d..7bae1d5 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,20 @@ +2022-10-07 Qing Zhao + + * c-attribs.cc (handle_strict_flex_array_attribute): New function. + (c_common_attribute_table): New item for strict_flex_array. + * c.opt: (fstrict-flex-arrays): New option. + (fstrict-flex-arrays=): New option. + +2022-10-07 Martin Liska + + * name-hint.h: Use std::move. + +2022-10-07 Jakub Jelinek + + * c-common.cc (attribute_fallthrough_p): Lookup fallthrough attribute + only in gnu namespace or as standard attribute, treat fallthrough + attributes in other namespaces like any other unknown attribute. + 2022-10-06 Joseph Myers * c-common.cc (c_common_reswords): Mark typeof as D_EXT11. Add diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 325b1f8..a25e1b4 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,13 @@ +2022-10-07 Qing Zhao + + * c-decl.cc (flexible_array_member_type_p): New function. + (one_element_array_type_p): Likewise. + (zero_length_array_type_p): Likewise. + (add_flexible_array_elts_to_size): Call new utility + routine flexible_array_member_type_p. + (is_flexible_array_member_p): New function. + (finish_struct): Set the new DECL_NOT_FLEXARRAY flag. + 2022-10-06 Joseph Myers * c-parser.cc (c_parse_init): Add D_EXT11 to mask if flag_no_asm diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0fe21fd..3aa9f03 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,55 @@ +2022-10-07 Marek Polacek + + PR c++/107085 + * call.cc (conv_binds_ref_to_temporary): New. + (ref_conv_binds_directly): Rename to... + (ref_conv_binds_to_temporary): ...this. Use + conv_binds_ref_to_temporary. + * cp-tree.h (ref_conv_binds_directly): Rename to... + (ref_conv_binds_to_temporary): ...this. + * method.cc (ref_xes_from_temporary): Use ref_conv_binds_to_temporary. + * parser.cc (warn_for_range_copy): Likewise. + +2022-10-07 Qing Zhao + + * module.cc (trees_out::core_bools): Stream out new bit + decl_not_flexarray. + (trees_in::core_bools): Stream in new bit decl_not_flexarray. + +2022-10-07 Patrick Palka + + * module.cc (trees_out::mark_class_def): Guard against + DECL_BIT_FIELD_REPRESENTATIVE not being a decl. + +2022-10-07 Jason Merrill + + * init.cc (expand_default_init): Also push the INIT_EXPR inside a + CLEANUP_POINT_EXPR. + +2022-10-07 Patrick Palka + + PR c++/104433 + * module.cc (trees_out::core_bools): Don't override + DECL_EXTERNAL to true for static variables from an inline + function. + +2022-10-07 Martin Liska + + * module.cc (enum module_state_counts): Use array size. + * name-lookup.cc (class namespace_limit_reached): Likewise. + (class module_state): Move up in the file. + +2022-10-07 Jakub Jelinek + + * parser.cc (cp_parser_check_std_attribute): Only do checks if + attribute is a standard attribute or in gnu namespace and only + lookup other attributes in those namespaces. + * cp-gimplify.cc (lookup_hotness_attribute): Adjust function comment. + Only return true for standard attribute or gnu namespace attribute. + (remove_hotness_attribute): Only remove hotness attributes when + they are standard or in gnu namespace, implement it in a single + loop rather than former 4 now 8 remove_attribute calls. + 2022-10-06 Jason Merrill * coroutines.cc (expand_one_await_expression): Change conversion diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 01720f7..a83c3c7 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,8 @@ +2022-10-07 Martin Liska + + * objc-gnu-runtime-abi-01.cc (generate_static_references): + Remove unused variable. + 2022-06-02 David Malcolm * objc-act.h (objc_get_sarif_source_language): New decl. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9577fc1..af8fc3f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,62 @@ +2022-10-07 Marek Polacek + + PR c++/107085 + * g++.dg/ext/reference_constructs_from_temporary1.C: Adjust expected + result. + * g++.dg/ext/reference_converts_from_temporary1.C: Likewise. + * g++.dg/cpp0x/elision4.C: New test. + +2022-10-07 Qing Zhao + + PR tree-optimization/101836 + * gcc.dg/pr101836.c: New test. + * gcc.dg/pr101836_1.c: New test. + * gcc.dg/pr101836_2.c: New test. + * gcc.dg/pr101836_3.c: New test. + * gcc.dg/pr101836_4.c: New test. + * gcc.dg/pr101836_5.c: New test. + * gcc.dg/strict-flex-array-2.c: New test. + * gcc.dg/strict-flex-array-3.c: New test. + +2022-10-07 Qing Zhao + + * g++.dg/strict-flex-array-1.C: New test. + * gcc.dg/strict-flex-array-1.c: New test. + +2022-10-07 David Malcolm + + PR analyzer/105783 + * gcc.dg/analyzer/pr105783.c: New test. + +2022-10-07 Patrick Palka + + * g++.dg/modules/bfield-3.H: New test. + +2022-10-07 Martin Liska + + * gcc.dg/live-patching-2.c: Update scanned pattern. + * gcc.dg/live-patching-5.c: New test. + +2022-10-07 Patrick Palka + + PR c++/104433 + * g++.dg/modules/static-2_a.H: New test. + * g++.dg/modules/static-2_b.C: New test. + +2022-10-07 Jason Merrill + + * g++.dg/init/elide9.C: New test. + +2022-10-07 Richard Biener + + PR tree-optimization/107153 + * gcc.dg/autopar/pr107153.c: New testcase. + +2022-10-07 Jakub Jelinek + + * g++.dg/cpp1z/fallthrough2.C: New test. + * g++.dg/cpp2a/attr-likely7.C: New test. + 2022-10-06 Aldy Hernandez PR tree-optimization/107170 -- cgit v1.1 From 6ffbf87ca66f4ed9cd79cff675fabe2109e46e85 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 17 Sep 2022 12:04:05 +0200 Subject: c++: track whether we expect a TARGET_EXPR to be elided A discussion at Cauldron made me think that with the formalization of copy elision in C++17, we should be able to determine before optimization which TARGET_EXPRs will become temporaries and which are initializers. This patch implements that: we set TARGET_EXPR_ELIDING_P if it's used as an initializer, and later check that we were right. There's an exception in the cp_gimplify_expr check to allow extra temporaries of non-addressable type: this is used by gimplify_init_ctor_preeval to materialize subobjects of a CONSTRUCTOR on the rhs of a MODIFY_EXPR rather than materializing the whole object. If the type isn't addressable, there's no way for a program to tell the difference, so this is a valid optimization. I considered changing replace_placeholders_for_class_temp_r to check TARGET_EXPR_ELIDING_P instead of potential_prvalue_result_of, but decided that would be wrong: if we have an eliding TARGET_EXPR inside a non-eliding one, we would miss replacing its placeholders. gcc/cp/ChangeLog: * cp-tree.h (TARGET_EXPR_ELIDING_P): New. (unsafe_copy_elision_p, set_target_expr_eliding) (cp_build_init_expr): Declare. * call.cc (unsafe_copy_elision_p): No longer static. (build_over_call, build_special_member_call) (build_new_method_call): Use cp_build_init_expr. * coroutines.cc (expand_one_await_expression) (build_actor_fn, flatten_await_stmt, handle_nested_conditionals) (await_statement_walker, morph_fn_to_coro): Use cp_build_init_expr. * cp-gimplify.cc (cp_gimplify_init_expr) (cp_gimplify_expr): Check TARGET_EXPR_ELIDING_P. (cp_fold_r): Propagate it. (cp_fold): Use cp_build_init_expr. * decl.cc (check_initializer): Use cp_build_init_expr. * except.cc (build_throw): Use cp_build_init_expr. * init.cc (get_nsdmi): Call set_target_expr_eliding. (perform_member_init, expand_default_init, expand_aggr_init_1) (build_new_1, build_vec_init): Use cp_build_init_expr. * method.cc (do_build_copy_constructor): Use cp_build_init_expr. * semantics.cc (simplify_aggr_init_expr, finalize_nrv_r) (finish_omp_reduction_clause): Use cp_build_init_expr. * tree.cc (build_target_expr): Call set_target_expr_eliding. (bot_manip): Copy TARGET_EXPR_ELIDING_P. * typeck.cc (cp_build_modify_expr): Call set_target_expr_eliding. (check_return_expr): Use cp_build_modify_expr. * typeck2.cc (split_nonconstant_init_1) (split_nonconstant_init): Use cp_build_init_expr. (massage_init_elt): Call set_target_expr_eliding. (process_init_constructor_record): Clear TARGET_EXPR_ELIDING_P on unsafe copy elision. (set_target_expr_eliding, cp_build_init_expr): New. --- gcc/cp/call.cc | 16 ++++++--------- gcc/cp/coroutines.cc | 43 +++++++++++++++++++-------------------- gcc/cp/cp-gimplify.cc | 13 ++++++++++-- gcc/cp/cp-tree.h | 11 ++++++++++ gcc/cp/decl.cc | 2 +- gcc/cp/except.cc | 2 +- gcc/cp/init.cc | 31 ++++++++++++++-------------- gcc/cp/method.cc | 4 ++-- gcc/cp/semantics.cc | 12 +++++++---- gcc/cp/tree.cc | 4 ++++ gcc/cp/typeck.cc | 6 ++++-- gcc/cp/typeck2.cc | 56 ++++++++++++++++++++++++++++++++++++++++++++++++--- 12 files changed, 138 insertions(+), 62 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 7771d80..70ec964 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -9144,7 +9144,7 @@ init_by_return_slot_p (tree exp) Places that use this function (or _opt) to decide to elide a copy should probably use make_safe_copy_elision instead. */ -static bool +bool unsafe_copy_elision_p (tree target, tree exp) { return unsafe_return_slot_p (target) && init_by_return_slot_p (exp); @@ -9941,7 +9941,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) && !unsafe) { tree to = cp_build_fold_indirect_ref (fa); - val = build2 (INIT_EXPR, DECL_CONTEXT (fn), to, arg); + val = cp_build_init_expr (to, arg); return val; } } @@ -10100,7 +10100,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) } call = cxx_constant_value (call, obj_arg, complain); if (obj_arg && !error_operand_p (call)) - call = build2 (INIT_EXPR, void_type_node, obj_arg, call); + call = cp_build_init_expr (obj_arg, call); call = convert_from_reference (call); } } @@ -10765,7 +10765,7 @@ build_special_member_call (tree instance, tree name, vec **args, check_self_delegation (arg); /* Avoid change of behavior on Wunused-var-2.C. */ instance = mark_lvalue_use (instance); - return build2 (INIT_EXPR, class_type, instance, arg); + return cp_build_init_expr (instance, arg); } } @@ -11183,9 +11183,7 @@ build_new_method_call (tree instance, tree fns, vec **args, { if (is_dummy_object (instance)) return get_target_expr (init, complain); - init = build2 (INIT_EXPR, TREE_TYPE (instance), instance, init); - TREE_SIDE_EFFECTS (init) = true; - return init; + return cp_build_init_expr (instance, init); } /* Otherwise go ahead with overload resolution. */ @@ -11232,9 +11230,7 @@ build_new_method_call (tree instance, tree fns, vec **args, ctor = digest_init (basetype, ctor, complain); if (ctor == error_mark_node) return error_mark_node; - ctor = build2 (INIT_EXPR, TREE_TYPE (instance), instance, ctor); - TREE_SIDE_EFFECTS (ctor) = true; - return ctor; + return cp_build_init_expr (instance, ctor); } } if (complain & tf_error) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 60b8466..01a3e83 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1732,7 +1732,7 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d) if (!same_type_ignoring_top_level_qualifiers_p (susp_type, void_coro_handle_type)) r = build1_loc (loc, VIEW_CONVERT_EXPR, void_coro_handle_type, r); - r = build2_loc (loc, INIT_EXPR, void_coro_handle_type, data->conthand, r); + r = cp_build_init_expr (loc, data->conthand, r); r = build1 (CONVERT_EXPR, void_type_node, r); append_to_statement_list (r, &body_list); is_cont = true; @@ -1755,7 +1755,7 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d) r = build_call_expr_internal_loc (loc, IFN_CO_YIELD, integer_type_node, 5, susp_idx, final_susp, r_l, d_l, data->coro_fp); - r = build2 (INIT_EXPR, integer_type_node, cond, r); + r = cp_build_init_expr (cond, r); finish_switch_cond (r, sw); r = build_case_label (build_int_cst (integer_type_node, 0), NULL_TREE, create_anon_label_with_ctx (loc, actor)); @@ -2304,7 +2304,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, vec *args = make_tree_vector_single (r); tree hfa = build_new_method_call (ash, hfa_m, &args, NULL_TREE, LOOKUP_NORMAL, NULL, tf_warning_or_error); - r = build2 (INIT_EXPR, handle_type, ash, hfa); + r = cp_build_init_expr (ash, hfa); r = coro_build_cvt_void_expr_stmt (r, loc); add_stmt (r); release_tree_vector (args); @@ -2776,17 +2776,19 @@ flatten_await_stmt (var_nest_node *n, hash_set *promoted, if (!VOID_TYPE_P (TREE_TYPE (then_cl))) { gcc_checking_assert (TREE_CODE (then_cl) != STATEMENT_LIST); - then_cl - = build2 (init_expr ? INIT_EXPR : MODIFY_EXPR, var_type, - var, then_cl); + if (init_expr) + then_cl = cp_build_init_expr (var, then_cl); + else + then_cl = build2 (MODIFY_EXPR, var_type, var, then_cl); } tree else_cl = COND_EXPR_ELSE (old_expr); if (!VOID_TYPE_P (TREE_TYPE (else_cl))) { gcc_checking_assert (TREE_CODE (else_cl) != STATEMENT_LIST); - else_cl - = build2 (init_expr ? INIT_EXPR : MODIFY_EXPR, var_type, - var, else_cl); + if (init_expr) + else_cl = cp_build_init_expr (var, else_cl); + else + else_cl = build2 (MODIFY_EXPR, var_type, var, else_cl); } n->init = build3 (COND_EXPR, var_type, cond, then_cl, else_cl); } @@ -2804,7 +2806,7 @@ flatten_await_stmt (var_nest_node *n, hash_set *promoted, DECL_ARTIFICIAL (cond_var) = true; layout_decl (cond_var, 0); gcc_checking_assert (!TYPE_NEEDS_CONSTRUCTING (cond_type)); - cond = build2 (INIT_EXPR, cond_type, cond_var, cond); + cond = cp_build_init_expr (cond_var, cond); var_nest_node *ins = new var_nest_node (cond_var, cond, n->prev, n); COND_EXPR_COND (n->init) = cond_var; @@ -2957,8 +2959,7 @@ handle_nested_conditionals (var_nest_node *n, vec& list, expression that performs the init and then records that the variable is live (and the DTOR should be run at the scope exit. */ - tree set_flag = build2 (INIT_EXPR, boolean_type_node, - flag, boolean_true_node); + tree set_flag = cp_build_init_expr (flag, boolean_true_node); n->init = build2 (COMPOUND_EXPR, boolean_type_node, n->init, set_flag); } @@ -3471,8 +3472,7 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) /* We want to initialize the new variable with the expression that contains the await(s) and potentially also needs to have truth_if expressions expanded. */ - tree new_s = build2_loc (sloc, INIT_EXPR, boolean_type_node, - newvar, cond_inner); + tree new_s = cp_build_init_expr (sloc, newvar, cond_inner); finish_expr_stmt (new_s); IF_COND (if_stmt) = newvar; add_stmt (if_stmt); @@ -3656,7 +3656,7 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) if (TREE_CODE (cond_inner) == CLEANUP_POINT_EXPR) cond_inner = TREE_OPERAND (cond_inner, 0); location_t sloc = EXPR_LOCATION (SWITCH_STMT_COND (sw_stmt)); - tree new_s = build2_loc (sloc, INIT_EXPR, sw_type, newvar, + tree new_s = cp_build_init_expr (sloc, newvar, cond_inner); finish_expr_stmt (new_s); SWITCH_STMT_COND (sw_stmt) = newvar; @@ -4735,7 +4735,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) } tree allocated = build1 (CONVERT_EXPR, coro_frame_ptr, new_fn); - tree r = build2 (INIT_EXPR, TREE_TYPE (coro_fp), coro_fp, allocated); + tree r = cp_build_init_expr (coro_fp, allocated); r = coro_build_cvt_void_expr_stmt (r, fn_start); add_stmt (r); @@ -4796,7 +4796,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) 1, 0,tf_warning_or_error); tree fnf_x = build_class_member_access_expr (deref_fp, fnf_m, NULL_TREE, false, tf_warning_or_error); - r = build2 (INIT_EXPR, boolean_type_node, fnf_x, boolean_true_node); + r = cp_build_init_expr (fnf_x, boolean_true_node); r = coro_build_cvt_void_expr_stmt (r, fn_start); add_stmt (r); @@ -4808,7 +4808,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /*protect=*/1, /*want_type=*/0, tf_warning_or_error); tree resume_x = build_class_member_access_expr (deref_fp, resume_m, NULL_TREE, false, tf_warning_or_error); - r = build2_loc (fn_start, INIT_EXPR, act_des_fn_ptr, resume_x, actor_addr); + r = cp_build_init_expr (fn_start, resume_x, actor_addr); finish_expr_stmt (r); tree destroy_addr = build1 (ADDR_EXPR, act_des_fn_ptr, destroy); @@ -4818,7 +4818,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) tree destroy_x = build_class_member_access_expr (deref_fp, destroy_m, NULL_TREE, false, tf_warning_or_error); - r = build2_loc (fn_start, INIT_EXPR, act_des_fn_ptr, destroy_x, destroy_addr); + r = cp_build_init_expr (fn_start, destroy_x, destroy_addr); finish_expr_stmt (r); /* [dcl.fct.def.coroutine] /13 @@ -5011,8 +5011,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) release_tree_vector (arg); } else - r = build2_loc (fn_start, INIT_EXPR, gro_type, - DECL_RESULT (orig), get_ro); + r = cp_build_init_expr (fn_start, DECL_RESULT (orig), get_ro); if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (gro_type)) /* If some part of the initalization code (prior to the await_resume @@ -5067,7 +5066,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) = build_class_member_access_expr (deref_fp, resume_idx_m, NULL_TREE, false, tf_warning_or_error); r = build_int_cst (short_unsigned_type_node, 0); - r = build2_loc (fn_start, INIT_EXPR, short_unsigned_type_node, resume_idx, r); + r = cp_build_init_expr (fn_start, resume_idx, r); r = coro_build_cvt_void_expr_stmt (r, fn_start); add_stmt (r); diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index cb8bbd8..d0e12c9 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -250,6 +250,7 @@ cp_gimplify_init_expr (tree *expr_p) if (TREE_CODE (from) == TARGET_EXPR) if (tree init = TARGET_EXPR_INITIAL (from)) { + gcc_checking_assert (TARGET_EXPR_ELIDING_P (from)); if (target_expr_needs_replace (from)) { /* If this was changed by cp_genericize_target_expr, we need to @@ -745,6 +746,11 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) /* A TARGET_EXPR that expresses direct-initialization should have been elided by cp_gimplify_init_expr. */ gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P (*expr_p)); + /* Likewise, but allow extra temps of trivial type so that + gimplify_init_ctor_preeval can materialize subobjects of a CONSTRUCTOR + on the rhs of an assignment, as in constexpr-aggr1.C. */ + gcc_checking_assert (!TARGET_EXPR_ELIDING_P (*expr_p) + || !TREE_ADDRESSABLE (TREE_TYPE (*expr_p))); ret = GS_UNHANDLED; break; @@ -1110,7 +1116,10 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_) cp_walk_tree (&init, cp_fold_r, data, NULL); *walk_subtrees = 0; if (TREE_CODE (init) == TARGET_EXPR) - *stmt_p = init; + { + TARGET_EXPR_ELIDING_P (init) = TARGET_EXPR_ELIDING_P (stmt); + *stmt_p = init; + } } break; @@ -2902,7 +2911,7 @@ cp_fold (tree x) loc = EXPR_LOCATION (x); tree s = build_fold_indirect_ref_loc (loc, CALL_EXPR_ARG (x, 0)); - r = build2_loc (loc, INIT_EXPR, TREE_TYPE (s), s, r); + r = cp_build_init_expr (s, r); } x = r; break; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 469eb2f..ab6f85a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -505,6 +505,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; DECL_MODULE_EXPORT_P (in _DECL) PACK_EXPANSION_FORCE_EXTRA_ARGS_P (in *_PACK_EXPANSION) LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR) + TARGET_EXPR_ELIDING_P (in TARGET_EXPR) 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, CALL_EXPR, or FIELD_DECL). @@ -5370,6 +5371,11 @@ get_vec_init_expr (tree t) #define TARGET_EXPR_DIRECT_INIT_P(NODE) \ TREE_LANG_FLAG_2 (TARGET_EXPR_CHECK (NODE)) +/* True if we expect this TARGET_EXPR to be used as an initializer, not to + materialize as a temporary. */ +#define TARGET_EXPR_ELIDING_P(NODE) \ + TREE_LANG_FLAG_3 (TARGET_EXPR_CHECK (NODE)) + /* True if NODE is a TARGET_EXPR that just expresses a copy of its INITIAL; if the initializer has void type, it's doing something more complicated. */ #define SIMPLE_TARGET_EXPR_P(NODE) \ @@ -6657,6 +6663,7 @@ extern bool is_list_ctor (tree); extern void validate_conversion_obstack (void); extern void mark_versions_used (tree); extern int unsafe_return_slot_p (tree); +extern bool unsafe_copy_elision_p (tree, tree); extern bool make_safe_copy_elision (tree, tree); extern bool cp_handle_deprecated_or_unavailable (tree, tsubst_flags_t = tf_warning_or_error); extern void cp_warn_deprecated_use_scopes (tree); @@ -8182,6 +8189,10 @@ extern tree build_functional_cast (location_t, tree, tree, tsubst_flags_t); extern tree add_exception_specifier (tree, tree, tsubst_flags_t); extern tree merge_exception_specifiers (tree, tree); +extern void set_target_expr_eliding (tree); +extern tree cp_build_init_expr (location_t, tree, tree); +inline tree cp_build_init_expr (tree t, tree i) +{ return cp_build_init_expr (input_location, t, i); } /* in mangle.cc */ extern void init_mangle (void); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 07148b9..82eb0c2 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -7500,7 +7500,7 @@ check_initializer (tree decl, tree init, int flags, vec **cleanups) } if (init && init != error_mark_node) - init_code = build2 (INIT_EXPR, type, decl, init); + init_code = cp_build_init_expr (decl, init); if (init_code && !TREE_SIDE_EFFECTS (init_code) && init_code != error_mark_node) diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc index 048612d..b8a85ed 100644 --- a/gcc/cp/except.cc +++ b/gcc/cp/except.cc @@ -755,7 +755,7 @@ build_throw (location_t loc, tree exp) tree tmp = decay_conversion (exp, tf_warning_or_error); if (tmp == error_mark_node) return error_mark_node; - exp = build2 (INIT_EXPR, temp_type, object, tmp); + exp = cp_build_init_expr (object, tmp); } /* Mark any cleanups from the initialization as MUST_NOT_THROW, since diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index 0ab0aaa..3d5d390 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -686,6 +686,8 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain) /* Now put it back so C++17 copy elision works. */ init = get_target_expr (init); + set_target_expr_eliding (init); + current_class_ptr = save_ccp; current_class_ref = save_ccr; return init; @@ -1006,7 +1008,7 @@ perform_member_init (tree member, tree init, hash_set &uninitialized) if (TREE_CODE (type) == ARRAY_TYPE) { init = build_vec_init_expr (type, init, tf_warning_or_error); - init = build2 (INIT_EXPR, type, decl, init); + init = cp_build_init_expr (decl, init); finish_expr_stmt (init); } else @@ -1014,7 +1016,7 @@ perform_member_init (tree member, tree init, hash_set &uninitialized) tree value = build_value_init (type, tf_warning_or_error); if (value == error_mark_node) return; - init = build2 (INIT_EXPR, type, decl, value); + init = cp_build_init_expr (decl, value); finish_expr_stmt (init); } } @@ -1025,7 +1027,7 @@ perform_member_init (tree member, tree init, hash_set &uninitialized) { if (init) { - init = build2 (INIT_EXPR, type, decl, TREE_VALUE (init)); + init = cp_build_init_expr (decl, TREE_VALUE (init)); finish_expr_stmt (init); } } @@ -1062,7 +1064,7 @@ perform_member_init (tree member, tree init, hash_set &uninitialized) if (TREE_CODE (type) == ARRAY_TYPE && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type))) init = build_vec_init_expr (type, init, tf_warning_or_error); - init = build2 (INIT_EXPR, type, decl, init); + init = cp_build_init_expr (decl, init); finish_expr_stmt (init); FOR_EACH_VEC_ELT (*cleanups, i, t) push_cleanup (NULL_TREE, t, false); @@ -1081,7 +1083,7 @@ perform_member_init (tree member, tree init, hash_set &uninitialized) /* Initialize the array only if it's not a flexible array member (i.e., if it has an upper bound). */ init = build_vec_init_expr (type, init, tf_warning_or_error); - init = build2 (INIT_EXPR, type, decl, init); + init = cp_build_init_expr (decl, init); finish_expr_stmt (init); } } @@ -2097,7 +2099,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, complete objects. */ gcc_assert (TREE_CODE (init) == CONSTRUCTOR || true_exp == exp); - init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init); + init = cp_build_init_expr (exp, init); TREE_SIDE_EFFECTS (init) = 1; finish_expr_stmt (init); return true; @@ -2136,8 +2138,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, TREE_TYPE (*p) = void_type_node; p = &TREE_OPERAND (*p, 0); } - *p = build2 (INIT_EXPR, TREE_TYPE (exp), exp, *p); - TREE_SIDE_EFFECTS (*p) = 1; + *p = cp_build_init_expr (exp, *p); finish_expr_stmt (init); return true; } @@ -2202,7 +2203,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, { tree e = maybe_constant_init (rval, exp); if (TREE_CONSTANT (e)) - rval = build2 (INIT_EXPR, type, exp, e); + rval = cp_build_init_expr (exp, e); } } @@ -2290,7 +2291,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, field_size = TYPE_SIZE (CLASSTYPE_AS_BASE (type)); init = build_zero_init_1 (type, NULL_TREE, /*static_storage_p=*/false, field_size); - init = build2 (INIT_EXPR, type, exp, init); + init = cp_build_init_expr (exp, init); finish_expr_stmt (init); } @@ -3678,7 +3679,7 @@ build_new_1 (vec **placement, tree type, tree nelts, tree val = build_value_init (type, complain | tf_no_cleanup); if (val == error_mark_node) return error_mark_node; - init_expr = build2 (INIT_EXPR, type, init_expr, val); + init_expr = cp_build_init_expr (init_expr, val); } else { @@ -4430,7 +4431,7 @@ build_vec_init (tree base, tree maxindex, tree init, if (BRACE_ENCLOSED_INITIALIZER_P (init)) init = digest_init (atype, init, complain); - stmt_expr = build2 (INIT_EXPR, atype, base, init); + stmt_expr = cp_build_init_expr (base, init); return stmt_expr; } @@ -4602,7 +4603,7 @@ build_vec_init (tree base, tree maxindex, tree init, gcc_checking_assert (!target_expr_needs_replace (elt)); if (digested) - one_init = build2 (INIT_EXPR, type, baseref, elt); + one_init = cp_build_init_expr (baseref, elt); else if (tree vi = get_vec_init_expr (elt)) one_init = expand_vec_init_expr (baseref, vi, complain, flags); else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) @@ -4623,7 +4624,7 @@ build_vec_init (tree base, tree maxindex, tree init, if (do_static_init) one_init = NULL_TREE; else - one_init = build2 (INIT_EXPR, type, baseref, e); + one_init = cp_build_init_expr (baseref, e); } else { @@ -4805,7 +4806,7 @@ build_vec_init (tree base, tree maxindex, tree init, { elt_init = build_value_init (type, complain); if (elt_init != error_mark_node) - elt_init = build2 (INIT_EXPR, type, to, elt_init); + elt_init = cp_build_init_expr (to, elt_init); } else { diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 622e1b9..c217d7e 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -680,7 +680,7 @@ do_build_copy_constructor (tree fndecl) else if (tree_int_cst_equal (TYPE_SIZE (current_class_type), CLASSTYPE_SIZE (current_class_type))) { - tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm); + tree t = cp_build_init_expr (current_class_ref, parm); finish_expr_stmt (t); } else @@ -695,7 +695,7 @@ do_build_copy_constructor (tree fndecl) current_class_ptr, alias_set); tree rhs = build2 (MEM_REF, array_type, TREE_OPERAND (parm, 0), alias_set); - tree t = build2 (INIT_EXPR, void_type_node, lhs, rhs); + tree t = cp_build_init_expr (lhs, rhs); finish_expr_stmt (t); } } diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 39b11ee..7d46c3c 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -2519,6 +2519,10 @@ finish_stmt_expr_expr (tree expr, tree stmt_expr) /* Update for array-to-pointer decay. */ type = TREE_TYPE (expr); + /* This TARGET_EXPR will initialize the outer one added by + finish_stmt_expr. */ + set_target_expr_eliding (expr); + /* Wrap it in a CLEANUP_POINT_EXPR and add it to the list like a normal statement, but don't convert to void or actually add the EXPR_STMT. */ @@ -4668,7 +4672,7 @@ simplify_aggr_init_expr (tree *tp) expand_call{,_inline}. */ cxx_mark_addressable (slot); CALL_EXPR_RETURN_SLOT_OPT (call_expr) = true; - call_expr = build2 (INIT_EXPR, TREE_TYPE (call_expr), slot, call_expr); + call_expr = cp_build_init_expr (slot, call_expr); } else if (style == pcc) { @@ -4687,7 +4691,7 @@ simplify_aggr_init_expr (tree *tp) { tree init = build_zero_init (type, NULL_TREE, /*static_storage_p=*/false); - init = build2 (INIT_EXPR, void_type_node, slot, init); + init = cp_build_init_expr (slot, init); call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (call_expr), init, call_expr); } @@ -4882,7 +4886,7 @@ finalize_nrv_r (tree* tp, int* walk_subtrees, void* data) tree init; if (DECL_INITIAL (dp->var) && DECL_INITIAL (dp->var) != error_mark_node) - init = build2 (INIT_EXPR, void_type_node, dp->result, + init = cp_build_init_expr (dp->result, DECL_INITIAL (dp->var)); else init = build_empty_stmt (EXPR_LOCATION (*tp)); @@ -6426,7 +6430,7 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) else init = fold_convert (TREE_TYPE (v), integer_zero_node); OMP_CLAUSE_REDUCTION_INIT (c) - = build2 (INIT_EXPR, TREE_TYPE (v), v, init); + = cp_build_init_expr (v, init); } } } diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 6d968a2..3532e44 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -533,6 +533,9 @@ build_target_expr (tree decl, tree value, tsubst_flags_t complain) if (t == error_mark_node) return error_mark_node; } + + set_target_expr_eliding (value); + t = build4 (TARGET_EXPR, type, decl, value, t, NULL_TREE); if (location_t eloc = cp_expr_location (value)) SET_EXPR_LOCATION (t, eloc); @@ -3194,6 +3197,7 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_) TARGET_EXPR_IMPLICIT_P (u) = TARGET_EXPR_IMPLICIT_P (t); TARGET_EXPR_LIST_INIT_P (u) = TARGET_EXPR_LIST_INIT_P (t); TARGET_EXPR_DIRECT_INIT_P (u) = TARGET_EXPR_DIRECT_INIT_P (t); + TARGET_EXPR_ELIDING_P (u) = TARGET_EXPR_ELIDING_P (t); /* Map the old variable to the new one. */ splay_tree_insert (target_remap, diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index cecf825..b4a8e3c 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -9294,7 +9294,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, if (! same_type_p (TREE_TYPE (rhs), lhstype)) /* Call convert to generate an error; see PR 11063. */ rhs = convert (lhstype, rhs); - result = build2 (INIT_EXPR, lhstype, lhs, rhs); + result = cp_build_init_expr (lhs, rhs); TREE_SIDE_EFFECTS (result) = 1; goto ret; } @@ -9542,6 +9542,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, result = build2_loc (loc, modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, lhstype, lhs, newrhs); + if (modifycode == INIT_EXPR) + set_target_expr_eliding (newrhs); TREE_SIDE_EFFECTS (result) = 1; if (!plain_assign) @@ -11105,7 +11107,7 @@ check_return_expr (tree retval, bool *no_warning) /* Actually copy the value returned into the appropriate location. */ if (retval && retval != result) - retval = build2 (INIT_EXPR, TREE_TYPE (result), result, retval); + retval = cp_build_init_expr (result, retval); if (tree set = maybe_set_retval_sentinel ()) retval = build2 (COMPOUND_EXPR, void_type_node, retval, set); diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index d5236d1..2644472 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -649,7 +649,7 @@ split_nonconstant_init_1 (tree dest, tree init, bool last, else { build_init: - code = build2 (INIT_EXPR, inner_type, sub, value); + code = cp_build_init_expr (sub, value); } code = build_stmt (input_location, EXPR_STMT, code); add_stmt (code); @@ -764,7 +764,7 @@ split_nonconstant_init (tree dest, tree init) } else if (init) { - tree ie = build2 (INIT_EXPR, void_type_node, dest, init); + tree ie = cp_build_init_expr (dest, init); code = add_stmt_to_compound (ie, code); } } @@ -773,7 +773,7 @@ split_nonconstant_init (tree dest, tree init) code = build_vec_init (dest, NULL_TREE, init, /*value-init*/false, /*from array*/1, tf_warning_or_error); else - code = build2 (INIT_EXPR, TREE_TYPE (dest), dest, init); + code = cp_build_init_expr (dest, init); return code; } @@ -1464,6 +1464,7 @@ digest_nsdmi_init (tree decl, tree init, tsubst_flags_t complain) && CP_AGGREGATE_TYPE_P (type)) init = reshape_init (type, init, complain); init = digest_init_flags (type, init, flags, complain); + set_target_expr_eliding (init); /* We may have temporary materialization in a NSDMI, if the initializer has something like A{} in it. Digesting the {} could have introduced @@ -1542,6 +1543,7 @@ massage_init_elt (tree type, tree init, int nested, int flags, tree t = fold_non_dependent_init (init, complain); if (TREE_CONSTANT (t)) init = t; + set_target_expr_eliding (init); } return init; } @@ -1771,6 +1773,13 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, { gcc_assert (ce->value); next = massage_init_elt (fldtype, next, nested, flags, complain); + /* We can't actually elide the temporary when initializing a + potentially-overlapping field from a function that returns by + value. */ + if (ce->index + && TREE_CODE (next) == TARGET_EXPR + && unsafe_copy_elision_p (ce->index, next)) + TARGET_EXPR_ELIDING_P (next) = false; ++idx; } } @@ -1804,6 +1813,9 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, a class, just build one up; if it's an array, recurse. */ next = build_constructor (init_list_type_node, NULL); next = massage_init_elt (fldtype, next, nested, flags, complain); + if (TREE_CODE (next) == TARGET_EXPR + && unsafe_copy_elision_p (field, next)) + TARGET_EXPR_ELIDING_P (next) = false; /* Warn when some struct elements are implicitly initialized. */ if ((complain & tf_warning) @@ -2727,3 +2739,41 @@ require_complete_eh_spec_types (tree fntype, tree decl) } } } + +/* Record that any TARGET_EXPR in T are going to be elided in + cp_gimplify_init_expr (or sooner). */ + +void +set_target_expr_eliding (tree t) +{ + if (!t) + return; + switch (TREE_CODE (t)) + { + case TARGET_EXPR: + TARGET_EXPR_ELIDING_P (t) = true; + break; + case COMPOUND_EXPR: + set_target_expr_eliding (TREE_OPERAND (t, 1)); + break; + case COND_EXPR: + set_target_expr_eliding (TREE_OPERAND (t, 1)); + set_target_expr_eliding (TREE_OPERAND (t, 2)); + break; + + default: + break; + } +} + +/* Call the above in the process of building an INIT_EXPR. */ + +tree +cp_build_init_expr (location_t loc, tree target, tree init) +{ + set_target_expr_eliding (init); + tree ie = build2_loc (loc, INIT_EXPR, TREE_TYPE (target), + target, init); + TREE_SIDE_EFFECTS (ie) = true; + return ie; +} -- cgit v1.1