diff options
205 files changed, 5036 insertions, 705 deletions
@@ -1,3 +1,7 @@ +2025-12-08 Nathan Myers <ncm@cantrip.org> + + * MAINTAINERS: add ncm + 2025-11-30 Jose E. Marchesi <jose.marchesi@oracle.com> * MAINTAINERS: Add Algol 68 subsystems. diff --git a/MAINTAINERS b/MAINTAINERS index 22d4172..53a35b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -706,6 +706,7 @@ Christoph Müllner cmuellner <christoph.muellner@vrull.eu> Steven Munroe munroesj <munroesj52@gmail.com> Philippe De Muyter - <phdm@macqel.be> Joseph Myers jsm28 <josmyers@redhat.com> +Nathan Myers ncm <ncm@cantrip.org> Szabolcs Nagy nsz <nsz@gcc.gnu.org> Victor Do Nascimento victorldn <victor.donascimento@arm.com> Quentin Neill qneill <quentin.neill.gnu@gmail.com> diff --git a/config/gthr.m4 b/config/gthr.m4 index 1199624..e8fac4a 100644 --- a/config/gthr.m4 +++ b/config/gthr.m4 @@ -5,6 +5,26 @@ dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. +dnl Define thread model + +dnl usage: GCC_AC_THREAD_MODEL +AC_DEFUN([GCC_AC_THREAD_MODEL], +[ +# Specify the threading model for this GCC runtime library +# Pass with no value to take from compiler's metadata +# Pass with a value to specify a thread package +# 'single' means single threaded -- without threads. +AC_CACHE_CHECK([for the threading model used by GCC], [gcc_cv_target_thread_file], [ + # Set new cache variable + gcc_cv_target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` +]) +# Set variable name (not prefixed enough to be a good cache variable +# name) traditionally used for this purpose, to avoid having to change +# a bunch of configure scripts. +target_thread_file="$gcc_cv_target_thread_file" +]) + + dnl Define header location by thread model dnl usage: GCC_AC_THREAD_HEADER([thread_model]) @@ -23,6 +43,9 @@ case $1 in vxworks) thread_header=config/gthr-vxworks.h ;; win32) thread_header=config/i386/gthr-win32.h ;; mcf) thread_header=config/i386/gthr-mcf.h ;; + *) + AC_MSG_ERROR([No known header for threading model '$1'.]) + ;; esac AC_SUBST(thread_header) ]) diff --git a/contrib/ChangeLog b/contrib/ChangeLog index ea2d807..6683ddc 100644 --- a/contrib/ChangeLog +++ b/contrib/ChangeLog @@ -1,3 +1,13 @@ +2025-12-08 Joseph Myers <josmyers@redhat.com> + + * test_installed (--with-alt-cc=, --with-alt-cxx=) + (--with-compat-options=, --with-libiconv=): New options. + +2025-12-08 Jonathan Wakely <jwakely@redhat.com> + + * check_GNU_style_lib.py (check_GNU_style_file): Do not check + libstdc++ files. + 2025-12-06 Mark Zhuang <mark.zhuang@spacemit.com> * prepare-commit-msg: check --default-prefix diff --git a/contrib/check_GNU_style_lib.py b/contrib/check_GNU_style_lib.py index faf30c4..fccb3d6 100755 --- a/contrib/check_GNU_style_lib.py +++ b/contrib/check_GNU_style_lib.py @@ -285,6 +285,9 @@ def check_GNU_style_file(file, format): # Skip testsuite files if 'testsuite' in t or t.endswith('.py'): continue + # Libstdc++ does not use GNU style + if t.startswith('libstdc++-v3/'): + continue for hunk in pfile: delta = 0 diff --git a/contrib/test_installed b/contrib/test_installed index 77492ca..42c3f12 100755 --- a/contrib/test_installed +++ b/contrib/test_installed @@ -42,6 +42,7 @@ if test -f site.exp; then exit 1 fi +libiconv=-liconv while true; do case "$1" in --with-testsuite=*) testsuite=`echo "$1" | sed 's/[^=]*=//'`; shift;; @@ -51,6 +52,10 @@ while true; do --with-gcc=*) GCC_UNDER_TEST=`echo "$1" | sed 's/[^=]*=//'`; shift;; --with-g++=*) GXX_UNDER_TEST=`echo "$1" | sed 's/[^=]*=//'`; shift;; --with-gfortran=*) GFORTRAN_UNDER_TEST=`echo "$1" | sed 's/[^=]*=//'`; shift;; + --with-alt-cc=*) ALT_CC_UNDER_TEST=`echo "$1" | sed 's/[^=]*=//'`; shift;; + --with-alt-cxx=*) ALT_CXX_UNDER_TEST=`echo "$1" | sed 's/[^=]*=//'`; shift;; + --with-compat-options=*) COMPAT_OPTIONS=`echo "$1" | sed 's/[^=]*=//'`; shift;; + --with-libiconv=*) libiconv=`echo "$1" | sed 's/[^=]*=//'`; shift;; --without-gcc) GCC_UNDER_TEST=no; shift;; --without-g++) GXX_UNDER_TEST=no; shift;; --without-gfortran) GFORTRAN_UNDER_TEST=no; shift;; @@ -78,6 +83,10 @@ Supported arguments: --with-gcc=/some/dir/bin/gcc use specified gcc program [gcc] --with-g++=/some/dir/bin/g++ use specified g++ program [g++] --with-gfortran=/some/dir/bin/gfortran use specified gfortran program [gfortran] +--with-alt-cc=/some/compiler use specified alternative compiler in compat tests +--with-alt-cxx=/some/compiler use specified alternative compiler in compat tests +--with-compat-options=opts use specified COMPAT_OPTIONS in compat tests +--with-libiconv=linker-args use given arguments to link with iconv [-liconv] --without-gcc do not run gcc testsuite --without-g++ do not run g++ testsuite --without-gfortran do not run gfortran testsuite @@ -108,6 +117,7 @@ cat >site.exp <<EOF set rootme "." set tmpdir "${tmpdir-`${PWDCMD-pwd}`}" set srcdir "${testsuite-${srcdir}/gcc/testsuite}" +set libiconv "$libiconv" set CFLAGS "" set CXXFLAGS "" set GCC_UNDER_TEST "${GCC_UNDER_TEST-${prefix}${prefix+/bin/}gcc}" @@ -123,6 +133,15 @@ if test x${target} != x; then echo "set target_triplet $target" >> site.exp echo "set target_alias $target" >> site.exp fi +if test x"$ALT_CC_UNDER_TEST" != x; then + echo "set ALT_CC_UNDER_TEST \"${ALT_CC_UNDER_TEST}\"" >> site.exp +fi +if test x"$ALT_CXX_UNDER_TEST" != x; then + echo "set ALT_CXX_UNDER_TEST \"${ALT_CXX_UNDER_TEST}\"" >> site.exp +fi +if test x"$COMPAT_OPTIONS" != x; then + echo "set COMPAT_OPTIONS \"${COMPAT_OPTIONS}\"" >> site.exp +fi test x"${GCC_UNDER_TEST}" = x"no" || runtest --tool gcc ${1+"$@"} test x"${GXX_UNDER_TEST}" = x"no" || runtest --tool g++ ${1+"$@"} diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ed720db..e6da5b8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,102 @@ +2025-12-08 Andrew Pinski <andrew.pinski@oss.qualcomm.com> + + PR tree-optimization/46555 + * tree-cfgcleanup.cc (execute_cleanup_cfg_post_optimizing): + Don't set todo to include cleanupcfg; do it manually. + Call make_forwarders_with_degenerate_phis if optimizing. + +2025-12-08 Andrew Pinski <andrew.pinski@oss.qualcomm.com> + + * tree-cfg.cc (make_forwarders_with_degenerate_phis): Add debug + dump. + +2025-12-08 Andrew Pinski <andrew.pinski@oss.qualcomm.com> + + * tree-ssa-dce.cc (sort_phi_args): Move to tree-cfg.cc. + (make_forwarders_with_degenerate_phis): Move to tree-cfg.cc. + (perform_tree_ssa_dce): Update for the updated return type + of make_forwarders_with_degenerate_phis. + * tree-cfg.cc (sort_phi_args): Moved from tree-ssa-dce.cc. + (make_forwarders_with_degenerate_phis): Moved from tree-ssa-dce.cc. + Update return type to bool and return true if an edge was split. + * tree-cfg.h (make_forwarders_with_degenerate_phis): New decl. + +2025-12-08 Eric Botcazou <ebotcazou@adacore.com> + + PR target/80881 + * config/mingw/winnt.cc (mingw_pe_unique_section): Put two dollar + signs for TLS sections after the prefix. + (mingw_pe_asm_named_section): Deal with all TLS sections uniformly. + +2025-12-08 Ezra Sitorus <Ezra.Sitorus@arm.com> + + * config/aarch64/aarch64-cores.def (AARCH64_CORE): Add C1-Nano, + C1-Pro, C1-Premium and C1-Ultra. + * config/aarch64/aarch64-tune.md: Regenerate. + * doc/invoke.texi: Document C1 cores. + +2025-12-08 Richard Biener <rguenther@suse.de> + + PR tree-optimization/123040 + * tree-ssa-sccvn.cc (vn_nary_build_or_lookup_1): Only insert + nary results. + +2025-12-08 Josef Melcr <josef.melcr@suse.com> + + PR ipa/122798 + * cgraph.cc (cgraph_edge::redirect_callee): Use + iterate_referring instead of referred_to_p. + * cgraphclones.cc (set_new_clone_decl_and_node_flags): Set local + to true iff the node does not have its address taken. + +2025-12-08 Richard Biener <rguenther@suse.de> + + PR tree-optimization/123038 + * tree-vect-patterns.cc (vect_recog_ctz_ffs_pattern): Reject + pattern for reductions when the call argument is used multiple + times. + +2025-12-08 Tamar Christina <tamar.christina@arm.com> + + PR target/123026 + * config/aarch64/aarch64-simd.md (reduc_sbool_ior_scal_<mode>, + reduc_sbool_and_scal_<mode>): Fix tmp operands[1] override. + +2025-12-08 Tamar Christina <tamar.christina@arm.com> + + PR tree-optimization/122868 + * tree-vect-stmts.cc (vectorizable_load): Move check for invariant loads + down into the loop. + +2025-12-08 H.J. Lu <hjl.tools@gmail.com> + + PR target/122343 + * config/i386/sse.md (*<avx512>_cmp<mode>3_dup_op): Don't allow + 2 volatile memory references. + +2025-12-07 Jason Merrill <jason@redhat.com> + + * config/darwin-c.cc (find_subframework_header): Use + _cpp_get_file_*. + +2025-12-07 H.J. Lu <hjl.tools@gmail.com> + + PR target/122343 + * common.opt: Add -ffuse-ops-with-volatile-access. + * common.opt.urls: Regenerated. + * recog.cc (general_operand): Allow volatile memory reference if + -ffuse-ops-with-volatile-access is enabled. + * simplify-rtx.cc (simplify_binary_operation_1): Keep PLUS for 2 + volatile memory references. + * doc/invoke.texi: Document -ffuse-ops-with-volatile-access. + +2025-12-07 Alexandre Oliva <oliva@adacore.com> + + * cselib.cc (dump_cselib_val): Split out of and rename to... + (dump_cselib_val_ptr): ... this. + (dump_cselib_table): Adjust. Skip cselib_preserved_hash_table + when not allocated. + 2025-12-06 Alexandre Oliva <oliva@adacore.com> PR rtl-optimization/122947 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 47f4b89..4568345 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20251207 +20251209 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 2c3194e..d623145 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2503,13 +2503,6 @@ libgcc.mvars: config.status Makefile specs xgcc$(exeext) : > tmp-libgcc.mvars echo GCC_CFLAGS = '$(GCC_CFLAGS)' >> tmp-libgcc.mvars echo INHIBIT_LIBC_CFLAGS = '$(INHIBIT_LIBC_CFLAGS)' >> tmp-libgcc.mvars - echo TARGET_SYSTEM_ROOT = '$(TARGET_SYSTEM_ROOT)' >> tmp-libgcc.mvars - if test @enable_default_pie@ = yes; then \ - NO_PIE_CFLAGS="-fno-PIE"; \ - else \ - NO_PIE_CFLAGS=; \ - fi; \ - echo NO_PIE_CFLAGS = "$$NO_PIE_CFLAGS" >> tmp-libgcc.mvars mv tmp-libgcc.mvars libgcc.mvars diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index fca1a9e..8b19deb 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,17 @@ +2025-12-08 Eric Botcazou <ebotcazou@adacore.com> + + PR ada/123037 + * rtinit.c [__MINGW32__]: Include <stdlib.h> and not <windows.h>. + * rtfinal.c [__MINGW32__]: Do not include <windows.h>. + +2025-12-07 Eric Botcazou <ebotcazou@adacore.com> + + PR ada/115349 + * sem_attr.adb (Resolve_Attribute) <Attribute_Reduce>: Use the base + type as Accum_Type if the reducer is an operator from Standard and + the type is numeric. Use the type of the first operand for other + operators. Streamline the error message given for limited types. + 2025-12-06 Denis Mazzucato <mazzucato@adacore.com> * sem_attr.adb (Resolve_Attribute): Check if the reducer is a diff --git a/gcc/ada/rtfinal.c b/gcc/ada/rtfinal.c index 88bbb0e..0bd3ce4 100644 --- a/gcc/ada/rtfinal.c +++ b/gcc/ada/rtfinal.c @@ -46,9 +46,7 @@ extern int __gnat_rt_init_count; /* see initialize.c */ #if defined (__MINGW32__) -#define WIN32_LEAN_AND_MEAN #include "mingw32.h" -#include <windows.h> extern CRITICAL_SECTION ProcListCS; extern HANDLE ProcListEvt; diff --git a/gcc/ada/rtinit.c b/gcc/ada/rtinit.c index 598550c..3b5af0d 100644 --- a/gcc/ada/rtinit.c +++ b/gcc/ada/rtinit.c @@ -70,9 +70,8 @@ int __gnat_rt_init_count = 0; and finalize properly the run-time. */ #if defined (__MINGW32__) -#define WIN32_LEAN_AND_MEAN +#include <stdlib.h> #include "mingw32.h" -#include <windows.h> extern void __gnat_init_float (void); diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb index ca19cad..74e9d6f 100644 --- a/gcc/ada/sem_attr.adb +++ b/gcc/ada/sem_attr.adb @@ -12919,7 +12919,7 @@ package body Sem_Attr is -- Where the context is augmented with the iteration -- variable I of the right type, and Init_Var of type - -- Accum_Subtype. If the Reducer has both procedure and + -- Accum_Typ. If the Reducer has both procedure and -- function interpretations with the proper reducer profile -- an ambiguity error is emitted. Note that, this could be a -- false positive as the two may coexist without ambiguity @@ -13204,7 +13204,7 @@ package body Sem_Attr is return; end if; - -- If no error has been posted and the accumulation type is + -- If no error has been posted and the accumulator type is -- constrained, then the resolution of the reducer can start. if Nkind (Reducer_N) = N_Attribute_Reference then @@ -13252,44 +13252,50 @@ package body Sem_Attr is end if; end if; - -- After resolving the reducer, determine the correct - -- Accum_Subtype: if the reducer is an attribute (Min or Max), - -- then the prefix type is the accumulation type. + -- After resolving the reducer, determine Accum_Typ: if the + -- reducer is an attribute (Min or Max), then its prefix is + -- the accumulator type. if Nkind (Reducer_E) = N_Attribute_Reference then - Accum_Typ := Etype (Prefix (Reducer_E)); + Accum_Typ := Entity (Prefix (Reducer_E)); - -- If an operator from standard, then the type of its first - -- formal woudl be Any_Type, in this case we make sure we don't - -- use an universal type to avoid resolution problems later on. + -- If the reducer is an operator from Standard, then the type + -- of its first operand would be Any_Type. In this case, make + -- sure we do not have an universal type to avoid resolution + -- problems later on, and use the base type of numeric types + -- to avoid spurious subtype mismatches for the initial value. - elsif Ekind (Reducer_E) = E_Operator - or else Scope (Reducer_E) = Standard_Standard - then + elsif Scope (Reducer_E) = Standard_Standard then if Accum_Typ = Universal_Integer then Accum_Typ := Standard_Integer; elsif Accum_Typ = Universal_Real then Accum_Typ := Standard_Float; + elsif Is_Numeric_Type (Accum_Typ) then + Accum_Typ := Base_Type (Accum_Typ); end if; - -- Otherwise, the Accum_Subtype is the subtype of the first - -- formal of the reducer subprogram RM 4.5.10(19/5). + -- Otherwise, Accum_Typ is the subtype of the first formal + -- of the reducer subprogram (RM 4.5.10(19/5)). + + elsif Ekind (Reducer_E) = E_Operator then + Accum_Typ := Etype (Left_Opnd (Reducer_E)); else Accum_Typ := Etype (First_Formal (Reducer_E)); end if; + Set_Etype (N, Accum_Typ); - -- Accumulation type must be nonlimited, RM 4.5.10(8/5) + -- The accumulator type must be nonlimited (RM 4.5.10(8/5)) if Is_Limited_Type (Accum_Typ) then Error_Msg_N - ("accumulated subtype of Reduce must be nonlimited", N); + ("type of reduction expression must be nonlimited", N); - -- If the Accum_Typ is an unconstrained array and the reducer + -- If Accum_Typ is an unconstrained array and the reducer -- subprogram is a function then a Constraint_Error will be - -- raised at runtime as most computations will change its - -- length type during the reduction execution, RM 4.5.10(25/5). + -- raised at run time, as most computations will change its + -- length during the reduction execution (RM 4.5.10(25/5)). -- For instance, this is the case with: -- [...]'Reduce ("&", ...) -- When the expression yields non-empty strings, the reduction @@ -13300,7 +13306,7 @@ package body Sem_Attr is elsif Nkind (Reducer_E) /= N_Attribute_Reference and then Ekind (Reducer_E) = E_Function - and then not Is_Numeric_Type (Base_Type (Accum_Typ)) + and then not Is_Numeric_Type (Accum_Typ) and then not Is_Constrained (Accum_Typ) then declare @@ -13318,6 +13324,7 @@ package body Sem_Attr is -- resolving the initial expression and array aggregate. Resolve (Init_Value_Expr, Accum_Typ); + if Nkind (P) = N_Aggregate then Resolve_Aggregate (P, Make_Array_Type (Index => Standard_Positive, diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 58fc1f4..9ede664 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,8 @@ +2025-12-07 David Malcolm <dmalcolm@redhat.com> + + * kf.cc (register_known_functions): Remove duplicate calls to + register_atomic_builtins and register_varargs_builtins. + 2025-11-28 Jakub Jelinek <jakub@redhat.com> * known-function-manager.cc (known_function_manager::add): Avoid diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc index b3c02e8..c9818de 100644 --- a/gcc/analyzer/kf.cc +++ b/gcc/analyzer/kf.cc @@ -2334,9 +2334,6 @@ register_known_functions (known_function_manager &kfm, kfm.add ("__builtin_strlen", std::make_unique<kf_strlen> ()); kfm.add ("strstr", std::make_unique<kf_strstr> ()); kfm.add ("__builtin_strstr", std::make_unique<kf_strstr> ()); - - register_atomic_builtins (kfm); - register_varargs_builtins (kfm); } /* Known POSIX functions, and some non-standard extensions. */ diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index a02fed1..e79f77e 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9774,6 +9774,13 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (field)); tree type = TREE_TYPE (field); + if (VECTOR_TYPE_P (type)) + { + error_at (DECL_SOURCE_LOCATION (field), + "bit-field %qD has invalid type", field); + type = TREE_TYPE (type); + TREE_TYPE (field) = type; + } if (width != TYPE_PRECISION (type)) { if (TREE_CODE (type) == BITINT_TYPE diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index d7c9a32..735cfc6 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -3187,7 +3187,7 @@ build_access_with_size_for_counted_by (location_t loc, tree ref, tree first_param = is_fam ? c_fully_fold (array_to_pointer_conversion (loc, ref), false, NULL) - : ref; + : c_fully_fold (ref, false, NULL); tree second_param = c_fully_fold (counted_by_ref, false, NULL); tree third_param = build_int_cst (c_build_pointer_type (counted_by_type), 0); diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc index 3c21e17..1a7d499 100644 --- a/gcc/cgraph.cc +++ b/gcc/cgraph.cc @@ -1696,8 +1696,12 @@ cgraph_edge::redirect_callee (cgraph_node *n) old_ref->remove_reference (); ipa_ref *new_ref = caller->create_reference (n, IPA_REF_ADDR, call_stmt); new_ref->lto_stmt_uid = lto_stmt_uid; - if (!old_callee->referred_to_p ()) + /* If the last reference to OLD_CALLEE has been redirected, unset + address_taken. old_ref is only used as a placeholder when looking for + a different reference. */ + if (!old_callee->iterate_referring (0, old_ref)) old_callee->address_taken = 0; + n->mark_address_taken (); } if (!inline_failed) diff --git a/gcc/cgraphclones.cc b/gcc/cgraphclones.cc index 49f0e58..816fc53 100644 --- a/gcc/cgraphclones.cc +++ b/gcc/cgraphclones.cc @@ -176,7 +176,9 @@ set_new_clone_decl_and_node_flags (cgraph_node *new_node) DECL_IS_REPLACEABLE_OPERATOR (new_node->decl) = 0; new_node->externally_visible = 0; - new_node->local = 1; + /* Clones of callbacks might have their address taken, and thus cannot be + local. */ + new_node->local = !new_node->address_taken; new_node->lowered = true; new_node->semantic_interposition = 0; } diff --git a/gcc/config/aarch64/aarch64-cores.def b/gcc/config/aarch64/aarch64-cores.def index b86d80c..851594a 100644 --- a/gcc/config/aarch64/aarch64-cores.def +++ b/gcc/config/aarch64/aarch64-cores.def @@ -229,6 +229,11 @@ AARCH64_CORE("grace", grace, cortexa57, V9A, (I8MM, BF16, SVE2_BITPERM, SVE2_AES AARCH64_CORE("neoverse-v3", neoversev3, cortexa57, V9_2A, (SVE2_BITPERM, RNG, LS64, MEMTAG, PROFILE), neoversev3, 0x41, 0xd84, -1) AARCH64_CORE("neoverse-v3ae", neoversev3ae, cortexa57, V9_2A, (SVE2_BITPERM, RNG, LS64, MEMTAG, PROFILE), neoversev3ae, 0x41, 0xd83, -1) +AARCH64_CORE("c1-nano", c1nano, cortexa53, V9_3A, (MEMTAG, SVE2_BITPERM, F16FML, SME2, RCPC3), cortexa53, 0x41, 0xd8a, -1) +AARCH64_CORE("c1-pro", c1pro, cortexa57, V9_3A, (MEMTAG, SVE2_BITPERM, F16FML, PROFILE, SME2, RCPC3), neoversen3, 0x41, 0xd8b, -1) +AARCH64_CORE("c1-premium", c1premium, cortexa57, V9_3A, (MEMTAG, SVE2_BITPERM, F16FML, PROFILE, SME2, RCPC3), neoversev3, 0x41, 0xd90, -1) +AARCH64_CORE("c1-ultra", c1ultra, cortexa57, V9_3A, (MEMTAG, SVE2_BITPERM, F16FML, PROFILE, SME2, RCPC3), cortexx925, 0x41, 0xd8c, -1) + AARCH64_CORE("demeter", demeter, cortexa57, V9A, (I8MM, BF16, SVE2_BITPERM, RNG, MEMTAG, PROFILE), neoversev2, 0x41, 0xd4f, -1) /* NVIDIA ('N') cores. */ diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md index 3f9d5f6..c02ffd6 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -3544,10 +3544,10 @@ rtx reduc = gen_lowpart (V4SImode, tmp); rtx res = gen_reg_rtx (V4SImode); emit_insn (gen_aarch64_uminpv4si (res, reduc, reduc)); - emit_move_insn (tmp, gen_lowpart (<MODE>mode, res)); + tmp = gen_lowpart (<MODE>mode, res); } - rtx val = gen_reg_rtx (DImode); - emit_move_insn (val, gen_lowpart (DImode, tmp)); + + rtx val = force_lowpart_subreg (DImode, tmp, <MODE>mode); rtx cc_reg = aarch64_gen_compare_reg (EQ, val, constm1_rtx); rtx cmp = gen_rtx_fmt_ee (EQ, SImode, cc_reg, constm1_rtx); rtx tmp2 = gen_reg_rtx (SImode); @@ -3607,10 +3607,10 @@ rtx reduc = gen_lowpart (V4SImode, tmp); rtx res = gen_reg_rtx (V4SImode); emit_insn (gen_aarch64_umaxpv4si (res, reduc, reduc)); - emit_move_insn (tmp, gen_lowpart (<MODE>mode, res)); + tmp = gen_lowpart (<MODE>mode, res); } - rtx val = gen_reg_rtx (DImode); - emit_move_insn (val, gen_lowpart (DImode, tmp)); + + rtx val = force_lowpart_subreg (DImode, tmp, <MODE>mode); rtx cc_reg = aarch64_gen_compare_reg (NE, val, const0_rtx); rtx cmp = gen_rtx_fmt_ee (NE, SImode, cc_reg, const0_rtx); rtx tmp2 = gen_reg_rtx (SImode); diff --git a/gcc/config/aarch64/aarch64-tune.md b/gcc/config/aarch64/aarch64-tune.md index 292796c..d6f1bbc 100644 --- a/gcc/config/aarch64/aarch64-tune.md +++ b/gcc/config/aarch64/aarch64-tune.md @@ -1,5 +1,5 @@ ;; -*- buffer-read-only: t -*- ;; Generated automatically by gentune.sh from aarch64-cores.def (define_attr "tune" - "cortexa34,cortexa35,cortexa53,cortexa57,cortexa72,cortexa73,thunderx,thunderxt88,thunderxt88p1,octeontx,octeontxt81,octeontxt83,thunderxt81,thunderxt83,ampere1,ampere1a,ampere1b,ampere1c,emag,xgene1,falkor,qdf24xx,exynosm1,phecda,thunderx2t99p1,vulcan,thunderx2t99,cortexa55,cortexa75,cortexa76,cortexa76ae,cortexa77,cortexa78,cortexa78ae,cortexa78c,cortexa65,cortexa65ae,cortexx1,cortexx1c,neoversen1,ares,neoversee1,octeontx2,octeontx2t98,octeontx2t96,octeontx2t93,octeontx2f95,octeontx2f95n,octeontx2f95mm,a64fx,fujitsu_monaka,tsv110,thunderx3t110,neoversev1,zeus,neoverse512tvb,saphira,oryon1,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53,cortexa75cortexa55,cortexa76cortexa55,cortexr82,cortexr82ae,applea12,applem1_0,applem1_1,applem1_2,applem1_3,applem2_0,applem2_1,applem2_2,applem2_3,applem3_0,applem3_1,applem3_2,applem4_0,applem4_1,applem4_2,cortexa510,cortexa520,cortexa520ae,cortexa710,cortexa715,cortexa720,cortexa720ae,cortexa725,cortexx2,cortexx3,cortexx4,cortexx925,neoversen2,cobalt100,neoversen3,neoversev2,grace,neoversev3,neoversev3ae,demeter,olympus,gb10,generic,generic_armv8_a,generic_armv9_a" + "cortexa34,cortexa35,cortexa53,cortexa57,cortexa72,cortexa73,thunderx,thunderxt88,thunderxt88p1,octeontx,octeontxt81,octeontxt83,thunderxt81,thunderxt83,ampere1,ampere1a,ampere1b,ampere1c,emag,xgene1,falkor,qdf24xx,exynosm1,phecda,thunderx2t99p1,vulcan,thunderx2t99,cortexa55,cortexa75,cortexa76,cortexa76ae,cortexa77,cortexa78,cortexa78ae,cortexa78c,cortexa65,cortexa65ae,cortexx1,cortexx1c,neoversen1,ares,neoversee1,octeontx2,octeontx2t98,octeontx2t96,octeontx2t93,octeontx2f95,octeontx2f95n,octeontx2f95mm,a64fx,fujitsu_monaka,tsv110,thunderx3t110,neoversev1,zeus,neoverse512tvb,saphira,oryon1,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53,cortexa75cortexa55,cortexa76cortexa55,cortexr82,cortexr82ae,applea12,applem1_0,applem1_1,applem1_2,applem1_3,applem2_0,applem2_1,applem2_2,applem2_3,applem3_0,applem3_1,applem3_2,applem4_0,applem4_1,applem4_2,cortexa510,cortexa520,cortexa520ae,cortexa710,cortexa715,cortexa720,cortexa720ae,cortexa725,cortexx2,cortexx3,cortexx4,cortexx925,neoversen2,cobalt100,neoversen3,neoversev2,grace,neoversev3,neoversev3ae,c1nano,c1pro,c1premium,c1ultra,demeter,olympus,gb10,generic,generic_armv8_a,generic_armv9_a" (const (symbol_ref "((enum attr_tune) aarch64_tune)"))) diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc index a729ea4..54abf8c 100644 --- a/gcc/config/gcn/gcn.cc +++ b/gcc/config/gcn/gcn.cc @@ -2940,14 +2940,17 @@ gcn_init_cumulative_args (CUMULATIVE_ARGS *cum /* Argument info to init */ , if (!caller && cfun->machine->normal_function) gcn_detect_incoming_pointer_arg (fndecl); - if ((omp_requires_mask & (OMP_REQUIRES_UNIFIED_SHARED_MEMORY - | OMP_REQUIRES_SELF_MAPS)) + static bool warned_xnack = 0; + if (!warned_xnack + && (omp_requires_mask & (OMP_REQUIRES_UNIFIED_SHARED_MEMORY + | OMP_REQUIRES_SELF_MAPS)) && gcn_devices[gcn_arch].xnack_default != HSACO_ATTR_UNSUPPORTED && flag_xnack == HSACO_ATTR_OFF) { warning_at (UNKNOWN_LOCATION, 0, - "Unified Shared Memory is enabled, but XNACK is disabled"); + "Unified Shared Memory is required, but XNACK is disabled"); inform (UNKNOWN_LOCATION, "Try -foffload-options=-mxnack=any"); + warned_xnack = 1; } reinit_regs (); diff --git a/gcc/config/gcn/mkoffload.cc b/gcc/config/gcn/mkoffload.cc index d9d89c6..ac6aae5 100644 --- a/gcc/config/gcn/mkoffload.cc +++ b/gcc/config/gcn/mkoffload.cc @@ -627,9 +627,12 @@ process_asm (FILE *in, FILE *out, FILE *cfile, uint32_t omp_requires) || TEST_XNACK_ON (elf_flags) || xnack_required); if (TEST_XNACK_OFF (elf_flags) && xnack_required) - fatal_error (input_location, - "conflicting settings; XNACK is forced off but Unified " - "Shared Memory is on"); + { + warning (input_location, + "conflicting settings; XNACK is forced off but Unified " + "Shared Memory is required"); + xnack_required = 0; + } /* Start generating the C code. */ if (gcn_stack_size) diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index fd9bcaa..438fa4e 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -4159,12 +4159,18 @@ static bool ix86_expand_sse_fp_minmax (rtx dest, enum rtx_code code, rtx cmp_op0, rtx cmp_op1, rtx if_true, rtx if_false) { - machine_mode mode; + machine_mode mode = GET_MODE (dest); bool is_min; rtx tmp; if (code == LT) ; + else if (code == LE && !HONOR_NANS (mode)) + { + /* We can swap LE to GE and then invert to LT. */ + std::swap (cmp_op0, cmp_op1); + std::swap (if_true, if_false); + } else if (code == UNGE) std::swap (if_true, if_false); else @@ -4177,7 +4183,6 @@ ix86_expand_sse_fp_minmax (rtx dest, enum rtx_code code, rtx cmp_op0, else return false; - mode = GET_MODE (dest); if (immediate_operand (if_false, mode)) if_false = force_reg (mode, if_false); if (immediate_operand (if_true, mode)) diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index db43045..75a9cb6 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -26397,7 +26397,20 @@ ix86_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, (TREE_OPERAND (gimple_assign_rhs1 (def), 0)))))) { if (fp) - m_num_sse_needed[where]++; + { + /* Scalar FP values residing in x87 registers need to be + spilled and reloaded. */ + auto mode2 = TYPE_MODE (TREE_TYPE (op)); + if (IS_STACK_MODE (mode2)) + { + int cost + = (ix86_cost->hard_register.fp_store[mode2 == SFmode + ? 0 : 1] + + ix86_cost->sse_load[sse_store_index (mode2)]); + stmt_cost += COSTS_N_INSNS (cost) / 2; + } + m_num_sse_needed[where]++; + } else { m_num_gpr_needed[where]++; diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 0be898c..fb79b2e 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -4900,7 +4900,8 @@ (match_operand:SI 3 "<cmp_imm_predicate>")] UNSPEC_PCMP_ITER))] "TARGET_AVX512F && ix86_pre_reload_split () - && rtx_equal_p (operands[1], operands[2])" + && rtx_equal_p (operands[1], operands[2]) + && (!MEM_P (operands[1]) || !MEM_VOLATILE_P (operands[1]))" "#" "&& 1" [(set (match_dup 0) (match_dup 4))] diff --git a/gcc/config/mingw/winnt.cc b/gcc/config/mingw/winnt.cc index b51fd8e..fe2fb4c 100644 --- a/gcc/config/mingw/winnt.cc +++ b/gcc/config/mingw/winnt.cc @@ -446,8 +446,11 @@ mingw_pe_unique_section (tree decl, int reloc) prefix = ".text$"; else if (decl_readonly_section (decl, reloc)) prefix = ".rdata$"; + /* Note that we need two dollar signs for TLS sections + because they need to be ASCII-sorted before .tls$ZZZ + to be properly laid out by the GNU linker. */ else if (DECL_THREAD_LOCAL_P (decl)) - prefix = ".tls$"; + prefix = ".tls$$"; else prefix = ".data$"; len = strlen (name) + strlen (prefix); @@ -522,9 +525,6 @@ mingw_pe_asm_named_section (const char *name, unsigned int flags, *f++ = 'e'; #endif - if (strcmp (name, ".tls$") == 0) - *f++ = 'd'; - if ((flags & (SECTION_CODE | SECTION_WRITE)) == 0) /* readonly data */ { @@ -533,6 +533,8 @@ mingw_pe_asm_named_section (const char *name, unsigned int flags, } else { + if (startswith (name, ".tls$")) + *f++ = 'd'; if (flags & SECTION_CODE) *f++ = 'x'; if (flags & SECTION_WRITE) diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md index cec0113..c694684 100644 --- a/gcc/config/riscv/autovec.md +++ b/gcc/config/riscv/autovec.md @@ -2302,6 +2302,37 @@ }) ;; ------------------------------------------------------------------------- +;; ---- [INT] Mask reductions +;; ------------------------------------------------------------------------- + +(define_expand "reduc_sbool_and_scal_<mode>" + [(match_operand:QI 0 "register_operand") + (match_operand:VB_VLS 1 "register_operand")] + "TARGET_VECTOR" +{ + riscv_vector::expand_mask_reduction (operands, AND); + DONE; +}) + +(define_expand "reduc_sbool_ior_scal_<mode>" + [(match_operand:QI 0 "register_operand") + (match_operand:VB_VLS 1 "register_operand")] + "TARGET_VECTOR" +{ + riscv_vector::expand_mask_reduction (operands, IOR); + DONE; +}) + +(define_expand "reduc_sbool_xor_scal_<mode>" + [(match_operand:QI 0 "register_operand") + (match_operand:VB_VLS 1 "register_operand")] + "TARGET_VECTOR" +{ + riscv_vector::expand_mask_reduction (operands, XOR); + DONE; +}) + +;; ------------------------------------------------------------------------- ;; ---- [FP] Tree reductions ;; ------------------------------------------------------------------------- ;; Includes: diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index 3cc954e..5b44165 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -612,7 +612,7 @@ (match_code "eq,ne,le,leu,gt,gtu,lt,ltu")) (define_predicate "comparison_swappable_operator" - (match_code "gtu")) + (match_code "gtu,gt")) (define_predicate "ge_operator" (match_code "ge,geu")) diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc index 4fc0528..24537d5 100644 --- a/gcc/config/riscv/riscv-c.cc +++ b/gcc/config/riscv/riscv-c.cc @@ -213,6 +213,49 @@ riscv_pragma_intrinsic (cpp_reader *) error ("unknown %<#pragma riscv intrinsic%> option %qs", name); } +/* Implement TARGETM.TARGET_OPTION.PRAGMA_PARSE. */ + +static bool +riscv_pragma_target_parse (tree args, tree pop_target) +{ + /* If args is not NULL then process it and setup the target-specific + information that it specifies. */ + if (args) + { + if (!riscv_process_target_attr_for_pragma (args)) + return false; + + riscv_override_options_internal (&global_options); + } + /* args is NULL, restore to the state described in pop_target. */ + else + { + pop_target = pop_target ? pop_target : target_option_default_node; + cl_target_option_restore (&global_options, &global_options_set, + TREE_TARGET_OPTION (pop_target)); + } + + target_option_current_node + = build_target_option_node (&global_options, &global_options_set); + + riscv_reset_previous_fndecl (); + + /* For the definitions, ensure all newly defined macros are considered + as used for -Wunused-macros. There is no point warning about the + compiler predefined macros. */ + cpp_options *cpp_opts = cpp_get_options (parse_in); + unsigned char saved_warn_unused_macros = cpp_opts->warn_unused_macros; + cpp_opts->warn_unused_macros = 0; + + cpp_force_token_locations (parse_in, BUILTINS_LOCATION); + riscv_cpu_cpp_builtins (parse_in); + cpp_stop_forcing_token_locations (parse_in); + + cpp_opts->warn_unused_macros = saved_warn_unused_macros; + + return true; +} + /* Implement TARGET_CHECK_BUILTIN_CALL. */ static bool riscv_check_builtin_call (location_t loc, vec<location_t> arg_loc, tree fndecl, @@ -272,5 +315,6 @@ riscv_register_pragmas (void) { targetm.resolve_overloaded_builtin = riscv_resolve_overloaded_builtin; targetm.check_builtin_call = riscv_check_builtin_call; + targetm.target_option.pragma_parse = riscv_pragma_target_parse; c_register_pragma ("riscv", "intrinsic", riscv_pragma_intrinsic); } diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 261c25c..abf9df7 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -664,6 +664,7 @@ bool expand_vec_cmp_float (rtx, rtx_code, rtx, rtx, bool); void expand_cond_len_unop (unsigned, rtx *); void expand_cond_len_binop (unsigned, rtx *); void expand_reduction (unsigned, unsigned, unsigned, rtx *, rtx); +void expand_mask_reduction (rtx *, rtx_code); void expand_vec_ceil (rtx, rtx, machine_mode, machine_mode); void expand_vec_floor (rtx, rtx, machine_mode, machine_mode); void expand_vec_nearbyint (rtx, rtx, machine_mode, machine_mode); @@ -848,12 +849,15 @@ riscv_option_valid_attribute_p (tree, tree, tree, int); extern bool riscv_option_valid_version_attribute_p (tree, tree, tree, int); extern bool +riscv_process_target_attr_for_pragma (tree); +extern bool riscv_process_target_version_attr (tree, location_t *); extern bool riscv_process_target_version_str (string_slice, location_t *); extern void riscv_override_options_internal (struct gcc_options *); extern void riscv_option_override (void); +extern void riscv_reset_previous_fndecl (void); extern rtx riscv_prefetch_cookie (rtx, rtx); extern bool riscv_prefetch_offset_address_p (rtx, machine_mode); diff --git a/gcc/config/riscv/riscv-target-attr.cc b/gcc/config/riscv/riscv-target-attr.cc index 94f0a29..eb3e688 100644 --- a/gcc/config/riscv/riscv-target-attr.cc +++ b/gcc/config/riscv/riscv-target-attr.cc @@ -44,6 +44,7 @@ public: , m_cpu_info (nullptr) , m_tune (nullptr) , m_priority (0) + , m_max_vect (false) { } @@ -51,6 +52,7 @@ public: bool handle_cpu (const char *); bool handle_tune (const char *); bool handle_priority (const char *); + bool handle_max_vect (const char *); void update_settings (struct gcc_options *opts) const; private: @@ -66,31 +68,35 @@ private: const riscv_cpu_info *m_cpu_info; const char *m_tune; int m_priority; + bool m_max_vect; }; } /* All the information needed to handle a target attribute. NAME is the name of the attribute. - HANDLER is the function that takes the attribute string as an argument. */ + HANDLER is the function that takes the attribute string as an argument. + REQUIRES_ARG indicates whether this attribute requires an argument value. */ struct riscv_attribute_info { const char *name; bool (riscv_target_attr_parser::*handler) (const char *); + bool requires_arg; }; /* The target attributes that we support. */ static const struct riscv_attribute_info riscv_target_attrs[] - = {{"arch", &riscv_target_attr_parser::handle_arch}, - {"cpu", &riscv_target_attr_parser::handle_cpu}, - {"tune", &riscv_target_attr_parser::handle_tune}, - {NULL, NULL}}; + = {{"arch", &riscv_target_attr_parser::handle_arch, true}, + {"cpu", &riscv_target_attr_parser::handle_cpu, true}, + {"tune", &riscv_target_attr_parser::handle_tune, true}, + {"max-vectorization", &riscv_target_attr_parser::handle_max_vect, false}, + {NULL, NULL, false}}; static const struct riscv_attribute_info riscv_target_version_attrs[] - = {{"arch", &riscv_target_attr_parser::handle_arch}, - {"priority", &riscv_target_attr_parser::handle_priority}, - {NULL, NULL}}; + = {{"arch", &riscv_target_attr_parser::handle_arch, true}, + {"priority", &riscv_target_attr_parser::handle_priority, true}, + {NULL, NULL, false}}; bool riscv_target_attr_parser::parse_arch (const char *str) @@ -254,6 +260,17 @@ riscv_target_attr_parser::handle_priority (const char *str) return true; } +/* Handle max-vectorization. There are no further options, just + enable it. */ + +bool +riscv_target_attr_parser::handle_max_vect (const char *str ATTRIBUTE_UNUSED) +{ + m_max_vect = true; + + return true; +} + void riscv_target_attr_parser::update_settings (struct gcc_options *opts) const { @@ -279,6 +296,9 @@ riscv_target_attr_parser::update_settings (struct gcc_options *opts) const if (m_priority) opts->x_riscv_fmv_priority = m_priority; + + if (m_max_vect) + opts->x_riscv_max_vectorization = true; } /* Parse ARG_STR which contains the definition of one target attribute. @@ -303,33 +323,50 @@ riscv_process_one_target_attr (char *arg_str, char *str_to_check = buf.get(); strcpy (str_to_check, arg_str); + /* Split attribute name from argument (if present). */ char *arg = strchr (str_to_check, '='); - - if (!arg) + if (arg) { - if (loc) - error_at (*loc, "attribute %<target(\"%s\")%> does not " - "accept an argument", str_to_check); - return false; + *arg = '\0'; + ++arg; + /* Check for empty argument after '='. */ + if (*arg == '\0') + { + if (loc) + error_at (*loc, "attribute %<target(\"%s\")%> has empty argument", + str_to_check); + return false; + } } - arg[0] = '\0'; - ++arg; - for (const auto *attr = attrs; - attr->name; - ++attr) + /* Find matching attribute. */ + for (const auto *attr = attrs; attr->name; ++attr) { - /* If the names don't match up, or the user has given an argument - to an attribute that doesn't accept one, or didn't give an argument - to an attribute that expects one, fail to match. */ - if (strncmp (str_to_check, attr->name, strlen (attr->name)) != 0) + if (strcmp (str_to_check, attr->name) != 0) continue; + /* Validate argument presence matches expectations. */ + if (attr->requires_arg && !arg) + { + if (loc) + error_at (*loc, "attribute %<target(\"%s\")%> expects " + "an argument", str_to_check); + return false; + } + + if (!attr->requires_arg && arg) + { + if (loc) + error_at (*loc, "attribute %<target(\"%s\")%> does not " + "accept an argument", str_to_check); + return false; + } + return (&attr_parser->*attr->handler) (arg); } if (loc) - error_at (*loc, "Got unknown attribute %<target(\"%s\")%>", str_to_check); + error_at (*loc, "unknown attribute %<target(\"%s\")%>", str_to_check); return false; } @@ -489,6 +526,17 @@ riscv_option_valid_attribute_p (tree fndecl, tree, tree args, int) return ret; } +/* Public wrapper for pragma processing. + Parse ARGS (a TREE_LIST of target attributes) and update global_options. + This is used by #pragma GCC target. */ + +bool +riscv_process_target_attr_for_pragma (tree args) +{ + location_t loc = UNKNOWN_LOCATION; + return riscv_process_target_attr (args, &loc, riscv_target_attrs); +} + /* Parse the tree in ARGS that contains the target_version attribute information and update the global target options space. If LOC is nonnull, report diagnostics against *LOC, otherwise remain silent. */ diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index c0f0b99..f3c4431 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -4885,6 +4885,54 @@ expand_reduction (unsigned unspec, unsigned unspec_for_vl0_safe, emit_insn (gen_pred_extract_first (m1_mode, scalar_dest, m1_tmp2)); } +/* Expand mask reductions. OPS are {dest, src} where DEST's mode + is QImode and SRC's mode is a mask mode. + CODE is one of AND, IOR, XOR. */ + +void +expand_mask_reduction (rtx *ops, rtx_code code) +{ + machine_mode mode = GET_MODE (ops[1]); + rtx dest = ops[0]; + gcc_assert (GET_MODE (dest) == QImode); + + rtx tmp = gen_reg_rtx (Xmode); + rtx cpop_ops[] = {tmp, ops[1]}; + emit_vlmax_insn (code_for_pred_popcount (mode, Xmode), CPOP_OP, cpop_ops); + + bool eq_zero = false; + + /* AND reduction is popcount (mask) == len, + IOR reduction is popcount (mask) != 0, + XOR reduction is popcount (mask) & 1 != 0. */ + if (code == AND) + { + rtx len = gen_int_mode (GET_MODE_NUNITS (mode), HImode); + tmp = expand_binop (Xmode, sub_optab, tmp, len, NULL, true, + OPTAB_DIRECT); + eq_zero = true; + } + else if (code == IOR) + ; + else if (code == XOR) + tmp = expand_binop (Xmode, and_optab, tmp, GEN_INT (1), NULL, true, + OPTAB_DIRECT); + else + gcc_unreachable (); + + rtx els = gen_label_rtx (); + rtx end = gen_label_rtx (); + + riscv_expand_conditional_branch (els, eq_zero ? EQ : NE, tmp, const0_rtx); + emit_move_insn (dest, const0_rtx); + emit_jump_insn (gen_jump (end)); + emit_barrier (); + + emit_label (els); + emit_move_insn (dest, const1_rtx); + emit_label (end); +} + /* Prepare ops for ternary operations. It can be called before or after RA. */ void @@ -5869,6 +5917,8 @@ get_swapped_cmp_rtx_code (rtx_code code) { case GTU: return LTU; + case GT: + return LT; default: gcc_unreachable (); } diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 7b6a29d..96519c9 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -12225,6 +12225,12 @@ riscv_override_options_internal (struct gcc_options *opts) /* Convert -march and -mrvv-vector-bits to a chunks count. */ riscv_vector_chunks = riscv_convert_vector_chunks (opts); + /* Set scalar costing to a high value such that we always pick + vectorization. Increase scalar costing by 100x. */ + if (opts->x_riscv_max_vectorization) + SET_OPTION_IF_UNSET (&global_options, &global_options_set, + param_vect_scalar_cost_multiplier, 10000); + if (opts->x_flag_cf_protection != CF_NONE) { if ((opts->x_flag_cf_protection & CF_RETURN) == CF_RETURN @@ -12462,6 +12468,39 @@ riscv_option_restore (struct gcc_options *opts, static GTY (()) tree riscv_previous_fndecl; +/* Reset the previous function declaration. */ + +void +riscv_reset_previous_fndecl (void) +{ + riscv_previous_fndecl = NULL; +} + +/* Implement TARGET_OPTION_SAVE. */ + +static void +riscv_option_save (struct cl_target_option *ptr, + struct gcc_options *opts, + struct gcc_options * /* opts_set */) +{ + ptr->x_riscv_arch_string = opts->x_riscv_arch_string; + ptr->x_riscv_tune_string = opts->x_riscv_tune_string; + ptr->x_riscv_cpu_string = opts->x_riscv_cpu_string; +} + +/* Implement TARGET_OPTION_PRINT. */ + +static void +riscv_option_print (FILE *file, int indent, struct cl_target_option *ptr) +{ + fprintf (file, "%*sarch = %s\n", indent, "", + ptr->x_riscv_arch_string ? ptr->x_riscv_arch_string : "default"); + fprintf (file, "%*stune = %s\n", indent, "", + ptr->x_riscv_tune_string ? ptr->x_riscv_tune_string : "default"); + if (ptr->x_riscv_cpu_string) + fprintf (file, "%*scpu = %s\n", indent, "", ptr->x_riscv_cpu_string); +} + /* Implement TARGET_CONDITIONAL_REGISTER_USAGE. */ static void @@ -12798,7 +12837,7 @@ riscv_get_interrupt_type (tree decl) /* Implement `TARGET_SET_CURRENT_FUNCTION'. Unpack the codegen decisions like tuning and ISA features from the DECL_FUNCTION_SPECIFIC_TARGET of the function, if such exists. This function may be called multiple - times on a single function so use aarch64_previous_fndecl to avoid + times on a single function so use riscv_previous_fndecl to avoid setting up identical state. */ /* Sanity checking for above function attributes. */ @@ -16309,9 +16348,15 @@ riscv_prefetch_offset_address_p (rtx x, machine_mode mode) #undef TARGET_OPTION_OVERRIDE #define TARGET_OPTION_OVERRIDE riscv_option_override +#undef TARGET_OPTION_SAVE +#define TARGET_OPTION_SAVE riscv_option_save + #undef TARGET_OPTION_RESTORE #define TARGET_OPTION_RESTORE riscv_option_restore +#undef TARGET_OPTION_PRINT +#define TARGET_OPTION_PRINT riscv_option_print + #undef TARGET_OPTION_VALID_ATTRIBUTE_P #define TARGET_OPTION_VALID_ATTRIBUTE_P riscv_option_valid_attribute_p diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt index b334e6c..452062c 100644 --- a/gcc/config/riscv/riscv.opt +++ b/gcc/config/riscv/riscv.opt @@ -341,6 +341,10 @@ Target Undocumented RejectNegative Joined Enum(vsetvl_strategy) Var(vsetvl_strat Target Undocumented Uinteger Var(riscv_two_source_permutes) Init(0) -param=riscv-two-source-permutes Enable permutes with two source vectors. +mmax-vectorization +Target Var(riscv_max_vectorization) Save +Override the scalar cost model such that vectorization is always profitable. + Enum Name(stringop_strategy) Type(enum stringop_strategy_enum) Valid arguments to -mstringop-strategy=: diff --git a/gcc/config/riscv/riscv.opt.urls b/gcc/config/riscv/riscv.opt.urls index fe88ec8..bfb1a2d 100644 --- a/gcc/config/riscv/riscv.opt.urls +++ b/gcc/config/riscv/riscv.opt.urls @@ -96,6 +96,8 @@ UrlSuffix(gcc/RISC-V-Options.html#index-minline-strncmp) minline-strlen UrlSuffix(gcc/RISC-V-Options.html#index-minline-strlen) +; skipping UrlSuffix for 'mmax-vectorization' due to finding no URLs + ; skipping UrlSuffix for 'mtls-dialect=' due to finding no URLs mfence-tso diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md index c4f60bf..ba4a43b 100644 --- a/gcc/config/riscv/vector.md +++ b/gcc/config/riscv/vector.md @@ -4199,6 +4199,7 @@ "TARGET_VECTOR" "vw<plus_minus:insn><any_extend:u>.wx\t%0,%3,%z4%p1" [(set_attr "type" "vi<widen_binop_insn_type>") + (set_attr "mode_idx" "3") (set_attr "mode" "<V_DOUBLE_TRUNC>")]) (define_insn "@pred_single_widen_add<any_extend:su><mode>_extended_scalar" @@ -4465,6 +4466,7 @@ "TARGET_VECTOR" "v<insn>.vx\t%0,%3,%4%p1" [(set_attr "type" "<int_binop_insn_type>") + (set_attr "mode_idx" "3") (set_attr "mode" "<MODE>")]) (define_insn "@pred_<optab><mode>_scalar" @@ -4486,6 +4488,7 @@ "TARGET_VECTOR" "v<insn>.vx\t%0,%3,%4%p1" [(set_attr "type" "<int_binop_insn_type>") + (set_attr "mode_idx" "3") (set_attr "mode" "<MODE>")]) (define_expand "@pred_<optab><mode>_scalar" @@ -4540,6 +4543,7 @@ "TARGET_VECTOR" "v<insn>.vx\t%0,%3,%4%p1" [(set_attr "type" "<int_binop_insn_type>") + (set_attr "mode_idx" "3") (set_attr "mode" "<MODE>")]) (define_insn "*pred_<optab><mode>_extended_scalar" @@ -4562,6 +4566,7 @@ "TARGET_VECTOR && !TARGET_64BIT" "v<insn>.vx\t%0,%3,%4%p1" [(set_attr "type" "<int_binop_insn_type>") + (set_attr "mode_idx" "3") (set_attr "mode" "<MODE>")]) (define_expand "@pred_<optab><mode>_scalar" @@ -4616,6 +4621,7 @@ "TARGET_VECTOR" "v<insn>.vx\t%0,%3,%z4%p1" [(set_attr "type" "<int_binop_insn_type>") + (set_attr "mode_idx" "3") (set_attr "mode" "<MODE>")]) (define_insn "*pred_<optab><mode>_extended_scalar" @@ -4638,6 +4644,7 @@ "TARGET_VECTOR && !TARGET_64BIT" "v<insn>.vx\t%0,%3,%z4%p1" [(set_attr "type" "<int_binop_insn_type>") + (set_attr "mode_idx" "3") (set_attr "mode" "<MODE>")]) (define_insn "@pred_<sat_op><mode>" @@ -4683,6 +4690,7 @@ "TARGET_VECTOR" "v<sat_op>.vx\t%0,%3,%z4%p1" [(set_attr "type" "<sat_insn_type>") + (set_attr "mode_idx" "3") (set_attr "mode" "<MODE>")]) (define_insn "@pred_<sat_op><mode>_scalar" diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 647e89a..5133dac 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -2166,3 +2166,8 @@ (and (match_code "subreg") (match_test "subreg_lowpart_offset (mode, GET_MODE (SUBREG_REG (op))) == SUBREG_BYTE (op)"))) + +; Else operand for LEN_LOAD. +(define_predicate "lxvl_else_operand" + (and (match_code "const_vector") + (match_test "op == CONST0_RTX (GET_MODE (op))"))) diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md index dd3573b..4d47833 100644 --- a/gcc/config/rs6000/vsx.md +++ b/gcc/config/rs6000/vsx.md @@ -5798,13 +5798,14 @@ (define_expand "len_load_v16qi" [(match_operand:V16QI 0 "vlogical_operand") (match_operand:V16QI 1 "memory_operand") - (match_operand:QI 2 "gpc_reg_operand") - (match_operand:QI 3 "zero_constant")] + (match_operand:V16QI 2 "lxvl_else_operand") + (match_operand:QI 3 "gpc_reg_operand") + (match_operand:QI 4 "zero_constant")] "TARGET_P9_VECTOR && TARGET_64BIT" { rtx mem = XEXP (operands[1], 0); mem = force_reg (DImode, mem); - rtx len = gen_lowpart (DImode, operands[2]); + rtx len = gen_lowpart (DImode, operands[3]); emit_insn (gen_lxvl (operands[0], mem, len)); DONE; }) diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md index c7b93bd..e181399 100644 --- a/gcc/config/s390/predicates.md +++ b/gcc/config/s390/predicates.md @@ -614,3 +614,8 @@ (define_predicate "vll_bias_operand" (and (match_code "const_int") (match_test "op == CONSTM1_RTX (QImode)"))) + +; Else operand for LEN_LOAD. +(define_predicate "vll_else_operand" + (and (match_code "const_vector") + (match_test "op == CONST0_RTX (GET_MODE (op))"))) diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md index 375e3e8..367389c 100644 --- a/gcc/config/s390/vector.md +++ b/gcc/config/s390/vector.md @@ -3557,15 +3557,16 @@ (define_expand "len_load_v16qi" [(match_operand:V16QI 0 "register_operand") (match_operand:V16QI 1 "memory_operand") - (match_operand:QI 2 "register_operand") - (match_operand:QI 3 "vll_bias_operand") + (match_operand:V16QI 2 "vll_else_operand") + (match_operand:QI 3 "register_operand") + (match_operand:QI 4 "vll_bias_operand") ] "TARGET_VX && TARGET_64BIT" { rtx mem = adjust_address (operands[1], BLKmode, 0); rtx len = gen_reg_rtx (SImode); - emit_move_insn (len, gen_rtx_ZERO_EXTEND (SImode, operands[2])); + emit_move_insn (len, gen_rtx_ZERO_EXTEND (SImode, operands[3])); emit_insn (gen_vllv16qi (operands[0], len, mem)); DONE; }) diff --git a/gcc/configure b/gcc/configure index d707435..f349c1d 100755 --- a/gcc/configure +++ b/gcc/configure @@ -635,7 +635,6 @@ LIBOBJS CET_HOST_FLAGS LD_PICFLAG PICFLAG -enable_default_pie libgccjit_version enable_host_bind_now LIBGDIAGNOSTICS @@ -21877,7 +21876,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 21880 "configure" +#line 21879 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -21983,7 +21982,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 21986 "configure" +#line 21985 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -34939,7 +34938,6 @@ $as_echo "#define ENABLE_DEFAULT_PIE 1" >>confdefs.h fi - # Check if -fno-PIE works. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fno-PIE option" >&5 $as_echo_n "checking for -fno-PIE option... " >&6; } diff --git a/gcc/configure.ac b/gcc/configure.ac index b6d9608..c652257 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -7765,7 +7765,6 @@ if test x$enable_default_pie = xyes ; then AC_DEFINE(ENABLE_DEFAULT_PIE, 1, [Define if your target supports default PIE and it is enabled.]) fi -AC_SUBST([enable_default_pie]) # Check if -fno-PIE works. AC_CACHE_CHECK([for -fno-PIE option], diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3ad8d16..b4c2b70 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2025-12-08 Egas Ribeiro <egas.g.ribeiro@tecnico.ulisboa.pt> + + * pt.cc (tsubst_expr): Add TARGET_EXPR case with explanatory + comment and gcc_unreachable. + +2025-12-08 Egas Ribeiro <egas.g.ribeiro@tecnico.ulisboa.pt> + + PR c++/119343 + * pt.cc (resolve_nondeduced_context): Remove mark_used call. + 2025-12-06 Jakub Jelinek <jakub@redhat.com> * decl2.cc (is_late_template_attribute): Call lookup_attribute_spec diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 8498730..ce30b52 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -22562,6 +22562,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) in response to the saved STMT_IS_FULL_EXPR_P setting. */ gcc_unreachable (); + case TARGET_EXPR: + /* TARGET_EXPR represents temporary objects and should not appear in + templated trees. */ + gcc_unreachable (); + case OFFSET_REF: { /* We should only get here for an OFFSET_REF like A::m; a .* in a @@ -24816,8 +24821,6 @@ resolve_nondeduced_context (tree orig_expr, tsubst_flags_t complain) } if (good == 1) { - if (!mark_used (goodfn, complain) && !(complain & tf_error)) - return error_mark_node; expr = goodfn; if (baselink) expr = build_baselink (BASELINK_BINFO (baselink), diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 11f6b02..5f36510 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -6007,6 +6007,16 @@ Specifies the core for which to tune the performance of this function and also whose architectural features to use. The behavior and valid arguments are the same as for the @option{-mcpu=} command-line option. +@cindex @code{max-vectorization} function attribute, RISC-V +@item max-vectorization +@itemx no-max-vectorization +@code{max-vectorization} tells GCC's vectorizer to treat all vector +loops as being more profitable than the original scalar loops when +optimizing the current function. @code{no-max-vectorization} disables +this behavior. +This corresponds to the behavior of the command-line options +@option{-mmax-vectorization} and @option{-mno-max-vectorization}. + @end table The above target attributes can be specified as follows: @@ -10722,7 +10732,7 @@ for more information about the @code{target} attribute and the attribute syntax. The @code{#pragma GCC target} pragma is presently implemented for -x86, ARM, AArch64, PowerPC, and S/390 targets only. +x86, ARM, AArch64, PowerPC, RISC-V, and S/390 targets only. @cindex pragma GCC optimize @item #pragma GCC optimize (@var{string}, @dots{}) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ac36fda..813403a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -22761,7 +22761,8 @@ performance of the code. Permissible values for this option are: @samp{cortex-a520}, @samp{cortex-a520ae}, @samp{cortex-a710}, @samp{cortex-a715}, @samp{cortex-a720}, @samp{cortex-a720ae}, @samp{ampere1}, @samp{ampere1a}, @samp{ampere1b}, @samp{ampere1c}, @samp{cobalt-100}, @samp{apple-m1}, -@samp{apple-m2}, @samp{apple-m3}, @samp{apple-m4} and @samp{native}. +@samp{apple-m2}, @samp{apple-m3}, @samp{apple-m4}, @samp{c1-nano}, +@samp{c1-pro}, @samp{c1-premium} @samp{c1-ultra} and @samp{native}. The values @samp{cortex-a57.cortex-a53}, @samp{cortex-a72.cortex-a53}, @samp{cortex-a73.cortex-a35}, @samp{cortex-a73.cortex-a53}, @@ -32162,6 +32163,12 @@ Do not or do generate unaligned vector memory accesses. The default is set to off unless the processor we are optimizing for explicitly supports element-misaligned vector memory access. +@item -mmax-vectorization +@itemx -mno-max-vectorization +Enable or disable an override to vectorizer cost model making vectorization +always appear profitable. Unlike @option{-fno-vect-cost-model} or +@option{-fvect-cost-model=unlimited} this option does not turn off cost +comparison between different vector modes. @opindex mcmodel= @opindex mcmodel=medlow diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 7bf2cc0..86ed4ff 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -5408,18 +5408,20 @@ This pattern is not allowed to @code{FAIL}. @cindex @code{len_load_@var{m}} instruction pattern @item @samp{len_load_@var{m}} -Load (operand 2 + operand 3) elements from memory operand 1 -into vector register operand 0, setting the other elements of -operand 0 to undefined values. Operands 0 and 1 have mode @var{m}, -which must be a vector mode. Operand 2 has whichever integer mode the -target prefers. Operand 3 conceptually has mode @code{QI}. - -Operand 2 can be a variable or a constant amount. Operand 3 specifies a +Load (operand 3 + operand 4) elements from memory operand 1 +into vector register operand 0. Operands 0 and 1 have mode @var{m}, +which must be a vector mode. Operand 3 has whichever integer mode the +target prefers. Operand 2 (the “else value”) is of mode @var{m} and +specifies which value is loaded for the remaining elements. The predicate +of operand 2 must only accept the else values that the target actually +supports. Operand 4 conceptually has mode @code{QI}. + +Operand 3 can be a variable or a constant amount. Operand 4 specifies a constant bias: it is either a constant 0 or a constant -1. The predicate on -operand 3 must only accept the bias values that the target actually supports. +operand 4 must only accept the bias values that the target actually supports. GCC handles a bias of 0 more efficiently than a bias of -1. -If (operand 2 + operand 3) exceeds the number of elements in mode +If (operand 3 + operand 4) exceeds the number of elements in mode @var{m}, the behavior is undefined. If the target prefers the length to be measured in bytes rather than diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 724da5b..4fd2183 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,12 @@ +2025-12-08 Harald Anlauf <anlauf@gmx.de> + Steven G. Kargl <kargl@gcc.gnu.org> + + PR fortran/123025 + * decl.cc (match_char_length): Add a check for the + obsolete '*' style of character declarations in the + alternate branch of checking so we dont miss two + use cases: + 2025-12-06 Paul Thomas <pault@gcc.gnu.org> PR fortran/122693 diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc index dfedb96..0e55171 100644 --- a/gcc/fortran/decl.cc +++ b/gcc/fortran/decl.cc @@ -1217,6 +1217,10 @@ match_char_length (gfc_expr **expr, bool *deferred, bool obsolescent_check) goto syntax; } + if (obsolescent_check + && !gfc_notify_std (GFC_STD_F95_OBS, "Old-style character length at %C")) + return MATCH_ERROR; + return MATCH_YES; syntax: diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index 3fc7631..5542318 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -5757,50 +5757,112 @@ arith_overflowed_p (enum tree_code code, const_tree type, return wi::min_precision (wres, sign) > TYPE_PRECISION (type); } -/* If IFN_{MASK,LEN,MASK_LEN}_LOAD/STORE call CALL is unconditional, - return a MEM_REF for the memory it references, otherwise return null. - VECTYPE is the type of the memory vector. MASK_P indicates it's for - MASK if true, otherwise it's for LEN. */ +/* Mask state for partial load/store operations (mask and length). */ +enum mask_load_store_state { + MASK_ALL_INACTIVE, /* All lanes/elements are inactive (can be elided). */ + MASK_ALL_ACTIVE, /* All lanes/elements are active (unconditional). */ + MASK_UNKNOWN +}; -static tree -gimple_fold_partial_load_store_mem_ref (gcall *call, tree vectype, bool mask_p) +/* Check the mask/length state of IFN_{MASK,LEN,MASK_LEN}_LOAD/STORE call CALL. + Returns whether all elements are active, all inactive, or mixed. + VECTYPE is the vector type of the operation. */ + +static enum mask_load_store_state +partial_load_store_mask_state (gcall *call, tree vectype) { - tree ptr = gimple_call_arg (call, 0); - tree alias_align = gimple_call_arg (call, 1); - if (!tree_fits_uhwi_p (alias_align)) - return NULL_TREE; + internal_fn ifn = gimple_call_internal_fn (call); + int mask_index = internal_fn_mask_index (ifn); + int len_index = internal_fn_len_index (ifn); + + /* Extract length and mask arguments up front. */ + tree len = len_index != -1 ? gimple_call_arg (call, len_index) : NULL_TREE; + tree bias = len ? gimple_call_arg (call, len_index + 1) : NULL_TREE; + tree mask = mask_index != -1 ? gimple_call_arg (call, mask_index) : NULL_TREE; + + poly_int64 nelts = GET_MODE_NUNITS (TYPE_MODE (vectype)); - if (mask_p) + poly_widest_int wlen = -1; + bool full_length_p = !len; /* No length means full length. */ + + /* Compute effective length. */ + if (len && poly_int_tree_p (len)) { - tree mask = gimple_call_arg (call, 2); - if (!integer_all_onesp (mask)) - return NULL_TREE; + gcc_assert (TREE_CODE (bias) == INTEGER_CST); + wlen = wi::to_poly_widest (len) + wi::to_widest (bias); + + if (known_eq (wlen, 0)) + return MASK_ALL_INACTIVE; + + if (known_eq (wlen, nelts)) + full_length_p = true; + else + full_length_p = false; } - else + + /* Check mask for early return cases. */ + if (mask) { - internal_fn ifn = gimple_call_internal_fn (call); - int len_index = internal_fn_len_index (ifn); - tree basic_len = gimple_call_arg (call, len_index); - if (!poly_int_tree_p (basic_len)) - return NULL_TREE; - tree bias = gimple_call_arg (call, len_index + 1); - gcc_assert (TREE_CODE (bias) == INTEGER_CST); - /* For LEN_LOAD/LEN_STORE/MASK_LEN_LOAD/MASK_LEN_STORE, - we don't fold when (bias + len) != VF. */ - if (maybe_ne (wi::to_poly_widest (basic_len) + wi::to_widest (bias), - GET_MODE_NUNITS (TYPE_MODE (vectype)))) - return NULL_TREE; + if (integer_zerop (mask)) + return MASK_ALL_INACTIVE; + + if (full_length_p && integer_all_onesp (mask)) + return MASK_ALL_ACTIVE; + } + else if (full_length_p) + /* No mask and full length means all active. */ + return MASK_ALL_ACTIVE; + + /* For VLA vectors, we can't do much more. */ + if (!nelts.is_constant ()) + return MASK_UNKNOWN; + + /* Same for VLS vectors with non-constant mask. */ + if (mask && TREE_CODE (mask) != VECTOR_CST) + return MASK_UNKNOWN; - /* For MASK_LEN_{LOAD,STORE}, we should also check whether - the mask is all ones mask. */ - if (ifn == IFN_MASK_LEN_LOAD || ifn == IFN_MASK_LEN_STORE) + /* Check VLS vector elements. */ + gcc_assert (wlen.is_constant ()); + + HOST_WIDE_INT active_len = wlen.to_constant ().to_shwi (); + if (active_len == -1) + active_len = nelts.to_constant (); + + /* Check if all elements in the active range match the mask. */ + for (HOST_WIDE_INT i = 0; i < active_len; i++) + { + bool elt_active = !mask || !integer_zerop (vector_cst_elt (mask, i)); + if (!elt_active) { - tree mask = gimple_call_arg (call, internal_fn_mask_index (ifn)); - if (!integer_all_onesp (mask)) - return NULL_TREE; + /* Found an inactive element. Check if all are inactive. */ + for (HOST_WIDE_INT j = 0; j < active_len; j++) + if (!mask || !integer_zerop (vector_cst_elt (mask, j))) + return MASK_UNKNOWN; /* Mixed state. */ + return MASK_ALL_INACTIVE; } } + /* All elements in active range are active. */ + return full_length_p ? MASK_ALL_ACTIVE : MASK_UNKNOWN; +} + + +/* If IFN_{MASK,LEN,MASK_LEN}_LOAD/STORE call CALL is unconditional + (all lanes active), return a MEM_REF for the memory it references. + Otherwise return NULL_TREE. VECTYPE is the type of the memory vector. */ + +static tree +gimple_fold_partial_load_store_mem_ref (gcall *call, tree vectype) +{ + /* Only fold if all lanes are active (unconditional). */ + if (partial_load_store_mask_state (call, vectype) != MASK_ALL_ACTIVE) + return NULL_TREE; + + tree ptr = gimple_call_arg (call, 0); + tree alias_align = gimple_call_arg (call, 1); + if (!tree_fits_uhwi_p (alias_align)) + return NULL_TREE; + unsigned HOST_WIDE_INT align = tree_to_uhwi (alias_align); if (TYPE_ALIGN (vectype) != align) vectype = build_aligned_type (vectype, align); @@ -5808,41 +5870,68 @@ gimple_fold_partial_load_store_mem_ref (gcall *call, tree vectype, bool mask_p) return fold_build2 (MEM_REF, vectype, ptr, offset); } -/* Try to fold IFN_{MASK,LEN}_LOAD call CALL. Return true on success. - MASK_P indicates it's for MASK if true, otherwise it's for LEN. */ +/* Try to fold IFN_{MASK,LEN}_LOAD/STORE call CALL. Return true on success. */ static bool -gimple_fold_partial_load (gimple_stmt_iterator *gsi, gcall *call, bool mask_p) +gimple_fold_partial_load_store (gimple_stmt_iterator *gsi, gcall *call) { + internal_fn ifn = gimple_call_internal_fn (call); tree lhs = gimple_call_lhs (call); - if (!lhs) - return false; + bool is_load = (lhs != NULL_TREE); + tree vectype; - if (tree rhs - = gimple_fold_partial_load_store_mem_ref (call, TREE_TYPE (lhs), mask_p)) + if (is_load) + vectype = TREE_TYPE (lhs); + else { - gassign *new_stmt = gimple_build_assign (lhs, rhs); - gimple_set_location (new_stmt, gimple_location (call)); - gimple_move_vops (new_stmt, call); - gsi_replace (gsi, new_stmt, false); - return true; + tree rhs = gimple_call_arg (call, internal_fn_stored_value_index (ifn)); + vectype = TREE_TYPE (rhs); } - return false; -} -/* Try to fold IFN_{MASK,LEN}_STORE call CALL. Return true on success. - MASK_P indicates it's for MASK if true, otherwise it's for LEN. */ + enum mask_load_store_state state + = partial_load_store_mask_state (call, vectype); -static bool -gimple_fold_partial_store (gimple_stmt_iterator *gsi, gcall *call, - bool mask_p) -{ - internal_fn ifn = gimple_call_internal_fn (call); - tree rhs = gimple_call_arg (call, internal_fn_stored_value_index (ifn)); - if (tree lhs - = gimple_fold_partial_load_store_mem_ref (call, TREE_TYPE (rhs), mask_p)) + /* Handle all-inactive case. */ + if (state == MASK_ALL_INACTIVE) { - gassign *new_stmt = gimple_build_assign (lhs, rhs); + if (is_load) + { + /* Replace load with else value. */ + int else_index = internal_fn_else_index (ifn); + tree else_value = gimple_call_arg (call, else_index); + gassign *new_stmt = gimple_build_assign (lhs, else_value); + gimple_set_location (new_stmt, gimple_location (call)); + gsi_replace (gsi, new_stmt, false); + return true; + } + else + { + /* Remove inactive store altogether. */ + unlink_stmt_vdef (call); + release_defs (call); + gsi_replace (gsi, gimple_build_nop (), true); + return true; + } + } + + /* We cannot simplify a gather/scatter or load/store lanes further. */ + if (internal_gather_scatter_fn_p (ifn) + || TREE_CODE (vectype) == ARRAY_TYPE) + return false; + + /* Handle all-active case by folding to regular memory operation. */ + if (tree mem_ref = gimple_fold_partial_load_store_mem_ref (call, vectype)) + { + gassign *new_stmt; + if (is_load) + new_stmt = gimple_build_assign (lhs, mem_ref); + else + { + tree rhs + = gimple_call_arg (call, internal_fn_stored_value_index (ifn)); + new_stmt = gimple_build_assign (mem_ref, rhs); + } + gimple_set_location (new_stmt, gimple_location (call)); gimple_move_vops (new_stmt, call); gsi_replace (gsi, new_stmt, false); @@ -6075,19 +6164,21 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace) cplx_result = true; uaddc_usubc = true; break; - case IFN_MASK_LOAD: - changed |= gimple_fold_partial_load (gsi, stmt, true); - break; - case IFN_MASK_STORE: - changed |= gimple_fold_partial_store (gsi, stmt, true); - break; case IFN_LEN_LOAD: + case IFN_MASK_LOAD: case IFN_MASK_LEN_LOAD: - changed |= gimple_fold_partial_load (gsi, stmt, false); - break; + case IFN_MASK_GATHER_LOAD: + case IFN_MASK_LEN_GATHER_LOAD: + case IFN_MASK_LOAD_LANES: + case IFN_MASK_LEN_LOAD_LANES: case IFN_LEN_STORE: + case IFN_MASK_STORE: case IFN_MASK_LEN_STORE: - changed |= gimple_fold_partial_store (gsi, stmt, false); + case IFN_MASK_SCATTER_STORE: + case IFN_MASK_LEN_SCATTER_STORE: + case IFN_MASK_STORE_LANES: + case IFN_MASK_LEN_STORE_LANES: + changed |= gimple_fold_partial_load_store (gsi, stmt); break; default: break; diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc index 13fbd2c..8df4f50 100644 --- a/gcc/internal-fn.cc +++ b/gcc/internal-fn.cc @@ -5006,6 +5006,7 @@ internal_fn_len_index (internal_fn fn) switch (fn) { case IFN_LEN_LOAD: + return 3; case IFN_LEN_STORE: return 2; @@ -5071,6 +5072,9 @@ internal_fn_else_index (internal_fn fn) case IFN_COND_LEN_NOT: return 2; + case IFN_LEN_LOAD: + return 2; + case IFN_COND_ADD: case IFN_COND_SUB: case IFN_COND_MUL: @@ -5401,7 +5405,7 @@ internal_len_load_store_bias (internal_fn ifn, machine_mode mode) { optab optab = direct_internal_fn_optab (ifn); insn_code icode = direct_optab_handler (optab, mode); - int bias_no = 3; + int bias_idx = internal_fn_len_index (ifn) + 1; if (icode == CODE_FOR_nothing) { @@ -5412,22 +5416,23 @@ internal_len_load_store_bias (internal_fn ifn, machine_mode mode) { /* Try MASK_LEN_LOAD. */ optab = direct_internal_fn_optab (IFN_MASK_LEN_LOAD); + bias_idx = internal_fn_len_index (IFN_MASK_LEN_LOAD) + 1; } else { /* Try MASK_LEN_STORE. */ optab = direct_internal_fn_optab (IFN_MASK_LEN_STORE); + bias_idx = internal_fn_len_index (IFN_MASK_LEN_STORE) + 1; } icode = convert_optab_handler (optab, mode, mask_mode); - bias_no = 4; } if (icode != CODE_FOR_nothing) { /* For now we only support biases of 0 or -1. Try both of them. */ - if (insn_operand_matches (icode, bias_no, GEN_INT (0))) + if (insn_operand_matches (icode, bias_idx, GEN_INT (0))) return 0; - if (insn_operand_matches (icode, bias_no, GEN_INT (-1))) + if (insn_operand_matches (icode, bias_idx, GEN_INT (-1))) return -1; } diff --git a/gcc/optabs-tree.cc b/gcc/optabs-tree.cc index 0de74c7..53788b9 100644 --- a/gcc/optabs-tree.cc +++ b/gcc/optabs-tree.cc @@ -615,28 +615,27 @@ target_supports_len_load_store_p (machine_mode mode, bool is_load, { optab op = is_load ? len_load_optab : len_store_optab; optab masked_op = is_load ? mask_len_load_optab : mask_len_store_optab; + internal_fn which_ifn; - if (direct_optab_handler (op, mode)) + enum insn_code icode; + if ((icode = direct_optab_handler (op, mode)) != CODE_FOR_nothing) { - if (ifn) - *ifn = is_load ? IFN_LEN_LOAD : IFN_LEN_STORE; - return true; + which_ifn = is_load ? IFN_LEN_LOAD : IFN_LEN_STORE; } machine_mode mask_mode; - enum insn_code icode; - if (targetm.vectorize.get_mask_mode (mode).exists (&mask_mode) + if (!icode + && targetm.vectorize.get_mask_mode (mode).exists (&mask_mode) && ((icode = convert_optab_handler (masked_op, mode, mask_mode)) != CODE_FOR_nothing)) - { - if (ifn) - *ifn = is_load ? IFN_MASK_LEN_LOAD : IFN_MASK_LEN_STORE; - if (elsvals && is_load) - get_supported_else_vals (icode, - internal_fn_else_index (IFN_MASK_LEN_LOAD), - *elsvals); - return true; - } - return false; + which_ifn = is_load ? IFN_MASK_LEN_LOAD : IFN_MASK_LEN_STORE; + + if (icode && elsvals && is_load) + get_supported_else_vals (icode, internal_fn_else_index (which_ifn), + *elsvals); + + if (icode && ifn) + *ifn = which_ifn; + return icode; } /* If target supports vector load/store with length for vector mode MODE, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8f13d2c..f8a8fba 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,236 @@ +2025-12-08 Andrew Pinski <andrew.pinski@oss.qualcomm.com> + + PR tree-optimization/46555 + * gcc.dg/tree-ssa/pr46555.c: New test. + +2025-12-08 Harald Anlauf <anlauf@gmx.de> + Steven G. Kargl <kargl@gcc.gnu.org> + + PR fortran/123025 + * gfortran.dg/assumed_charlen_dummy.f90: These tests failed + with the change because of the default -pedantic option + used by the dg.exp mechanisms. Overide this default. + * gfortran.dg/automatic_char_len_1.f90: Ditto. + * gfortran.dg/entry_23.f: Ditto. + * gfortran.dg/finalize_59.f90: Dito. + * gfortran.dg/g77/f90-intrinsic-bit.f: Ditto. + * gfortran.dg/g77/f90-intrinsic-mathematical.f: Ditto. + * gfortran.dg/g77/f90-intrinsic-numeric.f: Ditto. + * gfortran.dg/g77/intrinsic-unix-bessel.f: Ditto. + * gfortran.dg/g77/intrinsic-unix-erf.f: Ditto. + * gfortran.dg/initialization_9.f90: Ditto. + * gfortran.dg/intrinsic_actual_4.f90: Ditto. + * gfortran.dg/namelist_assumed_char.f90: Ditto. + * gfortran.dg/pr15140.f90: Ditto. + +2025-12-08 Egas Ribeiro <egas.g.ribeiro@tecnico.ulisboa.pt> + + PR c++/119343 + * g++.dg/template/sfinae-deleted-pr119343.C: New test. + +2025-12-08 Eric Botcazou <ebotcazou@adacore.com> + + * gcc.dg/tls/data-sections-1.c: New test. + +2025-12-08 Richard Biener <rguenther@suse.de> + + PR tree-optimization/123040 + * g++.dg/torture/pr123040.C: New testcase. + +2025-12-08 Richard Biener <rguenther@suse.de> + + PR tree-optimization/123038 + * gcc.dg/vect/pr123038.c: New testcase. + +2025-12-08 Tamar Christina <tamar.christina@arm.com> + + PR target/123026 + * gcc.target/aarch64/pr123026.c: New test. + +2025-12-08 H.J. Lu <hjl.tools@gmail.com> + + PR target/122343 + * gcc.target/i386/avx2-vpcmpgtq-1.c: Compile with + -fno-fuse-ops-with-volatile-access. + +2025-12-07 Eric Botcazou <ebotcazou@adacore.com> + + * gnat.dg/reduce3.adb: New test. + +2025-12-07 H.J. Lu <hjl.tools@gmail.com> + + PR target/122343 + * gcc.target/i386/20040112-1.c: Add -fomit-frame-pointer and use + check-function-bodies to check for loop. + * gcc.target/i386/avx-ne-convert-1.c: Compile with + -fno-fuse-ops-with-volatile-access. + * gcc.target/i386/avx10_2-bf16-1.c: Likewise. + * gcc.target/i386/avx10_2-convert-1.c: Likewise. + * gcc.target/i386/avx10_2-satcvt-1.c: Likewise. + * gcc.target/i386/avx512bf16-vcvtneps2bf16-1.c: Likewise. + * gcc.target/i386/avx512bf16vl-vcvtneps2bf16-1a.c: Likewise. + * gcc.target/i386/avx512bf16vl-vcvtneps2bf16-1b.c: Likewise. + * gcc.target/i386/avx512bitalg-vpshufbitqmb.c: Likewise. + * gcc.target/i386/avx512bw-vpcmpb-1.c: Likewise. + * gcc.target/i386/avx512bw-vpcmpub-1.c: Likewise. + * gcc.target/i386/avx512bw-vpcmpuw-1.c: Likewise. + * gcc.target/i386/avx512bw-vpcmpw-1.c: Likewise. + * gcc.target/i386/avx512dq-vcvtps2qq-1.c: Likewise. + * gcc.target/i386/avx512dq-vcvtps2uqq-1.c: Likewise. + * gcc.target/i386/avx512dq-vcvtqq2pd-1.c: Likewise. + * gcc.target/i386/avx512dq-vcvtqq2ps-1.c: Likewise. + * gcc.target/i386/avx512dq-vcvttps2qq-1.c: Likewise. + * gcc.target/i386/avx512dq-vcvttps2uqq-1.c: Likewise. + * gcc.target/i386/avx512dq-vcvtuqq2pd-1.c: Likewise. + * gcc.target/i386/avx512dq-vcvtuqq2ps-1.c: Likewise. + * gcc.target/i386/avx512dq-vextractf32x8-1.c: Likewise. + * gcc.target/i386/avx512dq-vextractf64x2-1.c: Likewise. + * gcc.target/i386/avx512dq-vextracti64x2-1.c: Likewise. + * gcc.target/i386/avx512dq-vfpclasspd-1.c: Likewise. + * gcc.target/i386/avx512dq-vfpclassps-1.c: Likewise. + * gcc.target/i386/avx512dq-vfpclasssd-1.c: Likewise. + * gcc.target/i386/avx512dq-vfpclassss-1.c: Likewise. + * gcc.target/i386/avx512dq-vpmullq-1.c: Likewise. + * gcc.target/i386/avx512dq-vpmullq-3.c: Likewise. + * gcc.target/i386/avx512f-pr100267-1.c: Likewise. + * gcc.target/i386/avx512f-vcmppd-1.c: Likewise. + * gcc.target/i386/avx512f-vcmpps-1.c: Likewise. + * gcc.target/i386/avx512f-vcvtps2pd-1.c: Likewise. + * gcc.target/i386/avx512f-vcvtsd2si-1.c: Likewise. + * gcc.target/i386/avx512f-vcvtsd2si64-1.c: Likewise. + * gcc.target/i386/avx512f-vcvtsd2usi-1.c: Likewise. + * gcc.target/i386/avx512f-vcvtsd2usi64-1.c: Likewise. + * gcc.target/i386/avx512f-vcvtsi2ss-1.c: Likewise. + * gcc.target/i386/avx512f-vcvtss2si-1.c: Likewise. + * gcc.target/i386/avx512f-vcvtss2si64-1.c: Likewise. + * gcc.target/i386/avx512f-vcvtss2usi-1.c: Likewise. + * gcc.target/i386/avx512f-vcvtss2usi64-1.c: Likewise. + * gcc.target/i386/avx512f-vcvttsd2si-1.c: Likewise. + * gcc.target/i386/avx512f-vcvttsd2si64-1.c: Likewise. + * gcc.target/i386/avx512f-vcvttsd2usi-1.c: Likewise. + * gcc.target/i386/avx512f-vcvttsd2usi64-1.c: Likewise. + * gcc.target/i386/avx512f-vcvttss2si-1.c: Likewise. + * gcc.target/i386/avx512f-vcvttss2si64-1.c: Likewise. + * gcc.target/i386/avx512f-vcvttss2usi-1.c: Likewise. + * gcc.target/i386/avx512f-vcvttss2usi64-1.c: Likewise. + * gcc.target/i386/avx512f-vextractf32x4-1.c: Likewise. + * gcc.target/i386/avx512f-vextractf64x4-1.c: Likewise. + * gcc.target/i386/avx512f-vextracti64x4-1.c: Likewise. + * gcc.target/i386/avx512f-vmovapd-1.c: Likewise. + * gcc.target/i386/avx512f-vmovaps-1.c: Likewise. + * gcc.target/i386/avx512f-vmovdqa64-1.c: Likewise. + * gcc.target/i386/avx512f-vpandnq-1.c: Likewise. + * gcc.target/i386/avx512f-vpbroadcastd-1.c: Likewise. + * gcc.target/i386/avx512f-vpbroadcastq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpd-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpeqq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpequq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpged-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpgeq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpgeud-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpgeuq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpled-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpleq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpleud-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpleuq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpltd-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpltq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpltud-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpltuq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpneqd-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpneqq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpnequd-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpnequq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpq-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpud-1.c: Likewise. + * gcc.target/i386/avx512f-vpcmpuq-1.c: Likewise. + * gcc.target/i386/avx512f-vrndscalepd-1.c: Likewise. + * gcc.target/i386/avx512f-vrndscaleps-1.c: Likewise. + * gcc.target/i386/avx512fp16-complex-fma.c: Likewise. + * gcc.target/i386/avx512fp16-vaddph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtpd2ph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtph2dq-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtph2pd-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtph2psx-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtph2qq-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtph2udq-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtph2uqq-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtph2uw-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtph2w-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtps2ph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtqq2ph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvttph2dq-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvttph2qq-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvttph2udq-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvttph2uqq-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvttph2uw-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvttph2w-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vcvtuqq2ph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vfcmaddcph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vfcmulcph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vfmaddcph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vfmulcph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vfpclassph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vfpclasssh-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vmulph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vrcpph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vrsqrtph-1a.c: Likewise. + * gcc.target/i386/avx512fp16-vsqrtph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vaddph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvtpd2ph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvtph2dq-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvtph2psx-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvtph2qq-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvtph2udq-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvtph2uqq-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvtph2uw-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvtph2w-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvtps2ph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvtqq2ph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvttph2dq-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvttph2udq-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvttph2uw-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvttph2w-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vcvtuqq2ph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vfcmaddcph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vfcmulcph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vfmaddcph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vfmulcph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vfpclassph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vmulph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vrcpph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vrsqrtph-1a.c: Likewise. + * gcc.target/i386/avx512fp16vl-vsqrtph-1a.c: Likewise. + * gcc.target/i386/avx512vl-pr100267-1.c: Likewise. + * gcc.target/i386/avx512vl-vcmppd-1.c: Likewise. + * gcc.target/i386/avx512vl-vcmpps-1.c: Likewise. + * gcc.target/i386/avx512vl-vcvtpd2ps-1.c: Likewise. + * gcc.target/i386/avx512vl-vcvtpd2udq-1.c: Likewise. + * gcc.target/i386/avx512vl-vcvttpd2udq-1.c: Likewise. + * gcc.target/i386/avx512vl-vcvttps2udq-1.c: Likewise. + * gcc.target/i386/avx512vl-vextractf32x4-1.c: Likewise. + * gcc.target/i386/avx512vl-vmovapd-1.c: Likewise. + * gcc.target/i386/avx512vl-vmovaps-1.c: Likewise. + * gcc.target/i386/avx512vl-vmovdqa64-1.c: Likewise. + * gcc.target/i386/avx512vl-vpcmpd-1.c: Likewise. + * gcc.target/i386/avx512vl-vpcmpeqq-1.c: Likewise. + * gcc.target/i386/avx512vl-vpcmpequq-1.c: Likewise. + * gcc.target/i386/avx512vl-vpcmpq-1.c: Likewise. + * gcc.target/i386/avx512vl-vpcmpud-1.c: Likewise. + * gcc.target/i386/avx512vl-vpcmpuq-1.c: Likewise. + * gcc.target/i386/pr122343-1a.c: New test. + * gcc.target/i386/pr122343-1b.c: Likewise. + * gcc.target/i386/pr122343-2a.c: Likewise. + * gcc.target/i386/pr122343-2b.c: Likewise. + * gcc.target/i386/pr122343-3.c: Likewise. + * gcc.target/i386/pr122343-4a.c: Likewise. + * gcc.target/i386/pr122343-4b.c: Likewise. + * gcc.target/i386/pr122343-5a.c: Likewise. + * gcc.target/i386/pr122343-5b.c: Likewise. + * gcc.target/i386/pr122343-6a.c: Likewise. + * gcc.target/i386/pr122343-6b.c: Likewise. + * gcc.target/i386/pr122343-7.c: Likewise. + 2025-12-06 Alexandre Oliva <oliva@adacore.com> PR rtl-optimization/122947 diff --git a/gcc/testsuite/g++.dg/template/sfinae-deleted-pr119343.C b/gcc/testsuite/g++.dg/template/sfinae-deleted-pr119343.C new file mode 100644 index 0000000..065ad60 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/sfinae-deleted-pr119343.C @@ -0,0 +1,31 @@ +// { dg-do compile { target c++11 } } +// PR c++/119343 - No SFINAE for deleted explicit specializations + +struct true_type { static constexpr bool value = true; }; +struct false_type { static constexpr bool value = false; }; + +struct X { + static void f()=delete; + template<int> static void g(); +}; +template<> void X::g<0>()=delete; +struct Y { + static void f(); + template<int> static void g(); +}; + +template<class T,class=void> +struct has_f : false_type {}; +template<class T> +struct has_f<T,decltype(void(T::f))> : true_type {}; + +static_assert(!has_f<X>::value, ""); +static_assert(has_f<Y>::value, ""); + +template<class T,class=void> +struct has_g0 : false_type {}; +template<class T> +struct has_g0<T,decltype(void(T::template g<0>))> : true_type {}; + +static_assert(!has_g0<X>::value, ""); +static_assert(has_g0<Y>::value, ""); diff --git a/gcc/testsuite/g++.dg/torture/pr123040.C b/gcc/testsuite/g++.dg/torture/pr123040.C new file mode 100644 index 0000000..3ba2d90 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr123040.C @@ -0,0 +1,61 @@ +// { dg-do compile } + +template <int kBytes, typename From, typename To> +void CopyBytes(From from, To to) { + __builtin_memcpy(to, from, kBytes); +} +template <typename From, typename To> void CopySameSize(From *from, To to) { + CopyBytes<sizeof(From)>(from, to); +} +template <typename> using MakeUnsigned = char; +template <typename Lane, int N> struct Simd { + using T = Lane; + static constexpr int kPrivateLanes = N; + template <typename NewT> using Rebind = Simd<NewT, 0>; +}; +template <class D> using TFromD = D::T; +template <class T, class D> using Rebind = D::template Rebind<T>; +template <class D> using RebindToUnsigned = Rebind<MakeUnsigned<D>, D>; +template <typename T, int> struct Vec128 { + using PrivateT = T; + static constexpr int kPrivateN = 6; + T raw[16]; +}; +template <class V> using DFromV = Simd<typename V::PrivateT, V::kPrivateN>; +template <class D> Vec128<TFromD<D>, D::kPrivateLanes> Zero(D); +template <class D> using VFromD = decltype(Zero(D())); +template <class D, class VFrom> VFromD<D> BitCast(D, VFrom v) { + VFromD<D> to; + CopySameSize(&v, to.raw); + return to; +} +template <int N> Vec128<signed char, N> And(Vec128<signed char, N> b) { + Vec128<signed char, N> a; + DFromV<decltype(a)> d; + RebindToUnsigned<decltype(d)> du; + auto au(a); + auto bu = BitCast(du, b); + for (int i = 0; i < N; ++i) + au.raw[i] &= bu.raw[i]; + return au; +} +void Or(Vec128<signed char, 16>); +template <int N> void IfVecThenElse(Vec128<signed char, N> yes) { + Vec128 __trans_tmp_2 = And(yes); + Or(__trans_tmp_2); +} +template <int N> void IfThenElseZero(Vec128<signed char, N> yes) { + IfVecThenElse(yes); +} +Vec128<signed char, 16> Abs_a; +char MaskedAbs___trans_tmp_5; +void MaskedAbs() { + Vec128<signed char, 16> __trans_tmp_4; + for (int i = 0; i < 16; ++i) { + MaskedAbs___trans_tmp_5 = Abs_a.raw[i] ? -Abs_a.raw[i] : 0; + Abs_a.raw[i] = MaskedAbs___trans_tmp_5; + } + __trans_tmp_4 = Abs_a; + Vec128 __trans_tmp_3 = __trans_tmp_4; + IfThenElseZero(__trans_tmp_3); +} diff --git a/gcc/testsuite/gcc.dg/pointer-counted-by-pr122982.c b/gcc/testsuite/gcc.dg/pointer-counted-by-pr122982.c new file mode 100644 index 0000000..1bad7f0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pointer-counted-by-pr122982.c @@ -0,0 +1,19 @@ +/* PR c/122982 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ + +int* f (int); + +struct __bounded_ptr { + int k; + int *buf __attribute__ ((counted_by (k))); +}; + +int* +f1 (int n) { return f (n); } + +void h1 (void) +{ + int *p = (struct __bounded_ptr) {3, f1 (3)}.buf; + __builtin_memset (p, 0, 3 * sizeof p); +} diff --git a/gcc/testsuite/gcc.dg/pr123018.c b/gcc/testsuite/gcc.dg/pr123018.c new file mode 100644 index 0000000..f1f701b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr123018.c @@ -0,0 +1,17 @@ +/* PR c/123018 */ +/* { dg-do compile } */ + +struct A { + int x : 8 __attribute__ ((vector_size (8))); /* { dg-error "bit-field 'x' has invalid type" } */ +}; +struct B { + float x : 8; /* { dg-error "bit-field 'x' has invalid type" } */ +}; +struct C { + int : 8 __attribute__ ((vector_size (8))); /* { dg-error "bit-field '\[^\n\r]*anonymous\[^\n\r]*' has invalid type" } */ + int x; +}; +struct D { + float : 8; /* { dg-error "bit-field '\[^\n\r]*anonymous\[^\n\r]*' has invalid type" } */ + int x; +}; diff --git a/gcc/testsuite/gcc.dg/tls/data-sections-1.c b/gcc/testsuite/gcc.dg/tls/data-sections-1.c new file mode 100644 index 0000000..c829256 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tls/data-sections-1.c @@ -0,0 +1,14 @@ +/* { dg-do run } */ +/* { dg-require-effective-target tls_runtime } */ +/* { dg-options "-fdata-sections" } */ +/* { dg-add-options tls } */ + +__thread int i = 1; + +int main (void) +{ + if (i != 1) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr123027.c b/gcc/testsuite/gcc.dg/torture/pr123027.c new file mode 100644 index 0000000..cba4cc9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr123027.c @@ -0,0 +1,20 @@ +/* { dg-do run } */ +/* { dg-options "-ffinite-math-only" } */ +/* { dg-add-options ieee } */ + +double a = 0.0; +double b = -0.0; + +int main() +{ + double min1 = a < b ? a : b; + double max1 = a > b ? a : b; + double min2 = b < a ? b : a; + double max2 = b > a ? b : a; + if (__builtin_copysign (1., min1) != -1. + || __builtin_copysign (1., max1) != -1. + || __builtin_copysign (1., min2) != 1. + || __builtin_copysign (1., max2) != 1.) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr46555.c b/gcc/testsuite/gcc.dg/tree-ssa/pr46555.c new file mode 100644 index 0000000..d4de7c2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr46555.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized-details -fdump-rtl-pro_and_epilogue" } */ +/* PR tree-optimization/46555 */ +/* Here should not remove the forwarder block (or rather recreate it and not + remove it again). This improves expansion to RTL as there is one less copy + (or constant formation) in some cases. In this case we also get the ability + to shrink wrap the function. */ + +int h(void); +int f(int a, int b, int c) +{ + if (a) + return 2; + h(); + if (b) + return 2; + h(); + if (c) + return 2; + h(); + return 4; +} + +/* { dg-final { scan-tree-dump-times "New forwarder block for edge" 1 "optimized" } } */ +/* Make sure we only have a PHI with 2 arguments here, 2 and 4. */ +/* { dg-final { scan-tree-dump "PHI <2..., 4...>|PHI <4..., 2...>" "optimized" } } */ +/* Make sure we can shrink wrap the function now too. */ +/* { dg-final { scan-rtl-dump "Performing shrink-wrapping" "pro_and_epilogue" { target { { { i?86-*-* x86_64-*-* } && { ! ia32 } } || { powerpc*-*-* aarch64*-*-* riscv*-*-* arm*-*-* } } } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr123038.c b/gcc/testsuite/gcc.dg/vect/pr123038.c new file mode 100644 index 0000000..bca831f --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr123038.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ + +unsigned char f(int b) +{ + for (int a = 0; a < 10; a += 1) + b = __builtin_ffs(b); + return b; +} diff --git a/gcc/testsuite/gcc.target/aarch64/pr123026.c b/gcc/testsuite/gcc.target/aarch64/pr123026.c new file mode 100644 index 0000000..4dcce8a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/pr123026.c @@ -0,0 +1,21 @@ +/* { dg-do run } */ +/* { dg-additional-options "-O3 -march=armv8-a -std=c99" } */ + +#include <stdbool.h> + +int g; + +__attribute__ ((noipa)) void +foo(bool a) { + for (int i = 0; i < 4; i++) + if (!i || a) + g += 1; +} + +int main() +{ + foo(0); + if (g != 1) + __builtin_abort(); + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store.c b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store.c index 1539f58..39db13b 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pfalse-store.c @@ -46,8 +46,5 @@ ALL_DATA (st2, x2_t) ALL_DATA (st3, x3_t) ALL_DATA (st4, x4_t) -/* FIXME: Currently, st1/2/3/4 are not folded with a pfalse - predicate, which is the reason for the 48 missing cases below. Once - folding is implemented for these intrinsics, the sum should be 60. */ -/* { dg-final { scan-assembler-times {\t.cfi_startproc\n\tret\n} 12 } } */ +/* { dg-final { scan-assembler-times {\t.cfi_startproc\n\tret\n} 60 } } */ /* { dg-final { scan-assembler-times {\t.cfi_startproc\n} 60 } } */ diff --git a/gcc/testsuite/gcc.target/i386/avx2-vpcmpgtq-1.c b/gcc/testsuite/gcc.target/i386/avx2-vpcmpgtq-1.c index 7a98380..5e6f431 100644 --- a/gcc/testsuite/gcc.target/i386/avx2-vpcmpgtq-1.c +++ b/gcc/testsuite/gcc.target/i386/avx2-vpcmpgtq-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-mavx2 -O2" } */ +/* { dg-options "-mavx2 -O2 -fno-fuse-ops-with-volatile-access" } */ /* { dg-final { scan-assembler "vpcmpgtq\[ \\t\]+\[^\n\]*%ymm\[0-9\]" } } */ #include <immintrin.h> diff --git a/gcc/testsuite/gcc.target/i386/pr121230.c b/gcc/testsuite/gcc.target/i386/pr121230.c new file mode 100644 index 0000000..67c9c5c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr121230.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O3 -march=athlon-xp -mfpmath=387 -fexcess-precision=standard" } */ + +typedef struct { + float a; + float b; +} f32_2; + +f32_2 add32_2(f32_2 x, f32_2 y) { + return (f32_2){ x.a + y.a, x.b + y.b}; +} + +/* We do not want the vectorizer to vectorize the store and/or the + conversion (with IA32 we do not support V2SF add) given that spills + FP regs to reload them to XMM. */ +/* { dg-final { scan-assembler-not "movss\[ \\t\]+\[0-9\]*\\\(%esp\\\), %xmm" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr123027.c b/gcc/testsuite/gcc.target/i386/pr123027.c new file mode 100644 index 0000000..b7effac --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr123027.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -msse -mfpmath=sse -ffinite-math-only" } */ + +float foo (float a, float b) +{ + return a < b ? a : b; +} + +float bar (float a, float b) +{ + return a > b ? a : b; +} + +/* { dg-final { scan-assembler-times "minss" 1 } } */ +/* { dg-final { scan-assembler-times "maxss" 1 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/p9-vec-length-epil-8.c b/gcc/testsuite/gcc.target/powerpc/p9-vec-length-epil-8.c index 34a2c8e..5dff0d0 100644 --- a/gcc/testsuite/gcc.target/powerpc/p9-vec-length-epil-8.c +++ b/gcc/testsuite/gcc.target/powerpc/p9-vec-length-epil-8.c @@ -13,5 +13,5 @@ #include "p9-vec-length-8.h" -/* { dg-final { scan-assembler-times {\mlxvl\M} 16 } } */ +/* { dg-final { scan-assembler-times {\mlxvl\M} 14 } } */ /* { dg-final { scan-assembler-times {\mstxvl\M} 7 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/pragma-target-1.c b/gcc/testsuite/gcc.target/riscv/pragma-target-1.c new file mode 100644 index 0000000..d1a0600 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pragma-target-1.c @@ -0,0 +1,59 @@ +/* Test for #pragma GCC target and push/pop options support in RISC-V */ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc -mabi=lp64d -O2" } */ + +/* Default compilation options - no vector */ +void default_func(void) { +#ifdef __riscv_vector + __builtin_abort(); /* Should not have vector by default */ +#endif +} + +/* Change target to enable vector */ +#pragma GCC push_options +#pragma GCC target("arch=rv64gcv") +void vector_func(void) { +#ifndef __riscv_vector + __builtin_abort(); /* Should have vector here */ +#endif +} +#pragma GCC pop_options + +/* Back to default - no vector */ +void after_pop_func(void) { +#ifdef __riscv_vector + __builtin_abort(); /* Should not have vector after pop */ +#endif +} + +/* Test multiple push/pop levels */ +#pragma GCC push_options +#pragma GCC target("arch=rv64gc") +void base_func(void) { +#ifdef __riscv_vector + __builtin_abort(); /* Should not have vector */ +#endif +} + +#pragma GCC push_options +#pragma GCC target("arch=rv64gcv") +void nested_vector_func(void) { +#ifndef __riscv_vector + __builtin_abort(); /* Should have vector here */ +#endif +} +#pragma GCC pop_options + +void after_nested_pop_func(void) { +#ifdef __riscv_vector + __builtin_abort(); /* Should not have vector after nested pop */ +#endif +} +#pragma GCC pop_options + +/* Final function should be back to original default */ +void final_func(void) { +#ifdef __riscv_vector + __builtin_abort(); /* Should not have vector */ +#endif +} diff --git a/gcc/testsuite/gcc.target/riscv/pragma-target-2.c b/gcc/testsuite/gcc.target/riscv/pragma-target-2.c new file mode 100644 index 0000000..077bcdd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pragma-target-2.c @@ -0,0 +1,26 @@ +/* Test for #pragma GCC target with tune parameter */ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc -mabi=lp64d -mtune=rocket -O2" } */ + +void default_tune(void) { + /* Default tune is rocket */ +} + +#pragma GCC push_options +#pragma GCC target("tune=sifive-7-series") +void sifive_tune(void) { + /* Tune should be sifive-7-series */ +} +#pragma GCC pop_options + +void back_to_rocket(void) { + /* Tune should be back to rocket */ +} + +#pragma GCC target("arch=rv64gcv;tune=generic") +void combined_options(void) { +#ifndef __riscv_vector + __builtin_abort(); /* Should have vector */ +#endif + /* Tune should be generic */ +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-1.c new file mode 100644 index 0000000..923c1f8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */ + +void __attribute__ (( target ("max-vectorization"))) +foo (char *restrict a, int *restrict b, short *restrict c, + int *restrict d, int stride) +{ + if (stride <= 1) + return; + + for (int i = 0; i < 3; i++) + { + int res = c[i]; + int t = b[d[i]]; + if (a[c[i]] != 0) + res = t * b[d[i]]; + c[i] = res; + } +} + +/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-2.c new file mode 100644 index 0000000..fc5c2ad --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/max-vect-2.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -mmax-vectorization -fdump-tree-vect-details" } */ + +void +foo (char *restrict a, int *restrict b, short *restrict c, + int *restrict d, int stride) +{ + if (stride <= 1) + return; + + for (int i = 0; i < 3; i++) + { + int res = c[i]; + int t = b[d[i]]; + if (a[c[i]] != 0) + res = t * b[d[i]]; + c[i] = res; + } +} + +/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122635-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122635-1.c new file mode 100644 index 0000000..0beb3d7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122635-1.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv64gcv_zvl256b -mabi=lp64d -mrvv-vector-bits=zvl -mno-autovec-segment" } */ + +typedef struct { + int a[6]; + float b[3]; +} c; + +int d(c *e) { + int f =0; + for (; f < 3; f++) { + e->a[2 * f] = e->b[f]; + e->a[2 * f + 1] = -e->a[2 * f]; + e->a[2 * f] = f + 3 * e->a[2 * f]; + e->a[2 * f + 1] = f + 3 * e->a[2 * f + 1]; + } + return 0; +} + +/* { dg-final { scan-assembler-not "vsetivli.*zero,0" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122635-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122635-2.c new file mode 100644 index 0000000..0de69b5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr122635-2.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv64gcv_zvl256b -mabi=lp64d -mrvv-vector-bits=zvl -mno-autovec-segment" } */ + +typedef struct { + int A[6]; + float b[]; +} a; + +int b(a *a) { + int b = 0; + for (; b < 3; b++) { + a->A[2 * b] = a->b[b] - b + a->A[2 * b]; + a->A[2 * b + 1] = b * a->A[2 * b + 1]; + } + return 0; +} + +/* { dg-final { scan-assembler-not "vsetivli.*zero,0" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123022-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123022-2.c new file mode 100644 index 0000000..0562b56 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123022-2.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv64gcv_zvl512b -mabi=lp64d -mrvv-vector-bits=zvl -fsigned-char" } */ + +#include "pr123022.c" + +/* { dg-final { scan-assembler-not "vset.*zero,1," } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123022.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123022.c new file mode 100644 index 0000000..1f5f165 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123022.c @@ -0,0 +1,21 @@ +/* { dg-do run } */ +/* { dg-require-effective-target rvv_zvl512b_ok } */ +/* { dg-options "-O3 -march=rv64gcv_zvl512b -mabi=lp64d -mrvv-vector-bits=zvl -fsigned-char" } */ +unsigned e[2][2]; +long a; +char c[2]; + +int +main () +{ + long long b; + c[1] = 3; + for (unsigned h = 0; h < 2; h++) + for (int i = c[0]; i < 5; i += 5) + for (int j = 0; j < 219; j++) + a = c[h] ? e[h][h] + 3326195747 : 0; + + b = a; + if (b != 3326195747) + __builtin_abort (); +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123074.C b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123074.C new file mode 100644 index 0000000..d203477 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123074.C @@ -0,0 +1,124 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv64gcv_zvl256b -mabi=lp64d -mrvv-vector-bits=zvl -mrvv-max-lmul=m2 -fpermissive -Wno-return-type" } */ + +namespace std { +template <typename _Iterator> _Iterator __miter_base(_Iterator); +template <typename _Default, typename, template <typename> class> +struct __detector { + using type = _Default; +}; +template <typename _Default, template <typename> class _Op> +using __detected_or = __detector<_Default, void, _Op>; +template <typename _Default, template <typename> class _Op> +using __detected_or_t = typename __detected_or<_Default, _Op>::type; +template <typename _Tp> class allocator { +public: + typedef _Tp value_type; +}; +template <typename> struct pointer_traits { + template <typename _Up> using rebind = _Up *; +}; +} // namespace std +namespace __gnu_cxx { +template <typename _Iterator, typename> class __normal_iterator { +public: + _Iterator base(); +}; +} // namespace __gnu_cxx +namespace std { +template <bool, typename _OutIter, typename _InIter> +void __assign_one(_OutIter __out, _InIter __in) { + *__out = *__in; +} +template <bool _IsMove, typename _BI1, typename _BI2> +__copy_move_backward_a2(_BI1 __first, _BI1 __last, _BI2 __result) { /* { dg-warning "with no type" "" } */ + while (__first != __last) { + --__last; + --__result; + __assign_one<_IsMove>(__result, __last); + } +} +template <bool _IsMove, typename _BI1, typename _BI2> +__copy_move_backward_a1(_BI1 __first, _BI1 __last, _BI2 __result) { /* { dg-warning "with no type" "" } */ + __copy_move_backward_a2<_IsMove>(__first, __last, __result); +} +template <bool _IsMove, typename _II, typename _OI> +__copy_move_backward_a(_II __first, _II __last, _OI __result) { /* { dg-warning "with no type" "" } */ + __copy_move_backward_a1<_IsMove>(__first, __last, __result); +} +template <typename _BI1, typename _BI2> +move_backward(_BI1 __first, _BI1 __last, _BI2 __result) { /* { dg-warning "with no type" "" } */ + __copy_move_backward_a<true>(__first, __miter_base(__last), __result); +} +struct __allocator_traits_base { + template <typename _Tp> using __pointer = typename _Tp::pointer; + template <typename _Tp> using __c_pointer = typename _Tp::const_pointer; +}; +template <typename _Alloc> struct allocator_traits : __allocator_traits_base { + typedef typename _Alloc::value_type value_type; + using pointer = __detected_or_t<value_type *, __pointer>; + template <template <typename> class, typename _Tp> struct _Ptr { + using type = typename pointer_traits<pointer>::rebind<_Tp>; + }; + using const_pointer = typename _Ptr<__c_pointer, value_type>::type; +}; +} // namespace std +namespace __gnu_cxx { +template <typename _Alloc> +struct __alloc_traits : std::allocator_traits<_Alloc> {}; +} // namespace __gnu_cxx +namespace std { +template <typename, typename _Alloc> struct _Vector_base { + typedef __gnu_cxx::__alloc_traits<_Alloc> _Tp_alloc_type; + typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer pointer; + struct { + pointer _M_finish; + } _M_impl; +}; +template <typename _Tp, typename _Alloc = allocator<_Tp>> +class vector : _Vector_base<_Tp, _Alloc> { + typedef _Vector_base<_Tp, _Alloc> _Base; + typedef typename _Base::_Tp_alloc_type _Alloc_traits; + +public: + typedef _Tp value_type; + typedef typename _Base::pointer pointer; + typedef typename _Alloc_traits::const_pointer const_pointer; + typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator; + typedef __gnu_cxx::__normal_iterator<const_pointer, vector> const_iterator; + iterator begin(); + iterator insert(const_iterator, const value_type &); + struct _Temporary_value {}; + template <typename _Arg> void _M_insert_aux(iterator, _Arg &&); +}; +template <typename _Tp, typename _Alloc> +typename vector<_Tp, _Alloc>::iterator +vector<_Tp, _Alloc>::insert(const_iterator, const value_type &) { + auto __pos = begin(); + _Temporary_value __x_copy; + _M_insert_aux(__pos, __x_copy); +} +template <typename _Tp, typename _Alloc> +template <typename _Arg> +void vector<_Tp, _Alloc>::_M_insert_aux(iterator __position, _Arg &&) { + move_backward(__position.base(), this->_M_impl._M_finish, + this->_M_impl._M_finish); +} +namespace internals { +struct distributing { + distributing &operator=(const distributing &); + int global_row; + *constraints; /* { dg-warning "with no type" "" } */ +}; +distributing &distributing::operator=(const distributing &in) { + global_row = in.global_row; + return; /* { dg-warning "return-statement with no value" "" } */ +} +insert_index(vector<distributing> my_indices) { /* { dg-warning "with no type" "" } */ + typedef vector<distributing>::iterator index_iterator; + index_iterator pos; + distributing row_value; + my_indices.insert(pos, row_value); +} +} // namespace internals +} // namespace std diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1-run.c new file mode 100644 index 0000000..b3bf8da --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1-run.c @@ -0,0 +1,49 @@ +/* { dg-do run } */ +/* { dg-require-effective-target riscv_v_ok } */ + +char p[128]; + +bool __attribute__((noipa)) +fand (int n) +{ + bool r = true; + for (int i = 0; i < n; ++i) + r &= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fior (int n) +{ + bool r = false; + for (int i = 0; i < n; ++i) + r |= (p[i] != 0); + return r; +} + +int main() +{ + __builtin_memset (p, 1, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (!fand (n)) + __builtin_abort (); + + p[0] = 0; + for (int n = 1; n < 77; ++n) + if (fand (n)) + __builtin_abort (); + + __builtin_memset (p, 0, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (fior (n)) + __builtin_abort (); + + p[0] = 1; + for (int n = 1; n < 77; ++n) + if (!fior (n)) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1.c new file mode 100644 index 0000000..b8c4f22 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-1.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */ + +char p[128]; + +bool __attribute__((noipa)) +fand (int n) +{ + bool r = true; + for (int i = 0; i < 16; ++i) + r &= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fior (int n) +{ + bool r = false; + for (int i = 0; i < 16; ++i) + r |= (p[i] != 0); + return r; +} + +/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */ +/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2-run.c new file mode 100644 index 0000000..1a64b2b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2-run.c @@ -0,0 +1,49 @@ +/* { dg-do run } */ +/* { dg-require-effective-target riscv_v_ok } */ + +short p[128]; + +bool __attribute__((noipa)) +fand (int n) +{ + bool r = true; + for (int i = 0; i < n; ++i) + r &= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fior (int n) +{ + bool r = false; + for (int i = 0; i < n; ++i) + r |= (p[i] != 0); + return r; +} + +int main() +{ + __builtin_memset (p, 1, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (!fand (n)) + __builtin_abort (); + + p[0] = 0; + for (int n = 1; n < 77; ++n) + if (fand (n)) + __builtin_abort (); + + __builtin_memset (p, 0, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (fior (n)) + __builtin_abort (); + + p[0] = 1; + for (int n = 1; n < 77; ++n) + if (!fior (n)) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2.c new file mode 100644 index 0000000..868f91b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-2.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */ + +short p[128]; + +bool __attribute__((noipa)) +fand () +{ + bool r = true; + for (int i = 0; i < 16; ++i) + r &= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fior () +{ + bool r = false; + for (int i = 0; i < 16; ++i) + r |= (p[i] != 0); + return r; +} + +/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */ +/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3-run.c new file mode 100644 index 0000000..693a9118 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3-run.c @@ -0,0 +1,49 @@ +/* { dg-do run } */ +/* { dg-require-effective-target riscv_v_ok } */ + +int p[128]; + +bool __attribute__((noipa)) +fand (int n) +{ + bool r = true; + for (int i = 0; i < n; ++i) + r &= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fior (int n) +{ + bool r = false; + for (int i = 0; i < n; ++i) + r |= (p[i] != 0); + return r; +} + +int main() +{ + __builtin_memset (p, 1, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (!fand (n)) + __builtin_abort (); + + p[0] = 0; + for (int n = 1; n < 77; ++n) + if (fand (n)) + __builtin_abort (); + + __builtin_memset (p, 0, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (fior (n)) + __builtin_abort (); + + p[0] = 1; + for (int n = 1; n < 77; ++n) + if (!fior (n)) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3.c new file mode 100644 index 0000000..d1a286b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-3.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */ + +int p[128]; + +bool __attribute__((noipa)) +fand () +{ + bool r = true; + for (int i = 0; i < 16; ++i) + r &= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fior () +{ + bool r = false; + for (int i = 0; i < 16; ++i) + r |= (p[i] != 0); + return r; +} + +/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */ +/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4-run.c new file mode 100644 index 0000000..b55925e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4-run.c @@ -0,0 +1,49 @@ +/* { dg-do run } */ +/* { dg-require-effective-target riscv_v_ok } */ + +long long p[128]; + +bool __attribute__((noipa)) +fand (int n) +{ + bool r = true; + for (int i = 0; i < n; ++i) + r &= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fior (int n) +{ + bool r = false; + for (int i = 0; i < n; ++i) + r |= (p[i] != 0); + return r; +} + +int main() +{ + __builtin_memset (p, 1, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (!fand (n)) + __builtin_abort (); + + p[0] = 0; + for (int n = 1; n < 77; ++n) + if (fand (n)) + __builtin_abort (); + + __builtin_memset (p, 0, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (fior (n)) + __builtin_abort (); + + p[0] = 1; + for (int n = 1; n < 77; ++n) + if (!fior (n)) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4.c new file mode 100644 index 0000000..34a44b1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-4.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */ + +long long p[128]; + +bool __attribute__((noipa)) +fand () +{ + bool r = true; + for (int i = 0; i < 16; ++i) + r &= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fior () +{ + bool r = false; + for (int i = 0; i < 16; ++i) + r |= (p[i] != 0); + return r; +} + +/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */ +/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5-run.c new file mode 100644 index 0000000..95570ac --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5-run.c @@ -0,0 +1,47 @@ +/* { dg-do run } */ +/* { dg-require-effective-target riscv_v_ok } */ + +char p[128]; + +bool __attribute__((noipa)) +fxort (int n) +{ + bool r = true; + for (int i = 0; i < n; ++i) + r ^= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fxorf (int n) +{ + bool r = false; + for (int i = 0; i < n; ++i) + r ^= (p[i] != 0); + return r; +} + +int main() +{ + __builtin_memset (p, 1, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (fxort (n) != !(n & 1)) + __builtin_abort (); + + for (int n = 0; n < 77; ++n) + if (fxorf (n) != (n & 1)) + __builtin_abort (); + + __builtin_memset (p, 0, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (!fxort (n)) + __builtin_abort (); + + for (int n = 0; n < 77; ++n) + if (fxorf (n)) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5.c new file mode 100644 index 0000000..f179970 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-5.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */ + +char p[128]; + +bool __attribute__((noipa)) +fxort () +{ + bool r = true; + for (int i = 0; i < 16; ++i) + r ^= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fxorf () +{ + bool r = false; + for (int i = 0; i < 16; ++i) + r ^= (p[i] != 0); + return r; +} + +/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */ +/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6-run.c new file mode 100644 index 0000000..267485b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6-run.c @@ -0,0 +1,47 @@ +/* { dg-do run } */ +/* { dg-require-effective-target riscv_v_ok } */ + +short p[128]; + +bool __attribute__((noipa)) +fxort (int n) +{ + bool r = true; + for (int i = 0; i < n; ++i) + r ^= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fxorf (int n) +{ + bool r = false; + for (int i = 0; i < n; ++i) + r ^= (p[i] != 0); + return r; +} + +int main() +{ + __builtin_memset (p, 1, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (fxort (n) != !(n & 1)) + __builtin_abort (); + + for (int n = 0; n < 77; ++n) + if (fxorf (n) != (n & 1)) + __builtin_abort (); + + __builtin_memset (p, 0, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (!fxort (n)) + __builtin_abort (); + + for (int n = 0; n < 77; ++n) + if (fxorf (n)) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6.c new file mode 100644 index 0000000..8486c6b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-6.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */ + +short p[128]; + +bool __attribute__((noipa)) +fxort () +{ + bool r = true; + for (int i = 0; i < 16; ++i) + r ^= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fxorf () +{ + bool r = false; + for (int i = 0; i < 16; ++i) + r ^= (p[i] != 0); + return r; +} + +/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */ +/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7-run.c new file mode 100644 index 0000000..242147b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7-run.c @@ -0,0 +1,47 @@ +/* { dg-do run } */ +/* { dg-require-effective-target riscv_v_ok } */ + +int p[128]; + +bool __attribute__((noipa)) +fxort (int n) +{ + bool r = true; + for (int i = 0; i < n; ++i) + r ^= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fxorf (int n) +{ + bool r = false; + for (int i = 0; i < n; ++i) + r ^= (p[i] != 0); + return r; +} + +int main() +{ + __builtin_memset (p, 1, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (fxort (n) != !(n & 1)) + __builtin_abort (); + + for (int n = 0; n < 77; ++n) + if (fxorf (n) != (n & 1)) + __builtin_abort (); + + __builtin_memset (p, 0, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (!fxort (n)) + __builtin_abort (); + + for (int n = 0; n < 77; ++n) + if (fxorf (n)) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7.c new file mode 100644 index 0000000..cc14996 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-7.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */ + +int p[128]; + +bool __attribute__((noipa)) +fxort () +{ + bool r = true; + for (int i = 0; i < 16; ++i) + r ^= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fxorf () +{ + bool r = false; + for (int i = 0; i < 16; ++i) + r ^= (p[i] != 0); + return r; +} + +/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */ +/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8-run.c new file mode 100644 index 0000000..bf73da5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8-run.c @@ -0,0 +1,47 @@ +/* { dg-do run } */ +/* { dg-require-effective-target riscv_v_ok } */ + +long long p[128]; + +bool __attribute__((noipa)) +fxort (int n) +{ + bool r = true; + for (int i = 0; i < n; ++i) + r ^= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fxorf (int n) +{ + bool r = false; + for (int i = 0; i < n; ++i) + r ^= (p[i] != 0); + return r; +} + +int main() +{ + __builtin_memset (p, 1, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (fxort (n) != !(n & 1)) + __builtin_abort (); + + for (int n = 0; n < 77; ++n) + if (fxorf (n) != (n & 1)) + __builtin_abort (); + + __builtin_memset (p, 0, sizeof(p)); + + for (int n = 0; n < 77; ++n) + if (!fxort (n)) + __builtin_abort (); + + for (int n = 0; n < 77; ++n) + if (fxorf (n)) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8.c new file mode 100644 index 0000000..6842f39 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/reduc/reduc-bool-8.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-march=rv64gcv -mabi=lp64d -fdump-tree-vect-details" } */ + +long long p[128]; + +bool __attribute__((noipa)) +fxort () +{ + bool r = true; + for (int i = 0; i < 16; ++i) + r ^= (p[i] != 0); + return r; +} + +bool __attribute__((noipa)) +fxorf () +{ + bool r = false; + for (int i = 0; i < 16; ++i) + r ^= (p[i] != 0); + return r; +} + +/* { dg-final { scan-tree-dump-times "optimized: loop vectorized" 2 "vect" } } */ +/* { dg-final { scan-assembler-times {vcpop\.m\s+[atx][0-9]+,\s*v[0-9]+} 2 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c index 14a961d..1b7a0d8 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c @@ -29,3 +29,4 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-times {vnmsub.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmseq.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmsne.vx} 1 } } */ +/* { dg-final { scan-assembler-times {vmslt.vx} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c index 738caa8..8e2c631 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c @@ -29,3 +29,4 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-times {vnmsub.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmseq.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmsne.vx} 1 } } */ +/* { dg-final { scan-assembler-times {vmslt.vx} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c index 1e7a977..a16623e 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c @@ -32,3 +32,4 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-times {vnmsub.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmseq.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmsne.vx} 1 } } */ +/* { dg-final { scan-assembler-times {vmslt.vx} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c index 70257d3..be50b83 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c @@ -29,3 +29,4 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-times {vnmsub.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmseq.vx} 1 } } */ /* { dg-final { scan-assembler-times {vmsne.vx} 1 } } */ +/* { dg-final { scan-assembler-times {vmslt.vx} 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c index bced156..fb50bae 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c @@ -29,3 +29,4 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-not {vnmsub.vx} } } */ /* { dg-final { scan-assembler-not {vmseq.vx} } } */ /* { dg-final { scan-assembler-not {vmsne.vx} } } */ +/* { dg-final { scan-assembler-not {vmslt.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c index cfb52fb..d79e0e0 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c @@ -29,3 +29,4 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-not {vnmsub.vx} } } */ /* { dg-final { scan-assembler-not {vmseq.vx} } } */ /* { dg-final { scan-assembler-not {vmsne.vx} } } */ +/* { dg-final { scan-assembler-not {vmslt.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c index 31846ef..6cdaf5d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c @@ -29,3 +29,4 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-not {vnmsub.vx} } } */ /* { dg-final { scan-assembler-not {vmseq.vx} } } */ /* { dg-final { scan-assembler-not {vmsne.vx} } } */ +/* { dg-final { scan-assembler-not {vmslt.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c index ea28e2b..9e3879a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c @@ -29,3 +29,4 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-not {vnmsub.vx} } } */ /* { dg-final { scan-assembler-not {vmseq.vx} } } */ /* { dg-final { scan-assembler-not {vmsne.vx} } } */ +/* { dg-final { scan-assembler-not {vmslt.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c index e3cddc4..e3ef3e3 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c @@ -29,3 +29,4 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-not {vnmsub.vx} } } */ /* { dg-final { scan-assembler-not {vmseq.vx} } } */ /* { dg-final { scan-assembler-not {vmsne.vx} } } */ +/* { dg-final { scan-assembler-not {vmslt.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c index c5cce62..20039c7 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c @@ -28,4 +28,5 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-not {vmadd.vx} } } */ /* { dg-final { scan-assembler-not {vnmsub.vx} } } */ /* { dg-final { scan-assembler-not {vmseq.vx} } } */ +/* { dg-final { scan-assembler-not {vmslt.vx} } } */ /* { dg-final { scan-assembler-not {vmsne.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c index 6ef8681..c973ea7 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c @@ -29,3 +29,4 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-not {vnmsub.vx} } } */ /* { dg-final { scan-assembler-not {vmseq.vx} } } */ /* { dg-final { scan-assembler-not {vmsne.vx} } } */ +/* { dg-final { scan-assembler-not {vmslt.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c index cc78959..e781c62 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c @@ -29,3 +29,4 @@ TEST_TERNARY_VX_SIGNED_0(T) /* { dg-final { scan-assembler-not {vnmsub.vx} } } */ /* { dg-final { scan-assembler-not {vmseq.vx} } } */ /* { dg-final { scan-assembler-not {vmsne.vx} } } */ +/* { dg-final { scan-assembler-not {vmslt.vx} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h index 764f301..a9bba40 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h @@ -404,6 +404,7 @@ DEF_AVG_CEIL(int32_t, int64_t) DEF_VX_BINARY_CASE_0_WRAP(T, %, rem) \ DEF_VX_BINARY_CASE_0_WRAP(T, ==, eq) \ DEF_VX_BINARY_CASE_0_WRAP(T, !=, ne) \ + DEF_VX_BINARY_CASE_0_WRAP(T, <, lt) \ DEF_VX_BINARY_CASE_2_WRAP(T, MAX_FUNC_0_WARP(T), max) \ DEF_VX_BINARY_CASE_2_WRAP(T, MAX_FUNC_1_WARP(T), max) \ DEF_VX_BINARY_CASE_2_WRAP(T, MIN_FUNC_0_WARP(T), min) \ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h index d4834c7..fad479a 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h @@ -6566,4 +6566,140 @@ uint64_t TEST_BINARY_DATA(uint64_t, ltu)[][3][N] = }, }; +int8_t TEST_BINARY_DATA(int8_t, lt)[][3][N] = +{ + { + { 127 }, + { + 0, 0, 0, 0, + -1, -1, -1, -1, + 127, 127, 127, 127, + -128, -128, -128, -128, + }, + { + 1, 1, 1, 1, + 1, 1, 1, 1, + 0, 0, 0, 0, + 1, 1, 1, 1, + }, + }, + { + { -1 }, + { + 0, 0, 0, 0, + 1, 1, 1, 1, + -2, -2, -2, -2, + -128, -128, -128, -128, + }, + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 1, 1, 1, 1, + 1, 1, 1, 1, + }, + }, +}; + +int16_t TEST_BINARY_DATA(int16_t, lt)[][3][N] = +{ + { + { 32767 }, + { + 0, 0, 0, 0, + -1, -1, -1, -1, + 32767, 32767, 32767, 32767, + -32768, -32768, -32768, -32768, + }, + { + 1, 1, 1, 1, + 1, 1, 1, 1, + 0, 0, 0, 0, + 1, 1, 1, 1, + }, + }, + { + { -1 }, + { + 0, 0, 0, 0, + 1, 1, 1, 1, + -2, -2, -2, -2, + -32768, -32768, -32768, -32768, + }, + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 1, 1, 1, 1, + 1, 1, 1, 1, + }, + }, +}; + +int32_t TEST_BINARY_DATA(int32_t, lt)[][3][N] = +{ + { + { 2147483647 }, + { + 0, 0, 0, 0, + -1, -1, -1, -1, + 2147483647, 2147483647, 2147483647, 2147483647, + -2147483648, -2147483648, -2147483648, -2147483648, + }, + { + 1, 1, 1, 1, + 1, 1, 1, 1, + 0, 0, 0, 0, + 1, 1, 1, 1, + }, + }, + { + { -1 }, + { + 0, 0, 0, 0, + 1, 1, 1, 1, + -2, -2, -2, -2, + -2147483648, -2147483648, -2147483648, -2147483648, + }, + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 1, 1, 1, 1, + 1, 1, 1, 1, + }, + }, +}; + +int64_t TEST_BINARY_DATA(int64_t, lt)[][3][N] = +{ + { + { 9223372036854775807ll }, + { + 0, 0, 0, 0, + -1, -1, -1, -1, + 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll, + -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, + }, + { + 1, 1, 1, 1, + 1, 1, 1, 1, + 0, 0, 0, 0, + 1, 1, 1, 1, + }, + }, + { + { -1 }, + { + 0, 0, 0, 0, + 1, 1, 1, 1, + -2, -2, -2, -2, + -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, + }, + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 1, 1, 1, 1, + 1, 1, 1, 1, + }, + }, +}; + #endif diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i16.c new file mode 100644 index 0000000..865a2f8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i16.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */ + +#include "vx_binary.h" +#include "vx_binary_data.h" + +#define T int16_t +#define NAME lt + +DEF_VX_BINARY_CASE_0_WRAP(T, <, NAME) + +#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vx_binary_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i32.c new file mode 100644 index 0000000..eeb2a66 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i32.c @@ -0,0 +1,16 @@ + +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */ + +#include "vx_binary.h" +#include "vx_binary_data.h" + +#define T int32_t +#define NAME lt + +DEF_VX_BINARY_CASE_0_WRAP(T, <, NAME) + +#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vx_binary_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i64.c new file mode 100644 index 0000000..c3a2052 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i64.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */ + +#include "vx_binary.h" +#include "vx_binary_data.h" + +#define T int64_t +#define NAME lt + +DEF_VX_BINARY_CASE_0_WRAP(T, <, NAME) + +#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vx_binary_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i8.c new file mode 100644 index 0000000..92a84f2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vmslt-run-1-i8.c @@ -0,0 +1,15 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */ + +#include "vx_binary.h" +#include "vx_binary_data.h" + +#define T int8_t +#define NAME lt + +DEF_VX_BINARY_CASE_0_WRAP(T, <, NAME) + +#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME) +#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n) + +#include "vx_binary_run.h" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp index 877cc55..e128b17 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp +++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp @@ -47,7 +47,7 @@ dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/xandesvector/*.\[cS\]]] \ "" $CFLAGS gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/vsetvl/*.\[cS\]]] \ "" $CFLAGS -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/*.\[cS\]]] \ +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/*.\[cCS\]]] \ "-O3 -ftree-vectorize" $CFLAGS dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/vls/*.\[cS\]]] \ "-O3 -ftree-vectorize -mrvv-vector-bits=scalable" $CFLAGS diff --git a/gcc/testsuite/gfortran.dg/assumed_charlen_dummy.f90 b/gcc/testsuite/gfortran.dg/assumed_charlen_dummy.f90 index 04f0b9f..2e0e77c 100644 --- a/gcc/testsuite/gfortran.dg/assumed_charlen_dummy.f90 +++ b/gcc/testsuite/gfortran.dg/assumed_charlen_dummy.f90 @@ -1,4 +1,5 @@ ! { dg-do compile } +! { dg-options " " } ! Test the fix for PR fortran/39893. ! Original testcase provided by Deji Akingunola. ! Reduced testcase provided by Dominique d'Humieres. diff --git a/gcc/testsuite/gfortran.dg/automatic_char_len_1.f90 b/gcc/testsuite/gfortran.dg/automatic_char_len_1.f90 index 3ccfcb7..7f102b7 100644 --- a/gcc/testsuite/gfortran.dg/automatic_char_len_1.f90 +++ b/gcc/testsuite/gfortran.dg/automatic_char_len_1.f90 @@ -1,4 +1,5 @@ ! { dg-do compile } +! { dg-options " " } ! PR18082 - Compiler would get stuck in loop, whilst treating ! the assignments. ! Test is one of PR cases. diff --git a/gcc/testsuite/gfortran.dg/entry_23.f b/gcc/testsuite/gfortran.dg/entry_23.f index ebc5f66..d10ea92 100644 --- a/gcc/testsuite/gfortran.dg/entry_23.f +++ b/gcc/testsuite/gfortran.dg/entry_23.f @@ -1,4 +1,5 @@ ! { dg-do run } +! { dg-options " " } ! PR 97799 - this used to segfault intermittently. ! Test case by George Hockney. PROGRAM MAIN diff --git a/gcc/testsuite/gfortran.dg/finalize_59.f90 b/gcc/testsuite/gfortran.dg/finalize_59.f90 index 8be5f71..e9e68d4 100644 --- a/gcc/testsuite/gfortran.dg/finalize_59.f90 +++ b/gcc/testsuite/gfortran.dg/finalize_59.f90 @@ -187,7 +187,7 @@ Program Cds_Principal Type(Uef_Vector) :: Cds_Mod_Les_materiaux Type (Cds_Materiau_Acier_EC) :: acier_ec Class (Cds_Materiau), pointer :: pt_materiau - Character *(8) :: nom_materiau + Character(len=8) :: nom_materiau !------------------------------------------------------------------------------------------------- CaLL Cds_Mod_Les_materiaux%Add (acier_ec) nom_materiau = "12345678" @@ -199,7 +199,7 @@ Function Get_Pt_Materiau_nom (vecteur, nom_materiau) ! Fonction : !-------------------- ! Parametres en entree - Character *(8), Intent (in) :: nom_materiau + Character(len=8), Intent (in) :: nom_materiau Type (Uef_Vector) , Intent (inout) :: vecteur ! Parametres en sortie diff --git a/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-bit.f b/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-bit.f index 0ce45de..2f03db1 100644 --- a/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-bit.f +++ b/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-bit.f @@ -1,4 +1,5 @@ c { dg-do run } +c { dg-options " " } c f90-intrinsic-bit.f c c Test Fortran 90 diff --git a/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-mathematical.f b/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-mathematical.f index d151fd0..f07336e 100644 --- a/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-mathematical.f +++ b/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-mathematical.f @@ -1,4 +1,5 @@ c { dg-do run } +c { dg-options " " } c f90-intrinsic-mathematical.f c c Test Fortran 90 intrinsic mathematical functions - Section 13.10.3 and diff --git a/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-numeric.f b/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-numeric.f index c8d7c56..c01efe6 100644 --- a/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-numeric.f +++ b/gcc/testsuite/gfortran.dg/g77/f90-intrinsic-numeric.f @@ -1,4 +1,5 @@ c { dg-do run } +c { dg-options " " } c f90-intrinsic-numeric.f c c Test Fortran 90 intrinsic numeric functions - Section 13.10.2 and 13.13 diff --git a/gcc/testsuite/gfortran.dg/g77/intrinsic-unix-bessel.f b/gcc/testsuite/gfortran.dg/g77/intrinsic-unix-bessel.f index b388806..406a8e4 100644 --- a/gcc/testsuite/gfortran.dg/g77/intrinsic-unix-bessel.f +++ b/gcc/testsuite/gfortran.dg/g77/intrinsic-unix-bessel.f @@ -1,4 +1,5 @@ c { dg-do run } +c { dg-options " " } c intrinsic-unix-bessel.f c c Test Bessel function intrinsics. diff --git a/gcc/testsuite/gfortran.dg/g77/intrinsic-unix-erf.f b/gcc/testsuite/gfortran.dg/g77/intrinsic-unix-erf.f index 250519a..6ed9590 100644 --- a/gcc/testsuite/gfortran.dg/g77/intrinsic-unix-erf.f +++ b/gcc/testsuite/gfortran.dg/g77/intrinsic-unix-erf.f @@ -1,4 +1,5 @@ c { dg-do run } +c { dg-options " " } c intrinsic-unix-erf.f c c Test Bessel function intrinsics. diff --git a/gcc/testsuite/gfortran.dg/initialization_9.f90 b/gcc/testsuite/gfortran.dg/initialization_9.f90 index d904047..fe7ca63 100644 --- a/gcc/testsuite/gfortran.dg/initialization_9.f90 +++ b/gcc/testsuite/gfortran.dg/initialization_9.f90 @@ -1,4 +1,5 @@ ! { dg-do compile } +! { dg-options " " } ! ! PR fortran/31639 ! Contributed by Martin Michlmayr <tbm AT cyrius DOT com> diff --git a/gcc/testsuite/gfortran.dg/intrinsic_actual_4.f90 b/gcc/testsuite/gfortran.dg/intrinsic_actual_4.f90 index 4521c96..3358b4a 100644 --- a/gcc/testsuite/gfortran.dg/intrinsic_actual_4.f90 +++ b/gcc/testsuite/gfortran.dg/intrinsic_actual_4.f90 @@ -1,4 +1,5 @@ ! { dg-do run } +! { dg-options " " } ! Tests the fix for PR27900, in which an ICE would be caused because ! the actual argument LEN had no type. ! diff --git a/gcc/testsuite/gfortran.dg/namelist_assumed_char.f90 b/gcc/testsuite/gfortran.dg/namelist_assumed_char.f90 index b7d063c..25edf64 100644 --- a/gcc/testsuite/gfortran.dg/namelist_assumed_char.f90 +++ b/gcc/testsuite/gfortran.dg/namelist_assumed_char.f90 @@ -8,7 +8,7 @@ ! Add -std=f95, add bar() ! subroutine foo(c) - character*(*) c + character*(*) c ! { dg-warning "Old-style character length" } namelist /abc/ c ! { dg-error "nonconstant character length in namelist" } end subroutine diff --git a/gcc/testsuite/gfortran.dg/pr15140.f90 b/gcc/testsuite/gfortran.dg/pr15140.f90 index 80c08dd..7f9af4f 100644 --- a/gcc/testsuite/gfortran.dg/pr15140.f90 +++ b/gcc/testsuite/gfortran.dg/pr15140.f90 @@ -1,4 +1,5 @@ ! { dg-do run } +! { dg-options "-std=legacy" } ! PR 15140: we used to fail an assertion, because we don't use the ! argument of the subroutine directly, but instead use a copy of it. function M(NAMES) diff --git a/gcc/testsuite/gnat.dg/reduce3.adb b/gcc/testsuite/gnat.dg/reduce3.adb new file mode 100644 index 0000000..55934d0 --- /dev/null +++ b/gcc/testsuite/gnat.dg/reduce3.adb @@ -0,0 +1,17 @@ +-- { dg-do run } +-- { dg-options "-gnat2022" } + +with Ada.Containers.Vectors; + +procedure Reduce3 is + + package Qs is new + Ada.Containers.Vectors (Index_Type => Positive, Element_Type => Positive); + + V : Qs.Vector; + Sum : Positive; + +begin + V.Append (1); + Sum := V'Reduce ("+", 0); +end; diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index 1d20e6a..f0a5e05 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -10173,6 +10173,224 @@ make_pass_fixup_cfg (gcc::context *ctxt) return new pass_fixup_cfg (ctxt); } + +/* Sort PHI argument values for make_forwarders_with_degenerate_phis. */ + +static int +sort_phi_args (const void *a_, const void *b_) +{ + auto *a = (const std::pair<edge, hashval_t> *) a_; + auto *b = (const std::pair<edge, hashval_t> *) b_; + hashval_t ha = a->second; + hashval_t hb = b->second; + if (ha < hb) + return -1; + else if (ha > hb) + return 1; + else if (a->first->dest_idx < b->first->dest_idx) + return -1; + else if (a->first->dest_idx > b->first->dest_idx) + return 1; + else + return 0; +} + +/* Look for a non-virtual PHIs and make a forwarder block when all PHIs + have the same argument on a set of edges. This is to not consider + control dependences of individual edges for same values but only for + the common set. Returns true if changed the CFG. */ + +bool +make_forwarders_with_degenerate_phis (function *fn) +{ + bool didsomething = false; + + basic_block bb; + FOR_EACH_BB_FN (bb, fn) + { + /* Only PHIs with three or more arguments have opportunities. */ + if (EDGE_COUNT (bb->preds) < 3) + continue; + /* Do not touch loop headers or blocks with abnormal predecessors. + ??? This is to avoid creating valid loops here, see PR103458. + We might want to improve things to either explicitely add those + loops or at least consider blocks with no backedges. */ + if (bb->loop_father->header == bb + || bb_has_abnormal_pred (bb)) + continue; + + /* Take one PHI node as template to look for identical + arguments. Build a vector of candidates forming sets + of argument edges with equal values. Note optimality + depends on the particular choice of the template PHI + since equal arguments are unordered leaving other PHIs + with more than one set of equal arguments within this + argument range unsorted. We'd have to break ties by + looking at other PHI nodes. */ + gphi_iterator gsi = gsi_start_nonvirtual_phis (bb); + if (gsi_end_p (gsi)) + continue; + gphi *phi = gsi.phi (); + auto_vec<std::pair<edge, hashval_t>, 8> args; + bool need_resort = false; + for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i) + { + edge e = gimple_phi_arg_edge (phi, i); + /* Skip abnormal edges since we cannot redirect them. */ + if (e->flags & EDGE_ABNORMAL) + continue; + /* Skip loop exit edges when we are in loop-closed SSA form + since the forwarder we'd create does not have a PHI node. */ + if (loops_state_satisfies_p (LOOP_CLOSED_SSA) + && loop_exit_edge_p (e->src->loop_father, e)) + continue; + + tree arg = gimple_phi_arg_def (phi, i); + if (!CONSTANT_CLASS_P (arg) && TREE_CODE (arg) != SSA_NAME) + need_resort = true; + args.safe_push (std::make_pair (e, iterative_hash_expr (arg, 0))); + } + if (args.length () < 2) + continue; + args.qsort (sort_phi_args); + /* The above sorting can be different between -g and -g0, as e.g. decls + can have different uids (-g could have bigger gaps in between them). + So, only use that to determine which args are equal, then change + second from hash value to smallest dest_idx of the edges which have + equal argument and sort again. If all the phi arguments are + constants or SSA_NAME, there is no need for the second sort, the hash + values are stable in that case. */ + hashval_t hash = args[0].second; + args[0].second = args[0].first->dest_idx; + bool any_equal = false; + for (unsigned i = 1; i < args.length (); ++i) + if (hash == args[i].second + && operand_equal_p (PHI_ARG_DEF_FROM_EDGE (phi, args[i - 1].first), + PHI_ARG_DEF_FROM_EDGE (phi, args[i].first))) + { + args[i].second = args[i - 1].second; + any_equal = true; + } + else + { + hash = args[i].second; + args[i].second = args[i].first->dest_idx; + } + if (!any_equal) + continue; + if (need_resort) + args.qsort (sort_phi_args); + + /* From the candidates vector now verify true candidates for + forwarders and create them. */ + gphi *vphi = get_virtual_phi (bb); + unsigned start = 0; + while (start < args.length () - 1) + { + unsigned i; + for (i = start + 1; i < args.length (); ++i) + if (args[start].second != args[i].second) + break; + /* args[start]..args[i-1] are equal. */ + if (start != i - 1) + { + /* Check all PHI nodes for argument equality + except for vops. */ + bool equal = true; + gphi_iterator gsi2 = gsi; + gsi_next (&gsi2); + for (; !gsi_end_p (gsi2); gsi_next (&gsi2)) + { + gphi *phi2 = gsi2.phi (); + if (virtual_operand_p (gimple_phi_result (phi2))) + continue; + tree start_arg + = PHI_ARG_DEF_FROM_EDGE (phi2, args[start].first); + for (unsigned j = start + 1; j < i; ++j) + { + if (!operand_equal_p (start_arg, + PHI_ARG_DEF_FROM_EDGE + (phi2, args[j].first))) + { + /* Another PHI might have a shorter set of + equivalent args. Go for that. */ + i = j; + if (j == start + 1) + equal = false; + break; + } + } + if (!equal) + break; + } + if (equal) + { + /* If we are asked to forward all edges the block + has all degenerate PHIs. Do nothing in that case. */ + if (start == 0 + && i == args.length () + && args.length () == gimple_phi_num_args (phi)) + break; + /* Instead of using make_forwarder_block we are + rolling our own variant knowing that the forwarder + does not need PHI nodes apart from eventually + a virtual one. */ + auto_vec<tree, 8> vphi_args; + if (vphi) + { + vphi_args.reserve_exact (i - start); + for (unsigned j = start; j < i; ++j) + vphi_args.quick_push + (PHI_ARG_DEF_FROM_EDGE (vphi, args[j].first)); + } + free_dominance_info (fn, CDI_DOMINATORS); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "New forwarder block for edge "); + fprintf (dump_file, "%d -> %d.\n", + args[start].first->src->index, + args[start].first->dest->index); + } + basic_block forwarder = split_edge (args[start].first); + profile_count count = profile_count::zero (); + bool irr = false; + for (unsigned j = start + 1; j < i; ++j) + { + edge e = args[j].first; + if (e->flags & EDGE_IRREDUCIBLE_LOOP) + irr = true; + redirect_edge_and_branch_force (e, forwarder); + redirect_edge_var_map_clear (e); + count += e->count (); + } + forwarder->count = count; + if (irr) + { + forwarder->flags |= BB_IRREDUCIBLE_LOOP; + single_succ_edge (forwarder)->flags + |= EDGE_IRREDUCIBLE_LOOP; + } + + if (vphi) + { + tree def = copy_ssa_name (vphi_args[0]); + gphi *vphi_copy = create_phi_node (def, forwarder); + for (unsigned j = start; j < i; ++j) + add_phi_arg (vphi_copy, vphi_args[j - start], + args[j].first, UNKNOWN_LOCATION); + SET_PHI_ARG_DEF + (vphi, single_succ_edge (forwarder)->dest_idx, def); + } + didsomething = true; + } + } + /* Continue searching for more opportunities. */ + start = i; + } + } + return didsomething; +} + /* Garbage collection support for edge_def. */ extern void gt_ggc_mx (tree&); diff --git a/gcc/tree-cfg.h b/gcc/tree-cfg.h index 520bb3a..2e01762 100644 --- a/gcc/tree-cfg.h +++ b/gcc/tree-cfg.h @@ -114,6 +114,7 @@ extern edge gimple_switch_edge (function *, gswitch *, unsigned); extern edge gimple_switch_default_edge (function *, gswitch *); extern bool cond_only_block_p (basic_block); extern void copy_phi_arg_into_existing_phi (edge, edge, bool = false); +extern bool make_forwarders_with_degenerate_phis (function *); /* Return true if the LHS of a call should be removed. */ diff --git a/gcc/tree-cfgcleanup.cc b/gcc/tree-cfgcleanup.cc index 872ded3..093fde9 100644 --- a/gcc/tree-cfgcleanup.cc +++ b/gcc/tree-cfgcleanup.cc @@ -1415,8 +1415,13 @@ execute_cleanup_cfg_post_optimizing (void) } maybe_remove_unreachable_handlers (); cleanup_dead_labels (); - if (group_case_labels ()) - todo |= TODO_cleanup_cfg; + if (group_case_labels () && cleanup_tree_cfg ()) + todo |= TODO_update_ssa; + + /* When optimizing undo the merging of forwarder blocks + that phis for better out of ssa expansion. */ + if (optimize) + make_forwarders_with_degenerate_phis (cfun); basic_block bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)); gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb); diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc index 317a0d6..9a9f6f9 100644 --- a/gcc/tree-ssa-dce.cc +++ b/gcc/tree-ssa-dce.cc @@ -1940,214 +1940,6 @@ tree_dce_done (bool aggressive) worklist.release (); } -/* Sort PHI argument values for make_forwarders_with_degenerate_phis. */ - -static int -sort_phi_args (const void *a_, const void *b_) -{ - auto *a = (const std::pair<edge, hashval_t> *) a_; - auto *b = (const std::pair<edge, hashval_t> *) b_; - hashval_t ha = a->second; - hashval_t hb = b->second; - if (ha < hb) - return -1; - else if (ha > hb) - return 1; - else if (a->first->dest_idx < b->first->dest_idx) - return -1; - else if (a->first->dest_idx > b->first->dest_idx) - return 1; - else - return 0; -} - -/* Look for a non-virtual PHIs and make a forwarder block when all PHIs - have the same argument on a set of edges. This is to not consider - control dependences of individual edges for same values but only for - the common set. */ - -static unsigned -make_forwarders_with_degenerate_phis (function *fn) -{ - unsigned todo = 0; - - basic_block bb; - FOR_EACH_BB_FN (bb, fn) - { - /* Only PHIs with three or more arguments have opportunities. */ - if (EDGE_COUNT (bb->preds) < 3) - continue; - /* Do not touch loop headers or blocks with abnormal predecessors. - ??? This is to avoid creating valid loops here, see PR103458. - We might want to improve things to either explicitely add those - loops or at least consider blocks with no backedges. */ - if (bb->loop_father->header == bb - || bb_has_abnormal_pred (bb)) - continue; - - /* Take one PHI node as template to look for identical - arguments. Build a vector of candidates forming sets - of argument edges with equal values. Note optimality - depends on the particular choice of the template PHI - since equal arguments are unordered leaving other PHIs - with more than one set of equal arguments within this - argument range unsorted. We'd have to break ties by - looking at other PHI nodes. */ - gphi_iterator gsi = gsi_start_nonvirtual_phis (bb); - if (gsi_end_p (gsi)) - continue; - gphi *phi = gsi.phi (); - auto_vec<std::pair<edge, hashval_t>, 8> args; - bool need_resort = false; - for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i) - { - edge e = gimple_phi_arg_edge (phi, i); - /* Skip abnormal edges since we cannot redirect them. */ - if (e->flags & EDGE_ABNORMAL) - continue; - /* Skip loop exit edges when we are in loop-closed SSA form - since the forwarder we'd create does not have a PHI node. */ - if (loops_state_satisfies_p (LOOP_CLOSED_SSA) - && loop_exit_edge_p (e->src->loop_father, e)) - continue; - - tree arg = gimple_phi_arg_def (phi, i); - if (!CONSTANT_CLASS_P (arg) && TREE_CODE (arg) != SSA_NAME) - need_resort = true; - args.safe_push (std::make_pair (e, iterative_hash_expr (arg, 0))); - } - if (args.length () < 2) - continue; - args.qsort (sort_phi_args); - /* The above sorting can be different between -g and -g0, as e.g. decls - can have different uids (-g could have bigger gaps in between them). - So, only use that to determine which args are equal, then change - second from hash value to smallest dest_idx of the edges which have - equal argument and sort again. If all the phi arguments are - constants or SSA_NAME, there is no need for the second sort, the hash - values are stable in that case. */ - hashval_t hash = args[0].second; - args[0].second = args[0].first->dest_idx; - bool any_equal = false; - for (unsigned i = 1; i < args.length (); ++i) - if (hash == args[i].second - && operand_equal_p (PHI_ARG_DEF_FROM_EDGE (phi, args[i - 1].first), - PHI_ARG_DEF_FROM_EDGE (phi, args[i].first))) - { - args[i].second = args[i - 1].second; - any_equal = true; - } - else - { - hash = args[i].second; - args[i].second = args[i].first->dest_idx; - } - if (!any_equal) - continue; - if (need_resort) - args.qsort (sort_phi_args); - - /* From the candidates vector now verify true candidates for - forwarders and create them. */ - gphi *vphi = get_virtual_phi (bb); - unsigned start = 0; - while (start < args.length () - 1) - { - unsigned i; - for (i = start + 1; i < args.length (); ++i) - if (args[start].second != args[i].second) - break; - /* args[start]..args[i-1] are equal. */ - if (start != i - 1) - { - /* Check all PHI nodes for argument equality. */ - bool equal = true; - gphi_iterator gsi2 = gsi; - gsi_next (&gsi2); - for (; !gsi_end_p (gsi2); gsi_next (&gsi2)) - { - gphi *phi2 = gsi2.phi (); - if (virtual_operand_p (gimple_phi_result (phi2))) - continue; - tree start_arg - = PHI_ARG_DEF_FROM_EDGE (phi2, args[start].first); - for (unsigned j = start + 1; j < i; ++j) - { - if (!operand_equal_p (start_arg, - PHI_ARG_DEF_FROM_EDGE - (phi2, args[j].first))) - { - /* Another PHI might have a shorter set of - equivalent args. Go for that. */ - i = j; - if (j == start + 1) - equal = false; - break; - } - } - if (!equal) - break; - } - if (equal) - { - /* If we are asked to forward all edges the block - has all degenerate PHIs. Do nothing in that case. */ - if (start == 0 - && i == args.length () - && args.length () == gimple_phi_num_args (phi)) - break; - /* Instead of using make_forwarder_block we are - rolling our own variant knowing that the forwarder - does not need PHI nodes apart from eventually - a virtual one. */ - auto_vec<tree, 8> vphi_args; - if (vphi) - { - vphi_args.reserve_exact (i - start); - for (unsigned j = start; j < i; ++j) - vphi_args.quick_push - (PHI_ARG_DEF_FROM_EDGE (vphi, args[j].first)); - } - free_dominance_info (fn, CDI_DOMINATORS); - basic_block forwarder = split_edge (args[start].first); - profile_count count = profile_count::zero (); - bool irr = false; - for (unsigned j = start + 1; j < i; ++j) - { - edge e = args[j].first; - if (e->flags & EDGE_IRREDUCIBLE_LOOP) - irr = true; - redirect_edge_and_branch_force (e, forwarder); - redirect_edge_var_map_clear (e); - count += e->count (); - } - forwarder->count = count; - if (irr) - { - forwarder->flags |= BB_IRREDUCIBLE_LOOP; - single_succ_edge (forwarder)->flags - |= EDGE_IRREDUCIBLE_LOOP; - } - - if (vphi) - { - tree def = copy_ssa_name (vphi_args[0]); - gphi *vphi_copy = create_phi_node (def, forwarder); - for (unsigned j = start; j < i; ++j) - add_phi_arg (vphi_copy, vphi_args[j - start], - args[j].first, UNKNOWN_LOCATION); - SET_PHI_ARG_DEF - (vphi, single_succ_edge (forwarder)->dest_idx, def); - } - todo |= TODO_cleanup_cfg; - } - } - /* Continue searching for more opportunities. */ - start = i; - } - } - return todo; -} /* Main routine to eliminate dead code. @@ -2174,8 +1966,8 @@ perform_tree_ssa_dce (bool aggressive) scev_initialize (); } - if (aggressive) - todo |= make_forwarders_with_degenerate_phis (cfun); + if (aggressive && make_forwarders_with_degenerate_phis (cfun)) + todo |= TODO_cleanup_cfg; calculate_dominance_info (CDI_DOMINATORS); diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index 09f92b2..0c519cf 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -2527,7 +2527,10 @@ vn_nary_build_or_lookup_1 (gimple_match_op *res_op, bool insert, else { tree val = vn_lookup_simplify_result (res_op); - if (!val && insert) + /* ??? In weird cases we can end up with internal-fn calls, + but this isn't expected so throw the result away. See + PR123040 for an example. */ + if (!val && insert && res_op->code.is_tree_code ()) { gimple_seq stmts = NULL; result = maybe_push_res_to_seq (res_op, &stmts); diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 53923c0..f9dd88e 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -2682,6 +2682,7 @@ again: = saved_can_use_partial_vectors_p; LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = false; LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo) = false; + LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo) = false; if (loop_vinfo->scan_map) loop_vinfo->scan_map->empty (); diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc index 555986b..af64cb8 100644 --- a/gcc/tree-vect-patterns.cc +++ b/gcc/tree-vect-patterns.cc @@ -1914,6 +1914,9 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo, && val_new == prec) || (ifnnew == IFN_POPCOUNT && ifn == IFN_CTZ)) { + if (vect_is_reduction (stmt_vinfo)) + return NULL; + /* .CTZ (X) = PREC - .CLZ ((X - 1) & ~X) .CTZ (X) = .POPCOUNT ((X - 1) & ~X). */ if (ifnnew == IFN_CLZ) @@ -1952,6 +1955,9 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo, } else if (ifnnew == IFN_CLZ) { + if (vect_is_reduction (stmt_vinfo)) + return NULL; + /* .CTZ (X) = (PREC - 1) - .CLZ (X & -X) .FFS (X) = PREC - .CLZ (X & -X). */ sub = prec - (ifn == IFN_CTZ); @@ -1971,6 +1977,9 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo, } else if (ifnnew == IFN_POPCOUNT) { + if (vect_is_reduction (stmt_vinfo)) + return NULL; + /* .CTZ (X) = PREC - .POPCOUNT (X | -X) .FFS (X) = (PREC + 1) - .POPCOUNT (X | -X). */ sub = prec + (ifn == IFN_FFS); @@ -1993,6 +2002,11 @@ vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo, /* .FFS (X) = .CTZ (X) + 1. */ add = 1; val_cmp++; + + if (vect_is_reduction (stmt_vinfo) + && defined_at_zero + && (!defined_at_zero_new || val != val_cmp)) + return NULL; } /* Create B = .IFNNEW (A). */ diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc index dc155dc..56ff1c8 100644 --- a/gcc/tree-vect-stmts.cc +++ b/gcc/tree-vect-stmts.cc @@ -9920,36 +9920,35 @@ vectorizable_load (vec_info *vinfo, bool hoist_p = (LOOP_VINFO_NO_DATA_DEPENDENCIES (loop_vinfo) && !nested_in_vect_loop); - /* It is unsafe to hoist a conditional load over the conditions that make - it valid. When early break this means that any invariant load can't be - hoisted unless it's in the loop header or if we know something else has - verified the load is valid to do. Alignment peeling would do this - since getting through the prologue means the load was done at least - once and so the vector main body is free to hoist it. However today - GCC will hoist the load above the PFA loop. As such that makes it - still invalid and so we can't allow it today. */ - auto stmt_bb - = gimple_bb (STMT_VINFO_STMT ( - vect_orig_stmt (SLP_TREE_SCALAR_STMTS (slp_node)[0]))); - if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo) - && !DR_SCALAR_KNOWN_BOUNDS (dr_info) - && stmt_bb != loop->header) - { - if (LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo) - && dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + bool uniform_p = true; + for (stmt_vec_info sinfo : SLP_TREE_SCALAR_STMTS (slp_node)) + { + /* It is unsafe to hoist a conditional load over the conditions that + make it valid. When early break this means that any invariant load + can't be hoisted unless it's in the loop header or if we know + something else has verified the load is valid to do. Alignment + peeling would do this since getting through the prologue means the + load was done at least once and so the vector main body is free to + hoist it. However today GCC will hoist the load above the PFA + loop. As such that makes it still invalid and so we can't allow it + today. */ + if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo) + && !DR_SCALAR_KNOWN_BOUNDS (STMT_VINFO_DR_INFO (sinfo)) + && gimple_bb (STMT_VINFO_STMT (vect_orig_stmt (sinfo))) + != loop->header) + { + if (LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo) + && dump_enabled_p ()) + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, "not hoisting invariant load due to early break" "constraints\n"); - else if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, + else if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, "not hoisting invariant load due to early break" "constraints\n"); - hoist_p = false; - } + hoist_p = false; + } - bool uniform_p = true; - for (stmt_vec_info sinfo : SLP_TREE_SCALAR_STMTS (slp_node)) - { hoist_p = hoist_p && hoist_defs_of_uses (sinfo->stmt, loop, false); if (sinfo != SLP_TREE_SCALAR_STMTS (slp_node)[0]) uniform_p = false; @@ -11393,10 +11392,18 @@ vectorizable_load (vec_info *vinfo, { tree ptr = build_int_cst (ref_type, align * BITS_PER_UNIT); gcall *call; + + /* Need conversion if the vectype is punned by VnQI. */ + els_vectype = vectype; + if (vmode != new_vmode) + els_vectype + = build_vector_type_for_mode (unsigned_intQI_type_node, + new_vmode); + vec_els = vect_get_mask_load_else (maskload_elsval, + els_vectype); + if (partial_ifn == IFN_MASK_LEN_LOAD) { - vec_els = vect_get_mask_load_else (maskload_elsval, - vectype); if (type_mode_padding_p && maskload_elsval != MASK_LOAD_ELSE_ZERO) need_zeroing = true; @@ -11406,9 +11413,10 @@ vectorizable_load (vec_info *vinfo, final_len, bias); } else - call = gimple_build_call_internal (IFN_LEN_LOAD, 4, + call = gimple_build_call_internal (IFN_LEN_LOAD, 5, dataref_ptr, ptr, - final_len, bias); + vec_els, final_len, + bias); gimple_call_set_nothrow (call, true); new_stmt = call; data_ref = NULL_TREE; diff --git a/libatomic/Makefile.in b/libatomic/Makefile.in index 95f9c72..c9e53e1 100644 --- a/libatomic/Makefile.in +++ b/libatomic/Makefile.in @@ -108,6 +108,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \ $(top_srcdir)/../config/clang-plugin.m4 \ $(top_srcdir)/../config/depstand.m4 \ $(top_srcdir)/../config/gcc-plugin.m4 \ + $(top_srcdir)/../config/gthr.m4 \ $(top_srcdir)/../config/lead-dot.m4 \ $(top_srcdir)/../config/lthostflags.m4 \ $(top_srcdir)/../config/multi.m4 \ @@ -171,7 +172,7 @@ libatomic_la_OBJECTS = $(am_libatomic_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent -am__v_lt_1 = +am__v_lt_1 = libatomic_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libatomic_la_LDFLAGS) $(LDFLAGS) -o $@ @@ -192,11 +193,11 @@ am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = +am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ -am__v_at_1 = +am__v_at_1 = depcomp = $(SHELL) $(top_srcdir)/../depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -209,7 +210,7 @@ LTCPPASCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ AM_V_CPPAS = $(am__v_CPPAS_@AM_V@) am__v_CPPAS_ = $(am__v_CPPAS_@AM_DEFAULT_V@) am__v_CPPAS_0 = @echo " CPPAS " $@; -am__v_CPPAS_1 = +am__v_CPPAS_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -219,7 +220,7 @@ LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = +am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ @@ -227,7 +228,7 @@ LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = +am__v_CCLD_1 = SOURCES = $(libatomic_la_SOURCES) $(EXTRA_libatomic_la_SOURCES) \ $(libatomic_convenience_la_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ @@ -422,10 +423,10 @@ AM_CCASFLAGS = $(XCFLAGS) AM_LDFLAGS = $(XLDFLAGS) $(SECTION_LDFLAGS) $(OPT_LDFLAGS) toolexeclib_LTLIBRARIES = libatomic.la noinst_LTLIBRARIES = libatomic_convenience.la -@LIBAT_BUILD_VERSIONED_SHLIB_FALSE@libatomic_version_script = +@LIBAT_BUILD_VERSIONED_SHLIB_FALSE@libatomic_version_script = @LIBAT_BUILD_VERSIONED_SHLIB_GNU_TRUE@@LIBAT_BUILD_VERSIONED_SHLIB_TRUE@libatomic_version_script = -Wl,--version-script,$(top_srcdir)/libatomic.map @LIBAT_BUILD_VERSIONED_SHLIB_SUN_TRUE@@LIBAT_BUILD_VERSIONED_SHLIB_TRUE@libatomic_version_script = -Wl,-M,libatomic.map-sun -@LIBAT_BUILD_VERSIONED_SHLIB_FALSE@libatomic_version_dep = +@LIBAT_BUILD_VERSIONED_SHLIB_FALSE@libatomic_version_dep = @LIBAT_BUILD_VERSIONED_SHLIB_GNU_TRUE@@LIBAT_BUILD_VERSIONED_SHLIB_TRUE@libatomic_version_dep = $(top_srcdir)/libatomic.map @LIBAT_BUILD_VERSIONED_SHLIB_SUN_TRUE@@LIBAT_BUILD_VERSIONED_SHLIB_TRUE@libatomic_version_dep = libatomic.map-sun libatomic_version_info = -version-info $(libtool_VERSION) @@ -443,7 +444,7 @@ libatomic_la_LDFLAGS = $(libatomic_version_info) $(libatomic_version_script) \ @PARTIAL_VXWORKS_FALSE@SIZEOBJS = load store cas exch fadd fsub fand fior fxor fnand tas @PARTIAL_VXWORKS_FALSE@EXTRA_libatomic_la_SOURCES = $(addsuffix _n.c,$(SIZEOBJS)) @PARTIAL_VXWORKS_FALSE@libatomic_la_DEPENDENCIES = $(libatomic_la_LIBADD) $(libatomic_version_dep) -@PARTIAL_VXWORKS_FALSE@empty = +@PARTIAL_VXWORKS_FALSE@empty = @PARTIAL_VXWORKS_FALSE@space = $(empty) $(empty) @PARTIAL_VXWORKS_FALSE@PAT_SPLIT = $(subst _,$(space),$(*F)) @PARTIAL_VXWORKS_FALSE@PAT_BASE = $(word 1,$(PAT_SPLIT)) @@ -452,7 +453,7 @@ libatomic_la_LDFLAGS = $(libatomic_version_info) $(libatomic_version_script) \ @PARTIAL_VXWORKS_FALSE@IFUNC_DEF = -DIFUNC_ALT=$(PAT_S) @PARTIAL_VXWORKS_FALSE@IFUNC_OPT = $(subst |,$(space),$(word $(PAT_S),$(IFUNC_OPTIONS))) @PARTIAL_VXWORKS_FALSE@@AMDEP_TRUE@M_DEPS = -MT $@ -MD -MP -MF $(DEPDIR)/$(@F).Ppo -@PARTIAL_VXWORKS_FALSE@@AMDEP_FALSE@M_DEPS = +@PARTIAL_VXWORKS_FALSE@@AMDEP_FALSE@M_DEPS = @PARTIAL_VXWORKS_FALSE@M_SIZE = -DN=$(PAT_N) @PARTIAL_VXWORKS_FALSE@M_IFUNC = $(if $(PAT_S),$(IFUNC_DEF) $(IFUNC_OPT)) @PARTIAL_VXWORKS_FALSE@M_FILE = $(PAT_BASE)_n.c @@ -485,10 +486,10 @@ libatomic_convenience_la_LIBADD = $(libatomic_la_LIBADD) # built after libatomic, which makes RPATH insecure. Removing libatomic.la # from $gcc_objdir seems to fix the issue. gcc_objdir = `pwd`/$(MULTIBUILDTOP)../../gcc/ -MULTISRCTOP = -MULTIBUILDTOP = -MULTIDIRS = -MULTISUBDIR = +MULTISRCTOP = +MULTIBUILDTOP = +MULTIDIRS = +MULTISUBDIR = MULTIDO = true MULTICLEAN = true all: auto-config.h @@ -538,7 +539,7 @@ auto-config.h: stamp-h1 stamp-h1: $(srcdir)/auto-config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status auto-config.h -$(srcdir)/auto-config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) +$(srcdir)/auto-config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ @@ -592,10 +593,10 @@ clean-toolexeclibLTLIBRARIES: rm -f $${locs}; \ } -libatomic.la: $(libatomic_la_OBJECTS) $(libatomic_la_DEPENDENCIES) $(EXTRA_libatomic_la_DEPENDENCIES) +libatomic.la: $(libatomic_la_OBJECTS) $(libatomic_la_DEPENDENCIES) $(EXTRA_libatomic_la_DEPENDENCIES) $(AM_V_CCLD)$(libatomic_la_LINK) -rpath $(toolexeclibdir) $(libatomic_la_OBJECTS) $(libatomic_la_LIBADD) $(LIBS) -libatomic_convenience.la: $(libatomic_convenience_la_OBJECTS) $(libatomic_convenience_la_DEPENDENCIES) $(EXTRA_libatomic_convenience_la_DEPENDENCIES) +libatomic_convenience.la: $(libatomic_convenience_la_OBJECTS) $(libatomic_convenience_la_DEPENDENCIES) $(EXTRA_libatomic_convenience_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libatomic_convenience_la_OBJECTS) $(libatomic_convenience_la_LIBADD) $(LIBS) mostlyclean-compile: diff --git a/libatomic/aclocal.m4 b/libatomic/aclocal.m4 index 91bff17..4d7c727 100644 --- a/libatomic/aclocal.m4 +++ b/libatomic/aclocal.m4 @@ -1191,6 +1191,7 @@ m4_include([../config/acx.m4]) m4_include([../config/clang-plugin.m4]) m4_include([../config/depstand.m4]) m4_include([../config/gcc-plugin.m4]) +m4_include([../config/gthr.m4]) m4_include([../config/lead-dot.m4]) m4_include([../config/lthostflags.m4]) m4_include([../config/multi.m4]) diff --git a/libatomic/configure b/libatomic/configure index dd0f086..a6db78e 100755 --- a/libatomic/configure +++ b/libatomic/configure @@ -12254,11 +12254,28 @@ libtool_VERSION=3:0:2 # Check for used threading-model -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for thread model used by GCC" >&5 -$as_echo_n "checking for thread model used by GCC... " >&6; } -target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $target_thread_file" >&5 -$as_echo "$target_thread_file" >&6; } + +# Specify the threading model for this GCC runtime library +# Pass with no value to take from compiler's metadata +# Pass with a value to specify a thread package +# 'single' means single threaded -- without threads. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the threading model used by GCC" >&5 +$as_echo_n "checking for the threading model used by GCC... " >&6; } +if ${gcc_cv_target_thread_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + + # Set new cache variable + gcc_cv_target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_target_thread_file" >&5 +$as_echo "$gcc_cv_target_thread_file" >&6; } +# Set variable name (not prefixed enough to be a good cache variable +# name) traditionally used for this purpose, to avoid having to change +# a bunch of configure scripts. +target_thread_file="$gcc_cv_target_thread_file" + case "$target" in *aarch64*) diff --git a/libatomic/configure.ac b/libatomic/configure.ac index 3da2f94..62c2a6b 100644 --- a/libatomic/configure.ac +++ b/libatomic/configure.ac @@ -177,9 +177,7 @@ libtool_VERSION=3:0:2 AC_SUBST(libtool_VERSION) # Check for used threading-model -AC_MSG_CHECKING([for thread model used by GCC]) -target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` -AC_MSG_RESULT([$target_thread_file]) +GCC_AC_THREAD_MODEL case "$target" in *aarch64*) diff --git a/libatomic/testsuite/Makefile.in b/libatomic/testsuite/Makefile.in index f540a75..5d6872b0d 100644 --- a/libatomic/testsuite/Makefile.in +++ b/libatomic/testsuite/Makefile.in @@ -94,6 +94,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \ $(top_srcdir)/../config/clang-plugin.m4 \ $(top_srcdir)/../config/depstand.m4 \ $(top_srcdir)/../config/gcc-plugin.m4 \ + $(top_srcdir)/../config/gthr.m4 \ $(top_srcdir)/../config/lead-dot.m4 \ $(top_srcdir)/../config/lthostflags.m4 \ $(top_srcdir)/../config/multi.m4 \ @@ -120,11 +121,11 @@ am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = +am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ -am__v_at_1 = +am__v_at_1 = SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 816b5c4..816983c 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,13 @@ +2025-12-07 Jason Merrill <jason@redhat.com> + + * include/cpplib.h (cpp_get_path, cpp_get_dir): Remove. + (_cpp_get_file_path, _cpp_get_file_name, _cpp_get_file_stat) + (_cpp_get_file_dir): Move prototypes from... + * internal.h: ...here. + * files.cc (_cpp_get_file_path): Rename from... + (cpp_get_path): ...this. + (cpp_get_dir): Remove. + 2025-11-10 Jakub Jelinek <jakub@redhat.com> * directives.cc: Implement CWG3053. diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in index 32a5a15..f0cbcb8 100644 --- a/libgcc/Makefile.in +++ b/libgcc/Makefile.in @@ -298,6 +298,8 @@ override CFLAGS := $(filter-out -fprofile-generate -fprofile-use,$(CFLAGS)) INTERNAL_CFLAGS = $(CFLAGS) $(LIBGCC2_CFLAGS) $(HOST_LIBGCC2_CFLAGS) \ $(INCLUDES) @set_have_cc_tls@ @set_use_emutls@ +NO_PIE_CFLAGS = @NO_PIE_CFLAGS@ + # Options to use when compiling crtbegin/end. CRTSTUFF_CFLAGS = -O2 $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \ $(NO_PIE_CFLAGS) -finhibit-size-directive -fno-inline -fno-exceptions \ diff --git a/libgcc/config/rs6000/t-slibgcc-aix b/libgcc/config/rs6000/t-slibgcc-aix index 6333687..4a3d624 100644 --- a/libgcc/config/rs6000/t-slibgcc-aix +++ b/libgcc/config/rs6000/t-slibgcc-aix @@ -40,7 +40,9 @@ SHLIB_LINK = \ -Wl,-bE:@shlib_map_file@ -o shr.o \ @multilib_flags@ @shlib_objs@ -lc \ `case @multilib_dir@ in \ - *pthread*) echo -L$(TARGET_SYSTEM_ROOT)/usr/lib/threads -lpthreads -lc_r $(TARGET_SYSTEM_ROOT)/usr/lib/libc.a ;; \ + *pthread*) \ + TARGET_SYSTEM_ROOT=\`$(CC) -print-sysroot\`; \ + echo -L$$TARGET_SYSTEM_ROOT/usr/lib/threads -lpthreads -lc_r $$TARGET_SYSTEM_ROOT/usr/lib/libc.a ;; \ *) echo -lc ;; esac` ; \ rm -f tmp-@shlib_base_name@.a ; \ $(AR_CREATE_FOR_TARGET) tmp-@shlib_base_name@.a shr.o ; \ @@ -53,7 +55,9 @@ SHLIB_LINK = \ -Wl,-bE:@shlib_map_file@ -o $$shr.o \ @multilib_flags@ @shlib_objs@ -lc \ `case @multilib_dir@ in \ - *pthread*) echo -L$(TARGET_SYSTEM_ROOT)/usr/lib/threads -lpthreads -lc_r $(TARGET_SYSTEM_ROOT)/usr/lib/libc.a ;; \ + *pthread*) \ + TARGET_SYSTEM_ROOT=\`$(CC) -print-sysroot\`; \ + echo -L$$TARGET_SYSTEM_ROOT/usr/lib/threads -lpthreads -lc_r $$TARGET_SYSTEM_ROOT/usr/lib/libc.a ;; \ *) echo -lc ;; esac` ; \ $(STRIP_FOR_TARGET) -X32_64 -e $$shr.o ; \ { echo "\#! $(SHLIB_SONAME)($$shr.o)" ; \ diff --git a/libgcc/configure b/libgcc/configure index d5e80d2..fe7a21c2 100755 --- a/libgcc/configure +++ b/libgcc/configure @@ -610,6 +610,7 @@ accel_dir_suffix use_tm_clone_registry force_explicit_eh_registry CET_FLAGS +NO_PIE_CFLAGS fixed_point enable_decimal_float decimal_float @@ -4836,6 +4837,40 @@ $as_echo "$libgcc_cv_fixed_point" >&6; } fixed_point=$libgcc_cv_fixed_point +# Check whether the compiler defines __PIE__ by default, so -fno-PIE is needed. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler defines __PIE__" >&5 +$as_echo_n "checking whether the compiler defines __PIE__... " >&6; } +if ${libgcc_cv_no_pie_cflags+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef __PIE__ +#error __PIE__ defined +#endif + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + libgcc_cv_no_pie_cflags='' +else + libgcc_cv_no_pie_cflags='-fno-PIE' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_no_pie_cflags" >&5 +$as_echo "$libgcc_cv_no_pie_cflags" >&6; } + +NO_PIE_CFLAGS=$libgcc_cv_no_pie_cflags + + # For platforms with the unwind ABI which includes an unwind library, # libunwind, we can choose to use the system libunwind. # config.gcc also contains tests of with_system_libunwind. @@ -5046,11 +5081,28 @@ $as_echo "$acl_cv_prog_gnu_ld" >&6; } with_gnu_ld=$acl_cv_prog_gnu_ld -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for thread model used by GCC" >&5 -$as_echo_n "checking for thread model used by GCC... " >&6; } -target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $target_thread_file" >&5 -$as_echo "$target_thread_file" >&6; } + +# Specify the threading model for this GCC runtime library +# Pass with no value to take from compiler's metadata +# Pass with a value to specify a thread package +# 'single' means single threaded -- without threads. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the threading model used by GCC" >&5 +$as_echo_n "checking for the threading model used by GCC... " >&6; } +if ${gcc_cv_target_thread_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + + # Set new cache variable + gcc_cv_target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_target_thread_file" >&5 +$as_echo "$gcc_cv_target_thread_file" >&6; } +# Set variable name (not prefixed enough to be a good cache variable +# name) traditionally used for this purpose, to avoid having to change +# a bunch of configure scripts. +target_thread_file="$gcc_cv_target_thread_file" + # Check for assembler CFI support. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether assembler supports CFI directives" >&5 @@ -5737,6 +5789,9 @@ case $target_thread_file in vxworks) thread_header=config/gthr-vxworks.h ;; win32) thread_header=config/i386/gthr-win32.h ;; mcf) thread_header=config/i386/gthr-mcf.h ;; + *) + as_fn_error $? "No known header for threading model '$target_thread_file'." "$LINENO" 5 + ;; esac diff --git a/libgcc/configure.ac b/libgcc/configure.ac index 65cd3c6..5945243 100644 --- a/libgcc/configure.ac +++ b/libgcc/configure.ac @@ -258,6 +258,20 @@ AC_CACHE_CHECK([whether fixed-point is supported], [libgcc_cv_fixed_point], fixed_point=$libgcc_cv_fixed_point AC_SUBST(fixed_point) +# Check whether the compiler defines __PIE__ by default, so -fno-PIE is needed. +AC_CACHE_CHECK([whether the compiler defines __PIE__], [libgcc_cv_no_pie_cflags], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ +#ifdef __PIE__ +#error __PIE__ defined +#endif + ]], [[]])], + [libgcc_cv_no_pie_cflags=''], + [libgcc_cv_no_pie_cflags='-fno-PIE'])]) + +NO_PIE_CFLAGS=$libgcc_cv_no_pie_cflags +AC_SUBST([NO_PIE_CFLAGS]) + # For platforms with the unwind ABI which includes an unwind library, # libunwind, we can choose to use the system libunwind. # config.gcc also contains tests of with_system_libunwind. @@ -305,9 +319,7 @@ AC_SUBST([use_tm_clone_registry]) AC_LIB_PROG_LD_GNU -AC_MSG_CHECKING([for thread model used by GCC]) -target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` -AC_MSG_RESULT([$target_thread_file]) +GCC_AC_THREAD_MODEL # Check for assembler CFI support. AC_CACHE_CHECK([whether assembler supports CFI directives], [libgcc_cv_cfi], diff --git a/libgomp/testsuite/lib/libgomp.exp b/libgomp/testsuite/lib/libgomp.exp index 076b775..cce2e93 100644 --- a/libgomp/testsuite/lib/libgomp.exp +++ b/libgomp/testsuite/lib/libgomp.exp @@ -725,6 +725,29 @@ int main() { } } "-lhipblas" ] } +# return 1 if OpenMP Unified Shared Memory is supported by offload devices + +proc check_effective_target_omp_usm { } { + if { [check_effective_target_offload_device_nvptx] + || [check_effective_target_offload_target_amdgcn] } { + if [check_runtime usm_available_ { + #include <omp.h> + #pragma omp requires unified_shared_memory + int main () + { + int a; + #pragma omp target map(from: a) + a = omp_is_initial_device (); + return a; + } + } ] { + return 1 + } + } + + return 0 +} + # return 1 if OpenMP Device Managed Memory is supported proc check_effective_target_omp_managedmem { } { diff --git a/libgomp/testsuite/libgomp.c++/target-std__array-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__array-concurrent-usm.C index 9923783..aa36f71 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__array-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__array-concurrent-usm.C @@ -1,3 +1,4 @@ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps #define MEM_SHARED diff --git a/libgomp/testsuite/libgomp.c++/target-std__bitset-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__bitset-concurrent-usm.C index 9023ef8..d08ea71 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__bitset-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__bitset-concurrent-usm.C @@ -1,3 +1,4 @@ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps #define MEM_SHARED diff --git a/libgomp/testsuite/libgomp.c++/target-std__deque-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__deque-concurrent-usm.C index 863a1de..b30ade4 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__deque-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__deque-concurrent-usm.C @@ -1,3 +1,4 @@ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps #define MEM_SHARED diff --git a/libgomp/testsuite/libgomp.c++/target-std__forward_list-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__forward_list-concurrent-usm.C index 60d5cee..65004b2 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__forward_list-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__forward_list-concurrent-usm.C @@ -1,3 +1,4 @@ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps #define MEM_SHARED diff --git a/libgomp/testsuite/libgomp.c++/target-std__list-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__list-concurrent-usm.C index 5057bf9..3cdd44d 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__list-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__list-concurrent-usm.C @@ -1,3 +1,4 @@ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps #define MEM_SHARED diff --git a/libgomp/testsuite/libgomp.c++/target-std__map-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__map-concurrent-usm.C index fe37426..b7d3dd8 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__map-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__map-concurrent-usm.C @@ -1,3 +1,4 @@ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps #define MEM_SHARED diff --git a/libgomp/testsuite/libgomp.c++/target-std__multimap-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__multimap-concurrent-usm.C index 79f9245..f243790 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__multimap-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__multimap-concurrent-usm.C @@ -1,3 +1,4 @@ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps #define MEM_SHARED diff --git a/libgomp/testsuite/libgomp.c++/target-std__multiset-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__multiset-concurrent-usm.C index 2d80756..d869e89 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__multiset-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__multiset-concurrent-usm.C @@ -1,3 +1,4 @@ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps #define MEM_SHARED diff --git a/libgomp/testsuite/libgomp.c++/target-std__set-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__set-concurrent-usm.C index 54f62e3..5fbf91b2 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__set-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__set-concurrent-usm.C @@ -1,3 +1,4 @@ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps #define MEM_SHARED diff --git a/libgomp/testsuite/libgomp.c++/target-std__span-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__span-concurrent-usm.C index 7ef16bf..09f9879 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__span-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__span-concurrent-usm.C @@ -1,4 +1,5 @@ // { dg-additional-options "-std=c++20" } +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps diff --git a/libgomp/testsuite/libgomp.c++/target-std__valarray-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__valarray-concurrent-usm.C index 41ec80e..828b67c 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__valarray-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__valarray-concurrent-usm.C @@ -1,3 +1,4 @@ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps #define MEM_SHARED diff --git a/libgomp/testsuite/libgomp.c++/target-std__vector-concurrent-usm.C b/libgomp/testsuite/libgomp.c++/target-std__vector-concurrent-usm.C index 967bff3..835f6d5 100644 --- a/libgomp/testsuite/libgomp.c++/target-std__vector-concurrent-usm.C +++ b/libgomp/testsuite/libgomp.c++/target-std__vector-concurrent-usm.C @@ -1,3 +1,4 @@ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory self_maps #define MEM_SHARED diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-implicit-map-4.c b/libgomp/testsuite/libgomp.c-c++-common/target-implicit-map-4.c index d0b0cd1..97bb97a 100644 --- a/libgomp/testsuite/libgomp.c-c++-common/target-implicit-map-4.c +++ b/libgomp/testsuite/libgomp.c-c++-common/target-implicit-map-4.c @@ -4,6 +4,7 @@ and for not mapping the stack variables 'A' and 'B' (not mapped but accessible -> USM makes this tested feature even more important.) */ +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory /* Ensure that defaultmap(default : pointer) uses correct OpenMP 5.2 diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-link-3.c b/libgomp/testsuite/libgomp.c-c++-common/target-link-3.c index c707b38..9664235 100644 --- a/libgomp/testsuite/libgomp.c-c++-common/target-link-3.c +++ b/libgomp/testsuite/libgomp.c-c++-common/target-link-3.c @@ -3,6 +3,7 @@ #include <stdint.h> #include <omp.h> +/* { dg-require-effective-target omp_usm } */ #pragma omp requires unified_shared_memory int A[3] = {-3,-4,-5}; diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-link-4.c b/libgomp/testsuite/libgomp.c-c++-common/target-link-4.c index 785055e..009c521 100644 --- a/libgomp/testsuite/libgomp.c-c++-common/target-link-4.c +++ b/libgomp/testsuite/libgomp.c-c++-common/target-link-4.c @@ -3,6 +3,7 @@ #include <stdint.h> #include <omp.h> +/* { dg-require-effective-target omp_usm } */ #pragma omp requires self_maps int A[3] = {-3,-4,-5}; diff --git a/libgomp/testsuite/libgomp.fortran/self_maps.f90 b/libgomp/testsuite/libgomp.fortran/self_maps.f90 index 208fd1c..6088968 100644 --- a/libgomp/testsuite/libgomp.fortran/self_maps.f90 +++ b/libgomp/testsuite/libgomp.fortran/self_maps.f90 @@ -1,4 +1,5 @@ ! Basic test whether self_maps work +! { dg-require-effective-target omp_usm } module m !$omp requires self_maps diff --git a/libgomp/testsuite/libgomp.graphite/force-parallel-1.c b/libgomp/testsuite/libgomp.graphite/force-parallel-1.c index 0393356..b873d7a 100644 --- a/libgomp/testsuite/libgomp.graphite/force-parallel-1.c +++ b/libgomp/testsuite/libgomp.graphite/force-parallel-1.c @@ -2,7 +2,7 @@ void abort (void); int x[10000000]; -void parloop (int N) +void __attribute__((noipa)) parloop (int N) { int i; diff --git a/libphobos/configure b/libphobos/configure index 1b54066..3965e64 100755 --- a/libphobos/configure +++ b/libphobos/configure @@ -14920,7 +14920,7 @@ case $d_thread_model in # TODO: These targets need porting. dce|mipssde|rtems|tpf|vxworks) DCFG_THREAD_MODEL="Single" ;; - *) as_fn_error "Thread implementation '$d_thread_model' not recognised" "$LINENO" 5 ;; + *) as_fn_error $? "Thread implementation '$d_thread_model' not recognised" "$LINENO" 5 ;; esac diff --git a/libphobos/m4/druntime/os.m4 b/libphobos/m4/druntime/os.m4 index ef8ca43..7bb9136 100644 --- a/libphobos/m4/druntime/os.m4 +++ b/libphobos/m4/druntime/os.m4 @@ -32,7 +32,7 @@ case $1 in # TODO: These targets need porting. dce|mipssde|rtems|tpf|vxworks) DCFG_THREAD_MODEL="Single" ;; - *) as_fn_error "Thread implementation '$1' not recognised" "$LINENO" 5 ;; + *) AC_MSG_ERROR([Thread implementation '$1' not recognised]) ;; esac AC_SUBST(DCFG_THREAD_MODEL) ]) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index c01d044..c2a99de 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,71 @@ +2025-12-08 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/122946 + * include/bits/version.def (concepts): Set value to 202207. + * include/bits/version.h: Regenerate. + * include/std/concepts (__comparison_common_type_with_impl) + (__comparison_common_type_with): New helper concepts. + (equality_comparable_with): Use __comparison_common_type_with. + * libsupc++/compare (three_way_comparable_with): Likewise. + (__glibcxx_want_concepts): Define to get __cpp_lib_concepts + here. + * testsuite/std/concepts/concepts.compare/move_only.cc: New + test. + +2025-12-08 Jonathan Wakely <jwakely@redhat.com> + + * include/bits/intcmp.h: Replace all uses of + __is_standard_integer with __is_signed_or_unsigned_integer. + * include/bits/max_size_type.h: Fix outdated comment. + * include/bits/sat_arith.h: Replace all uses of + __is_standard_integer with __is_signed_or_unsigned_integer. + * include/c_compatibility/stdckdint.h: Replace all uses of the + __cv_unqual_signed_or_unsigned_integer_type concept with + __is_signed_or_unsigned_integer. + (__cv_unqual_signed_or_unsigned_integer_type): Remove. + * include/ext/numeric_traits.h: Fix outdated comment. + * include/std/charconv (from_chars): Replace use of + __is_standard_integer with __is_signed_or_unsigned_integer. + Do not enable for cv-qualified char. + * include/std/mdspan: Likewise. + * include/std/type_traits (__is_unsigned_integer): Include + unsigned __int128 in type list. + (__is_signed_integer): Include signed __int128 in type list. + (__is_standard_integer): Rename to ... + (__is_signed_or_unsigned_integer): ... this. + * testsuite/23_containers/mdspan/extents/ctor_ints.cc: Test + with 128-bit integers. + * testsuite/23_containers/mdspan/submdspan/strided_slice.cc: + Likewise. + * testsuite/20_util/integer_comparisons/extended.cc: New test. + * testsuite/26_numerics/saturation/extended.cc: New test. + * testsuite/26_numerics/stdckdint/extended.cc: New test. + +2025-12-08 Tomasz Kamiński <tkaminsk@redhat.com> + + PR libstdc++/112591 + * include/std/variant (_Variadic_union): Separate specializations for + for union of only trivially destructible types (true as first template + argument). Unconditionally define destructor for _Variadic_union<false, + _First, _Rest...>. + * testsuite/20_util/variant/87619.cc: Add limit for the template depth. + * testsuite/20_util/variant/112591.cc: New test. + +2025-12-08 Jonathan Wakely <jwakely@redhat.com> + + * include/bits/iterator_concepts.h: Remove diagnostic pragmas. + +2025-12-08 Jonathan Wakely <jwakely@redhat.com> + + * include/Makefile.am: Add new header. + * include/Makefile.in: Regenerate. + * include/std/latch: Include <bits/intcmp.h> instead of + <utility>. + * include/std/utility: Include <bits/intcmp.h>. + (cmp_equal, cmp_not_equal, cmp_less, cmp_greater) + (cmp_less_equal, cmp_greater_equal, in_range): Move to ... + * include/bits/intcmp.h: New file. + 2025-12-06 Jason Merrill <jason@redhat.com> * src/c++23/std.cc.in: Add more #if. diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index e4eb773..103515c 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -4193,9 +4193,7 @@ dnl Substs: dnl thread_header dnl AC_DEFUN([GLIBCXX_ENABLE_THREADS], [ - AC_MSG_CHECKING([for thread model used by GCC]) - target_thread_file=`$CXX -v 2>&1 | sed -n 's/^Thread model: //p'` - AC_MSG_RESULT([$target_thread_file]) + AC_REQUIRE([GCC_AC_THREAD_MODEL]) GCC_AC_THREAD_HEADER([$target_thread_file]) ]) @@ -4208,6 +4206,7 @@ dnl dnl GLIBCXX_ENABLE_SYMVERS must be done before this. dnl AC_DEFUN([GLIBCXX_CHECK_GTHREADS], [ + AC_REQUIRE([GCC_AC_THREAD_MODEL]) GLIBCXX_ENABLE(libstdcxx-threads,auto,,[enable C++11 threads support]) if test x$enable_libstdcxx_threads = xauto || @@ -4220,7 +4219,6 @@ AC_DEFUN([GLIBCXX_CHECK_GTHREADS], [ CXXFLAGS="$CXXFLAGS -fno-exceptions \ -I${toplevel_srcdir}/libgcc -I${toplevel_builddir}/libgcc" - target_thread_file=`$CXX -v 2>&1 | sed -n 's/^Thread model: //p'` case $target_thread_file in posix) CXXFLAGS="$CXXFLAGS -DSUPPORTS_WEAK -DGTHREAD_USE_WEAK -D_PTHREADS" diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index b1e1275..5f1f18c 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -16330,11 +16330,29 @@ $as_echo "$enable_libstdcxx_pch" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for thread model used by GCC" >&5 -$as_echo_n "checking for thread model used by GCC... " >&6; } - target_thread_file=`$CXX -v 2>&1 | sed -n 's/^Thread model: //p'` - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $target_thread_file" >&5 -$as_echo "$target_thread_file" >&6; } +# Specify the threading model for this GCC runtime library +# Pass with no value to take from compiler's metadata +# Pass with a value to specify a thread package +# 'single' means single threaded -- without threads. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the threading model used by GCC" >&5 +$as_echo_n "checking for the threading model used by GCC... " >&6; } +if ${gcc_cv_target_thread_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + + # Set new cache variable + gcc_cv_target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_target_thread_file" >&5 +$as_echo "$gcc_cv_target_thread_file" >&6; } +# Set variable name (not prefixed enough to be a good cache variable +# name) traditionally used for this purpose, to avoid having to change +# a bunch of configure scripts. +target_thread_file="$gcc_cv_target_thread_file" + + + case $target_thread_file in aix) thread_header=config/rs6000/gthr-aix.h ;; @@ -16349,6 +16367,9 @@ case $target_thread_file in vxworks) thread_header=config/gthr-vxworks.h ;; win32) thread_header=config/i386/gthr-win32.h ;; mcf) thread_header=config/i386/gthr-mcf.h ;; + *) + as_fn_error $? "No known header for threading model '$target_thread_file'." "$LINENO" 5 + ;; esac @@ -16422,7 +16443,7 @@ $as_echo "$glibcxx_cv_atomic_word" >&6; } # Fake what AC_TRY_COMPILE does. cat > conftest.$ac_ext << EOF -#line 16425 "configure" +#line 16446 "configure" #include "${glibcxx_srcdir}/config/$atomic_word_dir/atomic_word.h" int main() { @@ -16568,7 +16589,7 @@ $as_echo "mutex" >&6; } # unnecessary for this test. cat > conftest.$ac_ext << EOF -#line 16571 "configure" +#line 16592 "configure" int main() { _Decimal32 d1; @@ -16610,7 +16631,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu # unnecessary for this test. cat > conftest.$ac_ext << EOF -#line 16613 "configure" +#line 16634 "configure" template<typename T1, typename T2> struct same { typedef T2 type; }; @@ -52252,6 +52273,7 @@ done # For gthread support. Depends on GLIBCXX_ENABLE_SYMVERS. + # Check whether --enable-libstdcxx-threads was given. if test "${enable_libstdcxx_threads+set}" = set; then : enableval=$enable_libstdcxx_threads; @@ -52281,7 +52303,6 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu CXXFLAGS="$CXXFLAGS -fno-exceptions \ -I${toplevel_srcdir}/libgcc -I${toplevel_builddir}/libgcc" - target_thread_file=`$CXX -v 2>&1 | sed -n 's/^Thread model: //p'` case $target_thread_file in posix) CXXFLAGS="$CXXFLAGS -DSUPPORTS_WEAK -DGTHREAD_USE_WEAK -D_PTHREADS" @@ -53969,7 +53990,7 @@ $as_echo "$glibcxx_cv_libbacktrace_atomics" >&6; } CXXFLAGS='-O0 -S' cat > conftest.$ac_ext << EOF -#line 53972 "configure" +#line 53993 "configure" #include <stddef.h> int main() { diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 7d65c6f..847fc13 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -134,6 +134,7 @@ bits_freestanding = \ ${bits_srcdir}/enable_special_members.h \ ${bits_srcdir}/functexcept.h \ ${bits_srcdir}/functional_hash.h \ + ${bits_srcdir}/intcmp.h \ ${bits_srcdir}/invoke.h \ ${bits_srcdir}/iterator_concepts.h \ ${bits_srcdir}/max_size_type.h \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index acf8ae9..1d6171b 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -492,6 +492,7 @@ bits_freestanding = \ ${bits_srcdir}/enable_special_members.h \ ${bits_srcdir}/functexcept.h \ ${bits_srcdir}/functional_hash.h \ + ${bits_srcdir}/intcmp.h \ ${bits_srcdir}/invoke.h \ ${bits_srcdir}/iterator_concepts.h \ ${bits_srcdir}/max_size_type.h \ diff --git a/libstdc++-v3/include/bits/intcmp.h b/libstdc++-v3/include/bits/intcmp.h new file mode 100644 index 0000000..bb9c7f2 --- /dev/null +++ b/libstdc++-v3/include/bits/intcmp.h @@ -0,0 +1,120 @@ +// Integer comparison functions -*- C++ -*- + +// Copyright (C) 2020-2025 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// 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 +// <http://www.gnu.org/licenses/>. + +/** @file bits/intcmp.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{utility} + */ + +#ifndef _GLIBCXX_INTCMP_H +#define _GLIBCXX_INTCMP_H 1 + +#ifdef _GLIBCXX_SYSHDR +#pragma GCC system_header +#endif + +#include <bits/version.h> + +#ifdef __glibcxx_integer_comparison_functions // C++ >= 20 + +#include <type_traits> +#include <ext/numeric_traits.h> // __int_traits + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + template<typename _Tp, typename _Up> + constexpr bool + cmp_equal(_Tp __t, _Up __u) noexcept + { + static_assert(__is_signed_or_unsigned_integer<_Tp>::value); + static_assert(__is_signed_or_unsigned_integer<_Up>::value); + + if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) + return __t == __u; + else if constexpr (is_signed_v<_Tp>) + return __t >= 0 && make_unsigned_t<_Tp>(__t) == __u; + else + return __u >= 0 && __t == make_unsigned_t<_Up>(__u); + } + + template<typename _Tp, typename _Up> + constexpr bool + cmp_not_equal(_Tp __t, _Up __u) noexcept + { return !std::cmp_equal(__t, __u); } + + template<typename _Tp, typename _Up> + constexpr bool + cmp_less(_Tp __t, _Up __u) noexcept + { + static_assert(__is_signed_or_unsigned_integer<_Tp>::value); + static_assert(__is_signed_or_unsigned_integer<_Up>::value); + + if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) + return __t < __u; + else if constexpr (is_signed_v<_Tp>) + return __t < 0 || make_unsigned_t<_Tp>(__t) < __u; + else + return __u >= 0 && __t < make_unsigned_t<_Up>(__u); + } + + template<typename _Tp, typename _Up> + constexpr bool + cmp_greater(_Tp __t, _Up __u) noexcept + { return std::cmp_less(__u, __t); } + + template<typename _Tp, typename _Up> + constexpr bool + cmp_less_equal(_Tp __t, _Up __u) noexcept + { return !std::cmp_less(__u, __t); } + + template<typename _Tp, typename _Up> + constexpr bool + cmp_greater_equal(_Tp __t, _Up __u) noexcept + { return !std::cmp_less(__t, __u); } + + template<typename _Res, typename _Tp> + constexpr bool + in_range(_Tp __t) noexcept + { + static_assert(__is_signed_or_unsigned_integer<_Res>::value); + static_assert(__is_signed_or_unsigned_integer<_Tp>::value); + using __gnu_cxx::__int_traits; + + if constexpr (is_signed_v<_Tp> == is_signed_v<_Res>) + return __int_traits<_Res>::__min <= __t + && __t <= __int_traits<_Res>::__max; + else if constexpr (is_signed_v<_Tp>) + return __t >= 0 + && make_unsigned_t<_Tp>(__t) <= __int_traits<_Res>::__max; + else + return __t <= make_unsigned_t<_Res>(__int_traits<_Res>::__max); + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // __glibcxx_integer_comparison_functions +#endif // _GLIBCXX_INTCMP_H diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index fd91b22..40ac808 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -39,9 +39,6 @@ #include <bits/ptr_traits.h> // to_address #include <bits/ranges_cmp.h> // identity, ranges::less -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" // __int128 - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -1032,6 +1029,5 @@ namespace ranges #endif // C++20 library concepts _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#pragma GCC diagnostic pop #endif // C++20 #endif // _ITERATOR_CONCEPTS_H diff --git a/libstdc++-v3/include/bits/max_size_type.h b/libstdc++-v3/include/bits/max_size_type.h index a34b91a..537acee 100644 --- a/libstdc++-v3/include/bits/max_size_type.h +++ b/libstdc++-v3/include/bits/max_size_type.h @@ -44,10 +44,8 @@ // [iterator.concept.winc]) that are one bit wider than the widest supported // integer type. // -// The set of integer types we consider includes __int128 and unsigned __int128 -// (when they exist), even though they are really integer types only in GNU -// mode. This is to obtain a consistent ABI for these integer-class types -// across strict mode and GNU mode. +// The set of integer types we consider includes the extended integer types +// __int128 and unsigned __int128 (when they exist). namespace std _GLIBCXX_VISIBILITY(default) { diff --git a/libstdc++-v3/include/bits/sat_arith.h b/libstdc++-v3/include/bits/sat_arith.h index e036fc8..bce86d9 100644 --- a/libstdc++-v3/include/bits/sat_arith.h +++ b/libstdc++-v3/include/bits/sat_arith.h @@ -46,7 +46,7 @@ namespace std _GLIBCXX_VISIBILITY(default) _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Add two integers, with saturation in case of overflow. - template<typename _Tp> requires __is_standard_integer<_Tp>::value + template<typename _Tp> requires __is_signed_or_unsigned_integer<_Tp>::value constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept { @@ -62,7 +62,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } /// Subtract one integer from another, with saturation in case of overflow. - template<typename _Tp> requires __is_standard_integer<_Tp>::value + template<typename _Tp> requires __is_signed_or_unsigned_integer<_Tp>::value constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept { @@ -78,7 +78,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } /// Multiply two integers, with saturation in case of overflow. - template<typename _Tp> requires __is_standard_integer<_Tp>::value + template<typename _Tp> requires __is_signed_or_unsigned_integer<_Tp>::value constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept { @@ -94,7 +94,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } /// Divide one integer by another, with saturation in case of overflow. - template<typename _Tp> requires __is_standard_integer<_Tp>::value + template<typename _Tp> requires __is_signed_or_unsigned_integer<_Tp>::value constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept { @@ -107,8 +107,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Divide one integer by another, with saturation in case of overflow. template<typename _Res, typename _Tp> - requires __is_standard_integer<_Res>::value - && __is_standard_integer<_Tp>::value + requires __is_signed_or_unsigned_integer<_Res>::value + && __is_signed_or_unsigned_integer<_Tp>::value constexpr _Res saturate_cast(_Tp __x) noexcept { diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 412b9ce..5c010a4 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -879,8 +879,12 @@ ftms = { ftms = { name = concepts; + // 201806 P0898R3 Standard Library Concepts + // 201907 P1754R1 Rename concepts to standard_case for C++20 + // 202002 P1964R2 Wording for boolean-testable + // 202207 P2404R3 Move-only types for equality_comparable_with, etc. values = { - v = 202002; + v = 202207; cxxmin = 20; extra_cond = "__cpp_concepts >= 201907L"; }; @@ -1090,17 +1094,17 @@ ftms = { name = padded_layouts; no_stdname = true; // internal values = { - v = 1; + v = 202403; cxxmin = 26; }; }; ftms = { name = submdspan; - no_stdname = true; // TODO: change once complete values = { - v = 1; + v = 202411; cxxmin = 26; + extra_cond = "__glibcxx_constant_wrapper >= 202506L"; }; }; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 2b96934..26d0689 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -985,9 +985,9 @@ #if !defined(__cpp_lib_concepts) # if (__cplusplus >= 202002L) && (__cpp_concepts >= 201907L) -# define __glibcxx_concepts 202002L +# define __glibcxx_concepts 202207L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_concepts) -# define __cpp_lib_concepts 202002L +# define __cpp_lib_concepts 202207L # endif # endif #endif /* !defined(__cpp_lib_concepts) */ @@ -1214,7 +1214,7 @@ #if !defined(__cpp_lib_padded_layouts) # if (__cplusplus > 202302L) -# define __glibcxx_padded_layouts 1L +# define __glibcxx_padded_layouts 202403L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_padded_layouts) # endif # endif @@ -1222,9 +1222,10 @@ #undef __glibcxx_want_padded_layouts #if !defined(__cpp_lib_submdspan) -# if (__cplusplus > 202302L) -# define __glibcxx_submdspan 1L +# if (__cplusplus > 202302L) && (__glibcxx_constant_wrapper >= 202506L) +# define __glibcxx_submdspan 202411L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_submdspan) +# define __cpp_lib_submdspan 202411L # endif # endif #endif /* !defined(__cpp_lib_submdspan) */ @@ -2037,7 +2038,7 @@ # define __cpp_lib_common_reference 202302L # endif # endif -#endif /* !defined(__cpp_lib_common_reference) && defined(__glibcxx_want_common_reference) */ +#endif /* !defined(__cpp_lib_common_reference) */ #undef __glibcxx_want_common_reference #if !defined(__cpp_lib_common_reference_wrapper) @@ -2047,7 +2048,7 @@ # define __cpp_lib_common_reference_wrapper 202302L # endif # endif -#endif /* !defined(__cpp_lib_common_reference_wrapper) && defined(__glibcxx_want_common_reference_wrapper) */ +#endif /* !defined(__cpp_lib_common_reference_wrapper) */ #undef __glibcxx_want_common_reference_wrapper #if !defined(__cpp_lib_formatters) diff --git a/libstdc++-v3/include/c_compatibility/stdckdint.h b/libstdc++-v3/include/c_compatibility/stdckdint.h index 1de2d18..5bdf4dc 100644 --- a/libstdc++-v3/include/c_compatibility/stdckdint.h +++ b/libstdc++-v3/include/c_compatibility/stdckdint.h @@ -40,15 +40,6 @@ namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) { #endif -/// @cond undocumented -namespace __detail -{ - template<typename _Tp> - concept __cv_unqual_signed_or_unsigned_integer_type - = std::same_as<_Tp, std::remove_cv_t<_Tp>> - && std::__is_standard_integer<_Tp>::value; -} -/// @endcond /** Checked integer arithmetic * @@ -71,10 +62,9 @@ template<typename _Tp1, typename _Tp2, typename _Tp3> inline bool ckd_add(_Tp1* __result, _Tp2 __a, _Tp3 __b) { - using __gnu_cxx::__detail::__cv_unqual_signed_or_unsigned_integer_type; - static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp1>); - static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp2>); - static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp3>); + static_assert(std::__is_signed_or_unsigned_integer<_Tp1>::value); + static_assert(std::__is_signed_or_unsigned_integer<_Tp2>::value); + static_assert(std::__is_signed_or_unsigned_integer<_Tp3>::value); return __builtin_add_overflow(__a, __b, __result); } @@ -82,10 +72,9 @@ template<typename _Tp1, typename _Tp2, typename _Tp3> inline bool ckd_sub(_Tp1* __result, _Tp2 __a, _Tp3 __b) { - using __gnu_cxx::__detail::__cv_unqual_signed_or_unsigned_integer_type; - static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp1>); - static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp2>); - static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp3>); + static_assert(std::__is_signed_or_unsigned_integer<_Tp1>::value); + static_assert(std::__is_signed_or_unsigned_integer<_Tp2>::value); + static_assert(std::__is_signed_or_unsigned_integer<_Tp3>::value); return __builtin_sub_overflow(__a, __b, __result); } @@ -93,15 +82,14 @@ template<typename _Tp1, typename _Tp2, typename _Tp3> inline bool ckd_mul(_Tp1* __result, _Tp2 __a, _Tp3 __b) { - using __gnu_cxx::__detail::__cv_unqual_signed_or_unsigned_integer_type; - static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp1>); - static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp2>); - static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp3>); + static_assert(std::__is_signed_or_unsigned_integer<_Tp1>::value); + static_assert(std::__is_signed_or_unsigned_integer<_Tp2>::value); + static_assert(std::__is_signed_or_unsigned_integer<_Tp3>::value); return __builtin_mul_overflow(__a, __b, __result); } /// @} #ifndef _GLIBCXX_DOXYGEN -} +} // namespace __gnu_cxx using __gnu_cxx::ckd_add; using __gnu_cxx::ckd_sub; diff --git a/libstdc++-v3/include/ext/numeric_traits.h b/libstdc++-v3/include/ext/numeric_traits.h index 6786dc6..78cb8e3 100644 --- a/libstdc++-v3/include/ext/numeric_traits.h +++ b/libstdc++-v3/include/ext/numeric_traits.h @@ -48,7 +48,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // or is_signed, digits10, max_digits10, or max_exponent10 for floats. // Unlike __is_integer (and std::is_integral) this trait is true for - // non-standard built-in integer types such as __int128 and __int20. + // non-standard built-in integer types such as __int20. template<typename _Tp> struct __is_integer_nonstrict : public std::__is_integer<_Tp> diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv index 8cf2c0b..47f5aaa 100644 --- a/libstdc++-v3/include/std/charconv +++ b/libstdc++-v3/include/std/charconv @@ -554,10 +554,10 @@ namespace __detail } // namespace __detail - /// std::from_chars for integral types. + /// std::from_chars for integer types. template<typename _Tp, - enable_if_t<__or_<__is_standard_integer<_Tp>, - is_same<char, remove_cv_t<_Tp>>>::value, int> = 0> + enable_if_t<__or_<__is_signed_or_unsigned_integer<_Tp>, + is_same<char, _Tp>>::value, int> = 0> _GLIBCXX23_CONSTEXPR from_chars_result from_chars(const char* __first, const char* __last, _Tp& __value, int __base = 10) diff --git a/libstdc++-v3/include/std/concepts b/libstdc++-v3/include/std/concepts index d9920a8..870b0a4 100644 --- a/libstdc++-v3/include/std/concepts +++ b/libstdc++-v3/include/std/concepts @@ -296,6 +296,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { { !static_cast<_Tp&&>(__t) } -> __boolean_testable_impl; }; } // namespace __detail + // [concept.comparisoncommontype], helpers for comparison common types + namespace __detail + { + template<typename _Tp, typename _Up, + typename _Cref = common_reference_t<const _Tp&, const _Up&>> + concept __comparison_common_type_with_impl + = same_as<common_reference_t<const _Tp&, const _Up&>, + common_reference_t<const _Up&, const _Tp&>> + && requires { + requires convertible_to<const _Tp&, const _Cref&> + || convertible_to<_Tp, const _Cref&>; + requires convertible_to<const _Up&, const _Cref&> + || convertible_to<_Up, const _Cref&>; + }; + + template<typename _Tp, typename _Up> + concept __comparison_common_type_with + = __comparison_common_type_with_impl<remove_cvref_t<_Tp>, + remove_cvref_t<_Up>>; + } // namespace __detail + // [concept.equalitycomparable], concept equality_comparable namespace __detail @@ -316,7 +337,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Up> concept equality_comparable_with = equality_comparable<_Tp> && equality_comparable<_Up> - && common_reference_with<__detail::__cref<_Tp>, __detail::__cref<_Up>> + && __detail::__comparison_common_type_with<_Tp, _Up> && equality_comparable<common_reference_t<__detail::__cref<_Tp>, __detail::__cref<_Up>>> && __detail::__weakly_eq_cmp_with<_Tp, _Up>; diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch index 9504df0..df126c6 100644 --- a/libstdc++-v3/include/std/latch +++ b/libstdc++-v3/include/std/latch @@ -41,7 +41,7 @@ #ifdef __cpp_lib_latch // C++ >= 20 && atomic_wait #include <bits/atomic_base.h> #include <ext/numeric_traits.h> -#include <utility> // cmp_equal, cmp_less_equal, etc. +#include <bits/intcmp.h> // cmp_equal, cmp_less_equal, etc. namespace std _GLIBCXX_VISIBILITY(default) { diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index 03cc4f0..dc0aa4f 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -271,7 +271,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION requires (_Extents.size() > 0) { return {_M_dyn_exts + _S_dynamic_index(__begin), - _M_dyn_exts + _S_dynamic_index(__end)}; + _S_dynamic_index(__end) - _S_dynamic_index(__begin)}; } private: @@ -352,11 +352,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _OffsetType, typename _ExtentType, typename _StrideType> struct strided_slice { - static_assert(__is_standard_integer<_OffsetType>::value + static_assert(__is_signed_or_unsigned_integer<_OffsetType>::value || __detail::__integral_constant_like<_OffsetType>); - static_assert(__is_standard_integer<_ExtentType>::value + static_assert(__is_signed_or_unsigned_integer<_ExtentType>::value || __detail::__integral_constant_like<_ExtentType>); - static_assert(__is_standard_integer<_StrideType>::value + static_assert(__is_signed_or_unsigned_integer<_StrideType>::value || __detail::__integral_constant_like<_StrideType>); using offset_type = _OffsetType; @@ -374,12 +374,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION [[no_unique_address]] _Mapping mapping = _Mapping(); size_t offset{}; }; + + template<typename _Tp> + constexpr bool __is_submdspan_mapping_result = false; + + template<typename _Mapping> + constexpr bool __is_submdspan_mapping_result<submdspan_mapping_result<_Mapping>> = true; + + template<typename _Mapping> + concept __submdspan_mapping_result = __is_submdspan_mapping_result<_Mapping>; + #endif // __glibcxx_submdspan template<typename _IndexType, size_t... _Extents> class extents { - static_assert(__is_standard_integer<_IndexType>::value, + static_assert(__is_signed_or_unsigned_integer<_IndexType>::value, "IndexType must be a signed or unsigned integer type"); static_assert( (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...), @@ -589,6 +599,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } } + template<typename _IndexType, size_t _Nm> + consteval _IndexType + __fwd_prod(span<const _IndexType, _Nm> __values) + { + _IndexType __ret = 1; + for(auto __value : __values) + __ret *= __value; + return __ret; + } + // Preconditions: _r < _Extents::rank() template<typename _Extents> constexpr typename _Extents::index_type @@ -792,6 +812,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Mapping> constexpr bool __is_right_padded_mapping = __padded_mapping_of< layout_right_padded, _Mapping>; + + template<typename _Mapping> + constexpr bool __is_padded_mapping = __is_left_padded_mapping<_Mapping> + || __is_right_padded_mapping<_Mapping>; #endif template<typename _PaddedMapping> @@ -866,6 +890,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __exts.extent(_Index)}; } + template<typename _Slice, typename _IndexType> + concept __acceptable_slice_type = same_as<_Slice, full_extent_t> + || same_as<_Slice, _IndexType> || __is_constant_wrapper<_Slice> + || __is_strided_slice<_Slice>; + template<typename _IndexType, typename... _Slices> consteval auto __subrank() @@ -890,6 +919,547 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __map[__i++] = __k; return __map; } + + template<typename _Slice> + constexpr auto + __slice_begin(_Slice __slice) + { + if constexpr (same_as<_Slice, full_extent_t>) + return 0; + else if constexpr (__is_strided_slice<_Slice>) + return __slice.offset; + else + return __slice; // collapsing slice + } + + template<typename _Mapping, typename... _Slices> + constexpr size_t + __suboffset(const _Mapping& __mapping, const _Slices&... __slices) + { + using _IndexType = typename _Mapping::index_type; + auto __any_past_the_end = [&]<size_t... _Is>(index_sequence<_Is...>) + { + auto __is_past_the_end = [](const auto& __slice, const auto& __ext) + { + using _Slice = remove_cvref_t<decltype(__slice)>; + if constexpr (is_convertible_v<_Slice, _IndexType>) + return false; + else if constexpr (same_as<_Slice, full_extent_t> + && __ext.static_extent(0) != 0 + && __ext.static_extent(0) != dynamic_extent) + return false; + else + return __mdspan::__slice_begin(__slice) == __ext.extent(0); + }; + + const auto& __exts = __mapping.extents(); + return ((__is_past_the_end(__slices...[_Is], + __mdspan::__extract_extent<_Is>(__exts))) || ...); + }; + + if constexpr ((same_as<_Slices, full_extent_t> && ...)) + return __mdspan::__offset(__mapping); + + if (__any_past_the_end(std::make_index_sequence<sizeof...(__slices)>())) + return __mapping.required_span_size(); + return __mapping(__mdspan::__slice_begin(__slices)...); + } + + template<typename _IndexType, size_t _Extent, typename _Slice> + consteval size_t + __static_slice_extent() + { + if constexpr (same_as<_Slice, full_extent_t>) + return _Extent; + else if constexpr (same_as<_Slice, constant_wrapper<_IndexType(0)>>) + return 0; + else if constexpr (__is_constant_wrapper<typename _Slice::extent_type> + && __is_constant_wrapper<typename _Slice::stride_type>) + return 1 + ((typename _Slice::extent_type{}) - 1) + / (typename _Slice::stride_type{}); + else + return dynamic_extent; + } + + template<size_t _K, typename _Extents, typename _Slice> + constexpr typename _Extents::index_type + __dynamic_slice_extent(const _Extents& __exts, _Slice __slice) + { + if constexpr (__is_strided_slice<_Slice>) + return __slice.extent == 0 ? 0 : 1 + (__slice.extent - 1) / __slice.stride; + else + return __exts.extent(_K); + } + + template<typename _IndexType, size_t... _Extents, typename... _Slices> + requires (sizeof...(_Slices) == sizeof...(_Extents)) + constexpr auto + __subextents(const extents<_IndexType, _Extents...>& __exts, + _Slices... __slices) + { + constexpr auto __inv_map = __mdspan::__inv_map_rank<_IndexType, _Slices...>(); + auto __impl = [&]<size_t... _Indices>(std::index_sequence<_Indices...>) + { + using _SubExts = extents<_IndexType, + __mdspan::__static_slice_extent<_IndexType, + _Extents...[__inv_map[_Indices]], + _Slices...[__inv_map[_Indices]]>()...>; + if constexpr (_SubExts::rank_dynamic() == 0) + return _SubExts{}; + else + { + using _StaticSubExtents = __mdspan::_StaticExtents< + __mdspan::__static_extents<_SubExts>()>; + auto __create = [&]<size_t... _Is>(std::index_sequence<_Is...>) + { + constexpr auto __slice_idx = [__inv_map](size_t __i) consteval + { + return __inv_map[_StaticSubExtents::_S_dynamic_index_inv(__i)]; + }; + + return _SubExts{__mdspan::__dynamic_slice_extent<__slice_idx(_Is)>( + __exts, __slices...[__slice_idx(_Is)])...}; + }; + constexpr auto __dyn_subrank = _SubExts::rank_dynamic(); + return __create(std::make_index_sequence<__dyn_subrank>()); + } + }; + + return __impl(std::make_index_sequence<__inv_map.size()>()); + } + + enum class _LayoutSide + { + __left, + __right, + __unknown + }; + + template<typename _Mapping> + consteval _LayoutSide + __mapping_side() + { + if constexpr (__is_left_padded_mapping<_Mapping> + || __mapping_of<layout_left, _Mapping>) + return _LayoutSide::__left; + if constexpr (__is_right_padded_mapping<_Mapping> + || __mapping_of<layout_right, _Mapping>) + return _LayoutSide::__right; + else + return _LayoutSide::__unknown; + } + + template<_LayoutSide _Side, size_t _Rank> + struct _StridesTrait + { + static constexpr const _LayoutSide _S_side = _Side; + + static constexpr size_t + _S_idx(size_t __k) noexcept + { + if constexpr (_Side == _LayoutSide::__left) + return __k; + else + return _Rank - 1 - __k; + } + + // Unifies the formulas for computing strides for padded and unpadded + // layouts. + template<typename _Mapping> + static constexpr typename _Mapping::index_type + _S_padded_extent(const _Mapping& __mapping, size_t __k) + { + if (__k == 0) + return __mapping.stride(_S_idx(1)); + else + return __mapping.extents().extent(_S_idx(__k)); + } + + template<typename _IndexType, typename... _Slices> + static consteval auto + _S_inv_map() + { + static_assert(_Side != _LayoutSide::__unknown); + auto __impl = [&]<size_t... _Is>(std::index_sequence<_Is...>) + { + return __mdspan::__inv_map_rank<_IndexType, _Slices...[_S_idx(_Is)]...>(); + }; + return __impl(std::make_index_sequence<_Rank>()); + } + }; + + template<typename _SubExts, typename _Mapping, typename... _Slices> + constexpr auto + __substrides_generic(const _Mapping& __mapping, const _Slices&... __slices) + { + using _IndexType = typename _Mapping::index_type; + if constexpr (_SubExts::rank() == 0) + return array<_IndexType, _SubExts::rank()>{}; + else + { + auto __stride = [&__mapping](size_t __k, auto __slice) -> _IndexType + { + if constexpr (__is_strided_slice<decltype(__slice)>) + if (__slice.stride < __slice.extent) + return __mapping.stride(__k) * __slice.stride; + return __mapping.stride(__k); + }; + + auto __impl = [&]<size_t... _Is>(std::index_sequence<_Is...>) + { + constexpr auto __inv_map + = __mdspan::__inv_map_rank<_IndexType, _Slices...>(); + return array<_IndexType, _SubExts::rank()>{ + __stride(__inv_map[_Is], __slices...[__inv_map[_Is]])...}; + }; + return __impl(std::make_index_sequence<_SubExts::rank()>()); + } + }; + + template<typename _SubExts, typename _Mapping, typename... _Slices> + constexpr auto + __substrides_standardized(const _Mapping& __mapping, + const _Slices&... __slices) + { + using _IndexType = typename _Mapping::index_type; + using _Trait = _StridesTrait<__mapping_side<_Mapping>(), + _Mapping::extents_type::rank()>; + using _SubTrait = _StridesTrait<__mapping_side<_Mapping>(), _SubExts::rank()>; + + constexpr size_t __sub_rank = _SubExts::rank(); + + std::array<_IndexType, __sub_rank> __ret; + if constexpr (__sub_rank > 0) + { + constexpr auto __inv_map + = _Trait::template _S_inv_map<_IndexType, _Slices...>(); + auto __loop = [&]<size_t... _Ks>(std::index_sequence<_Ks...>) + { + size_t __i0 = 0; + size_t __stride = 1; + auto __body = [&](size_t __k, auto __slice) + { + for (size_t __i = __i0; __i < __inv_map[__k]; ++__i) + __stride *= _Trait::_S_padded_extent(__mapping, __i); + + size_t __krev = _SubTrait::_S_idx(__k); + if constexpr (__is_strided_slice<decltype(__slice)>) + { + if (__slice.stride < __slice.extent) + __ret[__krev] = __stride * __slice.stride; + else + __ret[__krev] = __stride; + } + else + __ret[__krev] = __stride; + + __i0 = __inv_map[__k]; + }; + + ((__body(_Ks, __slices...[_Trait::_S_idx(__inv_map[_Ks])])),...); + }; + __loop(std::make_index_sequence<__sub_rank>()); + } + return __ret; + } + + + template<typename _SubExts, typename _Mapping, typename... _Slices> + constexpr auto + __substrides(const _Mapping& __mapping, const _Slices&... __slices) + { + if constexpr (__mdspan::__mapping_side<_Mapping>() == _LayoutSide::__unknown) + return __mdspan::__substrides_generic<_SubExts>(__mapping, __slices...); + else + return __mdspan::__substrides_standardized<_SubExts>(__mapping, __slices...); + } + + template<typename _Slice> + concept __is_unit_stride_slice = (__mdspan::__is_strided_slice<_Slice> + && __mdspan::__is_constant_wrapper<typename _Slice::stride_type> + && _Slice::stride_type::value == 1) + || std::same_as<_Slice, full_extent_t>; + + // These are (forced) exclusive categories: + // - full & collapsing: obvious, + // - unit_strided_slice: strided_slice{a, b, cw<1>}, but not `full`, + // - strided_slice: strided_slice{a, b, c} with c != cw<1>. + enum class _SliceKind + { + __strided_slice, + __unit_strided_slice, + __full, + __collapsing + }; + + template<typename _Slice> + consteval _SliceKind + __make_slice_kind() + { + if constexpr (std::same_as<_Slice, full_extent_t>) + return _SliceKind::__full; + else if constexpr (__mdspan::__is_strided_slice<_Slice>) + { + if constexpr (__mdspan::__is_unit_stride_slice<_Slice>) + return _SliceKind::__unit_strided_slice; + else + return _SliceKind::__strided_slice; + } + else + return _SliceKind::__collapsing; + } + + template<typename... _Slices> + consteval array<_SliceKind, sizeof...(_Slices)> + __make_slice_kind_array() + { + return array<_SliceKind, sizeof...(_Slices)>{ + __mdspan::__make_slice_kind<_Slices>()...}; + } + + // __block_size - 1 + // [full, ..., full, unit_slice , *] + consteval bool + __is_block(span<const _SliceKind> __slice_kinds, size_t __block_size) + { + if (__block_size == 0) + return false; + + if (__block_size > __slice_kinds.size()) + return false; + + for (size_t __i = 0; __i < __block_size - 1; ++__i) + if (__slice_kinds[__i] != _SliceKind::__full) + return false; + + auto __last = __slice_kinds[__block_size - 1]; + return __last == _SliceKind::__full + || __last == _SliceKind::__unit_strided_slice; + } + + // __u __u + __sub_rank-2 + // [unit_slice, i, ..., k, full, ..., full, unit_slice, *] + static consteval size_t + __padded_block_begin_generic(span<const _SliceKind> __slice_kinds, + size_t __sub_rank) + { + if (__slice_kinds[0] != _SliceKind::__full + && __slice_kinds[0] != _SliceKind::__unit_strided_slice) + return dynamic_extent; + else if (__slice_kinds.size() == 1) + return dynamic_extent; + else + { + size_t __u = 1; + while(__u < __slice_kinds.size() + && __slice_kinds[__u] == _SliceKind::__collapsing) + ++__u; + + if (__mdspan::__is_block(__slice_kinds.subspan(__u), __sub_rank -1)) + return __u; + return dynamic_extent; + } + } + + template<_LayoutSide _Side, size_t _Nm> + static consteval size_t + __padded_block_begin(span<const _SliceKind, _Nm> __slice_kinds, size_t __sub_rank) + { + if constexpr (_Side == _LayoutSide::__left) + return __mdspan::__padded_block_begin_generic(__slice_kinds, __sub_rank); + else + { + std::array<_SliceKind, _Nm> __rev_slices; + for(size_t __i = 0; __i < _Nm; ++__i) + __rev_slices[__i] = __slice_kinds[_Nm - 1 - __i]; + auto __rev_slice_kinds = span<const _SliceKind>(__rev_slices); + + auto __u = __mdspan::__padded_block_begin_generic(__rev_slice_kinds, + __sub_rank); + return __u == dynamic_extent ? dynamic_extent : _Nm - 1 - __u; + } + } + + template<_LayoutSide _Side, bool _Padded> + struct _SubMdspanMapping; + + template<> + struct _SubMdspanMapping<_LayoutSide::__left, false> + { + using _Layout = layout_left; + template<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>; + + template<typename _Mapping, size_t _Us> + static consteval size_t + _S_pad() + { + using _Extents = typename _Mapping::extents_type; + constexpr auto __sta_exts = __mdspan::__static_extents<_Extents>(0, _Us); + if constexpr (!__mdspan::__all_static(__sta_exts)) + return dynamic_extent; + else + return __mdspan::__fwd_prod(__sta_exts); + } + + template<size_t _Nm> + static consteval bool + _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, size_t __sub_rank) + { return __mdspan::__is_block(__slice_kinds, __sub_rank); } + }; + + template<> + struct _SubMdspanMapping<_LayoutSide::__left, true> + { + using _Layout = layout_left; + template<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>; + + template<typename _Mapping, size_t _Us> + static consteval size_t + _S_pad() + { + using _Extents = typename _Mapping::extents_type; + constexpr auto __sta_exts + = __mdspan::__static_extents<_Extents>(1, _Us); + constexpr auto __sta_padstride + = __mdspan::__get_static_stride<_Mapping>(); + if constexpr (__sta_padstride == dynamic_extent + || !__mdspan::__all_static(__sta_exts)) + return dynamic_extent; + else + return __sta_padstride * __mdspan::__fwd_prod(__sta_exts); + } + + template<size_t _Nm> + static consteval bool + _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, + size_t __sub_rank) + { + if (__sub_rank == 1) + return __slice_kinds[0] == _SliceKind::__unit_strided_slice + || __slice_kinds[0] == _SliceKind::__full; + else + return false; + } + }; + + template<> + struct _SubMdspanMapping<_LayoutSide::__right, false> + { + using _Layout = layout_right; + template<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>; + + template<typename _Mapping, size_t _Us> + static consteval size_t + _S_pad() + { + using _Extents = typename _Mapping::extents_type; + constexpr auto __rank = _Extents::rank(); + constexpr auto __sta_exts + = __mdspan::__static_extents<_Extents>(_Us + 1, __rank); + if constexpr (!__mdspan::__all_static(__sta_exts)) + return dynamic_extent; + else + return __fwd_prod(__sta_exts); + } + + template<size_t _Nm> + static consteval bool + _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, + size_t __sub_rank) + { + auto __rev_slice_kinds = array<_SliceKind, _Nm>{}; + for(size_t __i = 0; __i < _Nm; ++__i) + __rev_slice_kinds[__i] = __slice_kinds[_Nm - 1 - __i]; + return __mdspan::__is_block(span(__rev_slice_kinds), __sub_rank); + } + }; + + template<> + struct _SubMdspanMapping<_LayoutSide::__right, true> + { + using _Layout = layout_right; + template<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>; + + template<typename _Mapping, size_t _Us> + static consteval size_t + _S_pad() + { + using _Extents = typename _Mapping::extents_type; + constexpr auto __rank = _Extents::rank(); + constexpr auto __sta_exts + = __mdspan::__static_extents<_Extents>(_Us + 1, __rank - 1); + constexpr auto __sta_padstride + = __mdspan::__get_static_stride<_Mapping>(); + if constexpr (__sta_padstride == dynamic_extent + || !__mdspan::__all_static(__sta_exts)) + return dynamic_extent; + else + return __sta_padstride * __mdspan::__fwd_prod(__sta_exts); + } + + template<size_t _Nm> + static consteval bool + _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, + size_t __sub_rank) + { + if (__sub_rank == 1) + return __slice_kinds[_Nm - 1] == _SliceKind::__unit_strided_slice + || __slice_kinds[_Nm - 1] == _SliceKind::__full; + else + return false; + } + }; + + + template<typename _Mapping> + constexpr auto + __submdspan_mapping_impl(const _Mapping& __mapping) + { return submdspan_mapping_result{__mapping, 0}; } + + template<typename _Mapping, typename... _Slices> + requires (sizeof...(_Slices) > 0) + constexpr auto + __submdspan_mapping_impl(const _Mapping& __mapping, _Slices... __slices) + { + using _IndexType = typename _Mapping::index_type; + static_assert((__acceptable_slice_type<_Slices, _IndexType> && ...)); + + constexpr auto __side = __mdspan::__mapping_side<_Mapping>(); + constexpr auto __rank = sizeof...(_Slices); + using _Trait = _SubMdspanMapping<__side, __is_padded_mapping<_Mapping>>; + using _SliceView = span<const _SliceKind, __rank>; + + constexpr auto __slice_kinds = __mdspan::__make_slice_kind_array<_Slices...>(); + auto __offset = __mdspan::__suboffset(__mapping, __slices...); + auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...); + using _SubExts = decltype(__sub_exts); + constexpr auto __sub_rank = _SubExts::rank(); + if constexpr (__sub_rank == 0) + return submdspan_mapping_result{ + typename _Trait::_Layout::mapping(__sub_exts), __offset}; + else if constexpr (_Trait::_S_is_unpadded_submdspan( + _SliceView(__slice_kinds), __sub_rank)) + return submdspan_mapping_result{ + typename _Trait::_Layout::mapping(__sub_exts), __offset}; + else if constexpr ( + constexpr auto __u = __padded_block_begin<__side>( + _SliceView(__slice_kinds), __sub_rank); + __u != dynamic_extent) + { + constexpr auto __pad = _Trait::template _S_pad<_Mapping, __u>(); + using _Layout = typename _Trait::template _PaddedLayout<__pad>; + return submdspan_mapping_result{ + typename _Layout::mapping(__sub_exts, __mapping.stride(__u)), + __offset}; + } + else + { + auto __sub_strides + = __mdspan::__substrides<_SubExts>(__mapping, __slices...); + return submdspan_mapping_result{ + layout_stride::mapping(__sub_exts, __sub_strides), __offset}; + } + } #endif // __glibcxx_submdspan } @@ -1032,6 +1602,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } +#if __glibcxx_submdspan + template<typename... _Slices> + requires (extents_type::rank() == sizeof...(_Slices)) + friend constexpr auto + submdspan_mapping(const mapping& __mapping, _Slices... __slices) + { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } +#endif // __glibcxx_submdspan + [[no_unique_address]] extents_type _M_extents{}; }; @@ -1208,6 +1786,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } +#if __glibcxx_submdspan + template<typename... _Slices> + requires (extents_type::rank() == sizeof...(_Slices)) + friend constexpr auto + submdspan_mapping(const mapping& __mapping, _Slices... __slices) + { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } +#endif // __glibcxx_submdspan + [[no_unique_address]] extents_type _M_extents{}; }; @@ -1418,6 +2004,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } private: +#if __glibcxx_submdspan + template<typename... _Slices> + requires (extents_type::rank() == sizeof...(_Slices)) + friend constexpr auto + submdspan_mapping(const mapping& __mapping, _Slices... __slices) + { + if constexpr (sizeof...(_Slices) == 0) + return submdspan_mapping_result{__mapping, 0}; + else + { + auto __offset = __mdspan::__suboffset(__mapping, __slices...); + auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...); + auto __sub_strides + = __mdspan::__substrides<decltype(__sub_exts)>(__mapping, __slices...); + return submdspan_mapping_result{ + layout_stride::mapping(__sub_exts, __sub_strides), __offset}; + } + } +#endif + using _Strides = typename __array_traits<index_type, extents_type::rank()>::_Type; [[no_unique_address]] extents_type _M_extents; @@ -2028,6 +2634,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator==(const mapping& __self, const _LeftpadMapping& __other) noexcept { return __self._M_storage._M_equal(__other); } + + private: +#if __glibcxx_submdspan + template<typename... _Slices> + requires (extents_type::rank() == sizeof...(_Slices)) + friend constexpr auto + submdspan_mapping(const mapping& __mapping, _Slices... __slices) + { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } +#endif // __glibcxx_submdspan }; template<size_t _PaddingValue> @@ -2197,6 +2812,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator==(const mapping& __self, const _RightPaddedMapping& __other) noexcept { return __self._M_storage._M_equal(__other); } + +#if __glibcxx_submdspan + private: + template<typename... _Slices> + requires (extents_type::rank() == sizeof...(_Slices)) + friend constexpr auto + submdspan_mapping(const mapping& __mapping, _Slices... __slices) + { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } +#endif // __glibcxx_submdspan }; #endif // __glibcxx_padded_layouts @@ -2700,68 +3324,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __impl(make_index_sequence<__rank>()); } - template<typename _IndexType, size_t _Extent, typename _Slice> - consteval size_t - __static_slice_extent() - { - if constexpr (same_as<_Slice, full_extent_t>) - return _Extent; - else if constexpr (same_as<_Slice, constant_wrapper<_IndexType(0)>>) - return 0; - else if constexpr (__is_constant_wrapper<typename _Slice::extent_type> - && __is_constant_wrapper<typename _Slice::stride_type>) - return 1 + ((typename _Slice::extent_type{}) - 1) - / (typename _Slice::stride_type{}); - else - return dynamic_extent; - } + template<typename _Slice> + using __full_extent_t = std::full_extent_t; - template<size_t _K, typename _Extents, typename _Slice> - constexpr typename _Extents::index_type - __dynamic_slice_extent(const _Extents& __exts, _Slice __slice) + // Enables ADL-only calls from submdspan. + void submdspan_mapping() = delete; + + template<typename _Mapping, typename... _Slices> + concept __sliceable_mapping = requires(const _Mapping __m, _Slices... __slices) { - if constexpr (__is_strided_slice<_Slice>) - return __slice.extent == 0 ? 0 : 1 + (__slice.extent - 1) / __slice.stride; - else - return __exts.extent(_K); - } + { submdspan_mapping(__m, __slices...) } -> __submdspan_mapping_result; + }; - template<typename _IndexType, size_t... _Extents, typename... _Slices> - requires (sizeof...(_Slices) == sizeof...(_Extents)) + template<typename _Mapping, typename... _Slices> constexpr auto - __subextents(const extents<_IndexType, _Extents...>& __exts, - _Slices... __slices) + __submapping(const _Mapping& __mapping, _Slices... __slices) { - constexpr auto __inv_map = __mdspan::__inv_map_rank<_IndexType, _Slices...>(); - auto __impl = [&]<size_t... _Indices>(index_sequence<_Indices...>) - { - using _SubExtents = extents<_IndexType, - (__mdspan::__static_slice_extent<_IndexType, - _Extents...[__inv_map[_Indices]], - _Slices...[__inv_map[_Indices]]>())...>; - if constexpr (_SubExtents::rank_dynamic() == 0) - return _SubExtents{}; - else - { - using _StaticSubExtents = __mdspan::_StaticExtents< - __mdspan::__static_extents<_SubExtents>()>; - auto __create = [&]<size_t... _Is>(index_sequence<_Is...>) - { - constexpr auto __slice_idx = [__inv_map](size_t __i) consteval - { - return __inv_map[_StaticSubExtents::_S_dynamic_index_inv(__i)]; - }; - - return _SubExtents{ - (__mdspan::__dynamic_slice_extent<__slice_idx(_Is)>( - __exts, __slices...[__slice_idx(_Is)]))...}; - }; - constexpr auto __dyn_subrank = _SubExtents::rank_dynamic(); - return __create(make_index_sequence<__dyn_subrank>()); - } - }; - - return __impl(make_index_sequence<__inv_map.size()>()); + __mdspan::__check_valid_slices(__mapping.extents(), __slices...); + return submdspan_mapping(__mapping, __slices...); } } @@ -2792,6 +3372,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...); } + + template<typename _ElementType, typename _Extents, typename _Layout, + typename _Accessor, typename... _RawSlices> + requires (sizeof...(_RawSlices) == _Extents::rank() + && __mdspan::__sliceable_mapping<typename _Layout::mapping<_Extents>, + __mdspan::__full_extent_t<_RawSlices>...>) + constexpr auto + submdspan( + const mdspan<_ElementType, _Extents, _Layout, _Accessor>& __md, + _RawSlices... __raw_slices) + { + using _IndexType = typename _Extents::index_type; + auto [__mapping, __offset] = __mdspan::__submapping( + __md.mapping(), __mdspan::__slice_cast<_IndexType>(__raw_slices)...); + return std::mdspan( + __md.accessor().offset(__md.data_handle(), __offset), + std::move(__mapping), + typename _Accessor::offset_policy(__md.accessor())); + } #endif // __glibcxx_submdspan _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 7c157ea..3f0bcc4e 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -826,7 +826,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Check if a type is one of the signed integer types. __extension__ template<typename _Tp> - using __is_signed_integer = __is_one_of<__remove_cv_t<_Tp>, + using __is_signed_integer = __is_one_of<_Tp, signed char, signed short, signed int, signed long, signed long long #if defined(__GLIBCXX_TYPE_INT_N_0) @@ -841,12 +841,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if defined(__GLIBCXX_TYPE_INT_N_3) , signed __GLIBCXX_TYPE_INT_N_3 #endif +#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ + , signed __int128 +#endif >; // Check if a type is one of the unsigned integer types. __extension__ template<typename _Tp> - using __is_unsigned_integer = __is_one_of<__remove_cv_t<_Tp>, + using __is_unsigned_integer = __is_one_of<_Tp, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long #if defined(__GLIBCXX_TYPE_INT_N_0) @@ -861,11 +864,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if defined(__GLIBCXX_TYPE_INT_N_3) , unsigned __GLIBCXX_TYPE_INT_N_3 #endif +#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ + , unsigned __int128 +#endif >; // Check if a type is one of the signed or unsigned integer types. + // i.e. an integral type except bool, char, wchar_t, and charN_t. template<typename _Tp> - using __is_standard_integer + using __is_signed_or_unsigned_integer = __or_<__is_signed_integer<_Tp>, __is_unsigned_integer<_Tp>>; // __void_t (std::void_t for C++11) diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility index 3ae1852..0f6dd82 100644 --- a/libstdc++-v3/include/std/utility +++ b/libstdc++-v3/include/std/utility @@ -78,7 +78,7 @@ #include <bits/utility.h> #if __cplusplus >= 202002L -#include <ext/numeric_traits.h> // __is_standard_integer, __int_traits +#include <bits/intcmp.h> #endif #if __cplusplus > 202302L @@ -129,76 +129,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void as_const(const _Tp&&) = delete; #endif -#ifdef __cpp_lib_integer_comparison_functions // C++ >= 20 - template<typename _Tp, typename _Up> - constexpr bool - cmp_equal(_Tp __t, _Up __u) noexcept - { - static_assert(__is_standard_integer<_Tp>::value); - static_assert(__is_standard_integer<_Up>::value); - - if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) - return __t == __u; - else if constexpr (is_signed_v<_Tp>) - return __t >= 0 && make_unsigned_t<_Tp>(__t) == __u; - else - return __u >= 0 && __t == make_unsigned_t<_Up>(__u); - } - - template<typename _Tp, typename _Up> - constexpr bool - cmp_not_equal(_Tp __t, _Up __u) noexcept - { return !std::cmp_equal(__t, __u); } - - template<typename _Tp, typename _Up> - constexpr bool - cmp_less(_Tp __t, _Up __u) noexcept - { - static_assert(__is_standard_integer<_Tp>::value); - static_assert(__is_standard_integer<_Up>::value); - - if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) - return __t < __u; - else if constexpr (is_signed_v<_Tp>) - return __t < 0 || make_unsigned_t<_Tp>(__t) < __u; - else - return __u >= 0 && __t < make_unsigned_t<_Up>(__u); - } - - template<typename _Tp, typename _Up> - constexpr bool - cmp_greater(_Tp __t, _Up __u) noexcept - { return std::cmp_less(__u, __t); } - - template<typename _Tp, typename _Up> - constexpr bool - cmp_less_equal(_Tp __t, _Up __u) noexcept - { return !std::cmp_less(__u, __t); } - - template<typename _Tp, typename _Up> - constexpr bool - cmp_greater_equal(_Tp __t, _Up __u) noexcept - { return !std::cmp_less(__t, __u); } - - template<typename _Res, typename _Tp> - constexpr bool - in_range(_Tp __t) noexcept - { - static_assert(__is_standard_integer<_Res>::value); - static_assert(__is_standard_integer<_Tp>::value); - using __gnu_cxx::__int_traits; - - if constexpr (is_signed_v<_Tp> == is_signed_v<_Res>) - return __int_traits<_Res>::__min <= __t - && __t <= __int_traits<_Res>::__max; - else if constexpr (is_signed_v<_Tp>) - return __t >= 0 - && make_unsigned_t<_Tp>(__t) <= __int_traits<_Res>::__max; - else - return __t <= make_unsigned_t<_Res>(__int_traits<_Res>::__max); - } -#endif // __cpp_lib_integer_comparison_functions - #ifdef __cpp_lib_to_underlying // C++ >= 23 /// Convert an object of enumeration type to its underlying type. template<typename _Tp> diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index 2f44f97..f2f5583 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -393,8 +393,29 @@ namespace __variant _Variadic_union(in_place_index_t<_Np>, _Args&&...) = delete; }; - template<bool __trivially_destructible, typename _First, typename... _Rest> - union _Variadic_union<__trivially_destructible, _First, _Rest...> + template<typename _First, typename... _Rest> + union _Variadic_union<true, _First, _Rest...> + { + constexpr _Variadic_union() : _M_rest() { } + + template<typename... _Args> + constexpr + _Variadic_union(in_place_index_t<0>, _Args&&... __args) + : _M_first(in_place_index<0>, std::forward<_Args>(__args)...) + { } + + template<size_t _Np, typename... _Args> + constexpr + _Variadic_union(in_place_index_t<_Np>, _Args&&... __args) + : _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...) + { } + + _Uninitialized<_First> _M_first; + _Variadic_union<true, _Rest...> _M_rest; + }; + + template<typename _First, typename... _Rest> + union _Variadic_union<false, _First, _Rest...> { constexpr _Variadic_union() : _M_rest() { } @@ -410,24 +431,19 @@ namespace __variant : _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...) { } -#if __cpp_lib_variant >= 202106L _Variadic_union(const _Variadic_union&) = default; _Variadic_union(_Variadic_union&&) = default; _Variadic_union& operator=(const _Variadic_union&) = default; _Variadic_union& operator=(_Variadic_union&&) = default; - ~_Variadic_union() = default; - // If any alternative type is not trivially destructible then we need a // user-provided destructor that does nothing. The active alternative // will be destroyed by _Variant_storage::_M_reset() instead of here. - constexpr ~_Variadic_union() - requires (!__trivially_destructible) + _GLIBCXX20_CONSTEXPR ~_Variadic_union() { } -#endif _Uninitialized<_First> _M_first; - _Variadic_union<__trivially_destructible, _Rest...> _M_rest; + _Variadic_union<(is_trivially_destructible_v<_Rest> && ...), _Rest...> _M_rest; }; // _Never_valueless_alt is true for variant alternatives that can diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare index 08f2b2b..5b4f47a 100644 --- a/libstdc++-v3/libsupc++/compare +++ b/libstdc++-v3/libsupc++/compare @@ -34,6 +34,7 @@ #pragma GCC system_header #endif +#define __glibcxx_want_concepts #define __glibcxx_want_three_way_comparison #define __glibcxx_want_type_order #include <bits/version.h> @@ -499,10 +500,8 @@ namespace std _GLIBCXX_VISIBILITY(default) template<typename _Tp, typename _Up, typename _Cat = partial_ordering> concept three_way_comparable_with - = three_way_comparable<_Tp, _Cat> - && three_way_comparable<_Up, _Cat> - && common_reference_with<const remove_reference_t<_Tp>&, - const remove_reference_t<_Up>&> + = three_way_comparable<_Tp, _Cat> && three_way_comparable<_Up, _Cat> + && __detail::__comparison_common_type_with<_Tp, _Up> && three_way_comparable< common_reference_t<const remove_reference_t<_Tp>&, const remove_reference_t<_Up>&>, _Cat> diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in index 4962d4f..ef0da5d 100644 --- a/libstdc++-v3/src/c++23/std.cc.in +++ b/libstdc++-v3/src/c++23/std.cc.in @@ -1899,8 +1899,8 @@ export namespace std using std::submdspan_mapping_result; using std::submdspan_canonicalize_slices; using std::submdspan_extents; + using std::submdspan; #endif - // FIXME mdsubspan } #endif diff --git a/libstdc++-v3/testsuite/20_util/integer_comparisons/extended.cc b/libstdc++-v3/testsuite/20_util/integer_comparisons/extended.cc new file mode 100644 index 0000000..d862b16 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/integer_comparisons/extended.cc @@ -0,0 +1,60 @@ +// { dg-do compile { target c++20 } } + +#include <utility> + +template<typename T> +constexpr bool +test() +{ + using S = std::make_signed_t<T>; + using U = std::make_unsigned_t<T>; + + static_assert( std::cmp_less((S)-1, (U)1)); + static_assert( ! std::cmp_less((S)20, (U)10)); + static_assert( ! std::cmp_less((U)20, (S)10)); + + static_assert( std::cmp_greater((S)100, (U)1) ); + static_assert( std::cmp_greater((U)100, (S)1) ); + static_assert( ! std::cmp_greater((S)-100, (U)1) ); + + static_assert( std::cmp_less_equal((S)-1, (U)1)); + static_assert( std::cmp_less_equal((U)10, (S)10)); + static_assert( ! std::cmp_less_equal((U)-100, (S)-100)); + + static_assert( std::cmp_greater_equal((S)200, (U)2) ); + static_assert( std::cmp_greater_equal((U)2000, (S)2000) ); + static_assert( ! std::cmp_greater_equal((S)-100, (U)100) ); + + static_assert( std::cmp_equal((S)1, (U)1) ); + static_assert( ! std::cmp_equal((S)-2, (U)-2) ); + + static_assert( std::cmp_not_equal((S)-1, (U)-1) ); + static_assert( ! std::cmp_not_equal((S)100, (U)100) ); + + static_assert( std::in_range<S>((U)5) ); + static_assert( std::in_range<U>((S)5) ); + static_assert( ! std::in_range<S>((U)-5) ); + static_assert( ! std::in_range<U>((S)-5) ); + + return true; +} + +#ifdef __SIZEOF_INT128__ +static_assert(test<__int128>()); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_0 +static_assert(test<__GLIBCXX_TYPE_INT_N_0>()); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_1 +static_assert(test<__GLIBCXX_TYPE_INT_N_1>()); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_2 +static_assert(test<__GLIBCXX_TYPE_INT_N_2>()); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_3 +static_assert(test<__GLIBCXX_TYPE_INT_N_3>()); +#endif diff --git a/libstdc++-v3/testsuite/20_util/variant/112591.cc b/libstdc++-v3/testsuite/20_util/variant/112591.cc new file mode 100644 index 0000000..b1b07c4 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/variant/112591.cc @@ -0,0 +1,32 @@ +// { dg-do run { target c++17 } } + +#include <variant> +#include <testsuite_hooks.h> + +struct NonEmpty { int x; }; +struct TrivialEmpty {}; +struct NonTrivialEmpty { ~NonTrivialEmpty() {} }; + +template<typename T> +struct Compose : T +{ + std::variant<T, int> v; +}; + +template<typename T> +bool testAlias() +{ + Compose<T> c; + return static_cast<T*>(&c) == &std::get<T>(c.v); +} + +int main() +{ + VERIFY( !testAlias<NonEmpty>() ); + VERIFY( !testAlias<TrivialEmpty>() ); +#if __cplusplus >= 202002L + VERIFY( !testAlias<NonTrivialEmpty>() ); +#else + VERIFY( testAlias<NonTrivialEmpty>() ); +#endif +} diff --git a/libstdc++-v3/testsuite/20_util/variant/87619.cc b/libstdc++-v3/testsuite/20_util/variant/87619.cc index d988925..ac7dd46 100644 --- a/libstdc++-v3/testsuite/20_util/variant/87619.cc +++ b/libstdc++-v3/testsuite/20_util/variant/87619.cc @@ -16,6 +16,7 @@ // <http://www.gnu.org/licenses/>. // { dg-do compile { target c++17 } } +// { dg-options "-ftemplate-depth=270" } #include <variant> #include <utility> @@ -23,6 +24,7 @@ template<std::size_t I> struct S { + ~S() {} }; template <std::size_t... Is> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc index d5f07c1..fdbcb70 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc @@ -16,6 +16,13 @@ static_assert(!std::is_constructible_v<std::extents<int, 1, dyn, 3>, int, int>); // Not constructible from non integer-like objects. static_assert(!std::is_constructible_v<std::extents<int, 1>, int, A>); +#ifdef __SIZEOF_INT128__ +static_assert(std::is_constructible_v<std::extents<__int128, 1, 2>, + __int128, unsigned __int128>); +static_assert(std::is_constructible_v<std::extents<unsigned __int128, 1, 2>, + unsigned int, int>); +#endif + // No implicit conversion from integer-like objects. template<typename Extent, typename... OExtents> constexpr bool diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h b/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h index 619cab5..f0aeac3 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h @@ -87,6 +87,8 @@ template<> { using layout_same = std::layout_left; using layout_other = std::layout_right; + template<size_t PaddingValue> + using layout_same_padded = std::layout_left_padded<PaddingValue>; template<typename Extents> using extents_type = Extents; @@ -126,6 +128,8 @@ template<> struct LayoutTraits<PaddingSide::Right> { using layout_same = std::layout_right; + template<size_t PaddingValue> + using layout_same_padded = std::layout_right_padded<PaddingValue>; using layout_other = std::layout_left; template<typename IndexType, size_t... Extents> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/generic.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/generic.cc new file mode 100644 index 0000000..682ff62 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/generic.cc @@ -0,0 +1,71 @@ +// { dg-do compile { target c++26 } } +#include <mdspan> + +namespace adl +{ + struct NoFriend + { + template<typename Extents> + class mapping + { + public: + using extents_type = Extents; + using index_type = typename extents_type::index_type; + }; + }; + + struct NoFull + { + template<typename Extents> + class mapping + { + public: + using extents_type = Extents; + using index_type = typename extents_type::index_type; + + private: + friend constexpr auto + submdspan_mapping(mapping, int) + { return std::submdspan_mapping_result{mapping{}, 0}; } + }; + }; + + struct WrongReturnValue + { + template<typename Extents> + class mapping + { + public: + using extents_type = Extents; + using index_type = typename extents_type::index_type; + + private: + friend constexpr int + submdspan_mapping(mapping, std::full_extent_t) + { return 42; } + }; + }; +} + +template<typename MdSpan, typename... Slices> + concept submdspan_exists = requires (MdSpan md, Slices... slices) + { + std::submdspan(md, slices...); + }; + +template<typename Layout, bool Expected> +constexpr bool +test_invalid_mapping() +{ + using Extents = std::extents<int, 3>; + using MdSpan = std::mdspan<double, Extents, Layout>; + static_assert(submdspan_exists<MdSpan, int> == Expected); + static_assert(submdspan_exists<MdSpan, std::full_extent_t> == Expected); + static_assert(!submdspan_exists<MdSpan>); + static_assert(!submdspan_exists<MdSpan, int, int>); + return true; +} +static_assert(test_invalid_mapping<std::layout_left, true>()); +static_assert(test_invalid_mapping<adl::NoFriend, false>()); +static_assert(test_invalid_mapping<adl::NoFull, false>()); +static_assert(test_invalid_mapping<adl::WrongReturnValue, false>()); diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left.cc new file mode 100644 index 0000000..d6a85d0 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left.cc @@ -0,0 +1,9 @@ +// { dg-do run { target c++26 } } +#include "testcases.h" + +int +main() +{ + test_all<std::layout_left>(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc new file mode 100644 index 0000000..711ce35 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/left_padded.cc @@ -0,0 +1,12 @@ +// { dg-do run { target c++26 } } +// { dg-timeout-factor 2 } +#include "testcases.h" + +int +main() +{ + test_all<std::layout_left_padded<1>>(); + test_all<std::layout_left_padded<8>>(); + test_all<std::layout_left_padded<dyn>>(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right.cc new file mode 100644 index 0000000..2557072 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right.cc @@ -0,0 +1,9 @@ +// { dg-do run { target c++26 } } +#include "testcases.h" + +int +main() +{ + test_all<std::layout_right>(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right_padded.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right_padded.cc new file mode 100644 index 0000000..24ed6cb --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/right_padded.cc @@ -0,0 +1,12 @@ +// { dg-do run { target c++26 } } +// { dg-timeout-factor 2 } +#include "testcases.h" + +int +main() +{ + test_all<std::layout_right_padded<1>>(); + test_all<std::layout_right_padded<8>>(); + test_all<std::layout_right_padded<dyn>>(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/stride.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/stride.cc new file mode 100644 index 0000000..19451d7 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/stride.cc @@ -0,0 +1,9 @@ +// { dg-do run { target c++26 } } +#include "testcases.h" + +int +main() +{ + test_all<std::layout_stride>(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h new file mode 100644 index 0000000..d7b751d --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/selections/testcases.h @@ -0,0 +1,360 @@ +#include <mdspan> + +#include <vector> +#include <numeric> +#include "../../layout_traits.h" +#include <testsuite_hooks.h> + +constexpr size_t dyn = std::dynamic_extent; +constexpr auto all = std::full_extent; + +template<typename T> + constexpr bool is_strided_slice = false; + +template<typename O, typename E, typename S> + constexpr bool is_strided_slice<std::strided_slice<O, E, S>> = true; + +template<typename MDSpan> + constexpr void + fill(const MDSpan& md) + { + using IndexType = typename MDSpan::index_type; + auto exts = md.extents(); + if constexpr (exts.rank() == 3) + for(IndexType i = 0; i < exts.extent(0); ++i) + for(IndexType j = 0; j < exts.extent(1); ++j) + for(IndexType k = 0; k < exts.extent(2); ++k) + md[i, j, k] = 100 * i + 10 * j + k; + } + +template<typename Int, size_t Rank> + class multi_index_generator + { + struct sentinel + { }; + + class iterator + { + public: + constexpr + iterator(const std::array<Int, Rank>& shape) + : M_shape(shape) + { } + + constexpr iterator& + operator++() + { + if constexpr (Rank > 0) + { + ++M_indices[Rank-1]; + for(size_t i = Rank; i > 1; --i) + if (M_indices[i-1] == M_shape[i-1]) + { + M_indices[i-1] = 0; + ++M_indices[i-2]; + } + } + return *this; + } + + constexpr auto + operator*() + { return M_indices; } + + private: + friend constexpr bool + operator==(const iterator& it, sentinel) + { + if constexpr (Rank > 0) + return it.M_indices[0] == it.M_shape[0]; + else + return true; + } + + std::array<Int, Rank> M_indices{}; + std::array<Int, Rank> M_shape; + }; + + public: + constexpr + multi_index_generator(std::array<Int, Rank> shape) + : M_shape(shape) + { } + + constexpr iterator + begin() const + { return iterator(M_shape); } + + constexpr sentinel + end() const + { return sentinel{}; } + + private: + std::array<Int, Rank> M_shape; + }; + +constexpr bool +test_multi_index() +{ + auto shape = std::array{3, 5, 7, 1}; + auto gen = multi_index_generator(shape); + auto it = gen.begin(); + auto end = gen.end(); + for (int i = 0; i < shape[0]; ++i) + for (int j = 0; j < shape[1]; ++j) + for (int k = 0; k < shape[2]; ++k) + for (int l = 0; l < shape[3]; ++l) + { + VERIFY(it != end); + VERIFY(*it == std::array{i, j, k, l}); + ++it; + } + return true; +} +static_assert(test_multi_index()); + +struct +collapse +{ }; + +template<typename... Slices> + consteval auto + inv_collapsed_index_map() + { + constexpr size_t rank = sizeof...(Slices); + auto is_collapsing = std::array{std::same_as<Slices, collapse>...}; + constexpr auto collapsed_rank = ((!std::same_as<Slices, collapse>) + ... + 0); + + std::array<size_t, collapsed_rank> ret; + if constexpr (collapsed_rank > 0) + for(size_t k = 0, i = 0; i < rank; ++i) + if (!is_collapsing[i]) + ret[k++] = i; + return ret; + } + +static_assert(inv_collapsed_index_map<collapse, collapse, collapse>() + == std::array<size_t, 0>{}); + +static_assert(inv_collapsed_index_map<collapse, decltype(all), collapse>() + == std::array<size_t, 1>{1}); + +template<typename IndexType, typename Slice> + constexpr std::vector<IndexType> + make_selection(IndexType extent, const Slice& slice) + { + if constexpr (std::convertible_to<Slice, IndexType>) + return {static_cast<IndexType>(slice)}; + else if constexpr (std::same_as<Slice, std::full_extent_t>) + { + auto ret = std::vector<IndexType>(static_cast<size_t>(extent)); + std::ranges::iota(ret, 0); + return ret; + } + else if constexpr (is_strided_slice<Slice>) + { + auto ret = std::vector<IndexType>{}; + size_t n = static_cast<size_t>(slice.extent); + for(size_t i = 0; i < n; i += slice.stride) + ret.push_back(slice.offset + i); + return ret; + } + else + { + auto [begin, end] = slice; + auto ret = std::vector<IndexType>(static_cast<size_t>(end - begin)); + std::ranges::iota(ret, begin); + return ret; + } + } + +template<typename Layout, size_t... I, typename... Slices> + constexpr bool + check_selection(std::index_sequence<I...>, auto md, Slices... slices) + { + auto exts = md.extents(); + auto outer_shape = std::array{exts.extent(0), exts.extent(1), exts.extent(2)}; + + constexpr auto full_index = inv_collapsed_index_map<Slices...>(); + auto make_slice = [](size_t i, auto slice) + { + if constexpr (std::same_as<decltype(slice), collapse>) + return i; + else + return slice; + }; + + auto loop_body = [&]<size_t... J>(std::index_sequence<J...>, auto ijk, + auto... slices) + { + auto submd = submdspan(md, slices...[I]...); + auto selection = std::tuple{make_selection(exts.extent(I), slices...[I])...}; + auto inner_shape = std::array<size_t, full_index.size()>{ + std::get<full_index[J]>(selection).size()... + }; + + for (auto ij : multi_index_generator(inner_shape)) + { + ((ijk[full_index[J]] = get<full_index[J]>(selection)[ij[J]]),...); + VERIFY(submd[ij] == md[ijk]); + } + }; + + for (auto ijk : multi_index_generator(outer_shape)) + loop_body(std::make_index_sequence<full_index.size()>(), ijk, + make_slice(ijk[I], slices...[I])...); + return true; + } + +template<typename Layout, typename...MD, typename... Slices> + constexpr bool + check_selection(std::mdspan<MD...> md, Slices... slices) + { + auto indices = std::make_index_sequence<sizeof...(slices)>(); + return check_selection<Layout>(indices, md, slices...); + } + +template<typename Layout, typename IndexType, size_t... Extents, + typename... Slices> + constexpr bool + check_selection(std::extents<IndexType, Extents...>exts, Slices... slices) + { + auto run = [&](auto m) + { + auto storage = std::vector<double>(m.required_span_size()); + auto md = std::mdspan(storage.data(), m); + fill(md); + return check_selection<Layout>(md, slices...); + }; + + if constexpr (std::same_as<Layout, std::layout_stride>) + { + auto m = typename Layout::mapping(exts, std::array{15, 2, 50}); + return run(m); + } + else + { + auto m = typename Layout::mapping(exts); + return run(m); + } + } + +template<typename Layout> + constexpr bool + test_scalar_selection(auto exts) + { + check_selection<Layout>(exts, collapse{}, collapse{}, collapse{}); + return true; + } + +template<typename Layout> + constexpr bool + test_full_lines(auto exts) + { + check_selection<Layout>(exts, all, collapse{}, collapse{}); + check_selection<Layout>(exts, collapse{}, all, collapse{}); + check_selection<Layout>(exts, collapse{}, collapse{}, all); + return true; + } + +template<typename Layout> + constexpr bool + test_full_blocks(auto exts) + { + check_selection<Layout>(exts, all, all, collapse{}); + check_selection<Layout>(exts, all, collapse{}, all); + check_selection<Layout>(exts, collapse{}, all, all); + return true; + } + +template<typename Layout> + constexpr bool + test_cubes(auto exts) + { + auto s0 = std::pair{0, 2}; + auto s1 = std::pair{1, 4}; + auto s2 = std::pair{3, 7}; + + check_selection<Layout>(exts, all, all, all); + check_selection<Layout>(exts, all, all, s2); + check_selection<Layout>(exts, s0, all, all); + check_selection<Layout>(exts, s0, all, s2); + check_selection<Layout>(exts, s0, s1, s2); + return true; + } + +template<typename Layout> + constexpr bool + test_strided_line_selection(auto exts) + { + auto check = [&](auto s) + { + check_selection<Layout>(exts, collapse{}, s, collapse{}); + }; + + check(std::strided_slice(0, 2, 2)); + check(std::strided_slice(0, 3, 2)); + check(std::strided_slice(1, 3, 2)); + check(std::strided_slice(1, std::cw<3>, std::cw<2>)); + return true; + } + +template<typename Layout> + constexpr bool + test_strided_box_selection(auto exts) + { + auto s0 = std::strided_slice(0, 3, 2); + auto s1 = std::strided_slice(1, 4, 2); + auto s2 = std::strided_slice(0, 7, 3); + + check_selection<Layout>(exts, s0, s1, s2); + return true; + } + +template<typename Layout> + constexpr bool + test_all_cheap() + { + constexpr auto dyn_exts = std::extents(3, 5, 7); + constexpr auto sta_exts = std::extents<int, 3, 5, 7>{}; + + test_scalar_selection<Layout>(dyn_exts); + test_scalar_selection<Layout>(sta_exts); + static_assert(test_scalar_selection<Layout>(dyn_exts)); + static_assert(test_scalar_selection<Layout>(sta_exts)); + + test_full_lines<Layout>(dyn_exts); + test_full_lines<Layout>(sta_exts); + static_assert(test_full_lines<Layout>(dyn_exts)); + static_assert(test_full_lines<Layout>(sta_exts)); + + test_strided_box_selection<Layout>(dyn_exts); + test_strided_box_selection<Layout>(sta_exts); + static_assert(test_strided_box_selection<Layout>(dyn_exts)); + static_assert(test_strided_box_selection<Layout>(sta_exts)); + return true; + } + +template<typename Layout> + constexpr bool + test_all_expensive() + { + auto run = [](auto exts) + { + test_full_blocks<Layout>(exts); + test_cubes<Layout>(exts); + }; + + run(std::extents(3, 5, 7)); + run(std::extents<int, 3, 5, 7>{}); + return true; + } + +template<typename Layout> + constexpr bool + test_all() + { + test_all_cheap<Layout>(); + test_all_expensive<Layout>(); + return true; + } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice.cc index c43a821..6fa5aaa 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/strided_slice.cc @@ -34,6 +34,9 @@ test_all() test_initializers(0, 1, 2); test_initializers(std::integral_constant<short, 0>{}, size_t{1}, std::cw<2>); test_initializers(-1, 2, 2); +#ifdef __SIZEOF_INT128__ + test_initializers((__int128)1, (unsigned __int128)-2, std::cw<(__int128)3>); +#endif return true; } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc new file mode 100644 index 0000000..efd71d1 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_mapping.cc @@ -0,0 +1,301 @@ +// { dg-do run { target c++26 } } +#include <mdspan> + +#include <iostream> // TODO remove +#include "../layout_traits.h" +#include <testsuite_hooks.h> + +constexpr size_t dyn = std::dynamic_extent; +constexpr auto all = std::full_extent; + +template<typename Mapping, typename... Slices> + constexpr auto + call_submdspan_mapping(const Mapping& m, std::tuple<Slices...> slices) + { + auto impl = [&]<size_t... I>(std::index_sequence<I...>) + { return submdspan_mapping(m, get<I>(slices)...); }; + return impl(std::make_index_sequence<sizeof...(Slices)>()); + } + +template<typename Layout> + constexpr bool + test_layout_common_return_types() + { + constexpr auto padding_side = DeducePaddingSide::from_typename<Layout>(); + using Traits = LayoutTraits<padding_side>; + using layout_unpadded = typename Traits::layout_same; + + { + auto m0 = typename Layout::mapping(std::extents()); + auto result = submdspan_mapping(m0); + using layout_type = typename decltype(result.mapping)::layout_type; + static_assert(std::same_as<layout_type, Layout>); + } + + auto exts = Traits::make_extents(std::dims<5, int>(3, 5, 7, 11, 13)); + auto m = typename Layout::mapping(exts); + auto s251 = std::strided_slice{2, 5, std::cw<1>}; + + { + auto slices = std::tuple{0, 0, 0, 0, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = typename decltype(result.mapping)::layout_type; + static_assert(std::same_as<layout_type, layout_unpadded>); + } + + { + auto s0 = std::strided_slice{1, 1, std::cw<1>}; + auto slices = std::tuple{s0, all, all, s251, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = typename decltype(result.mapping)::layout_type; + static_assert(is_same_padded<padding_side, layout_type>); + } + + { + auto s0 = std::strided_slice{1, 2, std::cw<1>}; + auto slices = std::tuple{s0, all, all, s251, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = typename decltype(result.mapping)::layout_type; + static_assert(is_same_padded<padding_side, layout_type>); + } + + { + auto s0 = std::strided_slice{1, 2, std::cw<1>}; + auto slices = std::tuple{s0, 0, all, s251, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = typename decltype(result.mapping)::layout_type; + static_assert(is_same_padded<padding_side, layout_type>); + } + + { + auto s0 = std::strided_slice{1, 2, 1}; + auto slices = std::tuple{s0, all, all, s251, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = decltype(result.mapping)::layout_type; + static_assert(std::same_as<layout_type, std::layout_stride>); + } + + { + auto slices = std::tuple{1, all, all, s251, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = decltype(result.mapping)::layout_type; + static_assert(std::same_as<layout_type, std::layout_stride>); + } + + { + auto s3 = std::strided_slice{2, std::cw<7>, std::cw<2>}; + auto slices = std::tuple{all, all, all, s3, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = decltype(result.mapping)::layout_type; + static_assert(std::same_as<layout_type, std::layout_stride>); + } + return true; + } + +template<typename Layout> + constexpr bool + test_layout_unpadded_return_types() + { + constexpr auto padding_side = DeducePaddingSide::from_typename<Layout>(); + using Traits = LayoutTraits<padding_side>; + + auto exts = Traits::make_extents(std::dims<5, int>(3, 5, 7, 11, 13)); + auto m = typename Layout::mapping(exts); + auto s251 = std::strided_slice{2, 5, std::cw<1>}; + + { + auto slices = std::tuple{all, all, all, s251, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = typename decltype(result.mapping)::layout_type; + static_assert(std::same_as<layout_type, Layout>); + } + return true; + } + +template<typename Layout> + constexpr bool + test_layout_padded_return_types() + { + constexpr auto padding_side = DeducePaddingSide::from_typename<Layout>(); + using Traits = LayoutTraits<padding_side>; + + auto exts = Traits::make_extents(std::dims<5, int>(3, 5, 7, 11, 13)); + auto m = typename Layout::mapping(exts); + auto s251 = std::strided_slice{2, 5, std::cw<1>}; + + { + auto slices = std::tuple{all, all, all, s251, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = typename decltype(result.mapping)::layout_type; + using layout_expected = typename Traits::layout_same_padded<dyn>; + static_assert(std::same_as<layout_type, layout_expected>); + } + + { + auto slices = std::tuple{all, 0, 0, 0, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = typename decltype(result.mapping)::layout_type; + using layout_expected = typename Traits::layout_same; + static_assert(std::same_as<layout_type, layout_expected>); + } + + { + auto s121 = std::strided_slice{1, 2, std::cw<1>}; + auto slices = std::tuple{s121, 0, 0, 0, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = typename decltype(result.mapping)::layout_type; + using layout_expected = typename Traits::layout_same; + static_assert(std::same_as<layout_type, layout_expected>); + } + + { + auto s121 = std::strided_slice{1, 2, std::cw<1>}; + auto slices = std::tuple{0, s121, 0, 0, 0}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + using layout_type = typename decltype(result.mapping)::layout_type; + static_assert(std::same_as<layout_type, std::layout_stride>); + } + return true; + } + +template<typename Layout> + constexpr bool + test_layout_unpadded_padding_value() + { + using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>; + auto s0 = std::strided_slice{size_t(1), size_t(2), std::cw<size_t(1)>}; + auto s3 = std::strided_slice{size_t(2), size_t(5), std::cw<size_t(1)>}; + + auto check = [&](auto exts, size_t expected) + { + auto m = typename Layout::mapping(Traits::make_extents(exts)); + auto slices = std::tuple{s0, size_t(0), all, s3, size_t(0)}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + auto padding_value = decltype(result.mapping)::padding_value; + VERIFY(padding_value == expected); + }; + + check(std::extents(std::cw<3>, std::cw<5>, std::cw<7>, 11, 13), 3*5); + check(std::extents(std::cw<3>, std::cw<5>, 7, 11, 13), 3*5); + check(std::extents(std::cw<3>, 5, 7, 11, 13), dyn); + check(std::extents(3, 5, 7, 11, 13), dyn); + return true; + } + +template<typename Layout> +constexpr size_t static_padding_value = 1; + +template<size_t PaddingValue> +constexpr size_t static_padding_value<std::layout_left_padded<PaddingValue>> = PaddingValue; + +template<size_t PaddingValue> +constexpr size_t static_padding_value<std::layout_right_padded<PaddingValue>> = PaddingValue; + +template<typename Layout> + constexpr bool + test_layout_padded_padding_value() + { + using Traits = LayoutTraits<DeducePaddingSide::from_typename<Layout>()>; + auto s0 = std::strided_slice{size_t(1), size_t(2), std::cw<size_t(1)>}; + auto s3 = std::strided_slice{size_t(2), size_t(5), std::cw<size_t(1)>}; + + auto check = [&](auto exts, size_t expected) + { + auto m = typename Layout::mapping(Traits::make_extents(exts)); + auto slices = std::tuple{s0, size_t(0), all, s3, size_t(0)}; + auto result = call_submdspan_mapping(m, Traits::make_tuple(slices)); + auto padding_value = decltype(result.mapping)::padding_value; + VERIFY(padding_value == expected); + }; + + auto pad = [](int n, int m) -> size_t + { + constexpr auto padding_value = static_padding_value<Layout>; + if constexpr (padding_value != dyn) + { + auto npad = ((n + padding_value - 1) / padding_value) * padding_value; + return npad * m; + } + else + return dyn; + }; + + check(std::extents(std::cw<3>, std::cw<5>, std::cw<7>, 11, 13), pad(3, 5)); + check(std::extents(std::cw<3>, std::cw<5>, 7, 11, 13), pad(3, 5)); + check(std::extents(std::cw<3>, std::cw<6>, 7, 11, 13), pad(3, 6)); + check(std::extents(std::cw<3>, 5, 7, 11, 13), dyn); + check(std::extents(3, 5, 7, 11, 13), dyn); + return true; + } + +constexpr bool +test_layout_stride_return_types() +{ + auto exts = std::extents(3, 5); + auto m = std::layout_stride::mapping(exts, std::array{2, 12}); + + using index_type = decltype(exts)::index_type; + auto s1 = std::strided_slice{index_type(2), index_type(2), + std::cw<index_type(2)>}; + auto result = submdspan_mapping(m, index_type(1), s1); + using layout_type = decltype(result.mapping)::layout_type; + static_assert(std::same_as<layout_type, std::layout_stride>); + return true; +} + +template<typename Layout> + constexpr bool + test_return_types_all() + { + return true; + } + +template<typename Layout> + constexpr bool + test_return_types_unpadded_all() + { + test_layout_common_return_types<Layout>(); + static_assert(test_layout_common_return_types<Layout>()); + + test_layout_unpadded_return_types<Layout>(); + static_assert(test_layout_unpadded_return_types<Layout>()); + + test_layout_unpadded_padding_value<Layout>(); + static_assert(test_layout_unpadded_padding_value<Layout>()); + return true; + } + +template<typename Layout> + constexpr bool + test_return_types_padded_all() + { + test_layout_common_return_types<Layout>(); + static_assert(test_layout_common_return_types<Layout>()); + + test_layout_padded_return_types<Layout>(); + static_assert(test_layout_padded_return_types<Layout>()); + + test_layout_padded_padding_value<Layout>(); + static_assert(test_layout_padded_padding_value<Layout>()); + return true; + } + +int +main() +{ + test_return_types_unpadded_all<std::layout_left>(); + test_return_types_unpadded_all<std::layout_right>(); + + test_return_types_padded_all<std::layout_left_padded<1>>(); + test_return_types_padded_all<std::layout_left_padded<2>>(); + test_return_types_padded_all<std::layout_left_padded<dyn>>(); + + test_return_types_padded_all<std::layout_right_padded<1>>(); + test_return_types_padded_all<std::layout_right_padded<2>>(); + test_return_types_padded_all<std::layout_right_padded<dyn>>(); + + test_layout_stride_return_types(); + static_assert(test_layout_stride_return_types()); + return 0; +} + diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc new file mode 100644 index 0000000..39eb18c --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/submdspan/submdspan_neg.cc @@ -0,0 +1,122 @@ +// { dg-do compile { target c++26 } } +#include <mdspan> + +#include <vector> + +template<typename Layout, typename... Slices> + constexpr bool + check_slice_range(Slices... slices) + { + auto m = typename Layout::mapping<std::extents<int, 3, 5, 7>>{}; + auto storage = std::vector<double>(m.required_span_size()); + auto md = std::mdspan(storage.data(), m); + + auto submd = submdspan(md, slices...); // { dg-error "expansion of" } + (void) submd; + return true; + } + +template<typename Layout> + constexpr bool + test_int_under() + { + check_slice_range<Layout>(1, -1, 2); // { dg-error "expansion of" } + return true; + } +static_assert(test_int_under<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_int_under<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_int_under<std::layout_stride>()); // { dg-error "expansion of" } + +template<typename Layout> + constexpr bool + test_int_over() + { + check_slice_range<Layout>(1, 5, 2); // { dg-error "expansion of" } + return true; + } +static_assert(test_int_over<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_int_over<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_int_over<std::layout_stride>()); // { dg-error "expansion of" } + +template<typename Layout> + constexpr bool + test_tuple_under() + { + check_slice_range<Layout>(1, std::tuple{-1, 2}, 2); // { dg-error "expansion of" } + return true; + } +static_assert(test_tuple_under<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_tuple_under<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_tuple_under<std::layout_stride>()); // { dg-error "expansion of" } + +template<typename Layout> + constexpr bool + test_tuple_reversed() + { + check_slice_range<Layout>(1, std::tuple{3, 2}, 2); // { dg-error "expansion of" } + return true; + } +static_assert(test_tuple_reversed<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_tuple_reversed<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_tuple_reversed<std::layout_stride>()); // { dg-error "expansion of" } + +template<typename Layout> + constexpr bool + test_tuple_over() + { + check_slice_range<Layout>(1, std::tuple{0, 6}, 2); // { dg-error "expansion of" } + return true; + } +static_assert(test_tuple_over<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_tuple_over<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_tuple_over<std::layout_stride>()); // { dg-error "expansion of" } + +template<typename Layout> + constexpr bool + test_strided_slice_zero() + { + check_slice_range<Layout>(1, std::strided_slice{1, 1, 0}, 2); // { dg-error "expansion of" } + return true; + } +static_assert(test_strided_slice_zero<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_strided_slice_zero<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_strided_slice_zero<std::layout_stride>()); // { dg-error "expansion of" } + +template<typename Layout> + constexpr bool + test_strided_slice_offset_under() + { + check_slice_range<Layout>(1, std::strided_slice{-1, 1, 1}, 2); // { dg-error "expansion of" } + return true; + } +static_assert(test_strided_slice_offset_under<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_strided_slice_offset_under<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_strided_slice_offset_under<std::layout_stride>()); // { dg-error "expansion of" } + +template<typename Layout> + constexpr bool + test_strided_slice_offset_over() + { + check_slice_range<Layout>(1, std::strided_slice{6, 0, 1}, 2); // { dg-error "expansion of" } + return true; + } +static_assert(test_strided_slice_offset_over<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_strided_slice_offset_over<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_strided_slice_offset_over<std::layout_stride>()); // { dg-error "expansion of" } + +template<typename Layout> + constexpr bool + test_strided_slice_extent_over() + { + check_slice_range<Layout>(1, std::strided_slice{1, 5, 1}, 2); // { dg-error "expansion of" } + return true; + } +static_assert(test_strided_slice_extent_over<std::layout_left>()); // { dg-error "expansion of" } +static_assert(test_strided_slice_extent_over<std::layout_right>()); // { dg-error "expansion of" } +static_assert(test_strided_slice_extent_over<std::layout_stride>()); // { dg-error "expansion of" } + +// { dg-prune-output "static assertion failed" } +// { dg-prune-output "__glibcxx_assert_fail" } +// { dg-prune-output "non-constant condition" } +// { dg-prune-output "no matching function" } +// { dg-prune-output "does not satisfy placeholder constraints" } diff --git a/libstdc++-v3/testsuite/26_numerics/saturation/extended.cc b/libstdc++-v3/testsuite/26_numerics/saturation/extended.cc new file mode 100644 index 0000000..fbef628 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/saturation/extended.cc @@ -0,0 +1,55 @@ +// { dg-do compile { target c++26 } } + +#include <numeric> +#include <limits> + +template<typename T> +constexpr bool +test() +{ + using S = std::make_signed_t<T>; + using U = std::make_unsigned_t<T>; + + constexpr S smax = std::numeric_limits<S>::max(); + constexpr S smin = std::numeric_limits<S>::min(); + constexpr U umax = std::numeric_limits<U>::max(); + + static_assert( std::add_sat(smax, (S)1) == smax ); + static_assert( std::add_sat(smin, (S)-2) == smin ); + static_assert( std::add_sat(umax, (U)3) == umax ); + + static_assert( std::sub_sat(smax, (S)-1) == smax ); + static_assert( std::sub_sat(smin, (S)2) == smin ); + static_assert( std::sub_sat((U)0, (U)3) == (U)0 ); + + static_assert( std::mul_sat((S)(smax >> 1), (S)3) == smax ); + static_assert( std::mul_sat((S)(smin >> 1), (S)5) == smin ); + static_assert( std::mul_sat((U)(umax >> 1), (U)7) == umax ); + + static_assert( std::div_sat(smax, (S)2) == (smax >> 1) ); + static_assert( std::div_sat(smin, (S)4) == (smin >> 2) ); + static_assert( std::div_sat(smin, (S)-1) == smax ); + static_assert( std::div_sat(umax, (U)8) == (umax >> 3) ); + + return true; +} + +#ifdef __SIZEOF_INT128__ +static_assert(test<__int128>()); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_0 +static_assert(test<__GLIBCXX_TYPE_INT_N_0>()); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_1 +static_assert(test<__GLIBCXX_TYPE_INT_N_1>()); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_2 +static_assert(test<__GLIBCXX_TYPE_INT_N_2>()); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_3 +static_assert(test<__GLIBCXX_TYPE_INT_N_3>()); +#endif diff --git a/libstdc++-v3/testsuite/26_numerics/stdckdint/extended.cc b/libstdc++-v3/testsuite/26_numerics/stdckdint/extended.cc new file mode 100644 index 0000000..efc0792 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/stdckdint/extended.cc @@ -0,0 +1,65 @@ +// { dg-do run { target c++26 } } + +#include <stdckdint.h> +#include <limits> +#include <testsuite_hooks.h> + +template<typename T> +void +test() +{ + using S = std::make_signed_t<T>; + using U = std::make_unsigned_t<T>; + + constexpr S smax = std::numeric_limits<S>::max(); + constexpr S smin = std::numeric_limits<S>::min(); + constexpr U umax = std::numeric_limits<U>::max(); + S sout{}; + U uout{}; + + VERIFY( ckd_add(&sout, smax, (S)1) ); + VERIFY( ! ckd_add(&uout, smax, (U)1) && uout == ((U)smax + (U)1) ); + VERIFY( ! ckd_add(&sout, smin, (S)99) && sout == (smin + 99) ); + VERIFY( ckd_add(&uout, smin, (S)99) ); + VERIFY( ckd_add(&sout, smin, (S)-2) ); + VERIFY( ckd_add(&uout, umax, (U)3) ); + VERIFY( ! ckd_add(&sout, (U)9, (U)3) && sout == 12 ); + + VERIFY( ckd_sub(&sout, smax, (S)-1) ); + VERIFY( ! ckd_sub(&uout, smax, (S)-1) && uout == ((U)smax + (U)1) ); + VERIFY( ckd_sub(&sout, smin, (S)2) ); + VERIFY( ! ckd_sub(&sout, smin, (S)-2) && sout == (smin + 2) ); + VERIFY( ! ckd_sub(&sout, (U)0, (U)3) && sout == -3 ); + VERIFY( ckd_sub(&uout, (U)0, (U)3) ); + + VERIFY( ! ckd_mul(&sout, (S)(smax >> 2), (S)3) && sout == (smax/4*3) ); + VERIFY( ckd_mul(&sout, (S)(smax >> 1), (S)3) ); + VERIFY( ! ckd_mul(&uout, (S)(smax >> 1), (S)3) ); + VERIFY( ckd_mul(&sout, (S)(smin >> 1), (S)5) ); + VERIFY( ! ckd_mul(&uout, (U)(umax >> 2), (U)3) ); + VERIFY( ckd_mul(&sout, (U)(umax >> 2), (U)3) ); + VERIFY( ckd_mul(&uout, (U)(umax >> 1), (U)7) ); +} + +int main() +{ +#ifdef __SIZEOF_INT128__ + test<__int128>(); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_0 + test<__GLIBCXX_TYPE_INT_N_0>(); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_1 + test<__GLIBCXX_TYPE_INT_N_1>(); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_2 + test<__GLIBCXX_TYPE_INT_N_2>(); +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_3 + test<__GLIBCXX_TYPE_INT_N_3>(); +#endif +} diff --git a/libstdc++-v3/testsuite/std/concepts/concepts.compare/move_only.cc b/libstdc++-v3/testsuite/std/concepts/concepts.compare/move_only.cc new file mode 100644 index 0000000..01870d8 --- /dev/null +++ b/libstdc++-v3/testsuite/std/concepts/concepts.compare/move_only.cc @@ -0,0 +1,28 @@ +// { dg-do compile { target c++20 } } + +#include <concepts> +#include <compare> + +// P2404R3 Move-only types for equality_comparable_with, +// totally_ordered_with, and three_way_comparable_with + +// This was approved for C++23 but we treat it as a DR for C++20. + +#ifndef __cpp_lib_concepts +# error "Feature-test macro __cpp_lib_concepts is missing in <compare>" +#elif __cpp_lib_concepts < 202207L +# error "Feature-test macro __cpp_lib_concepts has wrong value in <compare>" +#endif + +struct MoveOnly +{ + MoveOnly(int); + MoveOnly(MoveOnly&&) = default; + auto operator<=>(const MoveOnly&) const = default; + std::strong_ordering operator<=>(int) const; + bool operator==(const MoveOnly&) const; +}; + +static_assert(std::equality_comparable_with<MoveOnly, int>); +static_assert(std::totally_ordered_with<MoveOnly, int>); +static_assert(std::three_way_comparable_with<MoveOnly, int>); |
